@@ -128,6 +128,69 @@ class FlowAnalysis {
128128 _conditionFalse = _current;
129129 }
130130
131+ void forEachStatement_bodyBegin (Set <VariableElement > loopAssigned) {
132+ _stack.add (_current);
133+ _current = _current.removePromotedAll (loopAssigned);
134+ }
135+
136+ void forEachStatement_end () {
137+ var afterIterable = _stack.removeLast ();
138+ _current = _current.combine (typeSystem, afterIterable);
139+ }
140+
141+ void forStatement_bodyBegin (ForStatement node, Expression condition) {
142+ _conditionalEnd (condition);
143+ // Tail of the stack: falseCondition, trueCondition
144+
145+ var trueCondition = _stack.removeLast ();
146+
147+ _statementToStackIndex[node] = _stack.length;
148+ _stack.add (_State .identity); // break
149+ _stack.add (_State .identity); // continue
150+
151+ _current = trueCondition;
152+ }
153+
154+ void forStatement_conditionBegin (Set <VariableElement > loopAssigned) {
155+ _current = _current.removePromotedAll (loopAssigned);
156+ }
157+
158+ void forStatement_end () {
159+ // Tail of the stack: falseCondition, break
160+ var breakState = _stack.removeLast ();
161+ var falseCondition = _stack.removeLast ();
162+
163+ _current = falseCondition.combine (typeSystem, breakState);
164+ }
165+
166+ void forStatement_updaterBegin () {
167+ // Tail of the stack: falseCondition, break, continue
168+ var afterBody = _current;
169+ var continueState = _stack.removeLast ();
170+
171+ _current = afterBody.combine (typeSystem, continueState);
172+ }
173+
174+ void functionExpression_begin () {
175+ _stack.add (_current);
176+
177+ Set <VariableElement > notPromoted = null ;
178+ for (var variable in _current.promoted.keys) {
179+ if (functionBody.isPotentiallyMutatedInScope (variable)) {
180+ notPromoted ?? = Set <VariableElement >.identity ();
181+ notPromoted.add (variable);
182+ }
183+ }
184+
185+ if (notPromoted != null ) {
186+ _current = _current.removePromotedAll (notPromoted);
187+ }
188+ }
189+
190+ void functionExpression_end () {
191+ _current = _stack.removeLast ();
192+ }
193+
131194 void handleBreak (AstNode target) {
132195 var breakIndex = _statementToStackIndex[target];
133196 if (breakIndex != null ) {
@@ -284,19 +347,77 @@ class FlowAnalysis {
284347 }
285348 }
286349
350+ /// The [notPromoted] set contains all variables that are potentially
351+ /// assigned in other cases that might target this with `continue` , so
352+ /// these variables might have different types and are "un-promoted" from
353+ /// the "afterExpression" state.
354+ void switchStatement_beginCase (Set <VariableElement > notPromoted) {
355+ _current = _stack.last.removePromotedAll (notPromoted);
356+ }
357+
358+ void switchStatement_end (SwitchStatement node, bool hasDefault) {
359+ // Tail of the stack: break, continue, afterExpression
360+ var afterExpression = _current = _stack.removeLast ();
361+ _stack.removeLast (); // continue
362+ var breakState = _stack.removeLast ();
363+
364+ if (hasDefault) {
365+ _current = breakState;
366+ } else {
367+ _current = breakState.combine (typeSystem, afterExpression);
368+ }
369+ }
370+
371+ void switchStatement_expressionEnd (SwitchStatement node) {
372+ _statementToStackIndex[node] = _stack.length;
373+ _stack.add (_State .identity); // break
374+ _stack.add (_State .identity); // continue
375+ _stack.add (_current); // afterExpression
376+ }
377+
287378 void trueLiteral (BooleanLiteral expression) {
288379 _condition = expression;
289380 _conditionTrue = _current;
290381 _conditionFalse = _State .identity;
291382 }
292383
384+ void tryStatement_bodyBegin () {
385+ _stack.add (_current);
386+ // Tail of the stack: beforeBody
387+ }
388+
389+ void tryStatement_bodyEnd (Set <VariableElement > notPromoted) {
390+ var beforeBody = _stack.removeLast ();
391+ var beforeCatch = beforeBody.removePromotedAll (notPromoted);
392+ _stack.add (beforeCatch);
393+ _stack.add (_current); // afterBodyAndCatches
394+ // Tail of the stack: beforeCatch, afterBodyAndCatches
395+ }
396+
397+ void tryStatement_catchBegin () {
398+ var beforeCatch = _stack[_stack.length - 2 ];
399+ _current = beforeCatch;
400+ }
401+
402+ void tryStatement_catchEnd () {
403+ var afterBodyAndCatches = _stack.last;
404+ _stack.last = afterBodyAndCatches.combine (typeSystem, _current);
405+ }
406+
407+ void tryStatement_finallyBegin () {
408+ var afterBodyAndCatches = _stack.removeLast ();
409+ _stack.removeLast (); // beforeCatch
410+
411+ _current = afterBodyAndCatches;
412+ }
413+
293414 void verifyStackEmpty () {
294415 assert (_stack.isEmpty);
295416 }
296417
297418 void whileStatement_bodyBegin (WhileStatement node) {
298419 _conditionalEnd (node.condition);
299- // Tail of the stack: falseCondition, trueCondition
420+ // Tail of the stack: falseCondition, trueCondition
300421
301422 var trueCondition = _stack.removeLast ();
302423
@@ -307,8 +428,7 @@ class FlowAnalysis {
307428 _current = trueCondition;
308429 }
309430
310- void whileStatement_conditionBegin (
311- WhileStatement node, Set <VariableElement > loopAssigned) {
431+ void whileStatement_conditionBegin (Set <VariableElement > loopAssigned) {
312432 _current = _current.removePromotedAll (loopAssigned);
313433 }
314434
@@ -341,7 +461,7 @@ class FlowAnalysis {
341461
342462/// Sets of variables that are potentially assigned in loops.
343463class LoopAssignedVariables {
344- static final _emptySet = Set <VariableElement >();
464+ static final emptySet = Set <VariableElement >();
345465
346466 /// Mapping from a loop [AstNode] to the set of variables that are
347467 /// potentially assigned in this loop.
@@ -352,7 +472,7 @@ class LoopAssignedVariables {
352472
353473 /// Return the set of variables that are potentially assigned in the [loop] .
354474 Set <VariableElement > operator [](AstNode loop) {
355- return _map[loop] ?? _emptySet ;
475+ return _map[loop] ?? emptySet ;
356476 }
357477
358478 void beginLoop () {
0 commit comments