Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 3919491

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Improvements for flow analysis.
Support for 'for'. Support for 'for-each'. Support for 'switch'. Support for local functions and closures. Support for 'try/catch/finally'. [email protected] Change-Id: Idd0e528b706c1094e2bfdf32f84a9bcd7c80968a Reviewed-on: https://dart-review.googlesource.com/c/89921 Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 17a4396 commit 3919491

File tree

2 files changed

+1150
-43
lines changed

2 files changed

+1150
-43
lines changed

pkg/analyzer/lib/src/dart/resolver/flow_analysis.dart

Lines changed: 125 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
343463
class 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

Comments
 (0)