@@ -244,12 +244,25 @@ public function specifyTypesInCondition(
244
244
&& in_array (strtolower ((string ) $ expr ->right ->name ), ['count ' , 'sizeof ' ], true )
245
245
&& $ leftType ->isInteger ()->yes ()
246
246
) {
247
+ $ argType = $ scope ->getType ($ expr ->right ->getArgs ()[0 ]->value );
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 ());
254
+ }
255
+
256
+ $ narrowed = $ this ->narrowUnionByArraySize ($ expr ->right , $ argType , $ sizeType , $ context , $ scope , $ rootExpr );
257
+ if ($ narrowed !== null ) {
258
+ return $ narrowed ;
259
+ }
260
+ }
261
+
247
262
if (
248
263
$ context ->true () && (IntegerRangeType::createAllGreaterThanOrEqualTo (1 - $ offset )->isSuperTypeOf ($ leftType )->yes ())
249
264
|| ($ context ->false () && (new ConstantIntegerType (1 - $ offset ))->isSuperTypeOf ($ leftType )->yes ())
250
265
) {
251
- $ argType = $ scope ->getType ($ expr ->right ->getArgs ()[0 ]->value );
252
-
253
266
if ($ context ->truthy () && $ argType ->isArray ()->maybe ()) {
254
267
$ countables = [];
255
268
if ($ argType instanceof UnionType) {
@@ -936,6 +949,43 @@ public function specifyTypesInCondition(
936
949
return new SpecifiedTypes ([], [], false , [], $ rootExpr );
937
950
}
938
951
952
+ private function narrowUnionByArraySize (FuncCall $ countFuncCall , UnionType $ argType , Type $ sizeType , TypeSpecifierContext $ context , Scope $ scope , ?Expr $ rootExpr ): ?SpecifiedTypes
953
+ {
954
+ if (count ($ countFuncCall ->getArgs ()) === 1 ) {
955
+ $ isNormalCount = TrinaryLogic::createYes ();
956
+ } else {
957
+ $ mode = $ scope ->getType ($ countFuncCall ->getArgs ()[1 ]->value );
958
+ $ isNormalCount = (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->or ($ argType ->getIterableValueType ()->isArray ()->negate ());
959
+ }
960
+
961
+ if (
962
+ $ isNormalCount ->yes ()
963
+ && $ argType ->isConstantArray ()->yes ()
964
+ ) {
965
+ $ result = [];
966
+ foreach ($ argType ->getTypes () as $ innerType ) {
967
+ $ arraySize = $ innerType ->getArraySize ();
968
+ $ isSize = $ sizeType ->isSuperTypeOf ($ arraySize );
969
+ if ($ context ->truthy ()) {
970
+ if ($ isSize ->no ()) {
971
+ continue ;
972
+ }
973
+ }
974
+ if ($ context ->falsey ()) {
975
+ if (!$ isSize ->yes ()) {
976
+ continue ;
977
+ }
978
+ }
979
+
980
+ $ result [] = $ innerType ;
981
+ }
982
+
983
+ return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , TypeCombinator::union (...$ result ), $ context , false , $ scope , $ rootExpr );
984
+ }
985
+
986
+ return null ;
987
+ }
988
+
939
989
private function specifyTypesForConstantBinaryExpression (
940
990
Expr $ exprNode ,
941
991
ConstantScalarType $ constantType ,
@@ -986,36 +1036,11 @@ private function specifyTypesForConstantBinaryExpression(
986
1036
) {
987
1037
$ argType = $ scope ->getType ($ exprNode ->getArgs ()[0 ]->value );
988
1038
989
- if (count ($ exprNode ->getArgs ()) === 1 ) {
990
- $ isNormalCount = TrinaryLogic::createYes ();
991
- } else {
992
- $ mode = $ scope ->getType ($ exprNode ->getArgs ()[1 ]->value );
993
- $ isNormalCount = (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->or ($ argType ->getIterableValueType ()->isArray ()->negate ());
994
- }
995
-
996
- if (
997
- $ isNormalCount ->yes ()
998
- && $ argType instanceof UnionType
999
- ) {
1000
- $ result = [];
1001
- foreach ($ argType ->getTypes () as $ innerType ) {
1002
- $ arraySize = $ innerType ->getArraySize ();
1003
- $ isSize = $ constantType ->isSuperTypeOf ($ arraySize );
1004
- if ($ context ->truthy ()) {
1005
- if ($ isSize ->no ()) {
1006
- continue ;
1007
- }
1008
- }
1009
- if ($ context ->falsey ()) {
1010
- if (!$ isSize ->yes ()) {
1011
- continue ;
1012
- }
1013
- }
1014
-
1015
- $ result [] = $ innerType ;
1039
+ if ($ argType instanceof UnionType) {
1040
+ $ narrowed = $ this ->narrowUnionByArraySize ($ exprNode , $ argType , $ constantType , $ context , $ scope , $ rootExpr );
1041
+ if ($ narrowed !== null ) {
1042
+ return $ narrowed ;
1016
1043
}
1017
-
1018
- return $ this ->create ($ exprNode ->getArgs ()[0 ]->value , TypeCombinator::union (...$ result ), $ context , false , $ scope , $ rootExpr );
1019
1044
}
1020
1045
1021
1046
if ($ context ->truthy () || $ constantType ->getValue () === 0 ) {
@@ -1025,6 +1050,13 @@ private function specifyTypesForConstantBinaryExpression(
1025
1050
}
1026
1051
1027
1052
if ($ argType ->isArray ()->yes ()) {
1053
+ if (count ($ exprNode ->getArgs ()) === 1 ) {
1054
+ $ isNormalCount = TrinaryLogic::createYes ();
1055
+ } else {
1056
+ $ mode = $ scope ->getType ($ exprNode ->getArgs ()[1 ]->value );
1057
+ $ isNormalCount = (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->or ($ argType ->getIterableValueType ()->isArray ()->negate ());
1058
+ }
1059
+
1028
1060
$ funcTypes = $ this ->create ($ exprNode , $ constantType , $ context , false , $ scope , $ rootExpr );
1029
1061
if ($ isNormalCount ->yes () && $ argType ->isList ()->yes () && $ context ->truthy () && $ constantType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT ) {
1030
1062
$ valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty ();
0 commit comments