@@ -988,71 +988,74 @@ 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 ());
991+ $ resultTypes = [];
992+ $ innerTypes = $ type instanceof UnionType ? $ type ->getTypes () : [$ type ];
993+ foreach ($ innerTypes as $ innerType ) {
994+ $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ innerType ->getArraySize ());
997995 if ($ isSizeSuperTypeOfArraySize ->no ()) {
998- return new NeverType () ;
996+ continue ;
999997 }
1000998 if ($ context ->falsey () && $ isSizeSuperTypeOfArraySize ->maybe ()) {
1001- return new NeverType () ;
999+ continue ;
10021000 }
10031001
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 ();
1002+ if (
1003+ $ innerType ->isList ()->yes ()
1004+ && $ sizeType instanceof ConstantIntegerType
1005+ && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1006+ ) {
1007+ // turn optional offsets non-optional
1008+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1009+ for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1010+ $ offsetType = new ConstantIntegerType ($ i );
1011+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
10161012 }
1013+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1014+ continue ;
1015+ }
10171016
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 ++) {
1017+ if (
1018+ $ innerType ->isList ()->yes ()
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 ++) {
1025+ $ offsetType = new ConstantIntegerType ($ i );
1026+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
1027+ }
1028+ if ($ sizeType ->getMax () !== null ) {
1029+ for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
10251030 $ offsetType = new ConstantIntegerType ($ i );
1026- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1031+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), true );
10271032 }
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 ());
1033+ } elseif ($ innerType ->isConstantArray ()->yes ()) {
1034+ for ($ i = $ sizeType ->getMin ();; $ i ++) {
1035+ $ offsetType = new ConstantIntegerType ($ i );
1036+ $ hasOffset = $ innerType ->hasOffsetValueType ($ offsetType );
1037+ if ($ hasOffset ->no ()) {
1038+ break ;
10411039 }
1042- } else {
1043- return TypeCombinator::intersect ($ type , new NonEmptyArrayType ());
1040+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
10441041 }
1045-
1046- return $ valueTypesBuilder ->getArray ();
1042+ } else {
1043+ $ resultTypes [] = TypeCombinator::intersect ($ innerType , new NonEmptyArrayType ());
1044+ continue ;
10471045 }
10481046
1049- return $ context ->truthy () ? $ type : new NeverType ();
1047+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1048+ continue ;
10501049 }
10511050
1052- return $ context ->truthy () ? TypeCombinator::intersect ($ type , new NonEmptyArrayType ()) : new NeverType ();
1053- });
1051+ if (!$ context ->truthy ()) {
1052+ continue ;
1053+ }
1054+
1055+ $ resultTypes [] = $ innerType ;
1056+ }
10541057
1055- return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , $ resultType , $ context , $ scope )->setRootExpr ($ rootExpr );
1058+ return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , TypeCombinator:: union (... $ resultTypes ) , $ context , $ scope )->setRootExpr ($ rootExpr );
10561059 }
10571060
10581061 private function specifyTypesForConstantBinaryExpression (
0 commit comments