@@ -988,71 +988,75 @@ private function specifyTypesForCountFuncCall(
988
988
return null ;
989
989
}
990
990
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 ;
999
998
}
1000
- if ($ context ->falsey () && $ isSizeSuperTypeOfArraySize ->maybe ()) {
1001
- return new NeverType () ;
999
+ if ($ context ->falsey () && ! $ isSizeSuperTypeOfArraySize ->yes ()) {
1000
+ continue ;
1002
1001
}
1003
1002
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 ));
1016
1013
}
1014
+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1015
+ continue ;
1016
+ }
1017
1017
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 ++) {
1025
1031
$ offsetType = new ConstantIntegerType ($ i );
1026
- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1032
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), true );
1027
1033
}
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 ;
1041
1040
}
1042
- } else {
1043
- return TypeCombinator::intersect ($ type , new NonEmptyArrayType ());
1041
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
1044
1042
}
1045
-
1046
- return $ valueTypesBuilder ->getArray ();
1043
+ } else {
1044
+ $ resultTypes [] = TypeCombinator::intersect ($ innerType , new NonEmptyArrayType ());
1045
+ continue ;
1047
1046
}
1048
1047
1049
- return $ context ->truthy () ? $ type : new NeverType ();
1048
+ $ resultTypes [] = $ valueTypesBuilder ->getArray ();
1049
+ continue ;
1050
1050
}
1051
1051
1052
- return $ context ->truthy () ? TypeCombinator::intersect ($ type , new NonEmptyArrayType ()) : new NeverType ();
1053
- });
1052
+ if (!$ context ->truthy ()) {
1053
+ continue ;
1054
+ }
1055
+
1056
+ $ resultTypes [] = $ innerType ;
1057
+ }
1054
1058
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 );
1056
1060
}
1057
1061
1058
1062
private function specifyTypesForConstantBinaryExpression (
0 commit comments