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