Begin adding summary support for `for` elements.

Change-Id: Icdcfba5caaac34375b65c838dabc97e9b9201ee9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97120
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
index a2e6994..3f6a387 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -520,6 +520,15 @@
           rightParenthesis: TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
           body: body);
 
+  static ForElement forElement(
+          ForLoopParts forLoopParts, CollectionElement body) =>
+      astFactory.forElement(
+          forKeyword: TokenFactory.tokenFromKeyword(Keyword.FOR),
+          leftParenthesis: TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
+          forLoopParts: forLoopParts,
+          rightParenthesis: TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
+          body: body);
+
   static FormalParameterList formalParameterList(
           [List<FormalParameter> parameters]) =>
       astFactory.formalParameterList(
@@ -529,6 +538,17 @@
           null,
           TokenFactory.tokenFromType(TokenType.CLOSE_PAREN));
 
+  static ForPartsWithExpression forPartsWithExpression(
+          Expression initialization,
+          Expression condition,
+          List<Expression> updaters) =>
+      astFactory.forPartsWithExpression(
+          initialization: initialization,
+          leftSeparator: TokenFactory.tokenFromType(TokenType.SEMICOLON),
+          condition: condition,
+          rightSeparator: TokenFactory.tokenFromType(TokenType.SEMICOLON),
+          updaters: updaters);
+
   @Deprecated('Use forStatement2')
   static ForStatement2 forStatement(Expression initialization,
           Expression condition, List<Expression> updaters, Statement body) =>
diff --git a/pkg/analyzer/lib/src/summary/expr_builder.dart b/pkg/analyzer/lib/src/summary/expr_builder.dart
index 960e342..bb2ccb2 100644
--- a/pkg/analyzer/lib/src/summary/expr_builder.dart
+++ b/pkg/analyzer/lib/src/summary/expr_builder.dart
@@ -42,7 +42,7 @@
 
   // The stack of values. Note that they are usually [Expression]s, but may be
   // any [CollectionElement] to support map/set/list literals.
-  final List<CollectionElement> stack = <CollectionElement>[];
+  final List<AstNode> stack = <AstNode>[];
 
   final List<UnlinkedExecutable> localFunctions;
 
@@ -329,6 +329,15 @@
         case UnlinkedExprOperation.ifElseElement:
           _pushIfElement(true);
           break;
+        case UnlinkedExprOperation.forParts:
+          _pushForParts();
+          break;
+        case UnlinkedExprOperation.forElement:
+          _pushForElement();
+          break;
+        case UnlinkedExprOperation.pushEmptyExpression:
+          _push(null);
+          break;
         case UnlinkedExprOperation.cascadeSectionBegin:
         case UnlinkedExprOperation.cascadeSectionEnd:
         case UnlinkedExprOperation.pushLocalFunctionReference:
@@ -629,9 +638,12 @@
 
   Expression _pop() => stack.removeLast() as Expression;
 
-  CollectionElement _popCollectionElement() => stack.removeLast();
+  CollectionElement _popCollectionElement() =>
+      stack.removeLast() as CollectionElement;
 
-  void _push(CollectionElement expr) {
+  AstNode _popNode() => stack.removeLast();
+
+  void _push(Expression expr) {
     stack.add(expr);
   }
 
@@ -656,11 +668,34 @@
     _push(AstTestFactory.propertyAccess(target, propertyNode));
   }
 
+  void _pushForElement() {
+    var body = _popCollectionElement();
+    var forLoopParts = _popNode() as ForLoopParts;
+    _pushCollectionElement(AstTestFactory.forElement(forLoopParts, body));
+  }
+
+  void _pushForParts() {
+    var updaterCount = _uc.ints[intPtr++];
+    var updaters = <Expression>[];
+    for (int i = 0; i < updaterCount; i++) {
+      updaters.insert(0, _pop());
+    }
+    Expression condition = _pop();
+    AstNode initialization = _popNode();
+    if (initialization is Expression || initialization == null) {
+      _pushNode(AstTestFactory.forPartsWithExpression(
+          initialization, condition, updaters));
+    } else {
+      throw UnimplementedError('TODO(paulberry)');
+    }
+  }
+
   void _pushIfElement(bool hasElse) {
     CollectionElement elseElement = hasElse ? _popCollectionElement() : null;
     CollectionElement thenElement = _popCollectionElement();
     Expression condition = _pop();
-    _push(AstTestFactory.ifElement(condition, thenElement, elseElement));
+    _pushCollectionElement(
+        AstTestFactory.ifElement(condition, thenElement, elseElement));
   }
 
   void _pushInstanceCreation() {
@@ -868,6 +903,10 @@
     _pushCollectionElement(AstTestFactory.mapLiteralEntry2(key, value));
   }
 
+  void _pushNode(AstNode node) {
+    stack.add(node);
+  }
+
   void _pushPrefix(TokenType operator) {
     Expression operand = _pop();
     _push(AstTestFactory.prefixExpression(operator, operand));
@@ -938,7 +977,7 @@
 
   void _pushSpread(TokenType operator) {
     Expression operand = _pop();
-    _push(AstTestFactory.spreadElement(operator, operand));
+    _pushCollectionElement(AstTestFactory.spreadElement(operator, operand));
   }
 
   List<Expression> _removeTopExpressions(int count) {
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 6cd172f..ca4f27a 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -991,7 +991,20 @@
   /// other two are collection elements.  Push an "if" element having the given
   /// condition, with the two collection elements as its "then" and "else"
   /// clauses, respectively.
-  ifElseElement
+  ifElseElement,
+
+  /// Pop the top n+2 values from the stack, where n is obtained from
+  /// [UnlinkedExpr.ints].  The first two are the initialization and condition
+  /// of the for-loop; the remainder are the updaters.
+  forParts,
+
+  /// Pop the top 2 values from the stack.  The first is the for loop parts.
+  /// The second is the body.
+  forElement,
+
+  /// Push the empty expression (used for missing initializers and conditions in
+  /// `for` loops)
+  pushEmptyExpression
 }
 
 /// Enum used to indicate the kind of a parameter.
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index c9e84f8..5a5bede 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -3887,6 +3887,19 @@
   /// condition, with the two collection elements as its "then" and "else"
   /// clauses, respectively.
   ifElseElement,
+
+  /// Pop the top n+2 values from the stack, where n is obtained from
+  /// [UnlinkedExpr.ints].  The first two are the initialization and condition
+  /// of the for-loop; the remainder are the updaters.
+  forParts,
+
+  /// Pop the top 2 values from the stack.  The first is the for loop parts.
+  /// The second is the body.
+  forElement,
+
+  /// Push the empty expression (used for missing initializers and conditions in
+  /// `for` loops)
+  pushEmptyExpression,
 }
 
 /// Unlinked summary information about an import declaration.
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index d38b602..8bb9b33 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -1906,6 +1906,7 @@
         case UnlinkedExprOperation.makeUntypedMap:
         case UnlinkedExprOperation.makeUntypedSet:
         case UnlinkedExprOperation.makeUntypedSetOrMap:
+        case UnlinkedExprOperation.forParts:
           intPtr++;
           break;
         case UnlinkedExprOperation.assignToRef:
@@ -5206,6 +5207,7 @@
         case UnlinkedExprOperation.makeUntypedMap:
         case UnlinkedExprOperation.makeUntypedSet:
         case UnlinkedExprOperation.makeUntypedSetOrMap:
+        case UnlinkedExprOperation.forParts:
           intPtr++;
           break;
         case UnlinkedExprOperation.makeTypedList:
diff --git a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
index f367937..ab5a11b 100644
--- a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
@@ -293,8 +293,10 @@
   }
 
   /// Serialize the given [expr] expression into this serializer state.
-  void _serialize(Expression expr) {
-    if (expr is IntegerLiteral) {
+  void _serialize(Expression expr, {bool emptyExpressionPermitted: false}) {
+    if (emptyExpressionPermitted && expr == null) {
+      operations.add(UnlinkedExprOperation.pushEmptyExpression);
+    } else if (expr is IntegerLiteral) {
       int value = expr.value ?? 0;
       if (value >= 0) {
         _pushInt(value);
@@ -558,9 +560,28 @@
         _serializeCollectionElement(elseElement);
         operations.add(UnlinkedExprOperation.ifElseElement);
       }
+    } else if (element is ForElement) {
+      var parts = element.forLoopParts;
+      if (parts is ForParts) {
+        if (parts is ForPartsWithExpression) {
+          _serialize(parts.initialization, emptyExpressionPermitted: true);
+        } else {
+          // See https://github.com/dart-lang/sdk/issues/35569
+          throw StateError('TODO(paulberry)');
+        }
+        _serialize(parts.condition, emptyExpressionPermitted: true);
+        for (var updater in parts.updaters) {
+          _serialize(updater);
+        }
+        operations.add(UnlinkedExprOperation.forParts);
+        ints.add(parts.updaters.length);
+      } else {
+        // See https://github.com/dart-lang/sdk/issues/35569
+        throw new StateError('TODO(paulberry)');
+      }
+      _serializeCollectionElement(element.body);
+      operations.add(UnlinkedExprOperation.forElement);
     } else {
-      // TODO(paulberry): Implement serialization for spread and control flow
-      //  elements.
       throw new StateError('Unsupported CollectionElement: $element');
     }
   }
diff --git a/pkg/analyzer/test/src/summary/expr_builder_test.dart b/pkg/analyzer/test/src/summary/expr_builder_test.dart
index 67a8ae9..46a6306 100644
--- a/pkg/analyzer/test/src/summary/expr_builder_test.dart
+++ b/pkg/analyzer/test/src/summary/expr_builder_test.dart
@@ -5,6 +5,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/scanner/reader.dart';
 import 'package:analyzer/src/dart/scanner/scanner.dart';
@@ -293,6 +294,51 @@
     checkSimpleExpression('0 <= 1');
   }
 
+  void test_list_for() {
+    experimentStatus = ExperimentStatus(control_flow_collections: true);
+    var sourceText = '[for (i = 0; i < 10; i++) i]';
+    // Resynthesis inserts synthetic "const" tokens; work around that.
+    var expectedText = 'const $sourceText';
+    checkSimpleExpression(sourceText,
+        expectedText: expectedText, extraDeclarations: 'int i;');
+  }
+
+  void test_list_for_empty_condition() {
+    experimentStatus = ExperimentStatus(control_flow_collections: true);
+    var sourceText = '[for (i = 0;; i++) i]';
+    // Resynthesis inserts synthetic "const" tokens; work around that.
+    var expectedText = 'const $sourceText';
+    checkSimpleExpression(sourceText,
+        expectedText: expectedText, extraDeclarations: 'int i;');
+  }
+
+  void test_list_for_empty_initializer() {
+    experimentStatus = ExperimentStatus(control_flow_collections: true);
+    var sourceText = '[for (; i < 10; i++) i]';
+    // Resynthesis inserts synthetic "const" tokens; work around that.
+    var expectedText = 'const $sourceText';
+    checkSimpleExpression(sourceText,
+        expectedText: expectedText, extraDeclarations: 'int i;');
+  }
+
+  void test_list_for_two_updaters() {
+    experimentStatus = ExperimentStatus(control_flow_collections: true);
+    var sourceText = '[for (i = 0; i < 10; i++, j++) i]';
+    // Resynthesis inserts synthetic "const" tokens; work around that.
+    var expectedText = 'const $sourceText';
+    checkSimpleExpression(sourceText,
+        expectedText: expectedText, extraDeclarations: 'int i; int j;');
+  }
+
+  void test_list_for_zero_updaters() {
+    experimentStatus = ExperimentStatus(control_flow_collections: true);
+    var sourceText = '[for (i = 0; i < 10;) i]';
+    // Resynthesis inserts synthetic "const" tokens; work around that.
+    var expectedText = 'const $sourceText';
+    checkSimpleExpression(sourceText,
+        expectedText: expectedText, extraDeclarations: 'int i;');
+  }
+
   void test_makeSymbol() {
     checkSimpleExpression('#foo');
   }
@@ -313,6 +359,15 @@
     checkSimpleExpression('const {0 : false}');
   }
 
+  void test_map_for() {
+    experimentStatus = ExperimentStatus(control_flow_collections: true);
+    var sourceText = '{1 : 2, for (i = 0; i < 10; i++) i : i}';
+    // Resynthesis inserts synthetic "const" tokens; work around that.
+    var expectedText = 'const $sourceText';
+    checkSimpleExpression(sourceText,
+        expectedText: expectedText, extraDeclarations: 'int i;');
+  }
+
   void test_modulo() {
     checkSimpleExpression('0 % 1');
   }
@@ -462,6 +517,15 @@
     checkSimpleExpression('true');
   }
 
+  void test_set_for() {
+    experimentStatus = ExperimentStatus(control_flow_collections: true);
+    var sourceText = '{1, for (i = 0; i < 10; i++) i}';
+    // Resynthesis inserts synthetic "const" tokens; work around that.
+    var expectedText = 'const $sourceText';
+    checkSimpleExpression(sourceText,
+        expectedText: expectedText, extraDeclarations: 'int i;');
+  }
+
   void test_subtract() {
     checkSimpleExpression('0 - 1');
   }
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index e5a4dfb..51ecb6a 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -7650,6 +7650,205 @@
         forTypeInferenceOnly: true);
   }
 
+  test_expr_list_for() {
+    experimentStatus = ExperimentStatus(
+        control_flow_collections: true, spread_collections: true);
+    UnlinkedVariable variable =
+        serializeVariableText('int i; var v = [for (i = 0; i < 10; i++) i];');
+    assertUnlinkedConst(
+        variable.initializer.bodyExpr, '[for (i = 0; i < 10; i++) i]',
+        isValidConst: false,
+        operators: [
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.less,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.forParts,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.forElement,
+          UnlinkedExprOperation.makeUntypedList
+        ],
+        assignmentOperators: [
+          UnlinkedExprAssignOperator.assign,
+          UnlinkedExprAssignOperator.postfixIncrement
+        ],
+        ints: [
+          0,
+          10,
+          1,
+          1
+        ],
+        referenceValidators: [
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor)
+        ]);
+  }
+
+  test_expr_list_for_empty_condition() {
+    experimentStatus = ExperimentStatus(
+        control_flow_collections: true, spread_collections: true);
+    UnlinkedVariable variable =
+        serializeVariableText('int i; var v = [for (i = 0;; i++) i];');
+    assertUnlinkedConst(variable.initializer.bodyExpr, '[for (i = 0;; i++) i]',
+        isValidConst: false,
+        operators: [
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.pushEmptyExpression,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.forParts,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.forElement,
+          UnlinkedExprOperation.makeUntypedList
+        ],
+        assignmentOperators: [
+          UnlinkedExprAssignOperator.assign,
+          UnlinkedExprAssignOperator.postfixIncrement
+        ],
+        ints: [
+          0,
+          1,
+          1
+        ],
+        referenceValidators: [
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor)
+        ]);
+  }
+
+  test_expr_list_for_empty_initializer() {
+    experimentStatus = ExperimentStatus(
+        control_flow_collections: true, spread_collections: true);
+    UnlinkedVariable variable =
+        serializeVariableText('int i; var v = [for (; i < 10; i++) i];');
+    assertUnlinkedConst(
+        variable.initializer.bodyExpr, '[for (; i < 10; i++) i]',
+        isValidConst: false,
+        operators: [
+          UnlinkedExprOperation.pushEmptyExpression,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.less,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.forParts,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.forElement,
+          UnlinkedExprOperation.makeUntypedList
+        ],
+        assignmentOperators: [
+          UnlinkedExprAssignOperator.postfixIncrement
+        ],
+        ints: [
+          10,
+          1,
+          1
+        ],
+        referenceValidators: [
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor)
+        ]);
+  }
+
+  test_expr_list_for_two_updaters() {
+    experimentStatus = ExperimentStatus(
+        control_flow_collections: true, spread_collections: true);
+    UnlinkedVariable variable = serializeVariableText(
+        'int i; int j; var v = [for (i = 0; i < 10; i++, j++) i];');
+    assertUnlinkedConst(
+        variable.initializer.bodyExpr, '[for (i = 0; i < 10; i++, j++) i]',
+        isValidConst: false,
+        operators: [
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.less,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.forParts,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.forElement,
+          UnlinkedExprOperation.makeUntypedList
+        ],
+        assignmentOperators: [
+          UnlinkedExprAssignOperator.assign,
+          UnlinkedExprAssignOperator.postfixIncrement,
+          UnlinkedExprAssignOperator.postfixIncrement
+        ],
+        ints: [
+          0,
+          10,
+          2,
+          1
+        ],
+        referenceValidators: [
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'j',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor)
+        ]);
+  }
+
+  test_expr_list_for_zero_updaters() {
+    experimentStatus = ExperimentStatus(
+        control_flow_collections: true, spread_collections: true);
+    UnlinkedVariable variable =
+        serializeVariableText('int i; var v = [for (i = 0; i < 10;) i];');
+    assertUnlinkedConst(
+        variable.initializer.bodyExpr, '[for (i = 0; i < 10;) i]',
+        isValidConst: false,
+        operators: [
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.less,
+          UnlinkedExprOperation.forParts,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.forElement,
+          UnlinkedExprOperation.makeUntypedList
+        ],
+        assignmentOperators: [
+          UnlinkedExprAssignOperator.assign
+        ],
+        ints: [
+          0,
+          10,
+          0,
+          1
+        ],
+        referenceValidators: [
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor)
+        ]);
+  }
+
   test_expr_makeTypedList() {
     UnlinkedVariable variable =
         serializeVariableText('var v = <int>[11, 22, 33];');
@@ -7742,6 +7941,101 @@
         forTypeInferenceOnly: true);
   }
 
+  test_expr_map_for() {
+    experimentStatus = ExperimentStatus(
+        control_flow_collections: true, spread_collections: true);
+    UnlinkedVariable variable = serializeVariableText(
+        'int i; var v = {1: 2, for (i = 0; i < 10; i++) i: i};');
+    assertUnlinkedConst(
+        variable.initializer.bodyExpr, '{1: 2, for (i = 0; i < 10; i++) i: i}',
+        isValidConst: false,
+        operators: [
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.makeMapLiteralEntry,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.less,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.forParts,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.makeMapLiteralEntry,
+          UnlinkedExprOperation.forElement,
+          UnlinkedExprOperation.makeUntypedSetOrMap
+        ],
+        assignmentOperators: [
+          UnlinkedExprAssignOperator.assign,
+          UnlinkedExprAssignOperator.postfixIncrement
+        ],
+        ints: [
+          1,
+          2,
+          0,
+          10,
+          1,
+          2
+        ],
+        referenceValidators: [
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor)
+        ]);
+  }
+
+  test_expr_set_for() {
+    experimentStatus = ExperimentStatus(
+        control_flow_collections: true, spread_collections: true);
+    UnlinkedVariable variable = serializeVariableText(
+        'int i; var v = {1, for (i = 0; i < 10; i++) i};');
+    assertUnlinkedConst(
+        variable.initializer.bodyExpr, '{1, for (i = 0; i < 10; i++) i}',
+        isValidConst: false,
+        operators: [
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.pushInt,
+          UnlinkedExprOperation.less,
+          UnlinkedExprOperation.assignToRef,
+          UnlinkedExprOperation.forParts,
+          UnlinkedExprOperation.pushReference,
+          UnlinkedExprOperation.forElement,
+          UnlinkedExprOperation.makeUntypedSetOrMap
+        ],
+        assignmentOperators: [
+          UnlinkedExprAssignOperator.assign,
+          UnlinkedExprAssignOperator.postfixIncrement
+        ],
+        ints: [
+          1,
+          0,
+          10,
+          1,
+          2
+        ],
+        referenceValidators: [
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor),
+          (EntityRef r) => checkTypeRef(r, null, 'i',
+              expectedKind: ReferenceKind.topLevelPropertyAccessor)
+        ]);
+  }
+
   test_expr_super() {
     UnlinkedVariable variable = serializeVariableText('''
 final v = super;