diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 8854f7c574..c11a6de87d 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1490,16 +1490,21 @@ private function resolveType(string $exprString, Expr $node): Type throw new ShouldNotHappenException(); } - $filteringExpr = null; - foreach ($arm->conds as $armCond) { - $armCondExpr = new BinaryOp\Identical($cond, $armCond); - - if ($filteringExpr === null) { - $filteringExpr = $armCondExpr; - continue; + if (count($arm->conds) === 1) { + $filteringExpr = new BinaryOp\Identical($cond, $arm->conds[0]); + } else { + $items = []; + foreach ($arm->conds as $filteringExpr) { + $items[] = new Expr\ArrayItem($filteringExpr); } - - $filteringExpr = new BinaryOp\BooleanOr($filteringExpr, $armCondExpr); + $filteringExpr = new FuncCall( + new Name\FullyQualified('in_array'), + [ + new Arg($cond), + new Arg(new Array_($items)), + new Arg(new ConstFetch(new Name\FullyQualified('true'))), + ], + ); } $filteringExprType = $matchScope->getType($filteringExpr); diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 99c91dd495..9ef1780a36 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -2849,7 +2849,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { throw new ShouldNotHappenException(); } - $filteringExpr = null; + $filteringExprs = []; $armCondScope = $matchScope; $condNodes = []; foreach ($arm->conds as $armCond) { @@ -2864,12 +2864,24 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { $hasAlwaysTrueCond = true; } $armCondScope = $armCondResult->getScope()->filterByFalseyValue($armCondExpr); - if ($filteringExpr === null) { - $filteringExpr = $armCondExpr; - continue; - } + $filteringExprs[] = $armCond; + } - $filteringExpr = new BinaryOp\BooleanOr($filteringExpr, $armCondExpr); + if (count($filteringExprs) === 1) { + $filteringExpr = new BinaryOp\Identical($expr->cond, $filteringExprs[0]); + } else { + $items = []; + foreach ($filteringExprs as $filteringExpr) { + $items[] = new ArrayItem($filteringExpr); + } + $filteringExpr = new FuncCall( + new Name\FullyQualified('in_array'), + [ + new Arg($expr->cond), + new Arg(new Array_($items)), + new Arg(new ConstFetch(new Name\FullyQualified('true'))), + ], + ); } $bodyScope = $matchScope->filterByTruthyValue($filteringExpr); diff --git a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php index 5469e009b8..1479b3a0ef 100644 --- a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php @@ -8,6 +8,7 @@ use PHPStan\Analyser\TypeSpecifier; use PHPStan\Analyser\TypeSpecifierAwareExtension; use PHPStan\Analyser\TypeSpecifierContext; +use PHPStan\Node\Expr\AlwaysRememberedExpr; use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\ArrayType; @@ -47,7 +48,8 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n return new SpecifiedTypes(); } - $needleType = $scope->getType($node->getArgs()[0]->value); + $needleExpr = $node->getArgs()[0]->value; + $needleType = $scope->getType($needleExpr); $arrayType = $scope->getType($node->getArgs()[1]->value); $arrayValueType = $arrayType->getIterableValueType(); $isStrictComparison = $isStrictComparison @@ -71,12 +73,21 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n ) ) { $specifiedTypes = $this->typeSpecifier->create( - $node->getArgs()[0]->value, + $needleExpr, $arrayValueType, $context, false, $scope, ); + if ($needleExpr instanceof AlwaysRememberedExpr) { + $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create( + $needleExpr->getExpr(), + $arrayValueType, + $context, + false, + $scope, + )); + } } if (