@@ -929,12 +929,14 @@ private function processStmtNode(
929929$ hasYield = $ result ->hasYield ();
930930$ throwPoints = $ result ->getThrowPoints ();
931931$ impurePoints = $ result ->getImpurePoints ();
932+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
933+
932934if ($ earlyTerminationExpr !== null ) {
933935return new StatementResult ($ scope , $ hasYield , true , [
934936new 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_) {
939941if ($ 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
24712474if ($ 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},
24772480true ,
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 );
24842488if (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 ();
25252531if (
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 ;
53865393if ($ 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 ();
53915399if (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 ();
54765485if ($ 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
56515664if ($ 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
57465761if ($ 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 ();
57895805foreach ($ var ->items as $ i => $ arrayItem ) {
57905806if ($ 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
58135831if ($ 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