@@ -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 ();
@@ -3299,6 +3304,7 @@ static function (): void {
32993304 $ hasYield = $ result ->hasYield ();
33003305 $ throwPoints = $ result ->getThrowPoints ();
33013306 $ impurePoints = $ result ->getImpurePoints ();
3307+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
33023308 $ result = $ this ->processExprNode ($ stmt , $ expr ->right , $ scope , $ nodeCallback , $ context ->enterDeep ());
33033309 if (
33043310 ($ expr instanceof BinaryOp \Div || $ expr instanceof BinaryOp \Mod) &&
@@ -3310,6 +3316,7 @@ static function (): void {
33103316 $ hasYield = $ hasYield || $ result ->hasYield ();
33113317 $ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
33123318 $ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
3319+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
33133320 } elseif ($ expr instanceof Expr \Include_) {
33143321 $ result = $ this ->processExprNode ($ stmt , $ expr ->expr , $ scope , $ nodeCallback , $ context ->enterDeep ());
33153322 $ throwPoints = $ result ->getThrowPoints ();
@@ -3995,6 +4002,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
39954002 $ impurePoints ,
39964003 static fn (): MutatingScope => $ scope ->filterByTruthyValue ($ expr ),
39974004 static fn (): MutatingScope => $ scope ->filterByFalseyValue ($ expr ),
4005+ $ isAlwaysTerminating ,
39984006 );
39994007 }
40004008
0 commit comments