@@ -929,12 +929,14 @@ private function processStmtNode(
929
929
$ hasYield = $ result ->hasYield ();
930
930
$ throwPoints = $ result ->getThrowPoints ();
931
931
$ impurePoints = $ result ->getImpurePoints ();
932
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
933
+
932
934
if ($ earlyTerminationExpr !== null ) {
933
935
return new StatementResult ($ scope , $ hasYield , true , [
934
936
new StatementExitPoint ($ stmt , $ scope ),
935
937
], $ overridingThrowPoints ?? $ throwPoints , $ impurePoints );
936
938
}
937
- return new StatementResult ($ scope , $ hasYield , false , [], $ overridingThrowPoints ?? $ throwPoints , $ impurePoints );
939
+ return new StatementResult ($ scope , $ hasYield , $ isAlwaysTerminating , [], $ overridingThrowPoints ?? $ throwPoints , $ impurePoints );
938
940
} elseif ($ stmt instanceof Node \Stmt \Namespace_) {
939
941
if ($ stmt ->name !== null ) {
940
942
$ scope = $ scope ->enterNamespace ($ stmt ->name ->toString ());
@@ -2466,20 +2468,22 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
2466
2468
$ hasYield = $ result ->hasYield ();
2467
2469
$ throwPoints = $ result ->getThrowPoints ();
2468
2470
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
2471
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
2469
2472
$ scope = $ result ->getScope ();
2470
2473
2471
2474
if ($ expr instanceof AssignRef) {
2472
2475
$ scope = $ scope ->exitExpressionAssign ($ expr ->expr );
2473
2476
}
2474
2477
2475
- return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints );
2478
+ return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints, isAlwaysTerminating: $ isAlwaysTerminating );
2476
2479
},
2477
2480
true ,
2478
2481
);
2479
2482
$ scope = $ result ->getScope ();
2480
2483
$ hasYield = $ result ->hasYield ();
2481
2484
$ throwPoints = $ result ->getThrowPoints ();
2482
2485
$ impurePoints = $ result ->getImpurePoints ();
2486
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
2483
2487
$ vars = $ this ->getAssignedVariables ($ expr ->var );
2484
2488
if (count ($ vars ) > 0 ) {
2485
2489
$ varChangedScope = false ;
@@ -2511,6 +2515,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
2511
2515
$ result ->hasYield (),
2512
2516
$ result ->getThrowPoints (),
2513
2517
$ result ->getImpurePoints (),
2518
+ isAlwaysTerminating: $ result ->isAlwaysTerminating (),
2514
2519
);
2515
2520
}
2516
2521
@@ -2522,6 +2527,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context): Exp
2522
2527
$ hasYield = $ result ->hasYield ();
2523
2528
$ throwPoints = $ result ->getThrowPoints ();
2524
2529
$ impurePoints = $ result ->getImpurePoints ();
2530
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
2525
2531
if (
2526
2532
($ expr instanceof Expr \AssignOp \Div || $ expr instanceof Expr \AssignOp \Mod) &&
2527
2533
!$ scope ->getType ($ expr ->expr )->toNumber ()->isSuperTypeOf (new ConstantIntegerType (0 ))->no ()
@@ -5382,12 +5388,14 @@ private function processAssignVar(
5382
5388
$ hasYield = false ;
5383
5389
$ throwPoints = [];
5384
5390
$ impurePoints = [];
5391
+ $ isAlwaysTerminating = false ;
5385
5392
$ isAssignOp = $ assignedExpr instanceof Expr \AssignOp && !$ enterExpressionAssign ;
5386
5393
if ($ var instanceof Variable && is_string ($ var ->name )) {
5387
5394
$ result = $ processExprCallback ($ scope );
5388
5395
$ hasYield = $ result ->hasYield ();
5389
5396
$ throwPoints = $ result ->getThrowPoints ();
5390
5397
$ impurePoints = $ result ->getImpurePoints ();
5398
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
5391
5399
if (in_array ($ var ->name , Scope::SUPERGLOBAL_VARIABLES , true )) {
5392
5400
$ impurePoints [] = new ImpurePoint ($ scope , $ var , 'superglobal ' , 'assign to superglobal variable ' , true );
5393
5401
}
@@ -5472,6 +5480,7 @@ private function processAssignVar(
5472
5480
$ hasYield = $ result ->hasYield ();
5473
5481
$ throwPoints = $ result ->getThrowPoints ();
5474
5482
$ impurePoints = $ result ->getImpurePoints ();
5483
+ $ isAlwaysTerminating = $ result ->isAlwaysTerminating ();
5475
5484
$ scope = $ result ->getScope ();
5476
5485
if ($ enterExpressionAssign ) {
5477
5486
$ scope = $ scope ->exitExpressionAssign ($ var );
@@ -5523,6 +5532,7 @@ private function processAssignVar(
5523
5532
$ hasYield = $ hasYield || $ result ->hasYield ();
5524
5533
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5525
5534
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5535
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5526
5536
$ scope = $ result ->getScope ();
5527
5537
5528
5538
$ varType = $ scope ->getType ($ var );
@@ -5628,6 +5638,7 @@ static function (): void {
5628
5638
$ hasYield = $ objectResult ->hasYield ();
5629
5639
$ throwPoints = $ objectResult ->getThrowPoints ();
5630
5640
$ impurePoints = $ objectResult ->getImpurePoints ();
5641
+ $ isAlwaysTerminating = $ objectResult ->isAlwaysTerminating ();
5631
5642
$ scope = $ objectResult ->getScope ();
5632
5643
5633
5644
$ propertyName = null ;
@@ -5638,6 +5649,7 @@ static function (): void {
5638
5649
$ hasYield = $ hasYield || $ propertyNameResult ->hasYield ();
5639
5650
$ throwPoints = array_merge ($ throwPoints , $ propertyNameResult ->getThrowPoints ());
5640
5651
$ impurePoints = array_merge ($ impurePoints , $ propertyNameResult ->getImpurePoints ());
5652
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ propertyNameResult ->isAlwaysTerminating ();
5641
5653
$ scope = $ propertyNameResult ->getScope ();
5642
5654
}
5643
5655
@@ -5646,6 +5658,7 @@ static function (): void {
5646
5658
$ hasYield = $ hasYield || $ result ->hasYield ();
5647
5659
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5648
5660
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5661
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5649
5662
$ scope = $ result ->getScope ();
5650
5663
5651
5664
if ($ var ->name instanceof Expr && $ this ->phpVersion ->supportsPropertyHooks ()) {
@@ -5733,6 +5746,7 @@ static function (): void {
5733
5746
$ hasYield = $ propertyNameResult ->hasYield ();
5734
5747
$ throwPoints = $ propertyNameResult ->getThrowPoints ();
5735
5748
$ impurePoints = $ propertyNameResult ->getImpurePoints ();
5749
+ $ isAlwaysTerminating = $ propertyNameResult ->isAlwaysTerminating ();
5736
5750
$ scope = $ propertyNameResult ->getScope ();
5737
5751
}
5738
5752
@@ -5741,6 +5755,7 @@ static function (): void {
5741
5755
$ hasYield = $ hasYield || $ result ->hasYield ();
5742
5756
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5743
5757
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5758
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5744
5759
$ scope = $ result ->getScope ();
5745
5760
5746
5761
if ($ propertyName !== null ) {
@@ -5785,6 +5800,7 @@ static function (): void {
5785
5800
$ hasYield = $ result ->hasYield ();
5786
5801
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5787
5802
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5803
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5788
5804
$ scope = $ result ->getScope ();
5789
5805
foreach ($ var ->items as $ i => $ arrayItem ) {
5790
5806
if ($ arrayItem === null ) {
@@ -5802,13 +5818,15 @@ static function (): void {
5802
5818
$ hasYield = $ hasYield || $ keyResult ->hasYield ();
5803
5819
$ throwPoints = array_merge ($ throwPoints , $ keyResult ->getThrowPoints ());
5804
5820
$ impurePoints = array_merge ($ impurePoints , $ keyResult ->getImpurePoints ());
5821
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ keyResult ->isAlwaysTerminating ();
5805
5822
$ itemScope = $ keyResult ->getScope ();
5806
5823
}
5807
5824
5808
5825
$ valueResult = $ this ->processExprNode ($ stmt , $ arrayItem ->value , $ itemScope , $ nodeCallback , $ context ->enterDeep ());
5809
5826
$ hasYield = $ hasYield || $ valueResult ->hasYield ();
5810
5827
$ throwPoints = array_merge ($ throwPoints , $ valueResult ->getThrowPoints ());
5811
5828
$ impurePoints = array_merge ($ impurePoints , $ valueResult ->getImpurePoints ());
5829
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ valueResult ->isAlwaysTerminating ();
5812
5830
5813
5831
if ($ arrayItem ->key === null ) {
5814
5832
$ dimExpr = new Node \Scalar \Int_ ($ i );
@@ -5829,6 +5847,7 @@ static function (): void {
5829
5847
$ hasYield = $ hasYield || $ result ->hasYield ();
5830
5848
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
5831
5849
$ impurePoints = array_merge ($ impurePoints , $ result ->getImpurePoints ());
5850
+ $ isAlwaysTerminating = $ isAlwaysTerminating || $ result ->isAlwaysTerminating ();
5832
5851
}
5833
5852
} elseif ($ var instanceof ExistingArrayDimFetch) {
5834
5853
$ dimFetchStack = [];
@@ -5907,7 +5926,7 @@ static function (): void {
5907
5926
}
5908
5927
}
5909
5928
5910
- return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints );
5929
+ return new ExpressionResult ($ scope , $ hasYield , $ throwPoints , $ impurePoints, isAlwaysTerminating: $ isAlwaysTerminating );
5911
5930
}
5912
5931
5913
5932
/**
0 commit comments