@@ -991,71 +991,74 @@ private function specifyTypesForCountFuncCall(
991991 return null ;
992992 }
993993
994- $ resultType = TypeTraverser::map ($ type , static function (Type $ type , callable $ traverse ) use ($ sizeType , $ context ) {
995- if ($ type instanceof UnionType) {
996- return $ traverse ($ type );
997- }
998-
999- $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ type ->getArraySize ());
994+ $ resultTypes = [];
995+ $ innerTypes = $ type instanceof UnionType ? $ type ->getTypes () : [$ type ];
996+ foreach ($ innerTypes as $ innerType ) {
997+ $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ innerType ->getArraySize ());
1000998 if ($ isSizeSuperTypeOfArraySize ->no ()) {
1001- return new NeverType () ;
999+ continue ;
10021000 }
10031001 if ($ context ->falsey () && $ isSizeSuperTypeOfArraySize ->maybe ()) {
1004- return new NeverType () ;
1002+ continue ;
10051003 }
10061004
1007- if ($ type ->isList ()->yes ()) {
1008- if (
1009- $ sizeType instanceof ConstantIntegerType
1010- && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1011- ) {
1012- // turn optional offsets non-optional
1013- $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1014- for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1015- $ offsetType = new ConstantIntegerType ($ i );
1016- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1017- }
1018- return $ valueTypesBuilder ->getArray ();
1005+ if (
1006+ $ innerType ->isList ()->yes ()
1007+ && $ sizeType instanceof ConstantIntegerType
1008+ && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1009+ ) {
1010+ // turn optional offsets non-optional
1011+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1012+ for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1013+ $ offsetType = new ConstantIntegerType ($ i );
1014+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
10191015 }
1016+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1017+ continue ;
1018+ }
10201019
1021- if (
1022- $ sizeType instanceof IntegerRangeType
1023- && $ sizeType ->getMin () !== null
1024- ) {
1025- // turn optional offsets non-optional
1026- $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1027- for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1020+ if (
1021+ $ innerType ->isList ()->yes ()
1022+ && $ sizeType instanceof IntegerRangeType
1023+ && $ sizeType ->getMin () !== null
1024+ ) {
1025+ // turn optional offsets non-optional
1026+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1027+ for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1028+ $ offsetType = new ConstantIntegerType ($ i );
1029+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
1030+ }
1031+ if ($ sizeType ->getMax () !== null ) {
1032+ for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
10281033 $ offsetType = new ConstantIntegerType ($ i );
1029- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1034+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), true );
10301035 }
1031- if ($ sizeType ->getMax () !== null ) {
1032- for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
1033- $ offsetType = new ConstantIntegerType ($ i );
1034- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), true );
1035- }
1036- } elseif ($ type ->isConstantArray ()->yes ()) {
1037- for ($ i = $ sizeType ->getMin ();; $ i ++) {
1038- $ offsetType = new ConstantIntegerType ($ i );
1039- $ hasOffset = $ type ->hasOffsetValueType ($ offsetType );
1040- if ($ hasOffset ->no ()) {
1041- break ;
1042- }
1043- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
1036+ } elseif ($ innerType ->isConstantArray ()->yes ()) {
1037+ for ($ i = $ sizeType ->getMin ();; $ i ++) {
1038+ $ offsetType = new ConstantIntegerType ($ i );
1039+ $ hasOffset = $ innerType ->hasOffsetValueType ($ offsetType );
1040+ if ($ hasOffset ->no ()) {
1041+ break ;
10441042 }
1045- } else {
1046- return TypeCombinator::intersect ($ type , new NonEmptyArrayType ());
1043+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
10471044 }
1048-
1049- return $ valueTypesBuilder ->getArray ();
1045+ } else {
1046+ $ resultTypes [] = TypeCombinator::intersect ($ innerType , new NonEmptyArrayType ());
1047+ continue ;
10501048 }
10511049
1052- return $ context ->truthy () ? $ type : new NeverType ();
1050+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1051+ continue ;
10531052 }
10541053
1055- return $ context ->truthy () ? TypeCombinator::intersect ($ type , new NonEmptyArrayType ()) : new NeverType ();
1056- });
1054+ if (!$ context ->truthy ()) {
1055+ continue ;
1056+ }
1057+
1058+ $ resultTypes [] = $ innerType ;
1059+ }
10571060
1058- return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , $ resultType , $ context , $ scope )->setRootExpr ($ rootExpr );
1061+ return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , TypeCombinator:: union (... $ resultTypes ) , $ context , $ scope )->setRootExpr ($ rootExpr );
10591062 }
10601063
10611064 private function specifyTypesForConstantBinaryExpression (
0 commit comments