[CFE] Avoid cloning bodies of lazy if elements.
Fixes https://github.com/dart-lang/sdk/issues/36812
Analyzer/DDC failures: https://github.com/dart-lang/sdk/issues/36873
Change-Id: I36d61d3035c9275078b368637d53f6385cf8c487
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101262
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_collection_builders.dart b/pkg/front_end/lib/src/fasta/kernel/constant_collection_builders.dart
index 7d83bc2..9173c09 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_collection_builders.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_collection_builders.dart
@@ -22,6 +22,8 @@
Message get messageForIteration;
+ _ListOrSetConstantBuilder<L, C> newTempBuilder();
+
/// Add an element (which is possibly a spread or an if element) to the
/// constant list being built by this builder.
void add(Expression element) {
@@ -32,12 +34,10 @@
if (evaluator.shouldBeUnevaluated) {
// Unevaluated if
evaluator.enterLazy();
- Constant then = evaluator._evaluateSubexpression(
- makeLiteral([evaluator.cloner.clone(element.then)]));
+ Constant then = (newTempBuilder()..add(element.then)).build();
Constant otherwise;
if (element.otherwise != null) {
- otherwise = evaluator._evaluateSubexpression(
- makeLiteral([evaluator.cloner.clone(element.otherwise)]));
+ otherwise = (newTempBuilder()..add(element.otherwise)).build();
} else {
otherwise = makeConstant([]);
}
@@ -128,6 +128,8 @@
}
void addConstant(Constant constant, TreeNode context);
+
+ Constant build();
}
class ListConstantBuilder
@@ -148,6 +150,10 @@
Message get messageForIteration => messageConstEvalIterationInConstList;
@override
+ ListConstantBuilder newTempBuilder() =>
+ new ListConstantBuilder(original, const DynamicType(), evaluator);
+
+ @override
void addConstant(Constant constant, TreeNode context) {
List<Constant> lastPart;
if (parts.last is List<Constant>) {
@@ -158,6 +164,7 @@
lastPart.add(evaluator.ensureIsSubtype(constant, elementType, context));
}
+ @override
Constant build() {
if (parts.length == 1) {
// Fully evaluated
@@ -199,6 +206,10 @@
Message get messageForIteration => messageConstEvalIterationInConstSet;
@override
+ SetConstantBuilder newTempBuilder() =>
+ new SetConstantBuilder(original, const DynamicType(), evaluator);
+
+ @override
void addConstant(Constant constant, TreeNode context) {
if (!evaluator.hasPrimitiveEqual(constant)) {
evaluator.report(context,
@@ -218,6 +229,7 @@
lastPart.add(evaluator.ensureIsSubtype(constant, elementType, context));
}
+ @override
Constant build() {
if (parts.length == 1) {
// Fully evaluated
@@ -274,6 +286,9 @@
MapConstantBuilder(
this.original, this.keyType, this.valueType, this.evaluator);
+ MapConstantBuilder newTempBuilder() => new MapConstantBuilder(
+ original, const DynamicType(), const DynamicType(), evaluator);
+
/// Add a map entry (which is possibly a spread or an if map entry) to the
/// constant map being built by this builder
void add(MapEntry element) {
@@ -284,14 +299,10 @@
if (evaluator.shouldBeUnevaluated) {
// Unevaluated if
evaluator.enterLazy();
- Constant then = evaluator._evaluateSubexpression(new MapLiteral(
- [evaluator.cloner.clone(element.then)],
- isConst: true));
+ Constant then = (newTempBuilder()..add(element.then)).build();
Constant otherwise;
if (element.otherwise != null) {
- otherwise = evaluator._evaluateSubexpression(new MapLiteral(
- [evaluator.cloner.clone(element.otherwise)],
- isConst: true));
+ otherwise = (newTempBuilder()..add(element.otherwise)).build();
} else {
otherwise =
new MapConstant(const DynamicType(), const DynamicType(), []);
diff --git a/tests/language_2/lazy_spread_test.dart b/tests/language_2/lazy_spread_test.dart
new file mode 100644
index 0000000..eedb957
--- /dev/null
+++ b/tests/language_2/lazy_spread_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that the body of an if element with unevaluated condition can
+// contain a spread.
+// Regression test for https://github.com/dart-lang/sdk/issues/36812
+
+// SharedOptions=--enable-experiment=constant-update-2018
+
+const b = bool.fromEnvironment("foo");
+
+main() {
+ const l1 = [1, 2, 3];
+ const l2 = [if (b) ...l1];
+ print(l2);
+}