@@ -927,12 +927,14 @@ private function processStmtNode(
927
927
$ hasYield = $ result ->hasYield ();
928
928
$ throwPoints = $ result ->getThrowPoints ();
929
929
$ impurePoints = $ result ->getImpurePoints ();
930
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
931
+
930
932
if ($ earlyTerminationExpr !== null ) {
931
933
return new StatementResult ($ scope , $ hasYield , true , [
932
934
new StatementExitPoint ($ stmt , $ scope ),
933
935
], $ overridingThrowPoints ?? $ throwPoints , $ impurePoints );
934
936
}
935
- return new StatementResult ($ scope , $ hasYield , false , [], $ overridingThrowPoints ?? $ throwPoints , $ impurePoints );
937
+ return new StatementResult ($ scope , $ hasYield , $ isAlwaysTerminating , [], $ overridingThrowPoints ?? $ throwPoints , $ impurePoints );
936
938
} elseif ($ stmt instanceof Node \Stmt \Namespace_) {
937
939
if ($ stmt ->name !== null ) {
938
940
$ scope = $ scope ->enterNamespace ($ stmt ->name ->toString ());
@@ -2464,20 +2466,22 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
2464
2466
$ hasYield = $ result ->hasYield ();
2465
2467
$ throwPoints = $ result ->getThrowPoints ();
2466
2468
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
2469
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
2467
2470
$ scope = $ result ->getScope ();
2468
2471
2469
2472
if ($ expr instanceof AssignRef) {
2470
2473
$ scope = $ scope ->exitExpressionAssign ($ expr ->expr );
2471
2474
}
2472
2475
2473
- return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints );
2476
+ return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints, isAlwaysTerminating: $ isAlwaysTerminating );
2474
2477
},
2475
2478
true ,
2476
2479
);
2477
2480
$ scope = $ result ->getScope ();
2478
2481
$ hasYield = $ result ->hasYield ();
2479
2482
$ throwPoints = $ result ->getThrowPoints ();
2480
2483
$ impurePoints = $ result ->getImpurePoints ();
2484
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
2481
2485
$ vars = $ this ->getAssignedVariables ($ expr ->var );
2482
2486
if (count ($ vars ) > 0 ) {
2483
2487
$ varChangedScope = false ;
@@ -2509,6 +2513,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
2509
2513
$ result ->hasYield (),
2510
2514
$ result ->getThrowPoints (),
2511
2515
$ result ->getImpurePoints (),
2516
+ isAlwaysTerminating: $ result ->isAlwaysTerminating (),
2512
2517
);
2513
2518
}
2514
2519
@@ -2520,6 +2525,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
2520
2525
$ hasYield = $ result ->hasYield ();
2521
2526
$ throwPoints = $ result ->getThrowPoints ();
2522
2527
$ impurePoints = $ result ->getImpurePoints ();
2528
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
2523
2529
if (
2524
2530
($ expr instanceof Expr \AssignOp \Div || $ expr instanceof Expr \AssignOp \Mod) &&
2525
2531
!$ scope ->getType ($ expr ->expr )->toNumber ()->isSuperTypeOf (new ConstantIntegerType (0 ))->no ()
@@ -5379,12 +5385,14 @@ private function processAssignVar(
5379
5385
$ hasYield = false ;
5380
5386
$ throwPoints = [];
5381
5387
$ impurePoints = [];
5388
+ $ isAlwaysTerminating = false ;
5382
5389
$ isAssignOp = $ assignedExpr instanceof Expr \AssignOp && !$ enterExpressionAssign ;
5383
5390
if ($ var instanceof Variable && is_string ($ var ->name )) {
5384
5391
$ result = $ processExprCallback ($ scope );
5385
5392
$ hasYield = $ result ->hasYield ();
5386
5393
$ throwPoints = $ result ->getThrowPoints ();
5387
5394
$ impurePoints = $ result ->getImpurePoints ();
5395
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
5388
5396
if (in_array ($ var ->name , Scope::SUPERGLOBAL_VARIABLES , true )) {
5389
5397
$ impurePoints [] = new ImpurePoint ($ scope , $ var , 'superglobal ' , 'assign to superglobal variable ' , true );
5390
5398
}
@@ -5469,6 +5477,7 @@ private function processAssignVar(
5469
5477
$ hasYield = $ result ->hasYield ();
5470
5478
$ throwPoints = $ result ->getThrowPoints ();
5471
5479
$ impurePoints = $ result ->getImpurePoints ();
5480
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
5472
5481
$ scope = $ result ->getScope ();
5473
5482
if ($ enterExpressionAssign ) {
5474
5483
$ scope = $ scope ->exitExpressionAssign ($ var );
@@ -5520,6 +5529,7 @@ private function processAssignVar(
5520
5529
$ hasYield = $ hasYield || $ result ->hasYield ();
5521
5530
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5522
5531
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5532
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5523
5533
$ scope = $ result ->getScope ();
5524
5534
5525
5535
$ varType = $ scope ->getType ($ var );
@@ -5625,6 +5635,7 @@ static function (): void {
5625
5635
$ hasYield = $ objectResult ->hasYield ();
5626
5636
$ throwPoints = $ objectResult ->getThrowPoints ();
5627
5637
$ impurePoints = $ objectResult ->getImpurePoints ();
5638
+ $ isAlwaysTerminating = $ objectResult ->isAlwaysTerminating ();
5628
5639
$ scope = $ objectResult ->getScope ();
5629
5640
5630
5641
$ propertyName = null ;
@@ -5635,6 +5646,7 @@ static function (): void {
5635
5646
$ hasYield = $ hasYield || $ propertyNameResult ->hasYield ();
5636
5647
$ throwPoints = array_merge ($ throwPoints , $ propertyNameResult ->getThrowPoints ());
5637
5648
$ impurePoints = array_merge ($ impurePoints , $ propertyNameResult ->getImpurePoints ());
5649
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ propertyNameResult ->isAlwaysTerminating ();
5638
5650
$ scope = $ propertyNameResult ->getScope ();
5639
5651
}
5640
5652
@@ -5643,6 +5655,7 @@ static function (): void {
5643
5655
$ hasYield = $ hasYield || $ result ->hasYield ();
5644
5656
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5645
5657
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5658
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5646
5659
$ scope = $ result ->getScope ();
5647
5660
5648
5661
if ($ var ->name instanceof Expr && $ this ->phpVersion ->supportsPropertyHooks ()) {
@@ -5730,6 +5743,7 @@ static function (): void {
5730
5743
$ hasYield = $ propertyNameResult ->hasYield ();
5731
5744
$ throwPoints = $ propertyNameResult ->getThrowPoints ();
5732
5745
$ impurePoints = $ propertyNameResult ->getImpurePoints ();
5746
+ $ isAlwaysTerminating = $ propertyNameResult ->isAlwaysTerminating ();
5733
5747
$ scope = $ propertyNameResult ->getScope ();
5734
5748
}
5735
5749
@@ -5738,6 +5752,7 @@ static function (): void {
5738
5752
$ hasYield = $ hasYield || $ result ->hasYield ();
5739
5753
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5740
5754
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5755
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5741
5756
$ scope = $ result ->getScope ();
5742
5757
5743
5758
if ($ propertyName !== null ) {
@@ -5782,6 +5797,7 @@ static function (): void {
5782
5797
$ hasYield = $ result ->hasYield ();
5783
5798
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5784
5799
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5800
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5785
5801
$ scope = $ result ->getScope ();
5786
5802
foreach ($ var ->items as $ i => $ arrayItem ) {
5787
5803
if ($ arrayItem === null ) {
@@ -5799,13 +5815,15 @@ static function (): void {
5799
5815
$ hasYield = $ hasYield || $ keyResult ->hasYield ();
5800
5816
$ throwPoints = array_merge ($ throwPoints , $ keyResult ->getThrowPoints ());
5801
5817
$ impurePoints = array_merge ($ impurePoints , $ keyResult ->getImpurePoints ());
5818
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ keyResult ->isAlwaysTerminating ();
5802
5819
$ itemScope = $ keyResult ->getScope ();
5803
5820
}
5804
5821
5805
5822
$ valueResult = $ this ->processExprNode ($ stmt , $ arrayItem ->value , $ itemScope , $ nodeCallback , $ context ->enterDeep ());
5806
5823
$ hasYield = $ hasYield || $ valueResult ->hasYield ();
5807
5824
$ throwPoints = array_merge ($ throwPoints , $ valueResult ->getThrowPoints ());
5808
5825
$ impurePoints = array_merge ($ impurePoints , $ valueResult ->getImpurePoints ());
5826
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ valueResult ->isAlwaysTerminating ();
5809
5827
5810
5828
if ($ arrayItem ->key === null ) {
5811
5829
$ dimExpr = new Node \Scalar \Int_ ($ i );
@@ -5826,6 +5844,7 @@ static function (): void {
5826
5844
$ hasYield = $ hasYield || $ result ->hasYield ();
5827
5845
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5828
5846
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5847
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5829
5848
}
5830
5849
} elseif ($ var instanceof ExistingArrayDimFetch) {
5831
5850
$ dimFetchStack = [];
@@ -5904,7 +5923,7 @@ static function (): void {
5904
5923
}
5905
5924
}
5906
5925
5907
- return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints );
5926
+ return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints, isAlwaysTerminating: $ isAlwaysTerminating );
5908
5927
}
5909
5928
5910
5929
/**
0 commit comments