Revert "[dartdevc] Remove explicit calls of the constant evaluator in DDC."

This reverts commit fb8df61606faf1564fbb53f53115017fc4d76483.

Reason for revert: Breaking Dart SDK -> Flutter engine build.

Original change's description:
> [dartdevc] Remove explicit calls of the constant evaluator in DDC.
> 
> These are unnecessary now that constant evaluation is performed as
> part of the front-end transformations.
> 
> Change-Id: I5de9bbf7ebab09528431f764895eb3e3b1b45379
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/111430
> Commit-Queue: Aske Simon Christensen <askesc@google.com>
> Reviewed-by: Vijay Menon <vsm@google.com>

TBR=vsm@google.com,askesc@google.com

Change-Id: Ife7c6f207c38d86e390c98de8af81f9cc5b863c4
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/113746
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 7805e71..c4ab9cf 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -360,7 +360,8 @@
     outFiles.add(File(outPaths.first + '.txt').writeAsString(sb.toString()));
   }
 
-  var compiler = ProgramCompiler(component, result.classHierarchy, options);
+  var compiler = ProgramCompiler(
+      component, result.classHierarchy, options, declaredVariables);
 
   var jsModule = compiler.emitModule(
       component, result.inputSummaries, inputSummaries, summaryModules);
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 8bd144f..0cd7d86 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -216,10 +216,10 @@
   final NullableInference _nullableInference;
 
   factory ProgramCompiler(Component component, ClassHierarchy hierarchy,
-      SharedCompilerOptions options) {
+      SharedCompilerOptions options, Map<String, String> declaredVariables) {
     var coreTypes = CoreTypes(component);
     var types = TypeSchemaEnvironment(coreTypes, hierarchy);
-    var constants = DevCompilerConstants();
+    var constants = DevCompilerConstants(types, declaredVariables);
     var nativeTypes = NativeTypeSet(coreTypes, constants);
     var jsTypeRep = JSTypeRep(types, hierarchy);
     return ProgramCompiler._(coreTypes, coreTypes.index, nativeTypes, constants,
@@ -4919,19 +4919,73 @@
   @override
   js_ast.Expression visitListConcatenation(ListConcatenation node) {
     // Only occurs inside unevaluated constants.
-    throw UnsupportedError("List concatenation");
+    List<js_ast.Expression> entries = [];
+    _concatenate(Expression node) {
+      if (node is ListConcatenation) {
+        node.lists.forEach(_concatenate);
+      } else {
+        node.accept(this);
+        if (node is ConstantExpression) {
+          var list = node.constant as ListConstant;
+          entries.addAll(list.entries.map(visitConstant));
+        } else if (node is ListLiteral) {
+          entries.addAll(node.expressions.map(_visitExpression));
+        }
+      }
+    }
+
+    node.lists.forEach(_concatenate);
+    return _emitConstList(node.typeArgument, entries);
   }
 
   @override
   js_ast.Expression visitSetConcatenation(SetConcatenation node) {
     // Only occurs inside unevaluated constants.
-    throw UnsupportedError("Set concatenation");
+    List<js_ast.Expression> entries = [];
+    _concatenate(Expression node) {
+      if (node is SetConcatenation) {
+        node.sets.forEach(_concatenate);
+      } else {
+        node.accept(this);
+        if (node is ConstantExpression) {
+          var set = node.constant as SetConstant;
+          entries.addAll(set.entries.map(visitConstant));
+        } else if (node is SetLiteral) {
+          entries.addAll(node.expressions.map(_visitExpression));
+        }
+      }
+    }
+
+    node.sets.forEach(_concatenate);
+    return _emitConstSet(node.typeArgument, entries);
   }
 
   @override
   js_ast.Expression visitMapConcatenation(MapConcatenation node) {
     // Only occurs inside unevaluated constants.
-    throw UnsupportedError("Map concatenation");
+    List<js_ast.Expression> entries = [];
+    _concatenate(Expression node) {
+      if (node is MapConcatenation) {
+        node.maps.forEach(_concatenate);
+      } else {
+        node.accept(this);
+        if (node is ConstantExpression) {
+          var map = node.constant as MapConstant;
+          for (var entry in map.entries) {
+            entries.add(visitConstant(entry.key));
+            entries.add(visitConstant(entry.value));
+          }
+        } else if (node is MapLiteral) {
+          for (var entry in node.entries) {
+            entries.add(_visitExpression(entry.key));
+            entries.add(_visitExpression(entry.value));
+          }
+        }
+      }
+    }
+
+    node.maps.forEach(_concatenate);
+    return _emitConstMap(node.keyType, node.valueType, entries);
   }
 
   @override
diff --git a/pkg/dev_compiler/lib/src/kernel/constants.dart b/pkg/dev_compiler/lib/src/kernel/constants.dart
index 2059f37..9044034 100644
--- a/pkg/dev_compiler/lib/src/kernel/constants.dart
+++ b/pkg/dev_compiler/lib/src/kernel/constants.dart
@@ -2,25 +2,43 @@
 // 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.
 
+// TODO(askesc): We should not need to call the constant evaluator
+// explicitly once constant-update-2018 is shipped.
+import 'package:front_end/src/api_prototype/constant_evaluator.dart'
+    show ConstantEvaluator, SimpleErrorReporter;
+
+import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart';
 import 'package:kernel/target/targets.dart';
+import 'package:kernel/type_environment.dart';
+import 'kernel_helpers.dart';
 
 /// Implements constant evaluation for dev compiler:
 ///
 /// [isConstant] determines if an expression is constant.
 /// [evaluate] computes the value of a constant expression, if available.
 class DevCompilerConstants {
-  DevCompilerConstants();
+  final _ConstantVisitor _visitor;
+  final ConstantEvaluator _evaluator;
+
+  DevCompilerConstants(
+      TypeEnvironment types, Map<String, String> declaredVariables)
+      : _visitor = _ConstantVisitor(types.coreTypes),
+        _evaluator = ConstantEvaluator(const DevCompilerConstantsBackend(),
+            declaredVariables, types, const _ErrorReporter());
 
   /// Determines if an expression is constant.
-  bool isConstant(Expression e) => e is ConstantExpression;
+  bool isConstant(Expression e) => _visitor.isConstant(e);
 
   /// Evaluates [e] to find its constant value, returning `null` if evaluation
   /// failed, or if the constant was unavailable.
   ///
   /// Returns [NullConstant] to represent the `null` value.
   Constant evaluate(Expression e) {
-    return e is ConstantExpression ? e.constant : null;
+    if (e == null) return null;
+
+    Constant result = _evaluator.evaluate(e);
+    return result is UnevaluatedConstant ? null : result;
   }
 
   /// If [node] is an annotation with a field named [name], returns that field's
@@ -42,6 +60,7 @@
   ///
   /// Given the node for `@MyAnnotation('FooBar')` this will return `'FooBar'`.
   Object getFieldValueFromAnnotation(Expression node, String name) {
+    node = unwrapUnevaluatedConstant(node);
     if (node is ConstantExpression) {
       var constant = node.constant;
       if (constant is InstanceConstant) {
@@ -78,6 +97,7 @@
   }
 
   Object _evaluateAnnotationArgument(Expression node) {
+    node = unwrapUnevaluatedConstant(node);
     if (node is ConstantExpression) {
       var constant = node.constant;
       if (constant is PrimitiveConstant) return constant.value;
@@ -92,6 +112,88 @@
   }
 }
 
+/// Finds constant expressions as defined in Dart language spec 4th ed,
+/// 16.1 Constants.
+class _ConstantVisitor extends ExpressionVisitor<bool> {
+  final CoreTypes coreTypes;
+  _ConstantVisitor(this.coreTypes);
+
+  bool isConstant(Expression e) => e.accept(this) as bool;
+
+  @override
+  defaultExpression(node) => false;
+  @override
+  defaultBasicLiteral(node) => true;
+  @override
+  visitTypeLiteral(node) => true; // TODO(jmesserly): deferred libraries?
+  @override
+  visitSymbolLiteral(node) => true;
+  @override
+  visitListLiteral(node) => node.isConst;
+  @override
+  visitMapLiteral(node) => node.isConst;
+  @override
+  visitStaticInvocation(node) {
+    return node.isConst ||
+        node.target == coreTypes.identicalProcedure &&
+            node.arguments.positional.every(isConstant) ||
+        isFromEnvironmentInvocation(coreTypes, node) &&
+            node.arguments.positional.every(isConstant) &&
+            node.arguments.named.every((n) => isConstant(n.value));
+  }
+
+  @override
+  visitDirectMethodInvocation(node) {
+    return node.receiver is BasicLiteral &&
+        isOperatorMethodName(node.name.name) &&
+        node.arguments.positional.every((p) => p is BasicLiteral);
+  }
+
+  @override
+  visitMethodInvocation(node) {
+    return node.receiver is BasicLiteral &&
+        isOperatorMethodName(node.name.name) &&
+        node.arguments.positional.every((p) => p is BasicLiteral);
+  }
+
+  @override
+  visitConstructorInvocation(node) => node.isConst;
+  @override
+  visitStringConcatenation(node) =>
+      node.expressions.every((e) => e is BasicLiteral);
+  @override
+  visitStaticGet(node) {
+    var target = node.target;
+    return target is Procedure || target is Field && target.isConst;
+  }
+
+  @override
+  visitVariableGet(node) => node.variable.isConst;
+  @override
+  visitNot(node) {
+    var operand = node.operand;
+    return operand is BoolLiteral ||
+        operand is DirectMethodInvocation &&
+            visitDirectMethodInvocation(operand) ||
+        operand is MethodInvocation && visitMethodInvocation(operand);
+  }
+
+  @override
+  visitLogicalExpression(node) =>
+      node.left is BoolLiteral && node.right is BoolLiteral;
+  @override
+  visitConditionalExpression(node) =>
+      node.condition is BoolLiteral &&
+      node.then is BoolLiteral &&
+      node.otherwise is BoolLiteral;
+
+  @override
+  visitLet(Let node) {
+    var init = node.variable.initializer;
+    return (init == null || isConstant(init)) && isConstant(node.body);
+  }
+}
+
 /// Implement the class for compiler specific behavior.
 class DevCompilerConstantsBackend extends ConstantsBackend {
   const DevCompilerConstantsBackend();
@@ -116,3 +218,11 @@
     }
   }
 }
+
+class _ErrorReporter extends SimpleErrorReporter {
+  const _ErrorReporter();
+
+  // Ignore reported errors.
+  @override
+  reportMessage(Uri uri, int offset, String message) {}
+}
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 9708afa..3b3b66a 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -101,6 +101,7 @@
 /// This function works regardless of whether the CFE is evaluating constants,
 /// or whether the constant is a field reference (such as "anonymous" above).
 Class getAnnotationClass(Expression node) {
+  node = unwrapUnevaluatedConstant(node);
   if (node is ConstantExpression) {
     var constant = node.constant;
     if (constant is InstanceConstant) return constant.classNode;
@@ -113,6 +114,19 @@
   return null;
 }
 
+Expression unwrapUnevaluatedConstant(Expression node) {
+  // TODO(jmesserly): see if we can configure CFE to preseve the original
+  // expression, rather than wrapping in an UnevaluatedConstant and then
+  // a ConstantExpression.
+  if (node is ConstantExpression) {
+    var constant = node.constant;
+    if (constant is UnevaluatedConstant) {
+      return constant.expression;
+    }
+  }
+  return node;
+}
+
 /// Returns true if [name] is an operator method that is available on primitive
 /// types (`int`, `double`, `num`, `String`, `bool`).
 ///
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index e472a73..33242c9 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -249,6 +249,7 @@
 
   bool _isInternalAnnotationField(
       Expression node, String fieldName, String className) {
+    node = unwrapUnevaluatedConstant(node);
     if (node is ConstantExpression) {
       var constant = node.constant;
       return constant is InstanceConstant &&
diff --git a/pkg/dev_compiler/tool/kernel_sdk.dart b/pkg/dev_compiler/tool/kernel_sdk.dart
index 004097b..11e2a33 100755
--- a/pkg/dev_compiler/tool/kernel_sdk.dart
+++ b/pkg/dev_compiler/tool/kernel_sdk.dart
@@ -75,9 +75,11 @@
   File(librarySpecPath)
       .copySync(p.join(p.dirname(outputDir), p.basename(librarySpecPath)));
 
-  var jsModule = ProgramCompiler(component, compilerResult.classHierarchy,
-          SharedCompilerOptions(moduleName: 'dart_sdk'))
-      .emitModule(component, [], [], {});
+  var jsModule = ProgramCompiler(
+      component,
+      compilerResult.classHierarchy,
+      SharedCompilerOptions(moduleName: 'dart_sdk'),
+      {}).emitModule(component, [], [], {});
   var moduleFormats = {
     'amd': ModuleFormat.amd,
     'common': ModuleFormat.common,