[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