@@ -230,6 +230,78 @@ void h(int k) {}
230230 assertEdge (iNode, jNode, hard: false );
231231 }
232232
233+ test_catch_cancels_promotions_based_on_assignments_in_body () async {
234+ await analyze ('''
235+ void f(int i) {
236+ if (i == null) return;
237+ try {
238+ g(i);
239+ i = null;
240+ if (i == null) return;
241+ g(i);
242+ } catch (_) {
243+ h(i);
244+ }
245+ }
246+ void g(int j) {}
247+ void h(int k) {}
248+ ''' );
249+ var iNode = decoratedTypeAnnotation ('int i' ).node;
250+ var jNode = decoratedTypeAnnotation ('int j' ).node;
251+ var kNode = decoratedTypeAnnotation ('int k' ).node;
252+ // No edge from i to j because i is promoted at the time of both calls to g.
253+ assertNoEdge (iNode, jNode);
254+ // But there is an edge from i to k, because there is no guarantee that i is
255+ // promoted at all times during the execution of the try block.
256+ assertEdge (iNode, kNode, hard: false );
257+ }
258+
259+ test_catch_falls_through_to_after_try () async {
260+ await analyze ('''
261+ void f(int i) {
262+ try {
263+ g(i);
264+ return;
265+ } catch (_) {
266+ if (i == null) return;
267+ }
268+ h(i);
269+ }
270+ void g(int j) {}
271+ void h(int k) {}
272+ ''' );
273+ var iNode = decoratedTypeAnnotation ('int i' ).node;
274+ var jNode = decoratedTypeAnnotation ('int j' ).node;
275+ var kNode = decoratedTypeAnnotation ('int k' ).node;
276+ // No edge from i to k because i's type is promoted to non-nullable
277+ assertNoEdge (iNode, kNode);
278+ // But there is an edge from i to j.
279+ assertEdge (iNode, jNode, hard: true );
280+ }
281+
282+ test_catch_resets_to_state_before_try () async {
283+ await analyze ('''
284+ void f(int i) {
285+ try {
286+ if (i == null) return;
287+ g(i);
288+ } catch (_) {
289+ h(i);
290+ }
291+ }
292+ void g(int j) {}
293+ void h(int k) {}
294+ ''' );
295+ var iNode = decoratedTypeAnnotation ('int i' ).node;
296+ var jNode = decoratedTypeAnnotation ('int j' ).node;
297+ var kNode = decoratedTypeAnnotation ('int k' ).node;
298+ // No edge from i to j because i's type is promoted to non-nullable
299+ assertNoEdge (iNode, jNode);
300+ // But there is an edge from i to k, since we assume an exception might
301+ // occur at any time during the body of the try.
302+ assertEdge (iNode, kNode, hard: false );
303+ }
304+
233305 test_conditionalExpression () async {
234306 await analyze ('''
235307int f(int i) => i == null ? g(i) : h(i);
@@ -455,6 +527,53 @@ class C {
455527 // field doesn't cause flow analysis to crash.
456528 }
457529
530+ test_finally_promotions_are_preserved () async {
531+ await analyze ('''
532+ void f(int i) {
533+ try {
534+ g(i);
535+ } finally {
536+ if (i == null) return;
537+ }
538+ h(i);
539+ }
540+ void g(int j) {}
541+ void h(int k) {}
542+ ''' );
543+ var iNode = decoratedTypeAnnotation ('int i' ).node;
544+ var jNode = decoratedTypeAnnotation ('int j' ).node;
545+ var kNode = decoratedTypeAnnotation ('int k' ).node;
546+ // No edge from i to k because i's type is promoted to non-nullable in the
547+ // finally block.
548+ assertNoEdge (iNode, kNode);
549+ // But there is an edge from i to j.
550+ assertEdge (iNode, jNode, hard: true );
551+ }
552+
553+ test_finally_temporarily_resets_to_state_before_try () async {
554+ await analyze ('''
555+ void f(int i) {
556+ try {
557+ if (i == null) return;
558+ g(i);
559+ } finally {
560+ h(i);
561+ }
562+ }
563+ void g(int j) {}
564+ void h(int k) {}
565+ ''' );
566+ var iNode = decoratedTypeAnnotation ('int i' ).node;
567+ var jNode = decoratedTypeAnnotation ('int j' ).node;
568+ var kNode = decoratedTypeAnnotation ('int k' ).node;
569+ // No edge from i to j because i's type is promoted to non-nullable in the
570+ // try-block.
571+ assertNoEdge (iNode, jNode);
572+ // But there is an edge from i to k, since we assume an exception might
573+ // occur at any time during the body of the try.
574+ assertEdge (iNode, kNode, hard: false );
575+ }
576+
458577 test_for_break_target () async {
459578 await analyze ('''
460579void f(int i) {
@@ -995,6 +1114,29 @@ bool b3 = b1 || b2;
9951114 // top level variable doesn't cause flow analysis to crash.
9961115 }
9971116
1117+ test_try_falls_through_to_after_try () async {
1118+ await analyze ('''
1119+ void f(int i) {
1120+ try {
1121+ g(i);
1122+ if (i == null) return;
1123+ } catch (_) {
1124+ return;
1125+ }
1126+ h(i);
1127+ }
1128+ void g(int j) {}
1129+ void h(int k) {}
1130+ ''' );
1131+ var iNode = decoratedTypeAnnotation ('int i' ).node;
1132+ var jNode = decoratedTypeAnnotation ('int j' ).node;
1133+ var kNode = decoratedTypeAnnotation ('int k' ).node;
1134+ // No edge from i to k because i's type is promoted to non-nullable
1135+ assertNoEdge (iNode, kNode);
1136+ // But there is an edge from i to j.
1137+ assertEdge (iNode, jNode, hard: true );
1138+ }
1139+
9981140 test_while_break_target () async {
9991141 await analyze ('''
10001142void f(int i) {
0 commit comments