@@ -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 ()
@@ -5380,12 +5386,14 @@ private function processAssignVar(
5380
5386
$ hasYield = false ;
5381
5387
$ throwPoints = [];
5382
5388
$ impurePoints = [];
5389
+ $ isAlwaysTerminating = false ;
5383
5390
$ isAssignOp = $ assignedExpr instanceof Expr \AssignOp && !$ enterExpressionAssign ;
5384
5391
if ($ var instanceof Variable && is_string ($ var ->name )) {
5385
5392
$ result = $ processExprCallback ($ scope );
5386
5393
$ hasYield = $ result ->hasYield ();
5387
5394
$ throwPoints = $ result ->getThrowPoints ();
5388
5395
$ impurePoints = $ result ->getImpurePoints ();
5396
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
5389
5397
if (in_array ($ var ->name , Scope::SUPERGLOBAL_VARIABLES , true )) {
5390
5398
$ impurePoints [] = new ImpurePoint ($ scope , $ var , 'superglobal ' , 'assign to superglobal variable ' , true );
5391
5399
}
@@ -5470,6 +5478,7 @@ private function processAssignVar(
5470
5478
$ hasYield = $ result ->hasYield ();
5471
5479
$ throwPoints = $ result ->getThrowPoints ();
5472
5480
$ impurePoints = $ result ->getImpurePoints ();
5481
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
5473
5482
$ scope = $ result ->getScope ();
5474
5483
if ($ enterExpressionAssign ) {
5475
5484
$ scope = $ scope ->exitExpressionAssign ($ var );
@@ -5521,6 +5530,7 @@ private function processAssignVar(
5521
5530
$ hasYield = $ hasYield || $ result ->hasYield ();
5522
5531
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5523
5532
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5533
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5524
5534
$ scope = $ result ->getScope ();
5525
5535
5526
5536
$ varType = $ scope ->getType ($ var );
@@ -5626,6 +5636,7 @@ static function (): void {
5626
5636
$ hasYield = $ objectResult ->hasYield ();
5627
5637
$ throwPoints = $ objectResult ->getThrowPoints ();
5628
5638
$ impurePoints = $ objectResult ->getImpurePoints ();
5639
+ $ isAlwaysTerminating = $ objectResult ->isAlwaysTerminating ();
5629
5640
$ scope = $ objectResult ->getScope ();
5630
5641
5631
5642
$ propertyName = null ;
@@ -5636,6 +5647,7 @@ static function (): void {
5636
5647
$ hasYield = $ hasYield || $ propertyNameResult ->hasYield ();
5637
5648
$ throwPoints = array_merge ($ throwPoints , $ propertyNameResult ->getThrowPoints ());
5638
5649
$ impurePoints = array_merge ($ impurePoints , $ propertyNameResult ->getImpurePoints ());
5650
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ propertyNameResult ->isAlwaysTerminating ();
5639
5651
$ scope = $ propertyNameResult ->getScope ();
5640
5652
}
5641
5653
@@ -5644,6 +5656,7 @@ static function (): void {
5644
5656
$ hasYield = $ hasYield || $ result ->hasYield ();
5645
5657
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5646
5658
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5659
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5647
5660
$ scope = $ result ->getScope ();
5648
5661
5649
5662
if ($ var ->name instanceof Expr && $ this ->phpVersion ->supportsPropertyHooks ()) {
@@ -5731,6 +5744,7 @@ static function (): void {
5731
5744
$ hasYield = $ propertyNameResult ->hasYield ();
5732
5745
$ throwPoints = $ propertyNameResult ->getThrowPoints ();
5733
5746
$ impurePoints = $ propertyNameResult ->getImpurePoints ();
5747
+ $ isAlwaysTerminating = $ propertyNameResult ->isAlwaysTerminating ();
5734
5748
$ scope = $ propertyNameResult ->getScope ();
5735
5749
}
5736
5750
@@ -5739,6 +5753,7 @@ static function (): void {
5739
5753
$ hasYield = $ hasYield || $ result ->hasYield ();
5740
5754
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5741
5755
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5756
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5742
5757
$ scope = $ result ->getScope ();
5743
5758
5744
5759
if ($ propertyName !== null ) {
@@ -5783,6 +5798,7 @@ static function (): void {
5783
5798
$ hasYield = $ result ->hasYield ();
5784
5799
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5785
5800
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5801
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5786
5802
$ scope = $ result ->getScope ();
5787
5803
foreach ($ var ->items as $ i => $ arrayItem ) {
5788
5804
if ($ arrayItem === null ) {
@@ -5800,13 +5816,15 @@ static function (): void {
5800
5816
$ hasYield = $ hasYield || $ keyResult ->hasYield ();
5801
5817
$ throwPoints = array_merge ($ throwPoints , $ keyResult ->getThrowPoints ());
5802
5818
$ impurePoints = array_merge ($ impurePoints , $ keyResult ->getImpurePoints ());
5819
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ keyResult ->isAlwaysTerminating ();
5803
5820
$ itemScope = $ keyResult ->getScope ();
5804
5821
}
5805
5822
5806
5823
$ valueResult = $ this ->processExprNode ($ stmt , $ arrayItem ->value , $ itemScope , $ nodeCallback , $ context ->enterDeep ());
5807
5824
$ hasYield = $ hasYield || $ valueResult ->hasYield ();
5808
5825
$ throwPoints = array_merge ($ throwPoints , $ valueResult ->getThrowPoints ());
5809
5826
$ impurePoints = array_merge ($ impurePoints , $ valueResult ->getImpurePoints ());
5827
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ valueResult ->isAlwaysTerminating ();
5810
5828
5811
5829
if ($ arrayItem ->key === null ) {
5812
5830
$ dimExpr = new Node \Scalar \Int_ ($ i );
@@ -5827,6 +5845,7 @@ static function (): void {
5827
5845
$ hasYield = $ hasYield || $ result ->hasYield ();
5828
5846
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5829
5847
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5848
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5830
5849
}
5831
5850
} elseif ($ var instanceof ExistingArrayDimFetch) {
5832
5851
$ dimFetchStack = [];
@@ -5905,7 +5924,7 @@ static function (): void {
5905
5924
}
5906
5925
}
5907
5926
5908
- return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints );
5927
+ return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints, isAlwaysTerminating: $ isAlwaysTerminating );
5909
5928
}
5910
5929
5911
5930
/**
0 commit comments