From 8bccc4f8866a9242fdf4b33beda4257186c20376 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 22 Jul 2025 16:46:04 +0200 Subject: [PATCH 1/2] Fix missing detection of dead code in arrow functions --- src/Analyser/NodeScopeResolver.php | 5 +++-- tests/PHPStan/Analyser/ExpressionResultTest.php | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 8ff656bb57..0434f735f0 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3192,7 +3192,7 @@ static function (): void { return new ExpressionResult( $result->getScope(), $result->hasYield(), - $result->isAlwaysTerminating(), + false, [], [], ); @@ -4804,7 +4804,7 @@ private function processArrowFunctionNode( $nodeCallback(new InArrowFunctionNode($arrowFunctionType, $expr), $arrowFunctionScope); $exprResult = $this->processExprNode($stmt, $expr->expr, $arrowFunctionScope, $nodeCallback, ExpressionContext::createTopLevel()); - return new ExpressionResult($scope, false, false, $exprResult->getThrowPoints(), $exprResult->getImpurePoints()); + return new ExpressionResult($scope, false, $exprResult->isAlwaysTerminating(), $exprResult->getThrowPoints(), $exprResult->getImpurePoints()); } /** @@ -5226,6 +5226,7 @@ private function processArgs( if ($callCallbackImmediately) { $throwPoints = array_merge($throwPoints, array_map(static fn (ThrowPoint $throwPoint) => $throwPoint->isExplicit() ? ThrowPoint::createExplicit($scope, $throwPoint->getType(), $arg->value, $throwPoint->canContainAnyThrowable()) : ThrowPoint::createImplicit($scope, $arg->value), $arrowFunctionResult->getThrowPoints())); $impurePoints = array_merge($impurePoints, $arrowFunctionResult->getImpurePoints()); + $isAlwaysTerminating = $isAlwaysTerminating || $arrowFunctionResult->isAlwaysTerminating(); } } else { $exprType = $scope->getType($arg->value); diff --git a/tests/PHPStan/Analyser/ExpressionResultTest.php b/tests/PHPStan/Analyser/ExpressionResultTest.php index dbca93c756..0a184435aa 100644 --- a/tests/PHPStan/Analyser/ExpressionResultTest.php +++ b/tests/PHPStan/Analyser/ExpressionResultTest.php @@ -99,6 +99,10 @@ public static function dataIsAlwaysTerminating(): array 'exit() ?? $x;', true, ], + [ + 'call_user_func(fn() => exit());', + true, + ], [ 'var_dump(1+exit());', true, From 425df39f15c5cf4b56d170eca3be45b4b9371e3e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 22 Jul 2025 16:55:05 +0200 Subject: [PATCH 2/2] Update ExpressionResultTest.php --- tests/PHPStan/Analyser/ExpressionResultTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/PHPStan/Analyser/ExpressionResultTest.php b/tests/PHPStan/Analyser/ExpressionResultTest.php index 0a184435aa..4315c53168 100644 --- a/tests/PHPStan/Analyser/ExpressionResultTest.php +++ b/tests/PHPStan/Analyser/ExpressionResultTest.php @@ -79,6 +79,10 @@ public static function dataIsAlwaysTerminating(): array 'fn() => yield (exit());', false, ], + [ + '(fn() => exit())();', // immediately invoked function expression + true, + ], [ '@exit();', true,