@@ -929,12 +929,14 @@ private function processStmtNode(
929929 $ hasYield = $ result ->hasYield ();
930930 $ throwPoints = $ result ->getThrowPoints ();
931931 $ impurePoints = $ result ->getImpurePoints ();
932+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
933+
932934 if ($ earlyTerminationExpr !== null ) {
933935 return new StatementResult ($ scope , $ hasYield , true , [
934936 new StatementExitPoint ($ stmt , $ scope ),
935937 ], $ overridingThrowPoints ?? $ throwPoints , $ impurePoints );
936938 }
937- return new StatementResult ($ scope , $ hasYield , false , [], $ overridingThrowPoints ?? $ throwPoints , $ impurePoints );
939+ return new StatementResult ($ scope , $ hasYield , $ isAlwaysTerminating , [], $ overridingThrowPoints ?? $ throwPoints , $ impurePoints );
938940 } elseif ($ stmt instanceof Node \Stmt \Namespace_) {
939941 if ($ stmt ->name !== null ) {
940942 $ scope = $ scope ->enterNamespace ($ stmt ->name ->toString ());
@@ -2466,20 +2468,22 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
24662468 $ hasYield = $ result ->hasYield ();
24672469 $ throwPoints = $ result ->getThrowPoints ();
24682470 $ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
2471+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
24692472 $ scope = $ result ->getScope ();
24702473
24712474 if ($ expr instanceof AssignRef) {
24722475 $ scope = $ scope ->exitExpressionAssign ($ expr ->expr );
24732476 }
24742477
2475- return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints );
2478+ return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints, isAlwaysTerminating: $ isAlwaysTerminating );
24762479 },
24772480 true ,
24782481 );
24792482 $ scope = $ result ->getScope ();
24802483 $ hasYield = $ result ->hasYield ();
24812484 $ throwPoints = $ result ->getThrowPoints ();
24822485 $ impurePoints = $ result ->getImpurePoints ();
2486+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
24832487 $ vars = $ this ->getAssignedVariables ($ expr ->var );
24842488 if (count ($ vars ) > 0 ) {
24852489 $ varChangedScope = false ;
@@ -2511,6 +2515,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
25112515 $ result ->hasYield (),
25122516 $ result ->getThrowPoints (),
25132517 $ result ->getImpurePoints (),
2518+ isAlwaysTerminating: $ result ->isAlwaysTerminating (),
25142519 );
25152520 }
25162521
@@ -2522,6 +2527,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
25222527 $ hasYield = $ result ->hasYield ();
25232528 $ throwPoints = $ result ->getThrowPoints ();
25242529 $ impurePoints = $ result ->getImpurePoints ();
2530+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
25252531 if (
25262532 ($ expr instanceof Expr \AssignOp \Div || $ expr instanceof Expr \AssignOp \Mod) &&
25272533 !$ scope ->getType ($ expr ->expr )->toNumber ()->isSuperTypeOf (new ConstantIntegerType (0 ))->no ()
@@ -5382,12 +5388,14 @@ private function processAssignVar(
53825388 $ hasYield = false ;
53835389 $ throwPoints = [];
53845390 $ impurePoints = [];
5391+ $ isAlwaysTerminating = false ;
53855392 $ isAssignOp = $ assignedExpr instanceof Expr \AssignOp && !$ enterExpressionAssign ;
53865393 if ($ var instanceof Variable && is_string ($ var ->name )) {
53875394 $ result = $ processExprCallback ($ scope );
53885395 $ hasYield = $ result ->hasYield ();
53895396 $ throwPoints = $ result ->getThrowPoints ();
53905397 $ impurePoints = $ result ->getImpurePoints ();
5398+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
53915399 if (in_array ($ var ->name , Scope::SUPERGLOBAL_VARIABLES , true )) {
53925400 $ impurePoints [] = new ImpurePoint ($ scope , $ var , 'superglobal ' , 'assign to superglobal variable ' , true );
53935401 }
@@ -5472,6 +5480,7 @@ private function processAssignVar(
54725480 $ hasYield = $ result ->hasYield ();
54735481 $ throwPoints = $ result ->getThrowPoints ();
54745482 $ impurePoints = $ result ->getImpurePoints ();
5483+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
54755484 $ scope = $ result ->getScope ();
54765485 if ($ enterExpressionAssign ) {
54775486 $ scope = $ scope ->exitExpressionAssign ($ var );
@@ -5523,6 +5532,7 @@ private function processAssignVar(
55235532 $ hasYield = $ hasYield || $ result ->hasYield ();
55245533 $ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
55255534 $ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5535+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
55265536 $ scope = $ result ->getScope ();
55275537
55285538 $ varType = $ scope ->getType ($ var );
@@ -5628,6 +5638,7 @@ static function (): void {
56285638 $ hasYield = $ objectResult ->hasYield ();
56295639 $ throwPoints = $ objectResult ->getThrowPoints ();
56305640 $ impurePoints = $ objectResult ->getImpurePoints ();
5641+ $ isAlwaysTerminating = $ objectResult ->isAlwaysTerminating ();
56315642 $ scope = $ objectResult ->getScope ();
56325643
56335644 $ propertyName = null ;
@@ -5638,6 +5649,7 @@ static function (): void {
56385649 $ hasYield = $ hasYield || $ propertyNameResult ->hasYield ();
56395650 $ throwPoints = array_merge ($ throwPoints , $ propertyNameResult ->getThrowPoints ());
56405651 $ impurePoints = array_merge ($ impurePoints , $ propertyNameResult ->getImpurePoints ());
5652+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ propertyNameResult ->isAlwaysTerminating ();
56415653 $ scope = $ propertyNameResult ->getScope ();
56425654 }
56435655
@@ -5646,6 +5658,7 @@ static function (): void {
56465658 $ hasYield = $ hasYield || $ result ->hasYield ();
56475659 $ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
56485660 $ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5661+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
56495662 $ scope = $ result ->getScope ();
56505663
56515664 if ($ var ->name instanceof Expr && $ this ->phpVersion ->supportsPropertyHooks ()) {
@@ -5733,6 +5746,7 @@ static function (): void {
57335746 $ hasYield = $ propertyNameResult ->hasYield ();
57345747 $ throwPoints = $ propertyNameResult ->getThrowPoints ();
57355748 $ impurePoints = $ propertyNameResult ->getImpurePoints ();
5749+ $ isAlwaysTerminating = $ propertyNameResult ->isAlwaysTerminating ();
57365750 $ scope = $ propertyNameResult ->getScope ();
57375751 }
57385752
@@ -5741,6 +5755,7 @@ static function (): void {
57415755 $ hasYield = $ hasYield || $ result ->hasYield ();
57425756 $ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
57435757 $ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5758+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
57445759 $ scope = $ result ->getScope ();
57455760
57465761 if ($ propertyName !== null ) {
@@ -5785,6 +5800,7 @@ static function (): void {
57855800 $ hasYield = $ result ->hasYield ();
57865801 $ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
57875802 $ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5803+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
57885804 $ scope = $ result ->getScope ();
57895805 foreach ($ var ->items as $ i => $ arrayItem ) {
57905806 if ($ arrayItem === null ) {
@@ -5802,13 +5818,15 @@ static function (): void {
58025818 $ hasYield = $ hasYield || $ keyResult ->hasYield ();
58035819 $ throwPoints = array_merge ($ throwPoints , $ keyResult ->getThrowPoints ());
58045820 $ impurePoints = array_merge ($ impurePoints , $ keyResult ->getImpurePoints ());
5821+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ keyResult ->isAlwaysTerminating ();
58055822 $ itemScope = $ keyResult ->getScope ();
58065823 }
58075824
58085825 $ valueResult = $ this ->processExprNode ($ stmt , $ arrayItem ->value , $ itemScope , $ nodeCallback , $ context ->enterDeep ());
58095826 $ hasYield = $ hasYield || $ valueResult ->hasYield ();
58105827 $ throwPoints = array_merge ($ throwPoints , $ valueResult ->getThrowPoints ());
58115828 $ impurePoints = array_merge ($ impurePoints , $ valueResult ->getImpurePoints ());
5829+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ valueResult ->isAlwaysTerminating ();
58125830
58135831 if ($ arrayItem ->key === null ) {
58145832 $ dimExpr = new Node \Scalar \Int_ ($ i );
@@ -5829,6 +5847,7 @@ static function (): void {
58295847 $ hasYield = $ hasYield || $ result ->hasYield ();
58305848 $ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
58315849 $ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5850+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
58325851 }
58335852 } elseif ($ var instanceof ExistingArrayDimFetch) {
58345853 $ dimFetchStack = [];
@@ -5907,7 +5926,7 @@ static function (): void {
59075926 }
59085927 }
59095928
5910- return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints );
5929+ return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints, isAlwaysTerminating: $ isAlwaysTerminating );
59115930 }
59125931
59135932 /**
0 commit comments