[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);
+}