@@ -988,71 +988,75 @@ private function specifyTypesForCountFuncCall(
988988 return null ;
989989 }
990990
991- $ resultType = TypeTraverser::map ($ type , static function (Type $ type , callable $ traverse ) use ($ sizeType , $ context ) {
992- if ($ type instanceof UnionType) {
993- return $ traverse ($ type );
994- }
995-
996- $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ type ->getArraySize ());
997- if ($ isSizeSuperTypeOfArraySize ->no ()) {
998- return new NeverType ();
991+ $ resultTypes = [];
992+ $ innerTypes = $ type instanceof UnionType ? $ type ->getTypes () : [$ type ];
993+ foreach ($ innerTypes as $ innerType ) {
994+ $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ innerType ->getArraySize ());
995+ if ($ context ->truthy () && $ isSizeSuperTypeOfArraySize ->no ()) {
996+ $ resultTypes [] = new ConstantArrayType ([], []);
997+ continue ;
999998 }
1000- if ($ context ->falsey () && $ isSizeSuperTypeOfArraySize ->maybe ()) {
1001- return new NeverType () ;
999+ if ($ context ->falsey () && ! $ isSizeSuperTypeOfArraySize ->yes ()) {
1000+ continue ;
10021001 }
10031002
1004- if ($ type ->isList ()->yes ()) {
1005- if (
1006- $ sizeType instanceof ConstantIntegerType
1007- && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1008- ) {
1009- // turn optional offsets non-optional
1010- $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1011- for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1012- $ offsetType = new ConstantIntegerType ($ i );
1013- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1014- }
1015- return $ valueTypesBuilder ->getArray ();
1003+ if (
1004+ $ innerType ->isList ()->yes ()
1005+ && $ sizeType instanceof ConstantIntegerType
1006+ && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1007+ ) {
1008+ // turn optional offsets non-optional
1009+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1010+ for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1011+ $ offsetType = new ConstantIntegerType ($ i );
1012+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
10161013 }
1014+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1015+ continue ;
1016+ }
10171017
1018- if (
1019- $ sizeType instanceof IntegerRangeType
1020- && $ sizeType ->getMin () !== null
1021- ) {
1022- // turn optional offsets non-optional
1023- $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1024- for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1018+ if (
1019+ $ innerType ->isList ()->yes ()
1020+ && $ sizeType instanceof IntegerRangeType
1021+ && $ sizeType ->getMin () !== null
1022+ ) {
1023+ // turn optional offsets non-optional
1024+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1025+ for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1026+ $ offsetType = new ConstantIntegerType ($ i );
1027+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
1028+ }
1029+ if ($ sizeType ->getMax () !== null ) {
1030+ for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
10251031 $ offsetType = new ConstantIntegerType ($ i );
1026- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1032+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), true );
10271033 }
1028- if ($ sizeType ->getMax () !== null ) {
1029- for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
1030- $ offsetType = new ConstantIntegerType ($ i );
1031- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), true );
1032- }
1033- } elseif ($ type ->isConstantArray ()->yes ()) {
1034- for ($ i = $ sizeType ->getMin ();; $ i ++) {
1035- $ offsetType = new ConstantIntegerType ($ i );
1036- $ hasOffset = $ type ->hasOffsetValueType ($ offsetType );
1037- if ($ hasOffset ->no ()) {
1038- break ;
1039- }
1040- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
1034+ } elseif ($ innerType ->isConstantArray ()->yes ()) {
1035+ for ($ i = $ sizeType ->getMin ();; $ i ++) {
1036+ $ offsetType = new ConstantIntegerType ($ i );
1037+ $ hasOffset = $ innerType ->hasOffsetValueType ($ offsetType );
1038+ if ($ hasOffset ->no ()) {
1039+ break ;
10411040 }
1042- } else {
1043- return TypeCombinator::intersect ($ type , new NonEmptyArrayType ());
1041+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
10441042 }
1045-
1046- return $ valueTypesBuilder ->getArray ();
1043+ } else {
1044+ $ resultTypes [] = TypeCombinator::intersect ($ innerType , new NonEmptyArrayType ());
1045+ continue ;
10471046 }
10481047
1049- return $ context ->truthy () ? $ type : new NeverType ();
1048+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1049+ continue ;
10501050 }
10511051
1052- return $ context ->truthy () ? TypeCombinator::intersect ($ type , new NonEmptyArrayType ()) : new NeverType ();
1053- });
1052+ if (!$ context ->truthy ()) {
1053+ continue ;
1054+ }
1055+
1056+ $ resultTypes [] = $ innerType ;
1057+ }
10541058
1055- return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , $ resultType , $ context , $ scope )->setRootExpr ($ rootExpr );
1059+ return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , TypeCombinator:: union (... $ resultTypes ) , $ context , $ scope )->setRootExpr ($ rootExpr );
10561060 }
10571061
10581062 private function specifyTypesForConstantBinaryExpression (
0 commit comments