Report errors for using control-flow and spread features in a const context

CFE detects the const context while parsing, so we can report the error message
early on before we do any transformations.

Change-Id: Ib1cadb28366eb6a9a18612206aa155b04a4a5b32
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99540
Commit-Queue: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index 01e5f4b..668da04 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -639,6 +639,30 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(Token token)>
+    templateCantUseControlFlowOrSpreadAsConstant =
+    const Template<Message Function(Token token)>(
+        messageTemplate:
+            r"""'#lexeme' is not supported in constant expressions.""",
+        withArguments: _withArgumentsCantUseControlFlowOrSpreadAsConstant);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(Token token)>
+    codeCantUseControlFlowOrSpreadAsConstant =
+    const Code<Message Function(Token token)>(
+        "CantUseControlFlowOrSpreadAsConstant",
+        templateCantUseControlFlowOrSpreadAsConstant,
+        analyzerCodes: <String>["NOT_CONSTANT_EXPRESSION"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsCantUseControlFlowOrSpreadAsConstant(Token token) {
+  String lexeme = token.lexeme;
+  return new Message(codeCantUseControlFlowOrSpreadAsConstant,
+      message: """'${lexeme}' is not supported in constant expressions.""",
+      arguments: {'token': token});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
         Token
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 e360c2e..0430c9d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -2316,6 +2316,18 @@
       push(invalidCollectionElement);
       return;
     }
+
+    if (constantContext != ConstantContext.none &&
+        !library.loader.target.enableConstantUpdate2018) {
+      handleRecoverableError(
+          fasta.templateCantUseControlFlowOrSpreadAsConstant
+              .withArguments(forToken),
+          forToken,
+          forToken);
+      push(invalidCollectionElement);
+      return;
+    }
+
     transformCollections = true;
     List<VariableDeclaration> variables =
         buildVariableDeclarations(variableOrExpression);
@@ -3718,6 +3730,18 @@
       push(invalidCollectionElement);
       return;
     }
+
+    if (constantContext != ConstantContext.none &&
+        !library.loader.target.enableConstantUpdate2018) {
+      handleRecoverableError(
+          fasta.templateCantUseControlFlowOrSpreadAsConstant
+              .withArguments(ifToken),
+          ifToken,
+          ifToken);
+      push(invalidCollectionElement);
+      return;
+    }
+
     transformCollections = true;
     if (entry is MapEntry) {
       push(forest.ifMapEntry(toValue(condition), entry, null, ifToken));
@@ -3744,6 +3768,18 @@
       push(invalidCollectionElement);
       return;
     }
+
+    if (constantContext != ConstantContext.none &&
+        !library.loader.target.enableConstantUpdate2018) {
+      handleRecoverableError(
+          fasta.templateCantUseControlFlowOrSpreadAsConstant
+              .withArguments(ifToken),
+          ifToken,
+          ifToken);
+      push(invalidCollectionElement);
+      return;
+    }
+
     transformCollections = true;
     if (thenEntry is MapEntry) {
       if (elseEntry is MapEntry) {
@@ -3804,6 +3840,18 @@
       push(invalidCollectionElement);
       return;
     }
+
+    if (constantContext != ConstantContext.none &&
+        !library.loader.target.enableConstantUpdate2018) {
+      handleRecoverableError(
+          fasta.templateCantUseControlFlowOrSpreadAsConstant
+              .withArguments(spreadToken),
+          spreadToken,
+          spreadToken);
+      push(invalidCollectionElement);
+      return;
+    }
+
     transformCollections = true;
     push(forest.spreadElement(toValue(expression), spreadToken));
   }
@@ -4115,6 +4163,18 @@
       push(invalidCollectionElement);
       return;
     }
+
+    if (constantContext != ConstantContext.none &&
+        !library.loader.target.enableConstantUpdate2018) {
+      handleRecoverableError(
+          fasta.templateCantUseControlFlowOrSpreadAsConstant
+              .withArguments(forToken),
+          forToken,
+          forToken);
+      push(invalidCollectionElement);
+      return;
+    }
+
     transformCollections = true;
     VariableDeclaration variable = buildForInVariable(lvalue);
     Expression problem = checkForInVariable(lvalue, variable, forToken);
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index d900666..c37983a 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -40,6 +40,7 @@
 CantInferPackagesFromPackageUri/example: Fail
 CantInferTypeDueToCircularity/example: Fail
 CantInferTypeDueToInconsistentOverrides/example: Fail
+CantUseControlFlowOrSpreadAsConstant/example: Fail
 CantUseSuperBoundedTypeForInstanceCreation/analyzerCode: Fail
 CantUseSuperBoundedTypeForInstanceCreation/example: Fail
 ColonInPlaceOfIn/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 962bdb7..bc98cf9 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -3200,6 +3200,10 @@
       prefix?.Object;
     }
 
+CantUseControlFlowOrSpreadAsConstant:
+  template: "'#lexeme' is not supported in constant expressions."
+  analyzerCode: NOT_CONSTANT_EXPRESSION
+
 CantUseDeferredPrefixAsConstant:
   template: >
     '#lexeme' can't be used in a constant expression because it's marked as