@@ -987,75 +987,76 @@ private function specifyTypesForCountFuncCall(
987
987
$ isNormalCount = (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->result ->or ($ type ->getIterableValueType ()->isArray ()->negate ());
988
988
}
989
989
990
- if (!$ isNormalCount ->yes () || (!$ type ->isConstantArray ()->yes () && !$ type ->isList ()->yes ())) {
990
+ $ isList = $ type ->isList ();
991
+ if (
992
+ !$ isNormalCount ->yes ()
993
+ || (!$ type ->isConstantArray ()->yes () && !$ isList ->yes ())
994
+ || $ type ->isIterableAtLeastOnce ()->no () // array{} cannot be used for further narrowing
995
+ ) {
991
996
return null ;
992
997
}
993
998
994
999
$ resultTypes = [];
995
- $ innerTypes = $ type instanceof UnionType ? $ type ->getTypes () : [$ type ];
996
- foreach ($ innerTypes as $ innerType ) {
997
- $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ innerType ->getArraySize ());
1000
+ foreach ($ type ->getArrays () as $ arrayType ) {
1001
+ $ isSizeSuperTypeOfArraySize = $ sizeType ->isSuperTypeOf ($ arrayType ->getArraySize ());
998
1002
if ($ isSizeSuperTypeOfArraySize ->no ()) {
999
1003
continue ;
1000
1004
}
1005
+
1001
1006
if ($ context ->falsey () && $ isSizeSuperTypeOfArraySize ->maybe ()) {
1002
1007
continue ;
1003
1008
}
1004
1009
1005
1010
if (
1006
- $ innerType -> isList () ->yes ()
1011
+ $ isList ->yes ()
1007
1012
&& $ sizeType instanceof ConstantIntegerType
1008
1013
&& $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
1009
1014
) {
1010
1015
// turn optional offsets non-optional
1011
1016
$ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1012
1017
for ($ i = 0 ; $ i < $ sizeType ->getValue (); $ i ++) {
1013
1018
$ offsetType = new ConstantIntegerType ($ i );
1014
- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
1019
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ arrayType ->getOffsetValueType ($ offsetType ));
1015
1020
}
1016
1021
$ resultTypes [] = $ valueTypesBuilder ->getArray ();
1017
1022
continue ;
1018
1023
}
1019
1024
1020
1025
if (
1021
- $ innerType -> isList () ->yes ()
1026
+ $ isList ->yes ()
1022
1027
&& $ sizeType instanceof IntegerRangeType
1023
1028
&& $ sizeType ->getMin () !== null
1024
1029
) {
1025
1030
// turn optional offsets non-optional
1026
1031
$ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1027
1032
for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1028
1033
$ offsetType = new ConstantIntegerType ($ i );
1029
- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ));
1034
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ arrayType ->getOffsetValueType ($ offsetType ));
1030
1035
}
1031
1036
if ($ sizeType ->getMax () !== null ) {
1032
1037
for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
1033
1038
$ offsetType = new ConstantIntegerType ($ i );
1034
- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), true );
1039
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ arrayType ->getOffsetValueType ($ offsetType ), true );
1035
1040
}
1036
- } elseif ($ innerType ->isConstantArray ()->yes ()) {
1041
+ } elseif ($ arrayType ->isConstantArray ()->yes ()) {
1037
1042
for ($ i = $ sizeType ->getMin ();; $ i ++) {
1038
1043
$ offsetType = new ConstantIntegerType ($ i );
1039
- $ hasOffset = $ innerType ->hasOffsetValueType ($ offsetType );
1044
+ $ hasOffset = $ arrayType ->hasOffsetValueType ($ offsetType );
1040
1045
if ($ hasOffset ->no ()) {
1041
1046
break ;
1042
1047
}
1043
- $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ innerType ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
1048
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ arrayType ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
1044
1049
}
1045
1050
} else {
1046
- $ resultTypes [] = TypeCombinator::intersect ($ innerType , new NonEmptyArrayType ());
1051
+ $ resultTypes [] = TypeCombinator::intersect ($ arrayType , new NonEmptyArrayType ());
1047
1052
continue ;
1048
1053
}
1049
1054
1050
1055
$ resultTypes [] = $ valueTypesBuilder ->getArray ();
1051
1056
continue ;
1052
1057
}
1053
1058
1054
- if (!$ context ->truthy ()) {
1055
- continue ;
1056
- }
1057
-
1058
- $ resultTypes [] = $ innerType ;
1059
+ $ resultTypes [] = $ arrayType ;
1059
1060
}
1060
1061
1061
1062
return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , TypeCombinator::union (...$ resultTypes ), $ context , $ scope )->setRootExpr ($ rootExpr );
0 commit comments