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..a59a5ae73d 100644 --- a/tests/PHPStan/Analyser/ExpressionResultTest.php +++ b/tests/PHPStan/Analyser/ExpressionResultTest.php @@ -81,6 +81,14 @@ public static function dataIsAlwaysTerminating(): array 'fn() => yield (exit());', false, ], + [ + '(fn() => exit())();', // immediately invoked function expression + true, + ], + [ + 'register_shutdown_function(fn() => exit());', + false, + ], [ '@exit();', true, @@ -101,6 +109,10 @@ public static function dataIsAlwaysTerminating(): array 'exit() ?? $x;', true, ], + [ + 'call_user_func(fn() => exit());', + true, + ], [ 'var_dump(1+exit());', true,