[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;