@@ -272,22 +272,20 @@ public function specifyTypesInCondition(
272272 ) {
273273 $ argType = $ scope ->getType ($ expr ->right ->getArgs ()[0 ]->value );
274274
275- if ($ argType instanceof UnionType) {
276- $ sizeType = null ;
277- if ($ leftType instanceof ConstantIntegerType) {
278- if ($ orEqual ) {
279- $ sizeType = IntegerRangeType::createAllGreaterThanOrEqualTo ($ leftType ->getValue ());
280- } else {
281- $ sizeType = IntegerRangeType::createAllGreaterThan ($ leftType ->getValue ());
282- }
283- } elseif ($ leftType instanceof IntegerRangeType) {
284- $ sizeType = $ leftType ;
275+ $ sizeType = null ;
276+ if ($ leftType instanceof ConstantIntegerType) {
277+ if ($ orEqual ) {
278+ $ sizeType = IntegerRangeType::createAllGreaterThanOrEqualTo ($ leftType ->getValue ());
279+ } else {
280+ $ sizeType = IntegerRangeType::createAllGreaterThan ($ leftType ->getValue ());
285281 }
282+ } elseif ($ leftType instanceof IntegerRangeType) {
283+ $ sizeType = $ leftType ;
284+ }
286285
287- $ narrowed = $ this ->narrowUnionByArraySize ($ expr ->right , $ argType , $ sizeType , $ context , $ scope , $ expr );
288- if ($ narrowed !== null ) {
289- return $ narrowed ;
290- }
286+ $ specifiedTypes = $ this ->specifyTypesForCountFuncCall ($ expr ->right , $ argType , $ sizeType , $ context , $ scope , $ expr );
287+ if ($ specifiedTypes !== null ) {
288+ $ result = $ result ->unionWith ($ specifiedTypes );
291289 }
292290
293291 if (
@@ -1046,66 +1044,52 @@ public function specifyTypesInCondition(
10461044 return (new SpecifiedTypes ([], []))->setRootExpr ($ expr );
10471045 }
10481046
1049- private function narrowUnionByArraySize (FuncCall $ countFuncCall , UnionType $ argType , ?Type $ sizeType , TypeSpecifierContext $ context , Scope $ scope , ?Expr $ rootExpr ): ?SpecifiedTypes
1047+ private function specifyTypesForCountFuncCall (FuncCall $ countFuncCall , Type $ type , ?Type $ sizeType , TypeSpecifierContext $ context , Scope $ scope , ?Expr $ rootExpr ): ?SpecifiedTypes
10501048 {
10511049 if ($ sizeType === null ) {
10521050 return null ;
10531051 }
10541052
1055- if (count ($ countFuncCall ->getArgs ()) === 1 ) {
1056- $ isNormalCount = TrinaryLogic::createYes ();
1057- } else {
1058- $ mode = $ scope ->getType ($ countFuncCall ->getArgs ()[1 ]->value );
1059- $ isNormalCount = (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->result ->or ($ argType ->getIterableValueType ()->isArray ()->negate ());
1060- }
1061-
10621053 if (
1063- $ isNormalCount ->yes ()
1064- && $ argType ->isConstantArray ()->yes ()
1054+ $ this -> isFuncCallWithNormalCount ( $ countFuncCall , $ scope ) ->yes ()
1055+ && $ type ->isConstantArray ()->yes ()
10651056 ) {
1066- $ result = [];
1067- foreach ($ argType ->getTypes () as $ innerType ) {
1068- $ arraySize = $ innerType ->getArraySize ();
1057+ $ resultType = TypeTraverser::map ($ type , function (Type $ type , callable $ traverse ) use ($ sizeType , $ context ) {
1058+ if ($ type instanceof UnionType) {
1059+ return $ traverse ($ type );
1060+ }
1061+
1062+ $ arraySize = $ type ->getArraySize ();
10691063 $ isSize = $ sizeType ->isSuperTypeOf ($ arraySize );
10701064 if ($ context ->truthy ()) {
10711065 if ($ isSize ->no ()) {
1072- continue ;
1066+ return new NeverType () ;
10731067 }
10741068
1075- $ constArray = $ this ->turnListIntoConstantArray ($ countFuncCall , $ innerType , $ sizeType, $ scope );
1069+ $ constArray = $ this ->turnListIntoConstantArray ($ type , $ sizeType );
10761070 if ($ constArray !== null ) {
1077- $ innerType = $ constArray ;
1071+ $ type = $ constArray ;
10781072 }
10791073 }
10801074 if ($ context ->falsey ()) {
10811075 if (!$ isSize ->yes ()) {
1082- continue ;
1076+ return new NeverType () ;
10831077 }
10841078 }
10851079
1086- $ result [] = $ innerType ;
1087- }
1080+ return $ type ;
1081+ });
10881082
1089- return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , TypeCombinator:: union (... $ result ) , $ context , $ scope )->setRootExpr ($ rootExpr );
1083+ return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , $ resultType , $ context , $ scope )->setRootExpr ($ rootExpr );
10901084 }
10911085
10921086 return null ;
10931087 }
10941088
1095- private function turnListIntoConstantArray (FuncCall $ countFuncCall , Type $ type , Type $ sizeType, Scope $ scope ): ?Type
1089+ private function turnListIntoConstantArray (Type $ type , Type $ sizeType ): ?Type
10961090 {
1097- $ argType = $ scope ->getType ($ countFuncCall ->getArgs ()[0 ]->value );
1098-
1099- if (count ($ countFuncCall ->getArgs ()) === 1 ) {
1100- $ isNormalCount = TrinaryLogic::createYes ();
1101- } else {
1102- $ mode = $ scope ->getType ($ countFuncCall ->getArgs ()[1 ]->value );
1103- $ isNormalCount = (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->result ->or ($ argType ->getIterableValueType ()->isArray ()->negate ());
1104- }
1105-
11061091 if (
1107- $ isNormalCount ->yes ()
1108- && $ type ->isList ()->yes ()
1092+ $ type ->isList ()->yes ()
11091093 && $ sizeType instanceof ConstantIntegerType
11101094 && $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
11111095 ) {
@@ -1119,8 +1103,7 @@ private function turnListIntoConstantArray(FuncCall $countFuncCall, Type $type,
11191103 }
11201104
11211105 if (
1122- $ isNormalCount ->yes ()
1123- && $ type ->isList ()->yes ()
1106+ $ type ->isList ()->yes ()
11241107 && $ sizeType instanceof IntegerRangeType
11251108 && $ sizeType ->getMin () !== null
11261109 ) {
@@ -1157,6 +1140,18 @@ private function turnListIntoConstantArray(FuncCall $countFuncCall, Type $type,
11571140 return null ;
11581141 }
11591142
1143+ private function isFuncCallWithNormalCount (FuncCall $ countFuncCall , Scope $ scope ): TrinaryLogic
1144+ {
1145+ $ argType = $ scope ->getType ($ countFuncCall ->getArgs ()[0 ]->value );
1146+
1147+ if (count ($ countFuncCall ->getArgs ()) === 1 ) {
1148+ return TrinaryLogic::createYes ();
1149+ }
1150+ $ mode = $ scope ->getType ($ countFuncCall ->getArgs ()[1 ]->value );
1151+
1152+ return (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->result ->or ($ argType ->getIterableValueType ()->isArray ()->negate ());
1153+ }
1154+
11601155 private function specifyTypesForConstantBinaryExpression (
11611156 Expr $ exprNode ,
11621157 Type $ constantType ,
@@ -2186,11 +2181,9 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
21862181 );
21872182 }
21882183
2189- if ($ argType instanceof UnionType) {
2190- $ narrowed = $ this ->narrowUnionByArraySize ($ unwrappedLeftExpr , $ argType , $ rightType , $ context , $ scope , $ expr );
2191- if ($ narrowed !== null ) {
2192- return $ narrowed ;
2193- }
2184+ $ specifiedTypes = $ this ->specifyTypesForCountFuncCall ($ unwrappedLeftExpr , $ argType , $ rightType , $ context , $ scope , $ expr );
2185+ if ($ specifiedTypes !== null ) {
2186+ return $ specifiedTypes ;
21942187 }
21952188
21962189 if ($ context ->truthy ()) {
@@ -2203,7 +2196,8 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
22032196 }
22042197
22052198 $ funcTypes = $ this ->create ($ unwrappedLeftExpr , $ rightType , $ context , $ scope )->setRootExpr ($ expr );
2206- $ constArray = $ this ->turnListIntoConstantArray ($ unwrappedLeftExpr , $ argType , $ rightType , $ scope );
2199+ $ isNormalCount = $ this ->isFuncCallWithNormalCount ($ unwrappedLeftExpr , $ scope );
2200+ $ constArray = $ isNormalCount ->yes () ? $ this ->turnListIntoConstantArray ($ argType , $ rightType ) : null ;
22072201 if ($ constArray !== null ) {
22082202 return $ funcTypes ->unionWith (
22092203 $ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , $ constArray , $ context , $ scope )->setRootExpr ($ expr ),
0 commit comments