From 707aa79d4d3eb67eeb4a8cd6b557c21962c8db70 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 22 Jul 2025 16:46:04 +0200 Subject: [PATCH 1/3] 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 fc89a44670..2e0ff16f64 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3206,7 +3206,7 @@ static function (): void { return new ExpressionResult( $result->getScope(), $result->hasYield(), - $result->isAlwaysTerminating(), + false, [], [], ); @@ -4818,7 +4818,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()); } /** @@ -5246,6 +5246,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 5012b0ef87..3b72dde94c 100644 --- a/tests/PHPStan/Analyser/ExpressionResultTest.php +++ b/tests/PHPStan/Analyser/ExpressionResultTest.php @@ -101,6 +101,10 @@ public static function dataIsAlwaysTerminating(): array 'exit() ?? $x;', true, ], + [ + 'call_user_func(fn() => exit());', + true, + ], [ 'var_dump(1+exit());', true, From 933a797f2dd852580f21350170695b4aecdaccdd Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 22 Jul 2025 16:55:05 +0200 Subject: [PATCH 2/3] 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 3b72dde94c..f350a30f45 100644 --- a/tests/PHPStan/Analyser/ExpressionResultTest.php +++ b/tests/PHPStan/Analyser/ExpressionResultTest.php @@ -81,6 +81,10 @@ public static function dataIsAlwaysTerminating(): array 'fn() => yield (exit());', false, ], + [ + '(fn() => exit())();', // immediately invoked function expression + true, + ], [ '@exit();', true, From a2f943f35bd9412f834ec352399dc0c6546d06c7 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Fri, 1 Aug 2025 13:31:33 +0200 Subject: [PATCH 3/3] 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 f350a30f45..a59a5ae73d 100644 --- a/tests/PHPStan/Analyser/ExpressionResultTest.php +++ b/tests/PHPStan/Analyser/ExpressionResultTest.php @@ -85,6 +85,10 @@ public static function dataIsAlwaysTerminating(): array '(fn() => exit())();', // immediately invoked function expression true, ], + [ + 'register_shutdown_function(fn() => exit());', + false, + ], [ '@exit();', true,