@@ -277,22 +277,20 @@ public function specifyTypesInCondition(
277277) {
278278$ argType = $ scope ->getType ($ expr ->right ->getArgs ()[0 ]->value );
279279
280- if ($ argType instanceof UnionType) {
281- $ sizeType = null ;
282- if ($ leftType instanceof ConstantIntegerType) {
283- if ($ orEqual ) {
284- $ sizeType = IntegerRangeType::createAllGreaterThanOrEqualTo ($ leftType ->getValue ());
285- } else {
286- $ sizeType = IntegerRangeType::createAllGreaterThan ($ leftType ->getValue ());
287- }
288- } elseif ($ leftType instanceof IntegerRangeType) {
289- $ sizeType = $ leftType ;
280+ $ sizeType = null ;
281+ if ($ leftType instanceof ConstantIntegerType) {
282+ if ($ orEqual ) {
283+ $ sizeType = IntegerRangeType::createAllGreaterThanOrEqualTo ($ leftType ->getValue ());
284+ } else {
285+ $ sizeType = IntegerRangeType::createAllGreaterThan ($ leftType ->getValue ());
290286}
287+ } elseif ($ leftType instanceof IntegerRangeType) {
288+ $ sizeType = $ leftType ;
289+ }
291290
292- $ narrowed = $ this ->narrowUnionByArraySize ($ expr ->right , $ argType , $ sizeType , $ context , $ scope , $ rootExpr );
293- if ($ narrowed !== null ) {
294- return $ narrowed ;
295- }
291+ $ specifiedTypes = $ this ->specifyTypesForCountFuncCall ($ expr ->right , $ argType , $ sizeType , $ context , $ scope , $ rootExpr );
292+ if ($ specifiedTypes !== null ) {
293+ $ result = $ result ->unionWith ($ specifiedTypes );
296294}
297295
298296if (
@@ -1010,66 +1008,52 @@ public function specifyTypesInCondition(
10101008return new SpecifiedTypes ([], [], false , [], $ rootExpr );
10111009}
10121010
1013- private function narrowUnionByArraySize (FuncCall $ countFuncCall , UnionType $ argType , ?Type $ sizeType , TypeSpecifierContext $ context , Scope $ scope , ?Expr $ rootExpr ): ?SpecifiedTypes
1011+ private function specifyTypesForCountFuncCall (FuncCall $ countFuncCall , Type $ type , ?Type $ sizeType , TypeSpecifierContext $ context , Scope $ scope , ?Expr $ rootExpr ): ?SpecifiedTypes
10141012{
10151013if ($ sizeType === null ) {
10161014return null ;
10171015}
10181016
1019- if (count ($ countFuncCall ->getArgs ()) === 1 ) {
1020- $ isNormalCount = TrinaryLogic::createYes ();
1021- } else {
1022- $ mode = $ scope ->getType ($ countFuncCall ->getArgs ()[1 ]->value );
1023- $ isNormalCount = (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->or ($ argType ->getIterableValueType ()->isArray ()->negate ());
1024- }
1025-
10261017if (
1027- $ isNormalCount ->yes ()
1028- && $ argType ->isConstantArray ()->yes ()
1018+ $ this -> isFuncCallWithNormalCount ( $ countFuncCall , $ scope ) ->yes ()
1019+ && $ type ->isConstantArray ()->yes ()
10291020) {
1030- $ result = [];
1031- foreach ($ argType ->getTypes () as $ innerType ) {
1032- $ arraySize = $ innerType ->getArraySize ();
1021+ $ resultType = TypeTraverser::map ($ type , function (Type $ type , callable $ traverse ) use ($ sizeType , $ context ) {
1022+ if ($ type instanceof UnionType) {
1023+ return $ traverse ($ type );
1024+ }
1025+
1026+ $ arraySize = $ type ->getArraySize ();
10331027$ isSize = $ sizeType ->isSuperTypeOf ($ arraySize );
10341028if ($ context ->truthy ()) {
10351029if ($ isSize ->no ()) {
1036- continue ;
1030+ return new NeverType () ;
10371031}
10381032
1039- $ constArray = $ this ->turnListIntoConstantArray ($ countFuncCall , $ innerType , $ sizeType, $ scope );
1033+ $ constArray = $ this ->turnListIntoConstantArray ($ type , $ sizeType );
10401034if ($ constArray !== null ) {
1041- $ innerType = $ constArray ;
1035+ $ type = $ constArray ;
10421036}
10431037}
10441038if ($ context ->falsey ()) {
10451039if (!$ isSize ->yes ()) {
1046- continue ;
1040+ return new NeverType () ;
10471041}
10481042}
10491043
1050- $ result [] = $ innerType ;
1051- }
1044+ return $ type ;
1045+ });
10521046
1053- return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , TypeCombinator:: union (... $ result ) , $ context , false , $ scope , $ rootExpr );
1047+ return $ this ->create ($ countFuncCall ->getArgs ()[0 ]->value , $ resultType , $ context , false , $ scope , $ rootExpr );
10541048}
10551049
10561050return null ;
10571051}
10581052
1059- private function turnListIntoConstantArray (FuncCall $ countFuncCall , Type $ type , Type $ sizeType, Scope $ scope ): ?Type
1053+ private function turnListIntoConstantArray (Type $ type , Type $ sizeType ): ?Type
10601054{
1061- $ argType = $ scope ->getType ($ countFuncCall ->getArgs ()[0 ]->value );
1062-
1063- if (count ($ countFuncCall ->getArgs ()) === 1 ) {
1064- $ isNormalCount = TrinaryLogic::createYes ();
1065- } else {
1066- $ mode = $ scope ->getType ($ countFuncCall ->getArgs ()[1 ]->value );
1067- $ isNormalCount = (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->or ($ argType ->getIterableValueType ()->isArray ()->negate ());
1068- }
1069-
10701055if (
1071- $ isNormalCount ->yes ()
1072- && $ type ->isList ()->yes ()
1056+ $ type ->isList ()->yes ()
10731057&& $ sizeType instanceof ConstantIntegerType
10741058&& $ sizeType ->getValue () < ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT
10751059) {
@@ -1083,8 +1067,7 @@ private function turnListIntoConstantArray(FuncCall $countFuncCall, Type $type,
10831067}
10841068
10851069if (
1086- $ isNormalCount ->yes ()
1087- && $ type ->isList ()->yes ()
1070+ $ type ->isList ()->yes ()
10881071&& $ sizeType instanceof IntegerRangeType
10891072&& $ sizeType ->getMin () !== null
10901073) {
@@ -1121,6 +1104,18 @@ private function turnListIntoConstantArray(FuncCall $countFuncCall, Type $type,
11211104return null ;
11221105}
11231106
1107+ private function isFuncCallWithNormalCount (FuncCall $ countFuncCall , Scope $ scope ): TrinaryLogic
1108+ {
1109+ $ argType = $ scope ->getType ($ countFuncCall ->getArgs ()[0 ]->value );
1110+
1111+ if (count ($ countFuncCall ->getArgs ()) === 1 ) {
1112+ return TrinaryLogic::createYes ();
1113+ }
1114+ $ mode = $ scope ->getType ($ countFuncCall ->getArgs ()[1 ]->value );
1115+
1116+ return (new ConstantIntegerType (COUNT_NORMAL ))->isSuperTypeOf ($ mode )->or ($ argType ->getIterableValueType ()->isArray ()->negate ());
1117+ }
1118+
11241119private function specifyTypesForConstantBinaryExpression (
11251120Expr $ exprNode ,
11261121Type $ constantType ,
@@ -2171,11 +2166,9 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
21712166);
21722167}
21732168
2174- if ($ argType instanceof UnionType) {
2175- $ narrowed = $ this ->narrowUnionByArraySize ($ unwrappedLeftExpr , $ argType , $ rightType , $ context , $ scope , $ rootExpr );
2176- if ($ narrowed !== null ) {
2177- return $ narrowed ;
2178- }
2169+ $ specifiedTypes = $ this ->specifyTypesForCountFuncCall ($ unwrappedLeftExpr , $ argType , $ rightType , $ context , $ scope , $ rootExpr );
2170+ if ($ specifiedTypes !== null ) {
2171+ return $ specifiedTypes ;
21792172}
21802173
21812174if ($ context ->truthy ()) {
@@ -2188,7 +2181,8 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty
21882181}
21892182
21902183$ funcTypes = $ this ->create ($ unwrappedLeftExpr , $ rightType , $ context , false , $ scope , $ rootExpr );
2191- $ constArray = $ this ->turnListIntoConstantArray ($ unwrappedLeftExpr , $ argType , $ rightType , $ scope );
2184+ $ isNormalCount = $ this ->isFuncCallWithNormalCount ($ unwrappedLeftExpr , $ scope );
2185+ $ constArray = $ isNormalCount ->yes () ? $ this ->turnListIntoConstantArray ($ argType , $ rightType ) : null ;
21922186if ($ constArray !== null ) {
21932187return $ funcTypes ->unionWith (
21942188$ this ->create ($ unwrappedLeftExpr ->getArgs ()[0 ]->value , $ constArray , $ context , false , $ scope , $ rootExpr ),
0 commit comments