@@ -689,7 +689,7 @@ private function processStmtNode(
689689
690690 if (!$ conditionType instanceof ConstantBooleanType || $ conditionType ->getValue ()) {
691691 $ exitPoints = $ branchScopeStatementResult ->getExitPoints ();
692- $ throwPoints = $ branchScopeStatementResult ->getThrowPoints ();
692+ $ throwPoints = array_merge ( $ throwPoints , $ branchScopeStatementResult ->getThrowPoints () );
693693 $ branchScope = $ branchScopeStatementResult ->getScope ();
694694 $ finalScope = $ branchScopeStatementResult ->isAlwaysTerminating () ? null : $ branchScope ;
695695 $ alwaysTerminating = $ branchScopeStatementResult ->isAlwaysTerminating ();
@@ -1126,23 +1126,8 @@ private function processStmtNode(
11261126 $ branchScopeResult = $ this ->processStmtNodes ($ stmt , $ stmt ->stmts , $ scope , $ nodeCallback );
11271127 $ branchScope = $ branchScopeResult ->getScope ();
11281128 $ finalScope = $ branchScopeResult ->isAlwaysTerminating () ? null : $ branchScope ;
1129- if (count ($ branchScopeResult ->getThrowPoints ()) > 0 ) {
1130- $ allCaught = false ;
1131- foreach ($ stmt ->catches as $ catch ) {
1132- foreach ($ catch ->types as $ type ) {
1133- if ($ type ->toString () === \Throwable::class) {
1134- continue ;
1135- }
1136- $ allCaught = true ;
1137- }
1138- }
1139- if (!$ allCaught ) {
1140- $ branchScope = $ branchScope ->mergeWith ($ branchScopeResult ->getThrowPoints ()[0 ]->getScope ());
1141- }
1142- }
1143- $ tryScope = $ branchScope ;
1129+
11441130 $ exitPoints = [];
1145- $ throwPoints = [];
11461131 $ alwaysTerminating = $ branchScopeResult ->isAlwaysTerminating ();
11471132 $ hasYield = $ branchScopeResult ->hasYield ();
11481133
@@ -1158,34 +1143,78 @@ private function processStmtNode(
11581143 $ exitPoints [] = $ exitPoint ;
11591144 }
11601145
1161- // todo filter caught
1162- $ throwPoints = array_merge ($ throwPoints , $ branchScopeResult ->getThrowPoints ());
1146+ $ throwPoints = $ branchScopeResult ->getThrowPoints ();
1147+ foreach ($ throwPoints as $ throwPoint ) {
1148+ if ($ finallyScope === null ) {
1149+ continue ;
1150+ }
1151+ $ finallyScope = $ finallyScope ->mergeWith ($ throwPoint ->getScope ());
1152+ }
1153+
1154+ $ throwPointsForLater = [];
11631155
11641156 foreach ($ stmt ->catches as $ catchNode ) {
11651157 $ nodeCallback ($ catchNode , $ scope );
1166- if (!$ this ->polluteCatchScopeWithTryAssignments ) {
1167- $ catchScopeResult = $ this ->processCatchNode ($ catchNode , $ scope ->mergeWith ($ tryScope ), $ nodeCallback );
1168- $ catchScopeForFinally = $ catchScopeResult ->getScope ();
1158+ $ catchType = TypeCombinator::union (...array_map (static function (Name $ name ): Type {
1159+ return new ObjectType ($ name ->toString ());
1160+ }, $ catchNode ->types ));
1161+ $ matchingThrowPoints = [];
1162+ $ newThrowPoints = [];
1163+ foreach ($ throwPoints as $ throwPoint ) {
1164+ $ isSuperType = $ catchType ->isSuperTypeOf ($ throwPoint ->getType ());
1165+ if (!$ isSuperType ->no ()) {
1166+ $ matchingThrowPoints [] = $ throwPoint ;
1167+ }
1168+ if ($ isSuperType ->yes ()) {
1169+ continue ;
1170+ }
1171+ $ newThrowPoints [] = $ throwPoint ;
1172+ }
1173+ $ throwPoints = $ newThrowPoints ;
1174+ if (count ($ matchingThrowPoints ) === 0 ) {
1175+ if (!$ this ->polluteCatchScopeWithTryAssignments ) {
1176+ $ catchScope = $ scope ->mergeWith ($ finalScope );
1177+ } else {
1178+ $ catchScope = $ branchScope ;
1179+ }
11691180 } else {
1170- $ catchScopeForFinally = $ this ->processCatchNode ($ catchNode , $ tryScope , $ nodeCallback )->getScope ();
1171- $ catchScopeResult = $ this ->processCatchNode ($ catchNode , $ scope ->mergeWith ($ tryScope ), static function (): void {
1172- });
1181+ $ catchScope = null ;
1182+ foreach ($ matchingThrowPoints as $ matchingThrowPoint ) {
1183+ if ($ catchScope === null ) {
1184+ $ catchScope = $ matchingThrowPoint ->getScope ();
1185+ } else {
1186+ $ catchScope = $ catchScope ->mergeWith ($ matchingThrowPoint ->getScope ());
1187+ }
1188+ }
1189+ }
1190+
1191+ $ catchScopeResult = $ this ->processCatchNode ($ catchNode , $ catchScope , $ nodeCallback );
1192+ if (count ($ matchingThrowPoints ) === 0 ) {
1193+ continue ;
11731194 }
11741195
11751196 $ finalScope = $ catchScopeResult ->isAlwaysTerminating () ? $ finalScope : $ catchScopeResult ->getScope ()->mergeWith ($ finalScope );
11761197 $ alwaysTerminating = $ alwaysTerminating && $ catchScopeResult ->isAlwaysTerminating ();
11771198 $ hasYield = $ hasYield || $ catchScopeResult ->hasYield ();
1199+ $ catchThrowPoints = $ catchScopeResult ->getThrowPoints ();
1200+ $ throwPointsForLater = array_merge ($ throwPointsForLater , $ catchThrowPoints );
11781201
11791202 if ($ finallyScope !== null ) {
1180- $ finallyScope = $ finallyScope ->mergeWith ($ catchScopeForFinally );
1203+ $ finallyScope = $ finallyScope ->mergeWith ($ catchScopeResult -> getScope () );
11811204 }
11821205 foreach ($ catchScopeResult ->getExitPoints () as $ exitPoint ) {
11831206 if ($ finallyScope !== null ) {
11841207 $ finallyScope = $ finallyScope ->mergeWith ($ exitPoint ->getScope ());
11851208 }
11861209 $ exitPoints [] = $ exitPoint ;
11871210 }
1188- $ throwPoints = array_merge ($ throwPoints , $ catchScopeResult ->getThrowPoints ());
1211+
1212+ foreach ($ catchThrowPoints as $ catchThrowPoint ) {
1213+ if ($ finallyScope === null ) {
1214+ continue ;
1215+ }
1216+ $ finallyScope = $ finallyScope ->mergeWith ($ catchThrowPoint ->getScope ());
1217+ }
11891218 }
11901219
11911220 if ($ finalScope === null ) {
@@ -1197,13 +1226,13 @@ private function processStmtNode(
11971226 $ finallyResult = $ this ->processStmtNodes ($ stmt ->finally , $ stmt ->finally ->stmts , $ finallyScope , $ nodeCallback );
11981227 $ alwaysTerminating = $ alwaysTerminating || $ finallyResult ->isAlwaysTerminating ();
11991228 $ hasYield = $ hasYield || $ finallyResult ->hasYield ();
1229+ $ throwPointsForLater = array_merge ($ throwPointsForLater , $ finallyResult ->getThrowPoints ());
12001230 $ finallyScope = $ finallyResult ->getScope ();
12011231 $ finalScope = $ finallyResult ->isAlwaysTerminating () ? $ finalScope : $ finalScope ->processFinallyScope ($ finallyScope , $ originalFinallyScope );
12021232 $ exitPoints = array_merge ($ exitPoints , $ finallyResult ->getExitPoints ());
1203- $ throwPoints = array_merge ($ throwPoints , $ finallyResult ->getThrowPoints ());
12041233 }
12051234
1206- return new StatementResult ($ finalScope , $ hasYield , $ alwaysTerminating , $ exitPoints , $ throwPoints );
1235+ return new StatementResult ($ finalScope , $ hasYield , $ alwaysTerminating , $ exitPoints , array_merge ( $ throwPoints, $ throwPointsForLater ) );
12071236 } elseif ($ stmt instanceof Unset_) {
12081237 $ hasYield = false ;
12091238 $ throwPoints = [];
0 commit comments