@@ -840,17 +840,20 @@ private function processStmtNode(
840840 } elseif ($ stmt instanceof Echo_) {
841841 $ hasYield = false ;
842842 $ throwPoints = [];
843+ $ isAlwaysTerminating = false ;
843844 foreach ($ stmt ->exprs as $ echoExpr ) {
844845 $ result = $ this ->processExprNode ($ stmt , $ echoExpr , $ scope , $ nodeCallback , ExpressionContext::createDeep ());
845846 $ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
846847 $ scope = $ result ->getScope ();
847848 $ hasYield = $ hasYield || $ result ->hasYield ();
849+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
848850 }
849851
850852 $ throwPoints = $ overridingThrowPoints ?? $ throwPoints ;
851853 $ impurePoints = [
852854 new ImpurePoint ($ scope , $ stmt , 'echo ' , 'echo ' , true ),
853855 ];
856+ return new StatementResult ($ scope , $ hasYield , $ isAlwaysTerminating , [], $ throwPoints , $ impurePoints );
854857 } elseif ($ stmt instanceof Return_) {
855858 if ($ stmt ->expr !== null ) {
856859 $ result = $ this ->processExprNode ($ stmt , $ stmt ->expr , $ scope , $ nodeCallback , ExpressionContext::createDeep ());
@@ -2408,6 +2411,7 @@ public function processExprNode(Node\Stmt $stmt, Expr $expr, MutatingScope $scop
24082411 return $ this ->processExprNode ($ stmt , $ newExpr , $ scope , $ nodeCallback , $ context );
24092412 }
24102413
2414+ $ isAlwaysTerminating = false ;
24112415 $ this ->callNodeCallbackWithExpression ($ nodeCallback , $ expr , $ scope , $ context );
24122416
24132417 if ($ expr instanceof Variable) {
@@ -2591,6 +2595,7 @@ static function (): void {
25912595
25922596 if ($ parametersAcceptor !== null ) {
25932597 $ expr = ArgumentsNormalizer::reorderFuncArguments ($ parametersAcceptor , $ expr ) ?? $ expr ;
2598+ $ isAlwaysTerminating = $ parametersAcceptor ->getReturnType () instanceof NeverType;
25942599 }
25952600 $ result = $ this ->processArgs ($ stmt , $ functionReflection , null , $ parametersAcceptor , $ expr , $ scope , $ nodeCallback , $ context );
25962601 $ scope = $ result ->getScope ();
@@ -3300,6 +3305,7 @@ static function (): void {
33003305 $ hasYield = $ result ->hasYield ();
33013306 $ throwPoints = $ result ->getThrowPoints ();
33023307 $ impurePoints = $ result ->getImpurePoints ();
3308+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
33033309 $ result = $ this ->processExprNode ($ stmt , $ expr ->right , $ scope , $ nodeCallback , $ context ->enterDeep ());
33043310 if (
33053311 ($ expr instanceof BinaryOp \Div || $ expr instanceof BinaryOp \Mod) &&
@@ -3311,6 +3317,7 @@ static function (): void {
33113317 $ hasYield = $ hasYield || $ result ->hasYield ();
33123318 $ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
33133319 $ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
3320+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
33143321 } elseif ($ expr instanceof Expr \Include_) {
33153322 $ result = $ this ->processExprNode ($ stmt , $ expr ->expr , $ scope , $ nodeCallback , $ context ->enterDeep ());
33163323 $ throwPoints = $ result ->getThrowPoints ();
@@ -3996,6 +4003,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
39964003 $ impurePoints ,
39974004 static fn (): MutatingScope => $ scope ->filterByTruthyValue ($ expr ),
39984005 static fn (): MutatingScope => $ scope ->filterByFalseyValue ($ expr ),
4006+ $ isAlwaysTerminating ,
39994007 );
40004008 }
40014009
0 commit comments