Version 2.13.0-203.0.dev
Merge commit '0873d4eb824506b5e7bac157b103b2f697b075b6' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index 4e018e2..76c3ebc 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -443,11 +443,11 @@
x.expr.as_('int').stmt,
checkPromoted(x, 'int'),
getSsaNodes((nodes) => ssaBeforeLoop = nodes[x]!),
- branchTarget((t) => do_([
- getSsaNodes((nodes) => expect(nodes[x], isNot(ssaBeforeLoop))),
- checkNotPromoted(x),
- x.write(expr('Null')).stmt,
- ], expr('bool'))),
+ do_([
+ getSsaNodes((nodes) => expect(nodes[x], isNot(ssaBeforeLoop))),
+ checkNotPromoted(x),
+ x.write(expr('Null')).stmt,
+ ], expr('bool')),
]);
});
@@ -473,19 +473,19 @@
var x = Var('x', 'int?');
h.run([
declare(x, initialized: true),
- branchTarget((t) => do_(
- [
- if_(x.expr.notEq(nullLiteral), [
- continue_(t),
- ]),
- return_(),
- checkReachable(false),
- checkNotPromoted(x),
- ],
- block([
- checkReachable(true),
- checkPromoted(x, 'int'),
- ]).thenExpr(expr('bool')))),
+ do_(
+ [
+ if_(x.expr.notEq(nullLiteral), [
+ continue_(),
+ ]),
+ return_(),
+ checkReachable(false),
+ checkNotPromoted(x),
+ ],
+ block([
+ checkReachable(true),
+ checkPromoted(x, 'int'),
+ ]).thenExpr(expr('bool'))),
]);
});
@@ -494,8 +494,7 @@
var x = Var('x', 'int?');
h.run([
declare(x, initialized: true),
- branchTarget((t) =>
- do_([], checkNotPromoted(x).thenExpr(x.expr.eq(nullLiteral)))),
+ do_([], checkNotPromoted(x).thenExpr(x.expr.eq(nullLiteral))),
checkPromoted(x, 'int'),
]);
});
@@ -697,23 +696,23 @@
declare(x, initialized: true),
declare(y, initialized: true),
declare(z, initialized: true),
- branchTarget((t) => for_(
- null,
- expr('bool'),
- block([
- checkPromoted(x, 'int'),
- checkNotPromoted(y),
- checkNotPromoted(z),
- ]).thenExpr(expr('Null')),
- [
- if_(expr('bool'), [
- x.expr.as_('int').stmt,
- y.expr.as_('int').stmt,
- continue_(t),
- ]),
- x.expr.as_('int').stmt,
- z.expr.as_('int').stmt,
- ])),
+ for_(
+ null,
+ expr('bool'),
+ block([
+ checkPromoted(x, 'int'),
+ checkNotPromoted(y),
+ checkNotPromoted(z),
+ ]).thenExpr(expr('Null')),
+ [
+ if_(expr('bool'), [
+ x.expr.as_('int').stmt,
+ y.expr.as_('int').stmt,
+ continue_(),
+ ]),
+ x.expr.as_('int').stmt,
+ z.expr.as_('int').stmt,
+ ]),
]);
});
@@ -729,14 +728,13 @@
declare(x, initialized: true),
declare(y, initialized: true),
declare(z, initialized: true),
- branchTarget((t) => for_(
- null, x.expr.eq(nullLiteral).or(z.expr.eq(nullLiteral)), null, [
- if_(expr('bool'), [
- x.expr.as_('int').stmt,
- y.expr.as_('int').stmt,
- break_(t),
- ]),
- ])),
+ for_(null, x.expr.eq(nullLiteral).or(z.expr.eq(nullLiteral)), null, [
+ if_(expr('bool'), [
+ x.expr.as_('int').stmt,
+ y.expr.as_('int').stmt,
+ break_(),
+ ]),
+ ]),
checkPromoted(x, 'int'),
checkNotPromoted(y),
checkNotPromoted(z),
@@ -752,14 +750,14 @@
h.run([
declare(x, initialized: true),
declare(y, initialized: true),
- branchTarget((t) => for_(null, expr('bool'), null, [
- x.write(expr('int?')).stmt,
- if_(expr('bool'), [break_(t)]),
- getSsaNodes((nodes) {
- xSsaInsideLoop = nodes[x]!;
- ySsaInsideLoop = nodes[y]!;
- }),
- ])),
+ for_(null, expr('bool'), null, [
+ x.write(expr('int?')).stmt,
+ if_(expr('bool'), [break_()]),
+ getSsaNodes((nodes) {
+ xSsaInsideLoop = nodes[x]!;
+ ySsaInsideLoop = nodes[y]!;
+ }),
+ ]),
getSsaNodes((nodes) {
// x's Ssa should have been changed because of the join at the end of
// of the loop. y's should not, since it retains the value it had
@@ -781,15 +779,15 @@
h.run([
declare(x, initialized: true),
declare(y, initialized: true),
- branchTarget((t) => for_(null, expr('bool'), null, [
- x.write(expr('int?')).stmt,
- if_(expr('bool'), [break_(t)]),
- if_(x.expr.is_('int'), []),
- getSsaNodes((nodes) {
- xSsaInsideLoop = nodes[x]!;
- ySsaInsideLoop = nodes[y]!;
- }),
- ])),
+ for_(null, expr('bool'), null, [
+ x.write(expr('int?')).stmt,
+ if_(expr('bool'), [break_()]),
+ if_(x.expr.is_('int'), []),
+ getSsaNodes((nodes) {
+ xSsaInsideLoop = nodes[x]!;
+ ySsaInsideLoop = nodes[y]!;
+ }),
+ ]),
getSsaNodes((nodes) {
// x's Ssa should have been changed because of the join at the end of
// the loop. y's should not, since it retains the value it had prior
@@ -867,12 +865,12 @@
h.run([
declare(x, initialized: false),
checkUnassigned(x, true),
- branchTarget((t) => forEachWithNonVariable(expr('List<int>'), [
- // Since a write to x occurs somewhere in the loop, x should no
- // longer be considered unassigned.
- checkUnassigned(x, false),
- break_(t), x.write(expr('int')).stmt,
- ])),
+ forEachWithNonVariable(expr('List<int>'), [
+ // Since a write to x occurs somewhere in the loop, x should no
+ // longer be considered unassigned.
+ checkUnassigned(x, false),
+ break_(), x.write(expr('int')).stmt,
+ ]),
// Even though the write to x is unreachable (since it occurs after a
// break), x should still be considered "possibly assigned" because of
// the conservative join done at the top of the loop.
@@ -1050,15 +1048,15 @@
test('handleBreak handles deep nesting', () {
var h = Harness();
h.run([
- branchTarget((t) => while_(booleanLiteral(true), [
- if_(expr('bool'), [
- if_(expr('bool'), [
- break_(t),
- ]),
- ]),
- return_(),
- checkReachable(false),
- ])),
+ while_(booleanLiteral(true), [
+ if_(expr('bool'), [
+ if_(expr('bool'), [
+ break_(),
+ ]),
+ ]),
+ return_(),
+ checkReachable(false),
+ ]),
checkReachable(true),
]);
});
@@ -1066,16 +1064,16 @@
test('handleBreak handles mixed nesting', () {
var h = Harness();
h.run([
- branchTarget((t) => while_(booleanLiteral(true), [
- if_(expr('bool'), [
- if_(expr('bool'), [
- break_(t),
- ]),
- break_(t),
- ]),
- break_(t),
- checkReachable(false),
- ])),
+ while_(booleanLiteral(true), [
+ if_(expr('bool'), [
+ if_(expr('bool'), [
+ break_(),
+ ]),
+ break_(),
+ ]),
+ break_(),
+ checkReachable(false),
+ ]),
checkReachable(true),
]);
});
@@ -1083,15 +1081,15 @@
test('handleContinue handles deep nesting', () {
var h = Harness();
h.run([
- branchTarget((t) => do_([
- if_(expr('bool'), [
- if_(expr('bool'), [
- continue_(t),
- ]),
- ]),
- return_(),
- checkReachable(false),
- ], checkReachable(true).thenExpr(booleanLiteral(true)))),
+ do_([
+ if_(expr('bool'), [
+ if_(expr('bool'), [
+ continue_(),
+ ]),
+ ]),
+ return_(),
+ checkReachable(false),
+ ], checkReachable(true).thenExpr(booleanLiteral(true))),
checkReachable(false),
]);
});
@@ -1099,16 +1097,16 @@
test('handleContinue handles mixed nesting', () {
var h = Harness();
h.run([
- branchTarget((t) => do_([
- if_(expr('bool'), [
- if_(expr('bool'), [
- continue_(t),
- ]),
- continue_(t),
- ]),
- continue_(t),
- checkReachable(false),
- ], checkReachable(true).thenExpr(booleanLiteral(true)))),
+ do_([
+ if_(expr('bool'), [
+ if_(expr('bool'), [
+ continue_(),
+ ]),
+ continue_(),
+ ]),
+ continue_(),
+ checkReachable(false),
+ ], checkReachable(true).thenExpr(booleanLiteral(true))),
checkReachable(false),
]);
});
@@ -1530,7 +1528,7 @@
h.run([
declare(x, initialized: true),
if_(x.expr.isNot('int'), [
- labeled(return_()),
+ labeled((_) => return_()),
]),
checkPromoted(x, 'int'),
]);
@@ -1542,12 +1540,12 @@
h.run([
declare(x, initialized: true),
if_(x.expr.isNot('int'), [
- branchTarget((t) => labeled(block([
+ labeled((t) => block([
if_(expr('bool'), [
break_(t),
]),
return_(),
- ]))),
+ ])),
]),
checkNotPromoted(x),
]);
@@ -1926,16 +1924,16 @@
declare(z, initialized: true),
y.expr.as_('int').stmt,
z.expr.as_('int').stmt,
- branchTarget((t) => switch_(
+ switch_(
expr('Null'),
[
case_([
x.expr.as_('int').stmt,
y.write(expr('int?')).stmt,
- break_(t),
+ break_(),
]),
],
- isExhaustive: false)),
+ isExhaustive: false),
checkNotPromoted(x),
checkNotPromoted(y),
checkPromoted(z, 'int'),
@@ -1956,23 +1954,23 @@
x.expr.as_('int').stmt,
y.expr.as_('int').stmt,
z.expr.as_('int').stmt,
- branchTarget((t) => switch_(
+ switch_(
expr('Null'),
[
case_([
w.expr.as_('int').stmt,
y.expr.as_('int').stmt,
x.write(expr('int?')).stmt,
- break_(t),
+ break_(),
]),
case_([
w.expr.as_('int').stmt,
x.expr.as_('int').stmt,
y.write(expr('int?')).stmt,
- break_(t),
+ break_(),
]),
],
- isExhaustive: true)),
+ isExhaustive: true),
checkPromoted(w, 'int'),
checkNotPromoted(x),
checkNotPromoted(y),
@@ -1985,16 +1983,16 @@
var x = Var('x', 'int?');
h.run([
declare(x, initialized: true),
- branchTarget((t) => switch_(
+ switch_(
expr('Null'),
[
case_([
x.expr.as_('int').stmt,
- break_(t),
+ break_(),
]),
case_([]),
],
- isExhaustive: true)),
+ isExhaustive: true),
checkNotPromoted(x),
]);
});
@@ -2825,14 +2823,13 @@
declare(x, initialized: true),
declare(y, initialized: true),
declare(z, initialized: true),
- branchTarget(
- (t) => while_(x.expr.eq(nullLiteral).or(z.expr.eq(nullLiteral)), [
- if_(expr('bool'), [
- x.expr.as_('int').stmt,
- y.expr.as_('int').stmt,
- break_(t),
- ]),
- ])),
+ while_(x.expr.eq(nullLiteral).or(z.expr.eq(nullLiteral)), [
+ if_(expr('bool'), [
+ x.expr.as_('int').stmt,
+ y.expr.as_('int').stmt,
+ break_(),
+ ]),
+ ]),
checkPromoted(x, 'int'),
checkNotPromoted(y),
checkNotPromoted(z),
@@ -2848,14 +2845,14 @@
h.run([
declare(x, initialized: true),
declare(y, initialized: true),
- branchTarget((t) => while_(expr('bool'), [
- x.write(expr('int?')).stmt,
- if_(expr('bool'), [break_(t)]),
- getSsaNodes((nodes) {
- xSsaInsideLoop = nodes[x]!;
- ySsaInsideLoop = nodes[y]!;
- }),
- ])),
+ while_(expr('bool'), [
+ x.write(expr('int?')).stmt,
+ if_(expr('bool'), [break_()]),
+ getSsaNodes((nodes) {
+ xSsaInsideLoop = nodes[x]!;
+ ySsaInsideLoop = nodes[y]!;
+ }),
+ ]),
getSsaNodes((nodes) {
// x's Ssa should have been changed because of the join at the end of
// the loop. y's should not, since it retains the value it had prior
@@ -2877,15 +2874,15 @@
h.run([
declare(x, initialized: true),
declare(y, initialized: true),
- branchTarget((t) => while_(expr('bool'), [
- x.write(expr('int?')).stmt,
- if_(expr('bool'), [break_(t)]),
- if_(x.expr.is_('int'), []),
- getSsaNodes((nodes) {
- xSsaInsideLoop = nodes[x]!;
- ySsaInsideLoop = nodes[y]!;
- }),
- ])),
+ while_(expr('bool'), [
+ x.write(expr('int?')).stmt,
+ if_(expr('bool'), [break_()]),
+ if_(x.expr.is_('int'), []),
+ getSsaNodes((nodes) {
+ xSsaInsideLoop = nodes[x]!;
+ ySsaInsideLoop = nodes[y]!;
+ }),
+ ]),
getSsaNodes((nodes) {
// x's Ssa should have been changed because of the join at the end of
// the loop. y's should not, since it retains the value it had prior
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 9e1ca0a..5e41049 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -22,19 +22,7 @@
Expression booleanLiteral(bool value) => _BooleanLiteral(value);
-/// Wrapper allowing creation of a statement that can be used as the target of
-/// `break` or `continue` statements. [callback] will be invoked to create the
-/// statement, and it will be passed a [BranchTargetPlaceholder] that can be
-/// passed to [break_] or [continue_].
-Statement branchTarget(Statement Function(BranchTargetPlaceholder) callback) {
- var branchTargetPlaceholder = BranchTargetPlaceholder._();
- var stmt = callback(branchTargetPlaceholder);
- branchTargetPlaceholder._target = stmt;
- return stmt;
-}
-
-Statement break_(BranchTargetPlaceholder branchTargetPlaceholder) =>
- new _Break(branchTargetPlaceholder);
+Statement break_([LabeledStatement? target]) => new _Break(target);
SwitchCase case_(List<Statement> body, {bool hasLabel = false}) =>
SwitchCase._(hasLabel, new _Block(body));
@@ -64,8 +52,7 @@
Statement checkUnassigned(Var variable, bool expectedUnassignedState) =>
new _CheckUnassigned(variable, expectedUnassignedState);
-Statement continue_(BranchTargetPlaceholder branchTargetPlaceholder) =>
- new _Continue(branchTargetPlaceholder);
+Statement continue_() => new _Continue();
Statement declare(Var variable,
{required bool initialized,
@@ -148,7 +135,11 @@
void Function(Map<Type, NonPromotionReason>) callback) =>
new _WhyNotPromoted_ImplicitThis(Type(staticType), callback);
-Statement labeled(Statement body) => new _LabeledStatement(body);
+Statement labeled(Statement Function(LabeledStatement) callback) {
+ var labeledStatement = LabeledStatement._();
+ labeledStatement._body = callback(labeledStatement);
+ return labeledStatement;
+}
Statement localFunction(List<Statement> body) => _LocalFunction(block(body));
@@ -169,14 +160,6 @@
Statement while_(Expression condition, List<Statement> body) =>
new _While(condition, block(body));
-/// Placeholder used by [branchTarget] to tie `break` and `continue` statements
-/// to their branch targets.
-class BranchTargetPlaceholder {
- late Statement _target;
-
- BranchTargetPlaceholder._();
-}
-
/// Representation of an expression in the pseudo-Dart language used for flow
/// analysis testing. Methods in this class may be used to create more complex
/// expressions based on this one.
@@ -398,6 +381,10 @@
Map<String, Map<String, String>> _promotionExceptions = {};
+ Statement? _currentBreakTarget;
+
+ Statement? _currentContinueTarget;
+
Harness({this.legacy = false, String? thisType})
: thisType = thisType == null ? null : Type(thisType);
@@ -544,6 +531,39 @@
'TODO(paulberry): least upper bound of $type1 and $type2');
}
}
+
+ void _visitLoopBody(Statement loop, Statement body,
+ FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+ var previousBreakTarget = _currentBreakTarget;
+ var previousContinueTarget = _currentContinueTarget;
+ _currentBreakTarget = loop;
+ _currentContinueTarget = loop;
+ body._visit(this, flow);
+ _currentBreakTarget = previousBreakTarget;
+ _currentContinueTarget = previousContinueTarget;
+ }
+}
+
+class LabeledStatement extends Statement {
+ late final Statement _body;
+
+ LabeledStatement._() : super._();
+
+ @override
+ String toString() => 'labeled: $_body';
+
+ @override
+ void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
+ _body._preVisit(assignedVariables);
+ }
+
+ @override
+ void _visit(
+ Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+ flow.labeledStatement_begin(this);
+ _body._visit(h, flow);
+ flow.labeledStatement_end();
+ }
}
/// Representation of an expression that can appear on the left hand side of an
@@ -752,9 +772,9 @@
}
class _Break extends Statement {
- final BranchTargetPlaceholder branchTargetPlaceholder;
+ final LabeledStatement? target;
- _Break(this.branchTargetPlaceholder) : super._();
+ _Break(this.target) : super._();
@override
String toString() => 'break;';
@@ -765,9 +785,7 @@
@override
void _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- // ignore: unnecessary_null_comparison
- assert(branchTargetPlaceholder._target != null);
- flow.handleBreak(branchTargetPlaceholder._target);
+ flow.handleBreak(target ?? h._currentBreakTarget!);
}
}
@@ -925,9 +943,7 @@
}
class _Continue extends Statement {
- final BranchTargetPlaceholder branchTargetPlaceholder;
-
- _Continue(this.branchTargetPlaceholder) : super._();
+ _Continue() : super._();
@override
String toString() => 'continue;';
@@ -938,9 +954,7 @@
@override
void _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- // ignore: unnecessary_null_comparison
- assert(branchTargetPlaceholder._target != null);
- flow.handleContinue(branchTargetPlaceholder._target);
+ flow.handleContinue(h._currentContinueTarget!);
}
}
@@ -1002,7 +1016,7 @@
void _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
flow.doStatement_bodyBegin(this);
- body._visit(h, flow);
+ h._visitLoopBody(this, body, flow);
flow.doStatement_conditionBegin();
condition._visit(h, flow);
flow.doStatement_end(condition);
@@ -1104,7 +1118,7 @@
flow.for_conditionBegin(this);
condition?._visit(h, flow);
flow.for_bodyBegin(forCollection ? null : this, condition);
- body._visit(h, flow);
+ h._visitLoopBody(this, body, flow);
flow.for_updaterBegin();
updater?._visit(h, flow);
flow.for_end();
@@ -1157,7 +1171,7 @@
if (variable != null && !declaresVariable) {
flow.write(this, variable, iteratedType, null);
}
- body._visit(h, flow);
+ h._visitLoopBody(this, body, flow);
flow.forEach_end();
}
}
@@ -1284,28 +1298,6 @@
}
}
-class _LabeledStatement extends Statement {
- final Statement body;
-
- _LabeledStatement(this.body) : super._();
-
- @override
- String toString() => 'labeled: $body';
-
- @override
- void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
- body._preVisit(assignedVariables);
- }
-
- @override
- void _visit(
- Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- flow.labeledStatement_begin(this);
- body._visit(h, flow);
- flow.labeledStatement_end();
- }
-}
-
class _LocalFunction extends Statement {
final Statement body;
@@ -1581,11 +1573,14 @@
expression._visit(h, flow);
flow.switchStatement_expressionEnd(this);
var oldSwitch = h._currentSwitch;
+ var previousBreakTarget = h._currentBreakTarget;
h._currentSwitch = this;
+ h._currentBreakTarget = this;
for (var case_ in cases) {
case_._visit(h, flow);
}
h._currentSwitch = oldSwitch;
+ h._currentBreakTarget = previousBreakTarget;
flow.switchStatement_end(isExhaustive);
}
}
@@ -1781,7 +1776,7 @@
flow.whileStatement_conditionBegin(this);
condition._visit(h, flow);
flow.whileStatement_bodyBegin(this, condition);
- body._visit(h, flow);
+ h._visitLoopBody(this, body, flow);
flow.whileStatement_end();
}
}
diff --git a/tools/VERSION b/tools/VERSION
index df1501b..5d714ab 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 202
+PRERELEASE 203
PRERELEASE_PATCH 0
\ No newline at end of file