[CFE] Compile if map entries in map literals

The compilation of if map entries is similar to the way that if list
and set elements are compiled.

Change-Id: I8a3a97f01a176922c8ecc9a7d8636fad18124be3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97310
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Kevin Millikin <kmillikin@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/collections.dart b/pkg/front_end/lib/src/fasta/kernel/collections.dart
index 02e8845..7afb5a0 100644
--- a/pkg/front_end/lib/src/fasta/kernel/collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/collections.dart
@@ -34,7 +34,7 @@
 /// appear in arbitrary expression contexts in the Kernel program.  They can
 /// only appear as elements in list or set literals.  They are translated into
 /// a lower-level representation and never serialized to .dill files.
-mixin CollectionElement on Expression {
+mixin ControlFlowElement on Expression {
   /// Spread and contol-flow elements are not expressions and do not have a
   /// static type.
   @override
@@ -51,7 +51,7 @@
 }
 
 /// A spread element in a list or set literal.
-class SpreadElement extends Expression with CollectionElement {
+class SpreadElement extends Expression with ControlFlowElement {
   Expression expression;
   bool isNullAware;
 
@@ -74,7 +74,7 @@
 }
 
 /// An 'if' element in a list or set literal.
-class IfElement extends Expression with CollectionElement {
+class IfElement extends Expression with ControlFlowElement {
   Expression condition;
   Expression then;
   Expression otherwise;
@@ -110,7 +110,7 @@
 }
 
 /// A 'for' element in a list or set literal.
-class ForElement extends Expression with CollectionElement {
+class ForElement extends Expression with ControlFlowElement {
   final List<VariableDeclaration> variables; // May be empty, but not null.
   Expression condition; // May be null.
   final List<Expression> updates; // May be empty, but not null.
@@ -147,7 +147,7 @@
 }
 
 /// A 'for-in' element in a list or set literal.
-class ForInElement extends Expression with CollectionElement {
+class ForInElement extends Expression with ControlFlowElement {
   VariableDeclaration variable; // Has no initializer.
   Expression iterable;
   Expression body;
@@ -181,7 +181,7 @@
   }
 }
 
-mixin _FakeMapEntryMixin implements MapEntry {
+mixin ControlFlowMapEntry implements MapEntry {
   @override
   Expression get key => throw UnsupportedError('SpreadMapEntry.key getter');
 
@@ -205,7 +205,7 @@
 }
 
 /// A spread element in a map literal.
-class SpreadMapEntry extends TreeNode with _FakeMapEntryMixin {
+class SpreadMapEntry extends TreeNode with ControlFlowMapEntry {
   Expression expression;
   bool isNullAware;
 
@@ -230,7 +230,7 @@
 }
 
 /// An 'if' element in a map literal.
-class IfMapEntry extends TreeNode with _FakeMapEntryMixin {
+class IfMapEntry extends TreeNode with ControlFlowMapEntry {
   Expression condition;
   MapEntry then;
   MapEntry otherwise;
@@ -266,7 +266,7 @@
 }
 
 /// A 'for' element in a map literal.
-class ForMapEntry extends TreeNode with _FakeMapEntryMixin {
+class ForMapEntry extends TreeNode with ControlFlowMapEntry {
   final List<VariableDeclaration> variables; // May be empty, but not null.
   Expression condition; // May be null.
   final List<Expression> updates; // May be empty, but not null.
@@ -303,7 +303,7 @@
 }
 
 /// A 'for-in' element in a map literal.
-class ForInMapEntry extends TreeNode with _FakeMapEntryMixin {
+class ForInMapEntry extends TreeNode with ControlFlowMapEntry {
   VariableDeclaration variable; // Has no initializer.
   Expression iterable;
   MapEntry body;
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 6754f26..11ae0bb 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -848,6 +848,80 @@
     }
   }
 
+  DartType inferMapEntry(
+      MapEntry entry,
+      int index,
+      DartType inferredKeyType,
+      DartType inferredValueType,
+      DartType spreadContext,
+      List<DartType> spreadTypes,
+      List<DartType> actualTypes,
+      bool inferenceNeeded,
+      bool typeChecksNeeded,
+      {bool nested: false}) {
+    if (entry is SpreadMapEntry) {
+      DartType spreadType = inferrer.inferExpression(
+          entry.expression, spreadContext, inferenceNeeded || typeChecksNeeded,
+          isVoidAllowed: true);
+      if (!nested) {
+        if (typeChecksNeeded) {
+          spreadTypes[index] = spreadType;
+        }
+        // Use 'dynamic' for error recovery.
+        int length = actualTypes.length;
+        actualTypes.add(const DynamicType());
+        actualTypes.add(const DynamicType());
+        storeSpreadMapEntryElementTypes(
+            spreadType, entry.isNullAware, actualTypes, length);
+      }
+      return spreadType;
+    } else if (entry is IfMapEntry) {
+      inferrer.inferExpression(entry.condition,
+          inferrer.coreTypes.boolClass.rawType, typeChecksNeeded,
+          isVoidAllowed: false);
+      inferMapEntry(
+          entry.then,
+          index,
+          inferredKeyType,
+          inferredValueType,
+          spreadContext,
+          spreadTypes,
+          actualTypes,
+          inferenceNeeded,
+          typeChecksNeeded,
+          nested: true);
+      if (entry.otherwise != null) {
+        inferMapEntry(
+            entry.otherwise,
+            index,
+            inferredKeyType,
+            inferredValueType,
+            spreadContext,
+            spreadTypes,
+            actualTypes,
+            inferenceNeeded,
+            typeChecksNeeded,
+            nested: true);
+      }
+      if (!nested) {
+        actualTypes.add(const DynamicType());
+        actualTypes.add(const DynamicType());
+      }
+      return null;
+    } else {
+      Expression key = entry.key;
+      inferrer.inferExpression(key, inferredKeyType, true, isVoidAllowed: true);
+      Expression value = entry.value;
+      inferrer.inferExpression(value, inferredValueType, true,
+          isVoidAllowed: true);
+      if (!nested) {
+        actualTypes.add(getInferredType(key, inferrer));
+        actualTypes.add(getInferredType(value, inferrer));
+      }
+      return null;
+    }
+  }
+
   void visitMapLiteralJudgment(MapLiteralJudgment node, DartType typeContext) {
     var mapClass = inferrer.coreTypes.mapClass;
     var mapType = mapClass.thisType;
@@ -929,60 +1003,36 @@
       }
       for (int i = 0; i < node.entries.length; ++i) {
         MapEntry entry = node.entries[i];
+        DartType spreadType = inferMapEntry(
+            entry,
+            i,
+            inferredKeyType,
+            inferredValueType,
+            spreadTypeContext,
+            spreadMapEntryTypes,
+            actualTypes,
+            inferenceNeeded,
+            typeChecksNeeded,
+            nested: false);
         if (entry is SpreadMapEntry) {
-          DartType spreadMapEntryType = inferrer.inferExpression(
-              entry.expression,
-              spreadTypeContext,
-              inferenceNeeded || typeChecksNeeded,
-              isVoidAllowed: true);
-          if (inferenceNeeded) {
-            formalTypes.add(mapType.typeArguments[0]);
-            formalTypes.add(mapType.typeArguments[1]);
-          }
-          if (typeChecksNeeded) {
-            spreadMapEntryTypes[i] = spreadMapEntryType;
-          }
-
-          bool isMap = inferrer.typeSchemaEnvironment.isSubtypeOf(
-              spreadMapEntryType, inferrer.coreTypes.mapClass.rawType);
+          bool isMap = inferrer.typeSchemaEnvironment
+              .isSubtypeOf(spreadType, inferrer.coreTypes.mapClass.rawType);
           bool isSet = inferrer.typeSchemaEnvironment.isSubtypeOf(
-              spreadMapEntryType, inferrer.coreTypes.iterableClass.rawType);
-
+              spreadType, inferrer.coreTypes.iterableClass.rawType);
           if (isMap && !isSet) {
             mapSpreadOffset = entry.expression.fileOffset;
           }
           if (!isMap && isSet) {
             iterableSpreadOffset = entry.expression.fileOffset;
           }
-
-          // Use 'dynamic' for error recovery.
-          int length = actualTypes.length;
-          actualTypes.add(const DynamicType());
-          actualTypes.add(const DynamicType());
-          storeSpreadMapEntryElementTypes(
-              spreadMapEntryType, entry.isNullAware, actualTypes, length);
         } else if (entry is IfMapEntry) {
-          node.entries[i] = new MapEntry(
-              new InvalidExpression('unimplemented spread entry')
-                ..fileOffset = node.fileOffset,
-              new NullLiteral());
-          actualTypes.add(const DynamicType());
-          actualTypes.add(const DynamicType());
         } else {
-          Expression key = entry.key;
-          inferrer.inferExpression(key, inferredKeyType, true,
-              isVoidAllowed: true);
-          actualTypes.add(getInferredType(key, inferrer));
-          Expression value = entry.value;
-          inferrer.inferExpression(value, inferredValueType, true,
-              isVoidAllowed: true);
-          actualTypes.add(getInferredType(value, inferrer));
-          if (inferenceNeeded) {
-            formalTypes.addAll(mapType.typeArguments);
-          }
-
           mapEntryOffset = entry.fileOffset;
         }
+        if (inferenceNeeded) {
+          formalTypes.add(mapType.typeArguments[0]);
+          formalTypes.add(mapType.typeArguments[1]);
+        }
       }
     }
     if (inferenceNeeded) {
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 8582a5b..1ea7bbc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
@@ -42,7 +42,13 @@
 import 'package:kernel/visitor.dart' show Transformer;
 
 import 'collections.dart'
-    show CollectionElement, IfElement, SpreadElement, SpreadMapEntry;
+    show
+        ControlFlowElement,
+        ControlFlowMapEntry,
+        IfElement,
+        IfMapEntry,
+        SpreadElement,
+        SpreadMapEntry;
 
 import '../source/source_loader.dart' show SourceLoader;
 
@@ -89,7 +95,7 @@
     // Translate elements in place up to the first non-expression, if any.
     int i = 0;
     for (; i < elements.length; ++i) {
-      if (elements[i] is CollectionElement) break;
+      if (elements[i] is ControlFlowElement) break;
       elements[i] = elements[i].accept(this)..parent = node;
     }
 
@@ -97,11 +103,11 @@
     if (i == elements.length) return node;
 
     if (isConst) {
-      // We don't desugar const lists here.  Remove non-expression elements for
-      // now so that they don't leak out of the transformation.
+      // We don't desugar const collections here.  Remove non-expression
+      // elements for now so that they don't leak out of the transformation.
       for (; i < elements.length; ++i) {
         Expression element = elements[i];
-        if (element is CollectionElement) {
+        if (element is ControlFlowElement) {
           elements[i] = InvalidExpression('unimplemented collection element')
             ..fileOffset = element.fileOffset
             ..parent = node;
@@ -131,7 +137,7 @@
     List<Statement> body = [result];
     // Add the elements up to the first non-expression.
     for (int j = 0; j < i; ++j) {
-      _translateExpressionElement(elements[j], isSet, result, body);
+      _addExpressionElement(elements[j], isSet, result, body);
     }
     // Translate the elements starting with the first non-expression.
     for (; i < elements.length; ++i) {
@@ -148,11 +154,11 @@
     } else if (element is IfElement) {
       _translateIfElement(element, elementType, isSet, result, body);
     } else {
-      _translateExpressionElement(element.accept(this), isSet, result, body);
+      _addExpressionElement(element.accept(this), isSet, result, body);
     }
   }
 
-  void _translateExpressionElement(Expression element, bool isSet,
+  void _addExpressionElement(Expression element, bool isSet,
       VariableDeclaration result, List<Statement> body) {
     body.add(new ExpressionStatement(new MethodInvocation(
         new VariableGet(result),
@@ -228,95 +234,128 @@
 
   @override
   TreeNode visitMapLiteral(MapLiteral node) {
+    // Translate entries in place up to the first control-flow entry, if any.
     int i = 0;
     for (; i < node.entries.length; ++i) {
-      if (node.entries[i] is SpreadMapEntry) break;
+      if (node.entries[i] is ControlFlowMapEntry) break;
       node.entries[i] = node.entries[i].accept(this)..parent = node;
     }
 
+    // If there were no control-flow entries we are done.
     if (i == node.entries.length) return node;
 
     if (node.isConst) {
-      // We don't desugar const maps here.  REmove spread for now so that they
-      // don't leak out.
+      // We don't desugar const maps here.  Remove control-flow entries for now
+      // so that they don't leak out of the transformation.
       for (; i < node.entries.length; ++i) {
         MapEntry entry = node.entries[i];
-        if (entry is SpreadMapEntry) {
-          entry.parent.replaceChild(
-              entry,
-              new MapEntry(
-                  InvalidExpression('unimplemented spread element')
-                    ..fileOffset = entry.fileOffset,
-                  new NullLiteral()));
+        if (entry is ControlFlowMapEntry) {
+          node.entries[i] = new MapEntry(
+              InvalidExpression('unimplemented map entry')
+                ..fileOffset = entry.fileOffset,
+              new NullLiteral())
+            ..parent = node;
+        } else {
+          node.entries[i] = node.entries[i].accept(this)..parent = node;
         }
       }
     }
 
-    VariableDeclaration map = new VariableDeclaration.forValue(
+    // Build a block expression and create an empty map.
+    VariableDeclaration result = new VariableDeclaration.forValue(
         new MapLiteral([], keyType: node.keyType, valueType: node.valueType),
         type: new InterfaceType(
             coreTypes.mapClass, [node.keyType, node.valueType]),
         isFinal: true);
-    List<Statement> body = [map];
+    List<Statement> body = [result];
+    // Add all the entries up to the first control-flow entry.
     for (int j = 0; j < i; ++j) {
-      body.add(new ExpressionStatement(new MethodInvocation(
-          new VariableGet(map),
-          new Name('[]='),
-          new Arguments([node.entries[j].key, node.entries[j].value]),
-          mapPut)));
+      _addNormalEntry(node.entries[j], result, body);
     }
     DartType mapEntryType =
         new InterfaceType(mapEntryClass, [node.keyType, node.valueType]);
     for (; i < node.entries.length; ++i) {
-      MapEntry entry = node.entries[i];
-      if (entry is SpreadMapEntry) {
-        Expression value = entry.expression.accept(this);
-        // Null-aware spreads require testing the subexpression's value.
-        VariableDeclaration temp;
-        if (entry.isNullAware) {
-          temp = new VariableDeclaration.forValue(value,
-              type: coreTypes.mapClass.rawType);
-          body.add(temp);
-          value = new VariableGet(temp);
-        }
-
-        VariableDeclaration elt =
-            new VariableDeclaration(null, type: mapEntryType, isFinal: true);
-        Statement statement = new ForInStatement(
-            elt,
-            new PropertyGet(value, new Name('entries'), mapEntries),
-            new ExpressionStatement(new MethodInvocation(
-                new VariableGet(map),
-                new Name('[]='),
-                new Arguments([
-                  new PropertyGet(
-                      new VariableGet(elt), new Name('key'), mapEntryKey),
-                  new PropertyGet(
-                      new VariableGet(elt), new Name('value'), mapEntryValue)
-                ]),
-                mapPut)));
-
-        if (entry.isNullAware) {
-          statement = new IfStatement(
-              new Not(new MethodInvocation(
-                  new VariableGet(temp),
-                  new Name('=='),
-                  new Arguments([new NullLiteral()]),
-                  objectEquals)),
-              statement,
-              null);
-        }
-        body.add(statement);
-      } else {
-        entry = entry.accept(this);
-        body.add(new ExpressionStatement(new MethodInvocation(
-            new VariableGet(map),
-            new Name('[]='),
-            new Arguments([entry.key, entry.value]),
-            mapPut)));
-      }
+      _translateEntry(node.entries[i], mapEntryType, result, body);
     }
 
-    return new BlockExpression(new Block(body), new VariableGet(map));
+    return new BlockExpression(new Block(body), new VariableGet(result));
+  }
+
+  void _translateEntry(MapEntry entry, DartType entryType,
+      VariableDeclaration result, List<Statement> body) {
+    if (entry is SpreadMapEntry) {
+      _translateSpreadEntry(entry, entryType, result, body);
+    } else if (entry is IfMapEntry) {
+      _translateIfEntry(entry, entryType, result, body);
+    } else {
+      _addNormalEntry(entry.accept(this), result, body);
+    }
+  }
+
+  void _addNormalEntry(
+      MapEntry entry, VariableDeclaration result, List<Statement> body) {
+    body.add(new ExpressionStatement(new MethodInvocation(
+        new VariableGet(result),
+        new Name('[]='),
+        new Arguments([entry.key, entry.value]),
+        mapPut)));
+  }
+
+  void _translateIfEntry(IfMapEntry entry, DartType entryType,
+      VariableDeclaration result, List<Statement> body) {
+    List<Statement> thenBody = [];
+    _translateEntry(entry.then, entryType, result, thenBody);
+    List<Statement> elseBody;
+    if (entry.otherwise != null) {
+      _translateEntry(
+          entry.otherwise, entryType, result, elseBody = <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);
+    }
+    body.add(new IfStatement(
+        entry.condition.accept(this), thenStatement, elseStatement));
+  }
+
+  void _translateSpreadEntry(SpreadMapEntry entry, DartType entryType,
+      VariableDeclaration result, List<Statement> body) {
+    Expression value = entry.expression.accept(this);
+    // Null-aware spreads require testing the subexpression's value.
+    VariableDeclaration temp;
+    if (entry.isNullAware) {
+      temp = new VariableDeclaration.forValue(value,
+          type: coreTypes.mapClass.rawType);
+      body.add(temp);
+      value = new VariableGet(temp);
+    }
+
+    VariableDeclaration elt =
+        new VariableDeclaration(null, type: entryType, isFinal: true);
+    Statement statement = new ForInStatement(
+        elt,
+        new PropertyGet(value, new Name('entries'), mapEntries),
+        new ExpressionStatement(new MethodInvocation(
+            new VariableGet(result),
+            new Name('[]='),
+            new Arguments([
+              new PropertyGet(
+                  new VariableGet(elt), new Name('key'), mapEntryKey),
+              new PropertyGet(
+                  new VariableGet(elt), new Name('value'), mapEntryValue)
+            ]),
+            mapPut)));
+
+    if (entry.isNullAware) {
+      statement = new IfStatement(
+          new Not(new MethodInvocation(new VariableGet(temp), new Name('=='),
+              new Arguments([new NullLiteral()]), objectEquals)),
+          statement,
+          null);
+    }
+    body.add(statement);
   }
 }
diff --git a/pkg/front_end/testcases/control_flow_collection.dart b/pkg/front_end/testcases/control_flow_collection.dart
index 3c9bad0..e6d645c 100644
--- a/pkg/front_end/testcases/control_flow_collection.dart
+++ b/pkg/front_end/testcases/control_flow_collection.dart
@@ -7,17 +7,24 @@
       1,
       if (oracle()) 2,
       if (oracle()) 3 else -1,
-      if (oracle()) if (oracle()) 4
+      if (oracle()) if (oracle()) 4,
   ];
   final aSet = <int>{
       1,
       if (oracle()) 2,
       if (oracle()) 3 else -1,
-      if (oracle()) if (oracle()) 4
+      if (oracle()) if (oracle()) 4,
+  };
+  final aMap = <int, int>{
+    1: 1,
+    if (oracle()) 2: 2,
+    if (oracle()) 3: 3 else -1: -1,
+    if (oracle()) if (oracle()) 4: 4,
   };
 
   print(aList);
   print(aSet);
+  print(aMap);
 }
 
 oracle() => true;
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 664a692..e8d44f8 100644
--- a/pkg/front_end/testcases/control_flow_collection.dart.legacy.expect
+++ b/pkg/front_end/testcases/control_flow_collection.dart.legacy.expect
@@ -11,11 +11,11 @@
 //       ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:10:21: Error: Unexpected token 'if'.
-//       if (oracle()) if (oracle()) 4
+//       if (oracle()) if (oracle()) 4,
 //                     ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:10:7: Error: Unexpected token 'if'.
-//       if (oracle()) if (oracle()) 4
+//       if (oracle()) if (oracle()) 4,
 //       ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:14:7: Error: Unexpected token 'if'.
@@ -27,21 +27,39 @@
 //       ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:16:21: Error: Unexpected token 'if'.
-//       if (oracle()) if (oracle()) 4
+//       if (oracle()) if (oracle()) 4,
 //                     ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:16:7: Error: Unexpected token 'if'.
-//       if (oracle()) if (oracle()) 4
+//       if (oracle()) if (oracle()) 4,
 //       ^^
 //
+// pkg/front_end/testcases/control_flow_collection.dart:20:5: Error: Unexpected token 'if'.
+//     if (oracle()) 2: 2,
+//     ^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:21: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'.
+//     if (oracle()) if (oracle()) 4: 4,
+//                   ^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:22:5: Error: Unexpected token 'if'.
+//     if (oracle()) if (oracle()) 4: 4,
+//     ^^
+//
 import self as self;
 import "dart:core" as core;
 
 static method main() → dynamic {
   final dynamic aList = <core::int>[1];
   final dynamic aSet = <core::int>{1};
+  final dynamic aMap = <core::int, core::int>{1: 1};
   core::print(aList);
   core::print(aSet);
+  core::print(aMap);
 }
 static method oracle() → dynamic
   return true;
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 664a692..e8d44f8 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
@@ -11,11 +11,11 @@
 //       ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:10:21: Error: Unexpected token 'if'.
-//       if (oracle()) if (oracle()) 4
+//       if (oracle()) if (oracle()) 4,
 //                     ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:10:7: Error: Unexpected token 'if'.
-//       if (oracle()) if (oracle()) 4
+//       if (oracle()) if (oracle()) 4,
 //       ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:14:7: Error: Unexpected token 'if'.
@@ -27,21 +27,39 @@
 //       ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:16:21: Error: Unexpected token 'if'.
-//       if (oracle()) if (oracle()) 4
+//       if (oracle()) if (oracle()) 4,
 //                     ^^
 //
 // pkg/front_end/testcases/control_flow_collection.dart:16:7: Error: Unexpected token 'if'.
-//       if (oracle()) if (oracle()) 4
+//       if (oracle()) if (oracle()) 4,
 //       ^^
 //
+// pkg/front_end/testcases/control_flow_collection.dart:20:5: Error: Unexpected token 'if'.
+//     if (oracle()) 2: 2,
+//     ^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:21: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'.
+//     if (oracle()) if (oracle()) 4: 4,
+//                   ^^
+//
+// pkg/front_end/testcases/control_flow_collection.dart:22:5: Error: Unexpected token 'if'.
+//     if (oracle()) if (oracle()) 4: 4,
+//     ^^
+//
 import self as self;
 import "dart:core" as core;
 
 static method main() → dynamic {
   final dynamic aList = <core::int>[1];
   final dynamic aSet = <core::int>{1};
+  final dynamic aMap = <core::int, core::int>{1: 1};
   core::print(aList);
   core::print(aSet);
+  core::print(aMap);
 }
 static method oracle() → dynamic
   return true;
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 f8e8bfe..edd1a14 100644
--- a/pkg/front_end/testcases/control_flow_collection.dart.strong.expect
+++ b/pkg/front_end/testcases/control_flow_collection.dart.strong.expect
@@ -30,8 +30,22 @@
       if(self::oracle())
         #t2.{core::Set::add}(4);
   } =>#t2;
+  final core::Map<core::int, core::int> aMap = block {
+    final core::Map<core::int, core::int> #t3 = <core::int, core::int>{};
+    #t3.{core::Map::[]=}(1, 1);
+    if(self::oracle())
+      #t3.{core::Map::[]=}(2, 2);
+    if(self::oracle())
+      #t3.{core::Map::[]=}(3, 3);
+    else
+      #t3.{core::Map::[]=}(1.{core::int::unary-}(), 1.{core::int::unary-}());
+    if(self::oracle())
+      if(self::oracle())
+        #t3.{core::Map::[]=}(4, 4);
+  } =>#t3;
   core::print(aList);
   core::print(aSet);
+  core::print(aMap);
 }
 static method oracle() → dynamic
   return true;
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 f8e8bfe..edd1a14 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
@@ -30,8 +30,22 @@
       if(self::oracle())
         #t2.{core::Set::add}(4);
   } =>#t2;
+  final core::Map<core::int, core::int> aMap = block {
+    final core::Map<core::int, core::int> #t3 = <core::int, core::int>{};
+    #t3.{core::Map::[]=}(1, 1);
+    if(self::oracle())
+      #t3.{core::Map::[]=}(2, 2);
+    if(self::oracle())
+      #t3.{core::Map::[]=}(3, 3);
+    else
+      #t3.{core::Map::[]=}(1.{core::int::unary-}(), 1.{core::int::unary-}());
+    if(self::oracle())
+      if(self::oracle())
+        #t3.{core::Map::[]=}(4, 4);
+  } =>#t3;
   core::print(aList);
   core::print(aSet);
+  core::print(aMap);
 }
 static method oracle() → dynamic
   return true;