@@ -1065,71 +1065,74 @@ private function specifyTypesForCountFuncCall(
10651065 return null ;
10661066 }
10671067
1068- $ resultType = TypeTraverser::map ($ type , static function (Type $ type , callable $ traverse ) use ($ sizeType , $ context ) {
1069- if ($ type instanceof UnionType) {
1070- return $ traverse ($ type );
1071- }
1072-
1073- $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ type ->getArraySize ());
1068+ $ resultTypes = [];
1069+ $ innerTypes = $ type instanceof UnionType ? $ type ->getTypes () : [$ type ];
1070+ foreach ($ innerTypes as $ innerType ) {
1071+ $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ innerType ->getArraySize ());
10741072 if ($ isSizeSuperTypeOfArraySize ->no ()) {
1075- return new NeverType () ;
1073+ continue ;
10761074 }
10771075 if ($ context ->falsey () && $ isSizeSuperTypeOfArraySize ->maybe ()) {
1078- return new NeverType () ;
1076+ continue ;
10791077 }
10801078
1081- if ($ type ->isList ()->yes ()) {
1082- if (
1083- $ sizeType instanceof ConstantIntegerType
1084- && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1085- ) {
1086- // turn optional offsets non-optional
1087- $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1088- for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1089- $ offsetType = new ConstantIntegerType ($ i );
1090- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1091- }
1092- return $ valueTypesBuilder ->getArray ();
1079+ if (
1080+ $ innerType ->isList ()->yes ()
1081+ && $ sizeType instanceof ConstantIntegerType
1082+ && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1083+ ) {
1084+ // turn optional offsets non-optional
1085+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1086+ for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1087+ $ offsetType = new ConstantIntegerType ($ i );
1088+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
10931089 }
1090+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1091+ continue ;
1092+ }
10941093
1095- if (
1096- $ sizeType instanceof IntegerRangeType
1097- && $ sizeType ->getMin () !== null
1098- ) {
1099- // turn optional offsets non-optional
1100- $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1101- for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1094+ if (
1095+ $ innerType ->isList ()->yes ()
1096+ && $ sizeType instanceof IntegerRangeType
1097+ && $ sizeType ->getMin () !== null
1098+ ) {
1099+ // turn optional offsets non-optional
1100+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1101+ for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1102+ $ offsetType = new ConstantIntegerType ($ i );
1103+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
1104+ }
1105+ if ($ sizeType ->getMax () !== null ) {
1106+ for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
11021107 $ offsetType = new ConstantIntegerType ($ i );
1103- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1108+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), true );
11041109 }
1105- if ($ sizeType ->getMax () !== null ) {
1106- for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
1107- $ offsetType = new ConstantIntegerType ($ i );
1108- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), true );
1109- }
1110- } elseif ($ type ->isConstantArray ()->yes ()) {
1111- for ($ i = $ sizeType ->getMin ();; $ i ++) {
1112- $ offsetType = new ConstantIntegerType ($ i );
1113- $ hasOffset = $ type ->hasOffsetValueType ($ offsetType );
1114- if ($ hasOffset ->no ()) {
1115- break ;
1116- }
1117- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
1110+ } elseif ($ innerType ->isConstantArray ()->yes ()) {
1111+ for ($ i = $ sizeType ->getMin ();; $ i ++) {
1112+ $ offsetType = new ConstantIntegerType ($ i );
1113+ $ hasOffset = $ innerType ->hasOffsetValueType ($ offsetType );
1114+ if ($ hasOffset ->no ()) {
1115+ break ;
11181116 }
1119- } else {
1120- return TypeCombinator::intersect ($ type , new NonEmptyArrayType ());
1117+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
11211118 }
1122-
1123- return $ valueTypesBuilder ->getArray ();
1119+ } else {
1120+ $ resultTypes [] = TypeCombinator::intersect ($ innerType , new NonEmptyArrayType ());
1121+ continue ;
11241122 }
11251123
1126- return $ context ->truthy () ? $ type : new NeverType ();
1124+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1125+ continue ;
11271126 }
11281127
1129- return $ context ->truthy () ? TypeCombinator::intersect ($ type , new NonEmptyArrayType ()) : new NeverType ();
1130- });
1128+ if (!$ context ->truthy ()) {
1129+ continue ;
1130+ }
1131+
1132+ $ resultTypes [] = $ innerType ;
1133+ }
11311134
1132- return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , $ resultType , $ context , $ scope )->setRootExpr ($ rootExpr );
1135+ return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , TypeCombinator:: union (... $ resultTypes ) , $ context , $ scope )->setRootExpr ($ rootExpr );
11331136 }
11341137
11351138 private function specifyTypesForConstantBinaryExpression (
0 commit comments