[cfe] Implement compilation of loops in lists and sets
Implement the translation of for and for-in loops in non-const lists
and sets. They are lowered to block expressions containing a loop.
It is impossible to target these loops with a break or continue
because they do not contain statements in their body.
Type inference is not yet implemented.
Change-Id: I35ff1650fde54cd376fe0b444891010435c74507
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97922
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 07f8ed9..224806d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -4058,7 +4058,7 @@
var entry = pop();
Token inToken = pop();
Token forToken = pop();
- pop(NullValue.AwaitToken);
+ Token awaitToken = pop(NullValue.AwaitToken);
Expression iterable = popForValue();
Object lvalue = pop(); // lvalue
exitLocalScope();
@@ -4083,10 +4083,12 @@
Statement prologue = buildForInBody(lvalue, variable, forToken, inToken);
if (entry is MapEntry) {
push(forest.forInMapEntry(
- variable, iterable, prologue, entry, problem, forToken));
+ variable, iterable, prologue, entry, problem, forToken,
+ isAsync: awaitToken != null));
} else {
push(forest.forInElement(
- variable, iterable, prologue, toValue(entry), problem, forToken));
+ variable, iterable, prologue, toValue(entry), problem, forToken,
+ isAsync: awaitToken != null));
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
index baeda38..1616ce7 100644
--- a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
@@ -328,15 +328,19 @@
@override
Expression forInElement(VariableDeclaration variable, Expression iterable,
- Statement prologue, Expression body, Expression problem, Token token) {
- return new ForInElement(variable, iterable, prologue, body, problem)
+ Statement prologue, Expression body, Expression problem, Token token,
+ {bool isAsync: false}) {
+ return new ForInElement(variable, iterable, prologue, body, problem,
+ isAsync: isAsync)
..fileOffset = offsetForToken(token);
}
@override
MapEntry forInMapEntry(VariableDeclaration variable, Expression iterable,
- Statement prologue, MapEntry body, Expression problem, Token token) {
- return new ForInMapEntry(variable, iterable, prologue, body, problem)
+ Statement prologue, MapEntry body, Expression problem, Token token,
+ {bool isAsync: false}) {
+ return new ForInMapEntry(variable, iterable, prologue, body, problem,
+ isAsync: isAsync)
..fileOffset = offsetForToken(token);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 0cda9bd..818a3b1 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -211,10 +211,12 @@
Token token);
Expression forInElement(VariableDeclaration variable, Expression iterable,
- Statement prologue, Expression body, Expression problem, Token token);
+ Statement prologue, Expression body, Expression problem, Token token,
+ {bool isAsync: false});
MapEntry forInMapEntry(VariableDeclaration variable, Expression iterable,
- Statement prologue, MapEntry body, Expression problem, Token token);
+ Statement prologue, MapEntry body, Expression problem, Token token,
+ {bool isAsync: false});
/// Return a representation of an assert that appears in a constructor's
/// initializer list.
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 6360473..4e50c70 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -11,14 +11,6 @@
@override
void defaultExpression(Expression node, DartType typeContext) {
- if (node is ForElement) {
- visitForElement(node, typeContext);
- return;
- }
- if (node is ForInElement) {
- visitForInElement(node, typeContext);
- return;
- }
unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
inferrer.helper.uri);
}
@@ -29,18 +21,6 @@
inferrer.helper.uri);
}
- void visitForElement(ForElement node, DartType typeContext) {
- node.parent.replaceChild(node,
- new InvalidExpression('unhandled for element in collection literal'));
- }
-
- void visitForInElement(ForInElement node, DartType typeContext) {
- node.parent.replaceChild(
- node,
- new InvalidExpression(
- 'unhandled for-in element in collection literal'));
- }
-
@override
void visitInvalidExpression(InvalidExpression node, DartType typeContext) {}
@@ -264,11 +244,12 @@
node.field.type, initializerType, node.value, node.fileOffset);
}
- void handleForInStatementDeclaringVariable(ForInStatement node) {
+ void handleForInDeclaringVariable(
+ VariableDeclaration variable, Expression iterable, Statement body,
+ {bool isAsync: false}) {
DartType elementType;
bool typeNeeded = false;
bool typeChecksNeeded = !inferrer.isTopLevel;
- final VariableDeclaration variable = node.variable;
if (VariableDeclarationJudgment.isImplicitlyTyped(variable)) {
typeNeeded = true;
elementType = const UnknownType();
@@ -276,45 +257,52 @@
elementType = variable.type;
}
- DartType inferredType =
- inferForInIterable(node, elementType, typeNeeded || typeChecksNeeded);
+ DartType inferredType = inferForInIterable(
+ iterable, elementType, typeNeeded || typeChecksNeeded,
+ isAsync: isAsync);
if (typeNeeded) {
inferrer.instrumentation?.record(inferrer.uri, variable.fileOffset,
'type', new InstrumentationValueForType(inferredType));
variable.type = inferredType;
}
- inferrer.inferStatement(node.body);
+ if (body != null) inferrer.inferStatement(body);
VariableDeclaration tempVar =
new VariableDeclaration(null, type: inferredType, isFinal: true);
VariableGet variableGet = new VariableGet(tempVar)
..fileOffset = variable.fileOffset;
+ TreeNode parent = variable.parent;
Expression implicitDowncast = inferrer.ensureAssignable(
- variable.type, inferredType, variableGet, node.fileOffset,
+ variable.type, inferredType, variableGet, parent.fileOffset,
template: templateForInLoopElementTypeNotAssignable);
if (implicitDowncast != null) {
- node.variable = tempVar..parent = node;
+ parent.replaceChild(variable, tempVar);
variable.initializer = implicitDowncast..parent = variable;
- node.body = combineStatements(variable, node.body)..parent = node;
+ if (body == null) {
+ ForInElement element = parent;
+ element.prologue = variable;
+ } else {
+ parent.replaceChild(body, combineStatements(variable, body));
+ }
}
}
DartType inferForInIterable(
- ForInStatement node, DartType elementType, bool typeNeeded) {
- Class iterableClass = node.isAsync
+ Expression iterable, DartType elementType, bool typeNeeded,
+ {bool isAsync: false}) {
+ Class iterableClass = isAsync
? inferrer.coreTypes.streamClass
: inferrer.coreTypes.iterableClass;
DartType context = inferrer.wrapType(elementType, iterableClass);
- Expression iterable = node.iterable;
inferrer.inferExpression(iterable, context, typeNeeded);
DartType inferredExpressionType =
inferrer.resolveTypeParameter(getInferredType(iterable, inferrer));
inferrer.ensureAssignable(
inferrer.wrapType(const DynamicType(), iterableClass),
inferredExpressionType,
- node.iterable,
- node.iterable.fileOffset,
+ iterable,
+ iterable.fileOffset,
template: templateForInLoopTypeNotIterable);
DartType inferredType;
if (typeNeeded) {
@@ -330,15 +318,17 @@
return inferredType;
}
- void handleForInStatementWithoutVariable(ForInStatement node) {
+ void handleForInWithoutVariable(
+ VariableDeclaration variable, Expression iterable, Statement body,
+ {bool isAsync: false}) {
DartType elementType;
bool typeChecksNeeded = !inferrer.isTopLevel;
DartType syntheticWriteType;
Expression syntheticAssignment;
- Block block = node.body;
- ExpressionStatement statement = block.statements[0];
- SyntheticExpressionJudgment judgment = statement.expression;
Expression rhs;
+ ExpressionStatement statement =
+ body is Block ? body.statements.first : body;
+ SyntheticExpressionJudgment judgment = statement.expression;
syntheticAssignment = judgment.desugared;
if (syntheticAssignment is VariableSet) {
syntheticWriteType = elementType = syntheticAssignment.variable.type;
@@ -368,18 +358,19 @@
inferrer.helper.uri);
}
- DartType inferredType =
- inferForInIterable(node, elementType, typeChecksNeeded);
+ DartType inferredType = inferForInIterable(
+ iterable, elementType, typeChecksNeeded,
+ isAsync: isAsync);
if (typeChecksNeeded) {
- node.variable.type = inferredType;
+ variable.type = inferredType;
}
- inferrer.inferStatement(node.body);
+ inferrer.inferStatement(body);
if (syntheticWriteType != null) {
inferrer.ensureAssignable(
greatestClosure(inferrer.coreTypes, syntheticWriteType),
- node.variable.type,
+ variable.type,
rhs,
rhs.fileOffset,
template: templateForInLoopElementTypeNotAssignable,
@@ -390,9 +381,11 @@
@override
void visitForInStatement(ForInStatement node, _) {
if (node.variable.name == null) {
- handleForInStatementWithoutVariable(node);
+ handleForInWithoutVariable(node.variable, node.iterable, node.body,
+ isAsync: node.isAsync);
} else {
- handleForInStatementDeclaringVariable(node);
+ handleForInDeclaringVariable(node.variable, node.iterable, node.body,
+ isAsync: node.isAsync);
}
}
@@ -697,16 +690,59 @@
return getSpreadElementType(spreadType, element.isNullAware) ??
const DynamicType();
} else if (element is IfElement) {
+ // TODO(kmillikin): Implement inference rules for if elements.
inferrer.inferExpression(element.condition,
inferrer.coreTypes.boolClass.rawType, typeChecksNeeded,
- isVoidAllowed: false);
+ isVoidAllowed: false); // Should be void allowed + runtime check?
inferElement(element.then, index, inferredTypeArgument, spreadTypes,
inferenceNeeded, typeChecksNeeded);
if (element.otherwise != null) {
inferElement(element.otherwise, index, inferredTypeArgument,
spreadTypes, inferenceNeeded, typeChecksNeeded);
}
- // TODO(kmillikin): Implement inference rules for if elements.
+ return const DynamicType();
+ } else if (element is ForElement) {
+ // TODO(kmillikin): Implement inference rules for for elements.
+ for (VariableDeclaration declaration in element.variables) {
+ if (declaration.initializer != null) {
+ inferrer.inferExpression(declaration.initializer, declaration.type,
+ inferenceNeeded || typeChecksNeeded,
+ isVoidAllowed: true);
+ }
+ }
+ if (element.condition != null) {
+ inferrer.inferExpression(
+ element.condition,
+ inferrer.coreTypes.boolClass.rawType,
+ inferenceNeeded || typeChecksNeeded,
+ isVoidAllowed: false); // Should be void allowed + runtime check.
+ }
+ for (Expression expression in element.updates) {
+ inferrer.inferExpression(expression, const UnknownType(),
+ inferenceNeeded || typeChecksNeeded,
+ isVoidAllowed: true);
+ }
+ inferElement(element.body, index, inferredTypeArgument, spreadTypes,
+ inferenceNeeded, typeChecksNeeded);
+ return const DynamicType();
+ } else if (element is ForInElement) {
+ // TODO(kmillikin): Implement inference rules for for-in elements.
+ if (element.variable.name == null) {
+ handleForInWithoutVariable(
+ element.variable, element.iterable, element.prologue,
+ isAsync: element.isAsync);
+ } else {
+ handleForInDeclaringVariable(
+ element.variable, element.iterable, element.prologue,
+ isAsync: element.isAsync);
+ }
+ if (element.problem != null) {
+ inferrer.inferExpression(element.problem, const UnknownType(),
+ inferenceNeeded || typeChecksNeeded,
+ isVoidAllowed: true);
+ }
+ inferElement(element.body, index, inferredTypeArgument, spreadTypes,
+ inferenceNeeded, typeChecksNeeded);
return const DynamicType();
} else {
return inferrer.inferExpression(
@@ -813,6 +849,8 @@
}
} else if (item is IfElement) {
// TODO(kmillikin): Insert type checks on if elements.
+ } else if (item is ForElement || item is ForInElement) {
+ // TODO(kmillikin): Insert type checks on loop elements.
} else {
inferrer.ensureAssignable(
node.typeArgument, actualTypes[i], item, item.fileOffset,
@@ -1553,6 +1591,8 @@
}
} else if (item is IfElement) {
// TODO(kmillikin): Insert type checks on if elements.
+ } else if (item is ForElement || item is ForInElement) {
+ // TODO(kmillikin): Insert type checks on loop elements.
} else {
inferrer.ensureAssignable(node.typeArgument, actualTypes[i],
node.expressions[i], node.expressions[i].fileOffset,
diff --git a/pkg/front_end/lib/src/fasta/kernel/inferred_type_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inferred_type_visitor.dart
index d747545..05513ad 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inferred_type_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inferred_type_visitor.dart
@@ -28,25 +28,11 @@
@override
DartType defaultExpression(Expression node, TypeInferrerImpl inferrer) {
- if (node is ForElement) {
- return visitForElement(node, inferrer);
- }
- if (node is ForInElement) {
- return visitForInElement(node, inferrer);
- }
unhandled("${node.runtimeType}", "getInferredType", node.fileOffset,
inferrer.uri);
return const InvalidType();
}
- DartType visitForElement(ForElement node, TypeInferrerImpl inferrer) {
- return const BottomType();
- }
-
- DartType visitForInElement(ForInElement node, TypeInferrerImpl inferrer) {
- return const BottomType();
- }
-
@override
DartType visitIntLiteral(IntLiteral node, TypeInferrerImpl inferrer) {
return inferrer.coreTypes.intClass.rawType;
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
index 1ea7bbc..6e28413 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
@@ -18,6 +18,7 @@
ExpressionStatement,
Field,
ForInStatement,
+ ForStatement,
IfStatement,
InterfaceType,
InvalidExpression,
@@ -33,6 +34,7 @@
SetLiteral,
Statement,
StaticInvocation,
+ transformList,
TreeNode,
VariableDeclaration,
VariableGet;
@@ -45,6 +47,8 @@
show
ControlFlowElement,
ControlFlowMapEntry,
+ ForElement,
+ ForInElement,
IfElement,
IfMapEntry,
SpreadElement,
@@ -153,6 +157,10 @@
_translateSpreadElement(element, elementType, isSet, result, body);
} else if (element is IfElement) {
_translateIfElement(element, elementType, isSet, result, body);
+ } else if (element is ForElement) {
+ _translateForElement(element, elementType, isSet, result, body);
+ } else if (element is ForInElement) {
+ _translateForInElement(element, elementType, isSet, result, body);
} else {
_addExpressionElement(element.accept(this), isSet, result, body);
}
@@ -169,22 +177,61 @@
void _translateIfElement(IfElement element, DartType elementType, bool isSet,
VariableDeclaration result, List<Statement> body) {
- List<Statement> thenBody = [];
- _translateElement(element.then, elementType, isSet, result, thenBody);
- List<Statement> elseBody;
+ List<Statement> thenStatements = [];
+ _translateElement(element.then, elementType, isSet, result, thenStatements);
+ List<Statement> elseStatements;
if (element.otherwise != null) {
_translateElement(element.otherwise, elementType, isSet, result,
- elseBody = <Statement>[]);
+ elseStatements = <Statement>[]);
}
- Statement thenStatement =
- thenBody.length == 1 ? thenBody.first : new Block(thenBody);
- Statement elseStatement;
- if (elseBody != null && elseBody.isNotEmpty) {
- elseStatement =
- elseBody.length == 1 ? elseBody.first : new Block(elseBody);
+ Statement thenBody = thenStatements.length == 1
+ ? thenStatements.first
+ : new Block(thenStatements);
+ Statement elseBody;
+ if (elseStatements != null && elseStatements.isNotEmpty) {
+ elseBody = elseStatements.length == 1
+ ? elseStatements.first
+ : new Block(elseStatements);
}
- body.add(new IfStatement(
- element.condition.accept(this), thenStatement, elseStatement));
+ body.add(new IfStatement(element.condition.accept(this), thenBody, elseBody)
+ ..fileOffset = element.fileOffset);
+ }
+
+ void _translateForElement(ForElement element, DartType elementType,
+ bool isSet, VariableDeclaration result, List<Statement> body) {
+ List<Statement> statements = <Statement>[];
+ _translateElement(element.body, elementType, isSet, result, statements);
+ Statement loopBody =
+ statements.length == 1 ? statements.first : new Block(statements);
+ ForStatement loop = new ForStatement(element.variables,
+ element.condition?.accept(this), element.updates, loopBody)
+ ..fileOffset = element.fileOffset;
+ transformList(loop.variables, this, loop);
+ transformList(loop.updates, this, loop);
+ body.add(loop);
+ }
+
+ void _translateForInElement(ForInElement element, DartType elementType,
+ bool isSet, VariableDeclaration result, List<Statement> body) {
+ List<Statement> statements;
+ Statement prologue = element.prologue;
+ if (prologue == null) {
+ statements = <Statement>[];
+ } else {
+ prologue = prologue.accept(this);
+ statements =
+ prologue is Block ? prologue.statements : <Statement>[prologue];
+ }
+ _translateElement(element.body, elementType, isSet, result, statements);
+ Statement loopBody =
+ statements.length == 1 ? statements.first : new Block(statements);
+ if (element.problem != null) {
+ body.add(new ExpressionStatement(element.problem.accept(this)));
+ }
+ body.add(new ForInStatement(
+ element.variable, element.iterable.accept(this), loopBody,
+ isAsync: element.isAsync)
+ ..fileOffset = element.fileOffset);
}
void _translateSpreadElement(SpreadElement element, DartType elementType,
diff --git a/pkg/front_end/testcases/control_flow_collection.dart b/pkg/front_end/testcases/control_flow_collection.dart
index e6d645c..6c1ea16 100644
--- a/pkg/front_end/testcases/control_flow_collection.dart
+++ b/pkg/front_end/testcases/control_flow_collection.dart
@@ -8,12 +8,18 @@
if (oracle()) 2,
if (oracle()) 3 else -1,
if (oracle()) if (oracle()) 4,
+ for (int i in <int>[5, 6, 7]) i,
+ for (int i in <int>[8, 9, 10]) if (oracle()) i,
+ for (int i = 11; i <= 14; ++i) i,
];
final aSet = <int>{
1,
if (oracle()) 2,
if (oracle()) 3 else -1,
if (oracle()) if (oracle()) 4,
+ for (int i in <int>[5, 6, 7]) i,
+ for (int i in <int>[8, 9, 10]) if (oracle()) i,
+ for (int i = 11; i <= 14; ++i) i,
};
final aMap = <int, int>{
1: 1,
diff --git a/pkg/front_end/testcases/control_flow_collection.dart.legacy.expect b/pkg/front_end/testcases/control_flow_collection.dart.legacy.expect
index e8d44f8..d0d69e1 100644
--- a/pkg/front_end/testcases/control_flow_collection.dart.legacy.expect
+++ b/pkg/front_end/testcases/control_flow_collection.dart.legacy.expect
@@ -18,35 +18,67 @@
// if (oracle()) if (oracle()) 4,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:14:7: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:11:7: Error: Unexpected token 'for'.
+// for (int i in <int>[5, 6, 7]) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:12:38: Error: Unexpected token 'if'.
+// for (int i in <int>[8, 9, 10]) if (oracle()) i,
+// ^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:12:7: Error: Unexpected token 'for'.
+// for (int i in <int>[8, 9, 10]) if (oracle()) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:13:7: Error: Unexpected token 'for'.
+// for (int i = 11; i <= 14; ++i) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:17:7: Error: Unexpected token 'if'.
// if (oracle()) 2,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:15:7: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:18:7: Error: Unexpected token 'if'.
// if (oracle()) 3 else -1,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:16:21: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:19:21: Error: Unexpected token 'if'.
// if (oracle()) if (oracle()) 4,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:16:7: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:19:7: Error: Unexpected token 'if'.
// if (oracle()) if (oracle()) 4,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:20:5: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:20:7: Error: Unexpected token 'for'.
+// for (int i in <int>[5, 6, 7]) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:21:38: Error: Unexpected token 'if'.
+// for (int i in <int>[8, 9, 10]) if (oracle()) i,
+// ^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:21:7: Error: Unexpected token 'for'.
+// for (int i in <int>[8, 9, 10]) if (oracle()) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:22:7: Error: Unexpected token 'for'.
+// for (int i = 11; i <= 14; ++i) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:26:5: Error: Unexpected token 'if'.
// if (oracle()) 2: 2,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:21:5: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:27:5: Error: Unexpected token 'if'.
// if (oracle()) 3: 3 else -1: -1,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:22:19: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:28:19: Error: Unexpected token 'if'.
// if (oracle()) if (oracle()) 4: 4,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:22:5: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:28:5: Error: Unexpected token 'if'.
// if (oracle()) if (oracle()) 4: 4,
// ^^
//
diff --git a/pkg/front_end/testcases/control_flow_collection.dart.legacy.transformed.expect b/pkg/front_end/testcases/control_flow_collection.dart.legacy.transformed.expect
index e8d44f8..d0d69e1 100644
--- a/pkg/front_end/testcases/control_flow_collection.dart.legacy.transformed.expect
+++ b/pkg/front_end/testcases/control_flow_collection.dart.legacy.transformed.expect
@@ -18,35 +18,67 @@
// if (oracle()) if (oracle()) 4,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:14:7: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:11:7: Error: Unexpected token 'for'.
+// for (int i in <int>[5, 6, 7]) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:12:38: Error: Unexpected token 'if'.
+// for (int i in <int>[8, 9, 10]) if (oracle()) i,
+// ^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:12:7: Error: Unexpected token 'for'.
+// for (int i in <int>[8, 9, 10]) if (oracle()) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:13:7: Error: Unexpected token 'for'.
+// for (int i = 11; i <= 14; ++i) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:17:7: Error: Unexpected token 'if'.
// if (oracle()) 2,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:15:7: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:18:7: Error: Unexpected token 'if'.
// if (oracle()) 3 else -1,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:16:21: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:19:21: Error: Unexpected token 'if'.
// if (oracle()) if (oracle()) 4,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:16:7: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:19:7: Error: Unexpected token 'if'.
// if (oracle()) if (oracle()) 4,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:20:5: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:20:7: Error: Unexpected token 'for'.
+// for (int i in <int>[5, 6, 7]) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:21:38: Error: Unexpected token 'if'.
+// for (int i in <int>[8, 9, 10]) if (oracle()) i,
+// ^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:21:7: Error: Unexpected token 'for'.
+// for (int i in <int>[8, 9, 10]) if (oracle()) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:22:7: Error: Unexpected token 'for'.
+// for (int i = 11; i <= 14; ++i) i,
+// ^^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:26:5: Error: Unexpected token 'if'.
// if (oracle()) 2: 2,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:21:5: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:27:5: Error: Unexpected token 'if'.
// if (oracle()) 3: 3 else -1: -1,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:22:19: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:28:19: Error: Unexpected token 'if'.
// if (oracle()) if (oracle()) 4: 4,
// ^^
//
-// pkg/front_end/testcases/control_flow_collection.dart:22:5: Error: Unexpected token 'if'.
+// pkg/front_end/testcases/control_flow_collection.dart:28:5: Error: Unexpected token 'if'.
// if (oracle()) if (oracle()) 4: 4,
// ^^
//
diff --git a/pkg/front_end/testcases/control_flow_collection.dart.strong.expect b/pkg/front_end/testcases/control_flow_collection.dart.strong.expect
index edd1a14..a86c82b 100644
--- a/pkg/front_end/testcases/control_flow_collection.dart.strong.expect
+++ b/pkg/front_end/testcases/control_flow_collection.dart.strong.expect
@@ -16,6 +16,13 @@
if(self::oracle())
if(self::oracle())
#t1.{core::List::add}(4);
+ for (core::int i in <core::int>[5, 6, 7])
+ #t1.{core::List::add}(i);
+ for (core::int i in <core::int>[8, 9, 10])
+ if(self::oracle())
+ #t1.{core::List::add}(i);
+ for (core::int i = 11; i.{core::num::<=}(14); i = i.{core::num::+}(1))
+ #t1.{core::List::add}(i);
} =>#t1;
final core::Set<core::int> aSet = block {
final core::Set<core::int> #t2 = col::LinkedHashSet::•<core::int>();
@@ -29,6 +36,13 @@
if(self::oracle())
if(self::oracle())
#t2.{core::Set::add}(4);
+ for (core::int i in <core::int>[5, 6, 7])
+ #t2.{core::Set::add}(i);
+ for (core::int i in <core::int>[8, 9, 10])
+ if(self::oracle())
+ #t2.{core::Set::add}(i);
+ for (core::int i = 11; i.{core::num::<=}(14); i = i.{core::num::+}(1))
+ #t2.{core::Set::add}(i);
} =>#t2;
final core::Map<core::int, core::int> aMap = block {
final core::Map<core::int, core::int> #t3 = <core::int, core::int>{};
diff --git a/pkg/front_end/testcases/control_flow_collection.dart.strong.transformed.expect b/pkg/front_end/testcases/control_flow_collection.dart.strong.transformed.expect
index edd1a14..a86c82b 100644
--- a/pkg/front_end/testcases/control_flow_collection.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/control_flow_collection.dart.strong.transformed.expect
@@ -16,6 +16,13 @@
if(self::oracle())
if(self::oracle())
#t1.{core::List::add}(4);
+ for (core::int i in <core::int>[5, 6, 7])
+ #t1.{core::List::add}(i);
+ for (core::int i in <core::int>[8, 9, 10])
+ if(self::oracle())
+ #t1.{core::List::add}(i);
+ for (core::int i = 11; i.{core::num::<=}(14); i = i.{core::num::+}(1))
+ #t1.{core::List::add}(i);
} =>#t1;
final core::Set<core::int> aSet = block {
final core::Set<core::int> #t2 = col::LinkedHashSet::•<core::int>();
@@ -29,6 +36,13 @@
if(self::oracle())
if(self::oracle())
#t2.{core::Set::add}(4);
+ for (core::int i in <core::int>[5, 6, 7])
+ #t2.{core::Set::add}(i);
+ for (core::int i in <core::int>[8, 9, 10])
+ if(self::oracle())
+ #t2.{core::Set::add}(i);
+ for (core::int i = 11; i.{core::num::<=}(14); i = i.{core::num::+}(1))
+ #t2.{core::Set::add}(i);
} =>#t2;
final core::Map<core::int, core::int> aMap = block {
final core::Map<core::int, core::int> #t3 = <core::int, core::int>{};
diff --git a/pkg/front_end/testcases/control_flow_collection.dart.type_promotion.expect b/pkg/front_end/testcases/control_flow_collection.dart.type_promotion.expect
new file mode 100644
index 0000000..ba82077
--- /dev/null
+++ b/pkg/front_end/testcases/control_flow_collection.dart.type_promotion.expect
@@ -0,0 +1,6 @@
+pkg/front_end/testcases/control_flow_collection.dart:13:33: Context: Write to i@364
+ for (int i = 11; i <= 14; ++i) i,
+ ^^
+pkg/front_end/testcases/control_flow_collection.dart:22:33: Context: Write to i@364
+ for (int i = 11; i <= 14; ++i) i,
+ ^^
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index c0b00c3..9775249 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -133,7 +133,6 @@
LanguageFeatures/Control-flow-collections/const_collections_A07_t01: CompileTimeError
LanguageFeatures/Control-flow-collections/const_collections_A07_t02: CompileTimeError
LanguageFeatures/Control-flow-collections/dynamic_semantics_set_A03_t01: CompileTimeError
-LanguageFeatures/Control-flow-collections/scoping_A02_t01: CompileTimeError
LanguageFeatures/Control-flow-collections/static_errors_A01_t01/01: MissingCompileTimeError
LanguageFeatures/Control-flow-collections/static_errors_A01_t01/02: MissingCompileTimeError
LanguageFeatures/Control-flow-collections/static_errors_A01_t01/03: MissingCompileTimeError
@@ -153,12 +152,6 @@
LanguageFeatures/Control-flow-collections/static_errors_A04_t01/02: MissingCompileTimeError
LanguageFeatures/Control-flow-collections/static_errors_A04_t01/03: MissingCompileTimeError
LanguageFeatures/Control-flow-collections/static_errors_A04_t01/04: MissingCompileTimeError
-LanguageFeatures/Control-flow-collections/static_errors_A05_t01/01: MissingCompileTimeError
-LanguageFeatures/Control-flow-collections/static_errors_A05_t01/02: MissingCompileTimeError
-LanguageFeatures/Control-flow-collections/static_errors_A06_t01/01: MissingCompileTimeError
-LanguageFeatures/Control-flow-collections/static_errors_A06_t01/02: MissingCompileTimeError
-LanguageFeatures/Control-flow-collections/static_errors_A07_t01: MissingCompileTimeError
-LanguageFeatures/Control-flow-collections/static_errors_A08_t01: MissingCompileTimeError
LanguageFeatures/Control-flow-collections/static_errors_A11_t01: MissingCompileTimeError
LanguageFeatures/Control-flow-collections/static_semantics_A01_t02/01: MissingCompileTimeError
LanguageFeatures/Control-flow-collections/static_semantics_A01_t02/02: MissingCompileTimeError
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index 65fbccd..d12394f 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -202,30 +202,24 @@
constructor6_test: CompileTimeError # Verification error
control_flow_collections/await_for_inference_test: CompileTimeError
control_flow_collections/await_for_test: CompileTimeError
-control_flow_collections/await_for_type_error_test/01: MissingCompileTimeError
control_flow_collections/await_for_type_error_test/02: MissingCompileTimeError
-control_flow_collections/await_for_type_error_test/03: MissingCompileTimeError
control_flow_collections/await_for_type_error_test/04: MissingCompileTimeError
control_flow_collections/await_for_type_error_test/05: MissingCompileTimeError
control_flow_collections/await_for_type_error_test/06: MissingCompileTimeError
-control_flow_collections/await_for_type_error_test/07: MissingCompileTimeError
control_flow_collections/await_for_type_error_test/08: MissingCompileTimeError
-control_flow_collections/await_for_type_error_test/09: MissingCompileTimeError
control_flow_collections/await_for_type_error_test/10: MissingCompileTimeError
control_flow_collections/await_for_type_error_test/11: MissingCompileTimeError
control_flow_collections/await_for_type_error_test/12: MissingCompileTimeError
control_flow_collections/await_for_type_error_test/13: MissingCompileTimeError
control_flow_collections/for_await_test: CompileTimeError
+control_flow_collections/for_await_test: Crash
control_flow_collections/for_const_test/00: MissingCompileTimeError
control_flow_collections/for_const_test/01: MissingCompileTimeError
control_flow_collections/for_const_test/03: MissingCompileTimeError
control_flow_collections/for_const_test/04: MissingCompileTimeError
-control_flow_collections/for_const_test/06: MissingCompileTimeError
control_flow_collections/for_const_test/07: MissingCompileTimeError
-control_flow_collections/for_const_test/08: MissingCompileTimeError
control_flow_collections/for_inference_test: CompileTimeError
control_flow_collections/for_test: CompileTimeError
-control_flow_collections/for_variable_test: CompileTimeError
control_flow_collections/if_await_test: Crash
control_flow_collections/if_const_error_test/02: MissingCompileTimeError
control_flow_collections/if_const_error_test/07: MissingCompileTimeError
@@ -261,19 +255,17 @@
control_flow_collections/type_error_test/14: MissingCompileTimeError
control_flow_collections/type_error_test/15: MissingCompileTimeError
control_flow_collections/type_error_test/16: MissingCompileTimeError
-control_flow_collections/type_error_test/20: MissingCompileTimeError
control_flow_collections/type_error_test/21: MissingCompileTimeError
-control_flow_collections/type_error_test/22: MissingCompileTimeError
+control_flow_collections/type_error_test/23: Crash
control_flow_collections/type_error_test/23: MissingCompileTimeError
control_flow_collections/type_error_test/24: MissingCompileTimeError
+control_flow_collections/type_error_test/25: Crash
control_flow_collections/type_error_test/25: MissingCompileTimeError
control_flow_collections/type_error_test/26: MissingCompileTimeError
control_flow_collections/type_error_test/27: MissingCompileTimeError
control_flow_collections/type_error_test/28: MissingCompileTimeError
control_flow_collections/type_error_test/29: MissingCompileTimeError
-control_flow_collections/type_error_test/30: MissingCompileTimeError
control_flow_collections/type_error_test/31: MissingCompileTimeError
-control_flow_collections/type_error_test/32: MissingCompileTimeError
control_flow_collections/type_error_test/33: MissingCompileTimeError
control_flow_collections/type_error_test/34: MissingCompileTimeError
control_flow_collections/type_error_test/35: MissingCompileTimeError