@@ -246,11 +246,16 @@ public function specifyTypesInCondition(
246
246
) {
247
247
$ argType = $ scope ->getType ($ expr ->right ->getArgs ()[0 ]->value );
248
248
249
- if ($ argType instanceof UnionType && $ leftType instanceof ConstantIntegerType) {
250
- if ($ orEqual ) {
251
- $ sizeType = IntegerRangeType::createAllGreaterThanOrEqualTo ($ leftType ->getValue ());
252
- } else {
253
- $ sizeType = IntegerRangeType::createAllGreaterThan ($ leftType ->getValue ());
249
+ if ($ argType instanceof UnionType) {
250
+ $ sizeType = null ;
251
+ if ($ leftType instanceof ConstantIntegerType) {
252
+ if ($ orEqual ) {
253
+ $ sizeType = IntegerRangeType::createAllGreaterThanOrEqualTo ($ leftType ->getValue ());
254
+ } else {
255
+ $ sizeType = IntegerRangeType::createAllGreaterThan ($ leftType ->getValue ());
256
+ }
257
+ } elseif ($ leftType instanceof IntegerRangeType) {
258
+ $ sizeType = $ leftType ;
254
259
}
255
260
256
261
$ narrowed = $ this ->narrowUnionByArraySize ($ expr ->right , $ argType , $ sizeType , $ context , $ scope , $ rootExpr );
@@ -949,8 +954,12 @@ public function specifyTypesInCondition(
949
954
return new SpecifiedTypes ([], [], false , [], $ rootExpr );
950
955
}
951
956
952
- private function narrowUnionByArraySize (FuncCall $ countFuncCall , UnionType $ argType , Type $ sizeType , TypeSpecifierContext $ context , Scope $ scope , ?Expr $ rootExpr ): ?SpecifiedTypes
957
+ private function narrowUnionByArraySize (FuncCall $ countFuncCall , UnionType $ argType , ? Type $ sizeType , TypeSpecifierContext $ context , Scope $ scope , ?Expr $ rootExpr ): ?SpecifiedTypes
953
958
{
959
+ if ($ sizeType === null ) {
960
+ return null ;
961
+ }
962
+
954
963
if (count ($ countFuncCall ->getArgs ()) === 1 ) {
955
964
$ isNormalCount = TrinaryLogic::createYes ();
956
965
} else {
@@ -971,7 +980,7 @@ private function narrowUnionByArraySize(FuncCall $countFuncCall, UnionType $argT
971
980
continue ;
972
981
}
973
982
974
- $ constArray = $ this ->turnListIntoConstantArray ($ countFuncCall , $ innerType , $ sizeType , $ scope );
983
+ $ constArray = $ this ->turnListIntoConstantArray ($ countFuncCall , $ innerType , $ sizeType , $ context , $ scope );
975
984
if ($ constArray !== null ) {
976
985
$ innerType = $ constArray ;
977
986
}
@@ -991,7 +1000,7 @@ private function narrowUnionByArraySize(FuncCall $countFuncCall, UnionType $argT
991
1000
return null ;
992
1001
}
993
1002
994
- private function turnListIntoConstantArray (FuncCall $ countFuncCall , Type $ type , Type $ sizeType , Scope $ scope ): ?Type
1003
+ private function turnListIntoConstantArray (FuncCall $ countFuncCall , Type $ type , Type $ sizeType , TypeSpecifierContext $ context , Scope $ scope ): ?Type
995
1004
{
996
1005
$ argType = $ scope ->getType ($ countFuncCall ->getArgs ()[0 ]->value );
997
1006
@@ -1017,6 +1026,38 @@ private function turnListIntoConstantArray(FuncCall $countFuncCall, Type $type,
1017
1026
return $ valueTypesBuilder ->getArray ();
1018
1027
}
1019
1028
1029
+ if (
1030
+ $ context ->truthy ()
1031
+ && $ isNormalCount ->yes ()
1032
+ && $ type ->isList ()->yes ()
1033
+ && $ sizeType instanceof IntegerRangeType
1034
+ && $ sizeType ->getMin () !== null
1035
+ ) {
1036
+ // turn optional offsets non-optional
1037
+ $ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
1038
+ for ($ i = 0 ; $ i < $ sizeType ->getMin (); $ i ++) {
1039
+ $ offsetType = new ConstantIntegerType ($ i );
1040
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ));
1041
+ }
1042
+ if ($ sizeType ->getMax () !== null ) {
1043
+ for ($ i = $ sizeType ->getMin (); $ i < $ sizeType ->getMax (); $ i ++) {
1044
+ $ offsetType = new ConstantIntegerType ($ i );
1045
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), true );
1046
+ }
1047
+ } else {
1048
+ for ($ i = $ sizeType ->getMin ();; $ i ++) {
1049
+ $ offsetType = new ConstantIntegerType ($ i );
1050
+ $ hasOffset = $ type ->hasOffsetValueType ($ offsetType );
1051
+ if ($ hasOffset ->no ()) {
1052
+ break ;
1053
+ }
1054
+ $ valueTypesBuilder ->setOffsetValueType ($ offsetType , $ type ->getOffsetValueType ($ offsetType ), !$ hasOffset ->yes ());
1055
+ }
1056
+
1057
+ }
1058
+ return $ valueTypesBuilder ->getArray ();
1059
+ }
1060
+
1020
1061
return null ;
1021
1062
}
1022
1063
@@ -1093,7 +1134,7 @@ private function specifyTypesForConstantBinaryExpression(
1093
1134
}
1094
1135
1095
1136
$ funcTypes = $ this ->create ($ exprNode , $ constantType , $ context , false , $ scope , $ rootExpr );
1096
- $ constArray = $ this ->turnListIntoConstantArray ($ exprNode , $ argType , $ constantType , $ scope );
1137
+ $ constArray = $ this ->turnListIntoConstantArray ($ exprNode , $ argType , $ constantType , $ context , $ scope );
1097
1138
if ($ context ->truthy () && $ constArray !== null ) {
1098
1139
$ valueTypes = $ this ->create ($ exprNode ->getArgs ()[0 ]->value , $ constArray , $ context , false , $ scope , $ rootExpr );
1099
1140
} else {
0 commit comments