171171use PHPStan \Type \ClosureType ;
172172use PHPStan \Type \Constant \ConstantArrayType ;
173173use PHPStan \Type \Constant \ConstantArrayTypeBuilder ;
174+ use PHPStan \Type \Constant \ConstantBooleanType ;
174175use PHPStan \Type \Constant \ConstantIntegerType ;
175176use PHPStan \Type \Constant \ConstantStringType ;
176177use PHPStan \Type \ErrorType ;
@@ -1078,7 +1079,7 @@ private function processStmtNode(
10781079 }
10791080 } elseif ($ stmt instanceof If_) {
10801081 $ conditionType = ($ this ->treatPhpDocTypesAsCertain ? $ scope ->getType ($ stmt ->cond ) : $ scope ->getNativeType ($ stmt ->cond ))->toBoolean ();
1081- $ ifAlwaysTrue = $ conditionType ->isTrue ();
1082+ $ ifAlwaysTrue = $ conditionType ->isTrue ()-> yes () ;
10821083 $ condResult = $ this ->processExprNode ($ stmt , $ stmt ->cond , $ scope , $ nodeCallback , ExpressionContext::createDeep (), $ context );
10831084 $ exitPoints = [];
10841085 $ throwPoints = $ overridingThrowPoints ?? $ condResult ->getThrowPoints ();
@@ -1088,54 +1089,47 @@ private function processStmtNode(
10881089 $ alwaysTerminating = true ;
10891090 $ hasYield = $ condResult ->hasYield ();
10901091
1091- if ($ context ->isTopLevel () || !$ conditionType ->isTrue ()->no ()) {
1092- $ branchScopeStatementResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ condResult ->getTruthyScope (), $ nodeCallback , $ context );
1093-
1094- if (!$ conditionType ->isTrue ()->no ()) {
1095- $ exitPoints = $ branchScopeStatementResult ->getExitPoints ();
1096- $ throwPoints = array_merge ($ throwPoints , $ branchScopeStatementResult ->getThrowPoints ());
1097- $ impurePoints = array_merge ($ impurePoints , $ branchScopeStatementResult ->getImpurePoints ());
1098- $ branchScope = $ branchScopeStatementResult ->getScope ();
1099- $ finalScope = $ branchScopeStatementResult ->isAlwaysTerminating () ? null : $ branchScope ;
1100- $ alwaysTerminating = $ branchScopeStatementResult ->isAlwaysTerminating ();
1101- if (count ($ branchScopeStatementResult ->getEndStatements ()) > 0 ) {
1102- $ endStatements = array_merge ($ endStatements , $ branchScopeStatementResult ->getEndStatements ());
1103- } elseif (count ($ stmt ->stmts ) > 0 ) {
1104- $ endStatements [] = new EndStatementResult ($ stmt ->stmts [count ($ stmt ->stmts ) - 1 ], $ branchScopeStatementResult );
1105- } else {
1106- $ endStatements [] = new EndStatementResult ($ stmt , $ branchScopeStatementResult );
1107- }
1108- $ hasYield = $ branchScopeStatementResult ->hasYield () || $ hasYield ;
1092+ $ branchScopeStatementResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ condResult ->getTruthyScope (), $ nodeCallback , $ context );
1093+
1094+ if (!$ conditionType instanceof ConstantBooleanType || $ conditionType ->getValue ()) {
1095+ $ exitPoints = $ branchScopeStatementResult ->getExitPoints ();
1096+ $ throwPoints = array_merge ($ throwPoints , $ branchScopeStatementResult ->getThrowPoints ());
1097+ $ impurePoints = array_merge ($ impurePoints , $ branchScopeStatementResult ->getImpurePoints ());
1098+ $ branchScope = $ branchScopeStatementResult ->getScope ();
1099+ $ finalScope = $ branchScopeStatementResult ->isAlwaysTerminating () ? null : $ branchScope ;
1100+ $ alwaysTerminating = $ branchScopeStatementResult ->isAlwaysTerminating ();
1101+ if (count ($ branchScopeStatementResult ->getEndStatements ()) > 0 ) {
1102+ $ endStatements = array_merge ($ endStatements , $ branchScopeStatementResult ->getEndStatements ());
1103+ } elseif (count ($ stmt ->stmts ) > 0 ) {
1104+ $ endStatements [] = new EndStatementResult ($ stmt ->stmts [count ($ stmt ->stmts ) - 1 ], $ branchScopeStatementResult );
1105+ } else {
1106+ $ endStatements [] = new EndStatementResult ($ stmt , $ branchScopeStatementResult );
11091107 }
1108+ $ hasYield = $ branchScopeStatementResult ->hasYield () || $ hasYield ;
11101109 }
11111110
11121111 $ scope = $ condResult ->getFalseyScope ();
1113- $ lastElseIfConditionIsTrue = TrinaryLogic:: createNo () ;
1112+ $ lastElseIfConditionIsTrue = false ;
11141113
11151114 $ condScope = $ scope ;
11161115 foreach ($ stmt ->elseifs as $ elseif ) {
11171116 $ nodeCallback ($ elseif , $ scope );
1118- if (!$ context ->isTopLevel ()) {
1119- if ($ ifAlwaysTrue ->yes () || $ lastElseIfConditionIsTrue ->yes ()) {
1120- continue ;
1121- }
1122- }
11231117 $ elseIfConditionType = ($ this ->treatPhpDocTypesAsCertain ? $ condScope ->getType ($ elseif ->cond ) : $ scope ->getNativeType ($ elseif ->cond ))->toBoolean ();
11241118 $ condResult = $ this ->processExprNode ($ stmt , $ elseif ->cond , $ condScope , $ nodeCallback , ExpressionContext::createDeep (), $ context );
11251119 $ throwPoints = array_merge ($ throwPoints , $ condResult ->getThrowPoints ());
11261120 $ impurePoints = array_merge ($ impurePoints , $ condResult ->getImpurePoints ());
11271121 $ condScope = $ condResult ->getScope ();
11281122 $ branchScopeStatementResult = $ this ->processStmtNodes ($ elseif , $ elseif ->stmts , $ condResult ->getTruthyScope (), $ nodeCallback , $ context );
11291123
1130- if (!$ context ->isTopLevel () && $ elseIfConditionType ->isTrue ()->no ()) {
1131- $ scope = $ condScope ->filterByFalseyValue ($ elseif ->cond );
1132- continue ;
1133- }
1134-
11351124 if (
1136- !$ ifAlwaysTrue ->yes ()
1137- && !$ lastElseIfConditionIsTrue ->yes ()
1138- && !$ elseIfConditionType ->isTrue ()->no ()
1125+ !$ ifAlwaysTrue
1126+ && (
1127+ !$ lastElseIfConditionIsTrue
1128+ && (
1129+ !$ elseIfConditionType instanceof ConstantBooleanType
1130+ || $ elseIfConditionType ->getValue ()
1131+ )
1132+ )
11391133 ) {
11401134 $ exitPoints = array_merge ($ exitPoints , $ branchScopeStatementResult ->getExitPoints ());
11411135 $ throwPoints = array_merge ($ throwPoints , $ branchScopeStatementResult ->getThrowPoints ());
@@ -1153,48 +1147,48 @@ private function processStmtNode(
11531147 $ hasYield = $ hasYield || $ branchScopeStatementResult ->hasYield ();
11541148 }
11551149
1156- if ($ elseIfConditionType ->isTrue ()->yes ()) {
1157- $ lastElseIfConditionIsTrue = $ elseIfConditionType ->isTrue ();
1150+ if (
1151+ $ elseIfConditionType ->isTrue ()->yes ()
1152+ ) {
1153+ $ lastElseIfConditionIsTrue = true ;
11581154 }
1155+
11591156 $ condScope = $ condScope ->filterByFalseyValue ($ elseif ->cond );
11601157 $ scope = $ condScope ;
11611158 }
11621159
11631160 if ($ stmt ->else === null ) {
1164- if (!$ ifAlwaysTrue-> yes () && !$ lastElseIfConditionIsTrue-> yes () ) {
1161+ if (!$ ifAlwaysTrue && !$ lastElseIfConditionIsTrue ) {
11651162 $ finalScope = $ scope ->mergeWith ($ finalScope );
11661163 $ alwaysTerminating = false ;
11671164 }
11681165 } else {
11691166 $ nodeCallback ($ stmt ->else , $ scope );
1167+ $ branchScopeStatementResult = $ this ->processStmtNodes ($ stmt ->else , $ stmt ->else ->stmts , $ scope , $ nodeCallback , $ context );
11701168
1171- if ($ context ->isTopLevel () || (!$ ifAlwaysTrue ->yes () && !$ lastElseIfConditionIsTrue ->yes ())) {
1172- $ branchScopeStatementResult = $ this ->processStmtNodes ($ stmt ->else , $ stmt ->else ->stmts , $ scope , $ nodeCallback , $ context );
1173-
1174- if (!$ ifAlwaysTrue ->yes () && !$ lastElseIfConditionIsTrue ->yes ()) {
1175- $ exitPoints = array_merge ($ exitPoints , $ branchScopeStatementResult ->getExitPoints ());
1176- $ throwPoints = array_merge ($ throwPoints , $ branchScopeStatementResult ->getThrowPoints ());
1177- $ impurePoints = array_merge ($ impurePoints , $ branchScopeStatementResult ->getImpurePoints ());
1178- $ branchScope = $ branchScopeStatementResult ->getScope ();
1179- $ finalScope = $ branchScopeStatementResult ->isAlwaysTerminating () ? $ finalScope : $ branchScope ->mergeWith ($ finalScope );
1180- $ alwaysTerminating = $ alwaysTerminating && $ branchScopeStatementResult ->isAlwaysTerminating ();
1181- if (count ($ branchScopeStatementResult ->getEndStatements ()) > 0 ) {
1182- $ endStatements = array_merge ($ endStatements , $ branchScopeStatementResult ->getEndStatements ());
1183- } elseif (count ($ stmt ->else ->stmts ) > 0 ) {
1184- $ endStatements [] = new EndStatementResult ($ stmt ->else ->stmts [count ($ stmt ->else ->stmts ) - 1 ], $ branchScopeStatementResult );
1185- } else {
1186- $ endStatements [] = new EndStatementResult ($ stmt ->else , $ branchScopeStatementResult );
1187- }
1188- $ hasYield = $ hasYield || $ branchScopeStatementResult ->hasYield ();
1169+ if (!$ ifAlwaysTrue && !$ lastElseIfConditionIsTrue ) {
1170+ $ exitPoints = array_merge ($ exitPoints , $ branchScopeStatementResult ->getExitPoints ());
1171+ $ throwPoints = array_merge ($ throwPoints , $ branchScopeStatementResult ->getThrowPoints ());
1172+ $ impurePoints = array_merge ($ impurePoints , $ branchScopeStatementResult ->getImpurePoints ());
1173+ $ branchScope = $ branchScopeStatementResult ->getScope ();
1174+ $ finalScope = $ branchScopeStatementResult ->isAlwaysTerminating () ? $ finalScope : $ branchScope ->mergeWith ($ finalScope );
1175+ $ alwaysTerminating = $ alwaysTerminating && $ branchScopeStatementResult ->isAlwaysTerminating ();
1176+ if (count ($ branchScopeStatementResult ->getEndStatements ()) > 0 ) {
1177+ $ endStatements = array_merge ($ endStatements , $ branchScopeStatementResult ->getEndStatements ());
1178+ } elseif (count ($ stmt ->else ->stmts ) > 0 ) {
1179+ $ endStatements [] = new EndStatementResult ($ stmt ->else ->stmts [count ($ stmt ->else ->stmts ) - 1 ], $ branchScopeStatementResult );
1180+ } else {
1181+ $ endStatements [] = new EndStatementResult ($ stmt ->else , $ branchScopeStatementResult );
11891182 }
1183+ $ hasYield = $ hasYield || $ branchScopeStatementResult ->hasYield ();
11901184 }
11911185 }
11921186
11931187 if ($ finalScope === null ) {
11941188 $ finalScope = $ scope ;
11951189 }
11961190
1197- if ($ stmt ->else === null && !$ ifAlwaysTrue-> yes () && !$ lastElseIfConditionIsTrue-> yes () ) {
1191+ if ($ stmt ->else === null && !$ ifAlwaysTrue && !$ lastElseIfConditionIsTrue ) {
11981192 $ endStatements [] = new EndStatementResult ($ stmt , new StatementResult ($ finalScope , $ hasYield , $ alwaysTerminating , $ exitPoints , $ throwPoints , $ impurePoints ));
11991193 }
12001194
@@ -1208,7 +1202,6 @@ private function processStmtNode(
12081202 $ condResult = $ this ->processExprNode ($ stmt , $ stmt ->expr , $ scope , $ nodeCallback , ExpressionContext::createDeep (), $ context );
12091203 $ throwPoints = $ overridingThrowPoints ?? $ condResult ->getThrowPoints ();
12101204 $ impurePoints = $ condResult ->getImpurePoints ();
1211- $ exprType = $ scope ->getType ($ stmt ->expr );
12121205 $ scope = $ condResult ->getScope ();
12131206 $ arrayComparisonExpr = new BinaryOp \NotIdentical (
12141207 $ stmt ->expr ,
@@ -1221,18 +1214,6 @@ private function processStmtNode(
12211214 $ originalScope = $ scope ;
12221215 $ bodyScope = $ scope ;
12231216
1224- $ isIterableAtLeastOnce = $ exprType ->isIterableAtLeastOnce ();
1225- if (!$ context ->isTopLevel () && $ isIterableAtLeastOnce ->no ()) {
1226- return new StatementResult (
1227- $ scope ,
1228- $ condResult ->hasYield (),
1229- $ condResult ->isAlwaysTerminating (),
1230- [],
1231- $ throwPoints ,
1232- $ impurePoints ,
1233- );
1234- }
1235-
12361217 if ($ context ->isTopLevel ()) {
12371218 $ originalScope = $ this ->polluteScopeWithAlwaysIterableForeach ? $ scope ->filterByTruthyValue ($ arrayComparisonExpr ) : $ scope ;
12381219 $ bodyScope = $ this ->enterForeach ($ originalScope , $ originalScope , $ stmt );
@@ -1269,6 +1250,8 @@ private function processStmtNode(
12691250 $ finalScope = $ breakExitPoint ->getScope ()->mergeWith ($ finalScope );
12701251 }
12711252
1253+ $ exprType = $ scope ->getType ($ stmt ->expr );
1254+ $ isIterableAtLeastOnce = $ exprType ->isIterableAtLeastOnce ();
12721255 if ($ exprType ->isIterable ()->no () || $ isIterableAtLeastOnce ->maybe ()) {
12731256 $ finalScope = $ finalScope ->mergeWith ($ scope ->filterByTruthyValue (new BooleanOr (
12741257 new BinaryOp \Identical (
@@ -1511,25 +1494,6 @@ private function processStmtNode(
15111494 $ bodyScope = $ condResult ->getTruthyScope ();
15121495 }
15131496
1514- if (!$ context ->isTopLevel () && $ isIterableAtLeastOnce ->no ()) {
1515- if (!isset ($ condResult )) {
1516- throw new ShouldNotHappenException ();
1517- }
1518- if ($ this ->polluteScopeWithLoopInitialAssignments ) {
1519- $ finalScope = $ condResult ->getFalseyScope ()->mergeWith ($ initScope );
1520- } else {
1521- $ finalScope = $ condResult ->getFalseyScope ()->mergeWith ($ scope );
1522- }
1523- return new StatementResult (
1524- $ finalScope ,
1525- $ hasYield ,
1526- false ,
1527- [],
1528- $ throwPoints ,
1529- $ impurePoints ,
1530- );
1531- }
1532-
15331497 if ($ context ->isTopLevel ()) {
15341498 $ count = 0 ;
15351499 do {
0 commit comments