Reland "[cfe] Compile null-aware spreads in non-const maps"
This is a reland of 3160b084d8032f313c4b6e6f681092eb5ba66973
Original change's description:
> [cfe] Compile null-aware spreads in non-const maps
>
> Change-Id: I22ee0b8821835bf8f2417f5fb4433898d06e7c36
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96060
> Reviewed-by: Kevin Millikin <kmillikin@google.com>
Change-Id: I46198eb380a1813723376e894d5d32261b25dfcb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96132
Reviewed-by: Régis Crelier <regis@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 123e9f2..c72f97c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -2554,7 +2554,7 @@
if (entry is MapEntry) {
entries.add(entry);
} else if (entry is SpreadElement) {
- entries.add(new SpreadMapEntry(entry.expression));
+ entries.add(new SpreadMapEntry(entry.expression, entry.isNullAware));
} else {
addProblem(
fasta.templateExpectedAfterButGot.withArguments(':'),
diff --git a/pkg/front_end/lib/src/fasta/kernel/collections.dart b/pkg/front_end/lib/src/fasta/kernel/collections.dart
index c2b4dcc..74f6789 100644
--- a/pkg/front_end/lib/src/fasta/kernel/collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/collections.dart
@@ -204,8 +204,9 @@
/// A spread element in a map literal.
class SpreadMapEntry extends TreeNode with _FakeMapEntryMixin {
Expression expression;
+ bool isNullAware;
- SpreadMapEntry(this.expression) {
+ SpreadMapEntry(this.expression, this.isNullAware) {
expression?.parent = this;
}
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 3c2bdb6..d900fac 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
@@ -237,11 +237,21 @@
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);
- body.add(new ForInStatement(
+ Statement statement = new ForInStatement(
elt,
- entry.expression.accept(this),
+ value,
new ExpressionStatement(new MethodInvocation(
new VariableGet(map),
new Name('[]='),
@@ -251,7 +261,19 @@
new PropertyGet(
new VariableGet(elt), new Name('value'), mapEntryValue)
]),
- mapPut))));
+ 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(
diff --git a/pkg/front_end/testcases/spread_collection.dart.strong.expect b/pkg/front_end/testcases/spread_collection.dart.strong.expect
index a05138f..8ca66da 100644
--- a/pkg/front_end/testcases/spread_collection.dart.strong.expect
+++ b/pkg/front_end/testcases/spread_collection.dart.strong.expect
@@ -27,19 +27,21 @@
#t5.{core::Map::[]=}(1, 1);
for (final core::MapEntry<core::int, core::int> #t6 in <core::int, core::int>{2: 2})
#t5.{core::Map::[]=}(#t6.{core::MapEntry::key}, #t6.{core::MapEntry::value});
- for (final core::MapEntry<core::int, core::int> #t7 in <core::int, core::int>{3: 3})
- #t5.{core::Map::[]=}(#t7.{core::MapEntry::key}, #t7.{core::MapEntry::value});
+ final core::Map<dynamic, dynamic> #t7 = <core::int, core::int>{3: 3};
+ if(!#t7.{core::Object::==}(null))
+ for (final core::MapEntry<core::int, core::int> #t8 in #t7)
+ #t5.{core::Map::[]=}(#t8.{core::MapEntry::key}, #t8.{core::MapEntry::value});
} =>#t5;
final core::Set<core::int> aSet = block {
- final core::Set<core::int> #t8 = col::LinkedHashSet::•<core::int>();
- #t8.{core::Set::add}(1);
- for (final core::int #t9 in <core::int>[2])
- #t8.{core::Set::add}(#t9);
- final dynamic #t10 = <core::int>[3];
- if(!#t10.{core::Object::==}(null))
- for (final core::int #t11 in #t10)
- #t8.{core::Set::add}(#t11);
- } =>#t8;
+ final core::Set<core::int> #t9 = col::LinkedHashSet::•<core::int>();
+ #t9.{core::Set::add}(1);
+ for (final core::int #t10 in <core::int>[2])
+ #t9.{core::Set::add}(#t10);
+ final dynamic #t11 = <core::int>[3];
+ if(!#t11.{core::Object::==}(null))
+ for (final core::int #t12 in #t11)
+ #t9.{core::Set::add}(#t12);
+ } =>#t9;
final dynamic aSetOrMap = invalid-expression "pkg/front_end/testcases/spread_collection.dart:9:21: Error: Not enough type information to disambiguate between literal set and literal map.
Try providing type arguments for the literal explicitly to disambiguate it.
final aSetOrMap = {...foo()};
diff --git a/pkg/front_end/testcases/spread_collection.dart.strong.transformed.expect b/pkg/front_end/testcases/spread_collection.dart.strong.transformed.expect
index a05138f..8ca66da 100644
--- a/pkg/front_end/testcases/spread_collection.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/spread_collection.dart.strong.transformed.expect
@@ -27,19 +27,21 @@
#t5.{core::Map::[]=}(1, 1);
for (final core::MapEntry<core::int, core::int> #t6 in <core::int, core::int>{2: 2})
#t5.{core::Map::[]=}(#t6.{core::MapEntry::key}, #t6.{core::MapEntry::value});
- for (final core::MapEntry<core::int, core::int> #t7 in <core::int, core::int>{3: 3})
- #t5.{core::Map::[]=}(#t7.{core::MapEntry::key}, #t7.{core::MapEntry::value});
+ final core::Map<dynamic, dynamic> #t7 = <core::int, core::int>{3: 3};
+ if(!#t7.{core::Object::==}(null))
+ for (final core::MapEntry<core::int, core::int> #t8 in #t7)
+ #t5.{core::Map::[]=}(#t8.{core::MapEntry::key}, #t8.{core::MapEntry::value});
} =>#t5;
final core::Set<core::int> aSet = block {
- final core::Set<core::int> #t8 = col::LinkedHashSet::•<core::int>();
- #t8.{core::Set::add}(1);
- for (final core::int #t9 in <core::int>[2])
- #t8.{core::Set::add}(#t9);
- final dynamic #t10 = <core::int>[3];
- if(!#t10.{core::Object::==}(null))
- for (final core::int #t11 in #t10)
- #t8.{core::Set::add}(#t11);
- } =>#t8;
+ final core::Set<core::int> #t9 = col::LinkedHashSet::•<core::int>();
+ #t9.{core::Set::add}(1);
+ for (final core::int #t10 in <core::int>[2])
+ #t9.{core::Set::add}(#t10);
+ final dynamic #t11 = <core::int>[3];
+ if(!#t11.{core::Object::==}(null))
+ for (final core::int #t12 in #t11)
+ #t9.{core::Set::add}(#t12);
+ } =>#t9;
final dynamic aSetOrMap = invalid-expression "pkg/front_end/testcases/spread_collection.dart:9:21: Error: Not enough type information to disambiguate between literal set and literal map.
Try providing type arguments for the literal explicitly to disambiguate it.
final aSetOrMap = {...foo()};