[Kernel] Build an invalid constant for evaluation errors

An invalid constant is (currently) represented by an unevaluated
invalid expression.  Using this instead of null fixes 63 out of 125
CFE constant-evaluation crashes with constant-update-2018 and
correctly signals 26 more previously-missed compile-time errors.

Change-Id: I5b4de3995b3a59978dfa08fc542ef0f027572eb6
Reviewed-on: https://dart-review.googlesource.com/c/89506
Commit-Queue: Kevin Millikin <kmillikin@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
index 5d76a5f..0d0fc88 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
@@ -56,117 +56,124 @@
 
   KernelConstantErrorReporter(this.loader, this.typeEnvironment);
 
-  void addProblem(TreeNode node, Message message) {
-    loader.addProblem(message, getFileOffset(node), noLength, getFileUri(node));
+  String addProblem(TreeNode node, Message message) {
+    int offset = getFileOffset(node);
+    Uri uri = getFileUri(node);
+    loader.addProblem(message, offset, noLength, uri);
+    return loader.target.context.format(
+        message.withLocation(uri, offset, noLength), message.code.severity);
   }
 
   @override
-  void freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type) {
-    addProblem(node, templateConstEvalFreeTypeParameter.withArguments(type));
+  String freeTypeParameter(
+      List<TreeNode> context, TreeNode node, DartType type) {
+    return addProblem(
+        node, templateConstEvalFreeTypeParameter.withArguments(type));
   }
 
   @override
-  void duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
-    addProblem(node, templateConstEvalDuplicateKey.withArguments(key));
+  String duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
+    return addProblem(node, templateConstEvalDuplicateKey.withArguments(key));
   }
 
   @override
-  void invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
-      DartType expectedType) {
-    addProblem(
+  String invalidDartType(List<TreeNode> context, TreeNode node,
+      Constant receiver, DartType expectedType) {
+    return addProblem(
         node,
         templateConstEvalInvalidType.withArguments(
             receiver, expectedType, receiver.getType(typeEnvironment)));
   }
 
   @override
-  void invalidBinaryOperandType(
+  String invalidBinaryOperandType(
       List<TreeNode> context,
       TreeNode node,
       Constant receiver,
       String op,
       DartType expectedType,
       DartType actualType) {
-    addProblem(
+    return addProblem(
         node,
         templateConstEvalInvalidBinaryOperandType.withArguments(
             op, receiver, expectedType, actualType));
   }
 
   @override
-  void invalidMethodInvocation(
+  String invalidMethodInvocation(
       List<TreeNode> context, TreeNode node, Constant receiver, String op) {
-    addProblem(node,
+    return addProblem(node,
         templateConstEvalInvalidMethodInvocation.withArguments(op, receiver));
   }
 
   @override
-  void invalidStaticInvocation(
+  String invalidStaticInvocation(
       List<TreeNode> context, TreeNode node, Member target) {
-    addProblem(
+    return addProblem(
         node,
         templateConstEvalInvalidStaticInvocation
             .withArguments(target.name.toString()));
   }
 
   @override
-  void invalidStringInterpolationOperand(
+  String invalidStringInterpolationOperand(
       List<TreeNode> context, TreeNode node, Constant constant) {
-    addProblem(
+    return addProblem(
         node,
         templateConstEvalInvalidStringInterpolationOperand
             .withArguments(constant));
   }
 
   @override
-  void invalidSymbolName(
+  String invalidSymbolName(
       List<TreeNode> context, TreeNode node, Constant constant) {
-    addProblem(
+    return addProblem(
         node, templateConstEvalInvalidSymbolName.withArguments(constant));
   }
 
   @override
-  void zeroDivisor(
+  String zeroDivisor(
       List<TreeNode> context, TreeNode node, IntConstant receiver, String op) {
-    addProblem(node,
+    return addProblem(node,
         templateConstEvalZeroDivisor.withArguments(op, '${receiver.value}'));
   }
 
   @override
-  void negativeShift(List<TreeNode> context, TreeNode node,
+  String negativeShift(List<TreeNode> context, TreeNode node,
       IntConstant receiver, String op, IntConstant argument) {
-    addProblem(
+    return addProblem(
         node,
         templateConstEvalNegativeShift.withArguments(
             op, '${receiver.value}', '${argument.value}'));
   }
 
   @override
-  void nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
-    addProblem(node, templateConstEvalNonConstantLiteral.withArguments(klass));
+  String nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
+    return addProblem(
+        node, templateConstEvalNonConstantLiteral.withArguments(klass));
   }
 
   @override
-  void failedAssertion(List<TreeNode> context, TreeNode node, String string) {
-    if (string == null) {
-      addProblem(node, messageConstEvalFailedAssertion);
-    } else {
-      addProblem(node,
-          templateConstEvalFailedAssertionWithMessage.withArguments(string));
-    }
+  String failedAssertion(List<TreeNode> context, TreeNode node, String string) {
+    return addProblem(
+        node,
+        (string == null)
+            ? messageConstEvalFailedAssertion
+            : templateConstEvalFailedAssertionWithMessage
+                .withArguments(string));
   }
 
   @override
-  void nonConstantVariableGet(
+  String nonConstantVariableGet(
       List<TreeNode> context, TreeNode node, String variableName) {
-    addProblem(node,
+    return addProblem(node,
         templateConstEvalNonConstantVariableGet.withArguments(variableName));
   }
 
   @override
-  void deferredLibrary(
+  String deferredLibrary(
       List<TreeNode> context, TreeNode node, String importName) {
-    addProblem(
+    return addProblem(
         node, templateConstEvalDeferredLibrary.withArguments(importName));
   }
 }
@@ -187,7 +194,7 @@
       List<TreeNode> context,
       StaticInvocation node,
       ErrorReporter errorReporter,
-      void abortEvaluation()) {
+      void abortEvaluation(String message)) {
     // VM-specific names of the fromEnvironment factory constructors.
     if (nativeName == 'Bool_fromEnvironment' ||
         nativeName == 'Integer_fromEnvironment' ||
diff --git a/pkg/kernel/lib/transformations/constants.dart b/pkg/kernel/lib/transformations/constants.dart
index 73f62ca..a76259f 100644
--- a/pkg/kernel/lib/transformations/constants.dart
+++ b/pkg/kernel/lib/transformations/constants.dart
@@ -398,12 +398,11 @@
         nodeCache = <Node, Constant>{};
 
   /// Evaluates [node] and possibly cache the evaluation result.
-  /// Returns `null` if expression can't be evaluated.
   Constant evaluate(Expression node) {
     try {
       return _evaluateSubexpression(node);
-    } on _AbortCurrentEvaluation catch (_) {
-      return null;
+    } on _AbortCurrentEvaluation catch (e) {
+      return new UnevaluatedConstant(new InvalidExpression(e.message));
     }
   }
 
@@ -416,7 +415,7 @@
       // environment.
       if (nodeCache.containsKey(node)) {
         final Constant constant = nodeCache[node];
-        if (constant == null) throw const _AbortCurrentEvaluation();
+        if (constant == null) throw new _AbortCurrentEvaluation('circularity');
         return constant;
       }
 
@@ -493,8 +492,8 @@
 
   visitListLiteral(ListLiteral node) {
     if (!node.isConst) {
-      errorReporter.nonConstLiteral(contextChain, node, 'List');
-      throw const _AbortCurrentEvaluation();
+      throw new _AbortCurrentEvaluation(
+          errorReporter.nonConstLiteral(contextChain, node, 'List'));
     }
     final List<Constant> entries = new List<Constant>(node.expressions.length);
     for (int i = 0; i < node.expressions.length; ++i) {
@@ -507,8 +506,8 @@
 
   visitMapLiteral(MapLiteral node) {
     if (!node.isConst) {
-      errorReporter.nonConstLiteral(contextChain, node, 'Map');
-      throw const _AbortCurrentEvaluation();
+      throw new _AbortCurrentEvaluation(
+          errorReporter.nonConstLiteral(contextChain, node, 'Map'));
     }
     final Set<Constant> usedKeys = new Set<Constant>();
     final List<ConstantMapEntry> entries =
@@ -520,8 +519,8 @@
         // TODO(kustermann): We should change the context handling from just
         // capturing the `TreeNode`s to a `(TreeNode, String message)` tuple and
         // report where the first key with the same value was.
-        errorReporter.duplicateKey(contextChain, node.entries[i], key);
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(
+            errorReporter.duplicateKey(contextChain, node.entries[i], key));
       }
       entries[i] = new ConstantMapEntry(key, value);
     }
@@ -533,8 +532,8 @@
   }
 
   visitFunctionExpression(FunctionExpression node) {
-    errorReporter.nonConstLiteral(contextChain, node, 'Function');
-    throw const _AbortCurrentEvaluation();
+    throw new _AbortCurrentEvaluation(
+        errorReporter.nonConstLiteral(contextChain, node, 'Function'));
   }
 
   visitConstructorInvocation(ConstructorInvocation node) {
@@ -584,9 +583,8 @@
               isValidSymbolName(nameValue.value)) {
             return canonicalize(new SymbolConstant(nameValue.value, null));
           }
-          errorReporter.invalidSymbolName(
-              contextChain, node.arguments.positional.first, nameValue);
-          throw const _AbortCurrentEvaluation();
+          throw new _AbortCurrentEvaluation(errorReporter.invalidSymbolName(
+              contextChain, node.arguments.positional.first, nameValue));
         }
 
         return canonicalize(result);
@@ -786,28 +784,27 @@
                 if (!condition.value) {
                   final Constant message = init.statement.message?.accept(this);
                   if (message == null) {
-                    errorReporter.failedAssertion(
-                        contextChain, init.statement.condition, null);
-                    throw const _AbortCurrentEvaluation();
+                    throw new _AbortCurrentEvaluation(
+                        errorReporter.failedAssertion(
+                            contextChain, init.statement.condition, null));
                   } else if (message is StringConstant) {
-                    errorReporter.failedAssertion(
-                        contextChain, init.statement.condition, message.value);
-                    throw const _AbortCurrentEvaluation();
+                    throw new _AbortCurrentEvaluation(
+                        errorReporter.failedAssertion(contextChain,
+                            init.statement.condition, message.value));
                   }
-                  errorReporter.invalidDartType(
-                      contextChain,
-                      init.statement.message,
-                      message,
-                      typeEnvironment.stringType);
-                  throw const _AbortCurrentEvaluation();
+                  throw new _AbortCurrentEvaluation(
+                      errorReporter.invalidDartType(
+                          contextChain,
+                          init.statement.message,
+                          message,
+                          typeEnvironment.stringType));
                 }
               } else {
-                errorReporter.invalidDartType(
+                throw new _AbortCurrentEvaluation(errorReporter.invalidDartType(
                     contextChain,
                     init.statement.condition,
                     condition,
-                    typeEnvironment.boolType);
-                throw const _AbortCurrentEvaluation();
+                    typeEnvironment.boolType));
               }
             }
           } else {
@@ -855,14 +852,14 @@
               return canonicalize(
                   new StringConstant(receiver.value + other.value));
             }
-            errorReporter.invalidBinaryOperandType(
-                contextChain,
-                node,
-                receiver,
-                '+',
-                typeEnvironment.stringType,
-                other.getType(typeEnvironment));
-            throw const _AbortCurrentEvaluation();
+            throw new _AbortCurrentEvaluation(
+                errorReporter.invalidBinaryOperandType(
+                    contextChain,
+                    node,
+                    receiver,
+                    '+',
+                    typeEnvironment.stringType,
+                    other.getType(typeEnvironment)));
         }
       }
     } else if (receiver is BoolConstant) {
@@ -885,14 +882,14 @@
                   : falseConstant;
           }
         }
-        errorReporter.invalidBinaryOperandType(
-            contextChain,
-            node,
-            receiver,
-            '${node.name.name}',
-            typeEnvironment.boolType,
-            right.getType(typeEnvironment));
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(
+            errorReporter.invalidBinaryOperandType(
+                contextChain,
+                node,
+                receiver,
+                '${node.name.name}',
+                typeEnvironment.boolType,
+                right.getType(typeEnvironment)));
       }
     } else if (receiver is IntConstant) {
       if (arguments.length == 0) {
@@ -907,9 +904,12 @@
         final op = node.name.name;
         if (other is IntConstant) {
           if ((op == '<<' || op == '>>') && other.value < 0) {
-            errorReporter.negativeShift(contextChain,
-                node.arguments.positional.first, receiver, op, other);
-            throw const _AbortCurrentEvaluation();
+            throw new _AbortCurrentEvaluation(errorReporter.negativeShift(
+                contextChain,
+                node.arguments.positional.first,
+                receiver,
+                op,
+                other));
           }
           switch (op) {
             case '|':
@@ -932,9 +932,8 @@
 
         if (other is IntConstant) {
           if (other.value == 0 && (op == '%' || op == '~/')) {
-            errorReporter.zeroDivisor(
-                contextChain, node.arguments.positional.first, receiver, op);
-            throw const _AbortCurrentEvaluation();
+            throw new _AbortCurrentEvaluation(errorReporter.zeroDivisor(
+                contextChain, node.arguments.positional.first, receiver, op));
           }
 
           return evaluateBinaryNumericOperation(
@@ -943,15 +942,14 @@
           return evaluateBinaryNumericOperation(
               node.name.name, receiver.value, other.value, node);
         }
-
-        errorReporter.invalidBinaryOperandType(
-            contextChain,
-            node,
-            receiver,
-            '${node.name.name}',
-            typeEnvironment.numType,
-            other.getType(typeEnvironment));
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(
+            errorReporter.invalidBinaryOperandType(
+                contextChain,
+                node,
+                receiver,
+                '${node.name.name}',
+                typeEnvironment.numType,
+                other.getType(typeEnvironment)));
       }
     } else if (receiver is DoubleConstant) {
       if (arguments.length == 0) {
@@ -969,19 +967,18 @@
           return evaluateBinaryNumericOperation(
               node.name.name, receiver.value, value, node);
         }
-        errorReporter.invalidBinaryOperandType(
-            contextChain,
-            node,
-            receiver,
-            '${node.name.name}',
-            typeEnvironment.numType,
-            other.getType(typeEnvironment));
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(
+            errorReporter.invalidBinaryOperandType(
+                contextChain,
+                node,
+                receiver,
+                '${node.name.name}',
+                typeEnvironment.numType,
+                other.getType(typeEnvironment)));
       }
     }
-    errorReporter.invalidMethodInvocation(
-        contextChain, node, receiver, node.name.name);
-    throw const _AbortCurrentEvaluation();
+    throw new _AbortCurrentEvaluation(errorReporter.invalidMethodInvocation(
+        contextChain, node, receiver, node.name.name));
   }
 
   visitLogicalExpression(LogicalExpression node) {
@@ -995,18 +992,18 @@
           if (right is BoolConstant) {
             return right;
           }
-          errorReporter.invalidBinaryOperandType(
-              contextChain,
-              node,
-              left,
-              '${node.operator}',
-              typeEnvironment.boolType,
-              right.getType(typeEnvironment));
-          throw const _AbortCurrentEvaluation();
+
+          throw new _AbortCurrentEvaluation(
+              errorReporter.invalidBinaryOperandType(
+                  contextChain,
+                  node,
+                  left,
+                  '${node.operator}',
+                  typeEnvironment.boolType,
+                  right.getType(typeEnvironment)));
         }
-        errorReporter.invalidMethodInvocation(
-            contextChain, node, left, '${node.operator}');
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(errorReporter.invalidMethodInvocation(
+            contextChain, node, left, '${node.operator}'));
       case '&&':
         if (left is BoolConstant) {
           if (!left.value) return falseConstant;
@@ -1015,26 +1012,24 @@
           if (right is BoolConstant) {
             return right;
           }
-          errorReporter.invalidBinaryOperandType(
-              contextChain,
-              node,
-              left,
-              '${node.operator}',
-              typeEnvironment.boolType,
-              right.getType(typeEnvironment));
-          throw const _AbortCurrentEvaluation();
+          throw new _AbortCurrentEvaluation(
+              errorReporter.invalidBinaryOperandType(
+                  contextChain,
+                  node,
+                  left,
+                  '${node.operator}',
+                  typeEnvironment.boolType,
+                  right.getType(typeEnvironment)));
         }
-        errorReporter.invalidMethodInvocation(
-            contextChain, node, left, '${node.operator}');
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(errorReporter.invalidMethodInvocation(
+            contextChain, node, left, '${node.operator}'));
       case '??':
         return (left is! NullConstant)
             ? left
             : _evaluateSubexpression(node.right);
       default:
-        errorReporter.invalidMethodInvocation(
-            contextChain, node, left, '${node.operator}');
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(errorReporter.invalidMethodInvocation(
+            contextChain, node, left, '${node.operator}'));
     }
   }
 
@@ -1045,9 +1040,8 @@
     } else if (constant == falseConstant) {
       return _evaluateSubexpression(node.otherwise);
     } else {
-      errorReporter.invalidDartType(
-          contextChain, node, constant, typeEnvironment.boolType);
-      throw const _AbortCurrentEvaluation();
+      throw new _AbortCurrentEvaluation(errorReporter.invalidDartType(
+          contextChain, node, constant, typeEnvironment.boolType));
     }
   }
 
@@ -1092,8 +1086,8 @@
     if (variable.parent is Let || _isFormalParameter(variable)) {
       final Constant constant = env.lookupVariable(node.variable);
       if (constant == null) {
-        errorReporter.nonConstantVariableGet(contextChain, node, variable.name);
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(errorReporter.nonConstantVariableGet(
+            contextChain, node, variable.name));
       }
       return constant;
     }
@@ -1113,14 +1107,14 @@
             return _evaluateSubexpression(target.initializer);
           });
         }
-        errorReporter.invalidStaticInvocation(contextChain, node, target);
-        throw new _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(
+            errorReporter.invalidStaticInvocation(contextChain, node, target));
       } else if (target is Procedure) {
         if (target.kind == ProcedureKind.Method) {
           return canonicalize(new TearOffConstant(target));
         }
-        errorReporter.invalidStaticInvocation(contextChain, node, target);
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(
+            errorReporter.invalidStaticInvocation(contextChain, node, target));
       } else {
         throw new Exception(
             'No support for ${target.runtimeType} in a static-get.');
@@ -1143,9 +1137,8 @@
       } else if (constant is StringConstant) {
         return constant.value;
       } else {
-        errorReporter.invalidStringInterpolationOperand(
-            contextChain, node, constant);
-        throw const _AbortCurrentEvaluation();
+        throw new _AbortCurrentEvaluation(errorReporter
+            .invalidStringInterpolationOperand(contextChain, node, constant));
       }
     }).join('');
     return canonicalize(new StringConstant(value));
@@ -1164,7 +1157,7 @@
             contextChain,
             node,
             errorReporter,
-            () => throw const _AbortCurrentEvaluation());
+            (String message) => throw new _AbortCurrentEvaluation(message));
         assert(constant != null);
         return canonicalize(constant);
       }
@@ -1180,8 +1173,8 @@
         return identical(left, right) ? trueConstant : falseConstant;
       }
     }
-    errorReporter.invalidStaticInvocation(contextChain, node, target);
-    throw const _AbortCurrentEvaluation();
+    throw new _AbortCurrentEvaluation(
+        errorReporter.invalidStaticInvocation(contextChain, node, target));
   }
 
   visitAsExpression(AsExpression node) {
@@ -1195,9 +1188,8 @@
     if (constant is BoolConstant) {
       return constant == trueConstant ? falseConstant : trueConstant;
     }
-    errorReporter.invalidDartType(
-        contextChain, node, constant, typeEnvironment.boolType);
-    throw const _AbortCurrentEvaluation();
+    throw new _AbortCurrentEvaluation(errorReporter.invalidDartType(
+        contextChain, node, constant, typeEnvironment.boolType));
   }
 
   visitSymbolLiteral(SymbolLiteral node) {
@@ -1225,8 +1217,8 @@
 
   @override
   visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
-    errorReporter.deferredLibrary(contextChain, node, node.import.name);
-    throw const _AbortCurrentEvaluation();
+    throw new _AbortCurrentEvaluation(
+        errorReporter.deferredLibrary(contextChain, node, node.import.name));
   }
 
   // Helper methods:
@@ -1260,8 +1252,8 @@
     }
 
     if (!typeEnvironment.isSubtypeOf(constantType, type)) {
-      errorReporter.invalidDartType(contextChain, node, constant, type);
-      throw const _AbortCurrentEvaluation();
+      throw new _AbortCurrentEvaluation(
+          errorReporter.invalidDartType(contextChain, node, constant, type));
     }
   }
 
@@ -1284,8 +1276,8 @@
     final result = env.subsituteType(type);
 
     if (!isInstantiated(result)) {
-      errorReporter.freeTypeParameter(contextChain, node, type);
-      throw const _AbortCurrentEvaluation();
+      throw new _AbortCurrentEvaluation(
+          errorReporter.freeTypeParameter(contextChain, node, type));
     }
 
     return result;
@@ -1469,14 +1461,15 @@
       List<TreeNode> context,
       StaticInvocation node,
       ErrorReporter errorReporter,
-      void abortEvaluation());
+      void abortEvaluation(String message));
   Constant lowerListConstant(ListConstant constant);
   Constant lowerMapConstant(MapConstant constant);
 }
 
 // Used as control-flow to abort the current evaluation.
 class _AbortCurrentEvaluation {
-  const _AbortCurrentEvaluation();
+  final String message;
+  _AbortCurrentEvaluation(this.message);
 }
 
 abstract class ErrorReporter {
@@ -1496,66 +1489,70 @@
     return node == null ? TreeNode.noOffset : node.fileOffset;
   }
 
-  void freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type);
-  void invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
-      DartType expectedType);
-  void invalidBinaryOperandType(List<TreeNode> context, TreeNode node,
+  String freeTypeParameter(
+      List<TreeNode> context, TreeNode node, DartType type);
+  String invalidDartType(List<TreeNode> context, TreeNode node,
+      Constant receiver, DartType expectedType);
+  String invalidBinaryOperandType(List<TreeNode> context, TreeNode node,
       Constant receiver, String op, DartType expectedType, DartType actualType);
-  void invalidMethodInvocation(
+  String invalidMethodInvocation(
       List<TreeNode> context, TreeNode node, Constant receiver, String op);
-  void invalidStaticInvocation(
+  String invalidStaticInvocation(
       List<TreeNode> context, TreeNode node, Member target);
-  void invalidStringInterpolationOperand(
+  String invalidStringInterpolationOperand(
       List<TreeNode> context, TreeNode node, Constant constant);
-  void invalidSymbolName(
+  String invalidSymbolName(
       List<TreeNode> context, TreeNode node, Constant constant);
-  void zeroDivisor(
+  String zeroDivisor(
       List<TreeNode> context, TreeNode node, IntConstant receiver, String op);
-  void negativeShift(List<TreeNode> context, TreeNode node,
+  String negativeShift(List<TreeNode> context, TreeNode node,
       IntConstant receiver, String op, IntConstant argument);
-  void nonConstLiteral(List<TreeNode> context, TreeNode node, String klass);
-  void duplicateKey(List<TreeNode> context, TreeNode node, Constant key);
-  void failedAssertion(List<TreeNode> context, TreeNode node, String message);
-  void nonConstantVariableGet(
+  String nonConstLiteral(List<TreeNode> context, TreeNode node, String klass);
+  String duplicateKey(List<TreeNode> context, TreeNode node, Constant key);
+  String failedAssertion(List<TreeNode> context, TreeNode node, String message);
+  String nonConstantVariableGet(
       List<TreeNode> context, TreeNode node, String variableName);
-  void deferredLibrary(
+  String deferredLibrary(
       List<TreeNode> context, TreeNode node, String importName);
 }
 
 class SimpleErrorReporter extends ErrorReporter {
   const SimpleErrorReporter();
 
-  void report(List<TreeNode> context, String message, TreeNode node) {
+  String report(List<TreeNode> context, String what, TreeNode node) {
     io.exitCode = 42;
     final Uri uri = getFileUri(node);
     final int fileOffset = getFileOffset(node);
-
-    io.stderr.writeln('$uri:$fileOffset Constant evaluation error: $message');
+    final String message = '$uri:$fileOffset Constant evaluation error: $what';
+    io.stderr.writeln(message);
+    return message;
   }
 
   @override
-  void freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type) {
-    report(context, 'Expected type to be instantiated but was ${type}', node);
+  String freeTypeParameter(
+      List<TreeNode> context, TreeNode node, DartType type) {
+    return report(
+        context, 'Expected type to be instantiated but was ${type}', node);
   }
 
   @override
-  void invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
-      DartType expectedType) {
-    report(
+  String invalidDartType(List<TreeNode> context, TreeNode node,
+      Constant receiver, DartType expectedType) {
+    return report(
         context,
         'Expected expression to evaluate to "$expectedType" but got "$receiver.',
         node);
   }
 
   @override
-  void invalidBinaryOperandType(
+  String invalidBinaryOperandType(
       List<TreeNode> context,
       TreeNode node,
       Constant receiver,
       String op,
       DartType expectedType,
       DartType actualType) {
-    report(
+    return report(
         context,
         'Calling "$op" on "$receiver" needs operand of type '
         '"$expectedType" (but got "$actualType")',
@@ -1563,23 +1560,23 @@
   }
 
   @override
-  void invalidMethodInvocation(
+  String invalidMethodInvocation(
       List<TreeNode> context, TreeNode node, Constant receiver, String op) {
-    report(context, 'Cannot call "$op" on "$receiver" in constant expression',
-        node);
+    return report(context,
+        'Cannot call "$op" on "$receiver" in constant expression', node);
   }
 
   @override
-  void invalidStaticInvocation(
+  String invalidStaticInvocation(
       List<TreeNode> context, TreeNode node, Member target) {
-    report(
+    return report(
         context, 'Cannot invoke "$target" inside a constant expression', node);
   }
 
   @override
-  void invalidStringInterpolationOperand(
+  String invalidStringInterpolationOperand(
       List<TreeNode> context, TreeNode node, Constant constant) {
-    report(
+    return report(
         context,
         'Only null/bool/int/double/String values are allowed as string '
         'interpolation expressions during constant evaluation (was: "$constant").',
@@ -1587,9 +1584,9 @@
   }
 
   @override
-  void invalidSymbolName(
+  String invalidSymbolName(
       List<TreeNode> context, TreeNode node, Constant constant) {
-    report(
+    return report(
         context,
         'The symbol name must be a valid public Dart member name, public '
         'constructor name, or library name, optionally qualified.',
@@ -1597,9 +1594,9 @@
   }
 
   @override
-  void zeroDivisor(
+  String zeroDivisor(
       List<TreeNode> context, TreeNode node, IntConstant receiver, String op) {
-    report(
+    return report(
         context,
         "Binary operator '$op' on '${receiver.value}' requires non-zero "
         "divisor, but divisor was '0'.",
@@ -1607,9 +1604,9 @@
   }
 
   @override
-  void negativeShift(List<TreeNode> context, TreeNode node,
+  String negativeShift(List<TreeNode> context, TreeNode node,
       IntConstant receiver, String op, IntConstant argument) {
-    report(
+    return report(
         context,
         "Binary operator '$op' on '${receiver.value}' requires non-negative "
         "operand, but was '${argument.value}'.",
@@ -1617,33 +1614,34 @@
   }
 
   @override
-  void nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
-    report(
+  String nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
+    return report(
         context,
         'Cannot have a non-constant $klass literal within a const context.',
         node);
   }
 
   @override
-  void duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
-    report(
+  String duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
+    return report(
         context,
         'Duplicate keys are not allowed in constant maps (found duplicate key "$key")',
         node);
   }
 
   @override
-  void failedAssertion(List<TreeNode> context, TreeNode node, String message) {
-    report(
+  String failedAssertion(
+      List<TreeNode> context, TreeNode node, String message) {
+    return report(
         context,
         'The assertion condition evaluated to "false" with message "$message"',
         node);
   }
 
   @override
-  void nonConstantVariableGet(
+  String nonConstantVariableGet(
       List<TreeNode> context, TreeNode node, String variableName) {
-    report(
+    return report(
         context,
         'The variable "$variableName" cannot be used inside a constant '
         'expression.',
@@ -1651,9 +1649,9 @@
   }
 
   @override
-  void deferredLibrary(
+  String deferredLibrary(
       List<TreeNode> context, TreeNode node, String importName) {
-    report(
+    return report(
         context,
         'Deferred "$importName" cannot be used inside a constant '
         'expression',
diff --git a/pkg/kernel/lib/vm/constants_native_effects.dart b/pkg/kernel/lib/vm/constants_native_effects.dart
index e3611d2..6507282 100644
--- a/pkg/kernel/lib/vm/constants_native_effects.dart
+++ b/pkg/kernel/lib/vm/constants_native_effects.dart
@@ -51,7 +51,7 @@
       List<TreeNode> context,
       StaticInvocation node,
       ErrorReporter errorReporter,
-      void abortEvaluation()) {
+      void abortEvaluation(String message)) {
     if ([
       'Bool_fromEnvironment',
       'Integer_fromEnvironment',
@@ -118,9 +118,11 @@
                 makeConstant: (v) => new StringConstant(v));
         }
       } else {
-        errorReporter.invalidDartType(context, node.arguments.positional.first,
-            argument, new InterfaceType(stringClass));
-        abortEvaluation();
+        abortEvaluation(errorReporter.invalidDartType(
+            context,
+            node.arguments.positional.first,
+            argument,
+            new InterfaceType(stringClass)));
       }
     }
 
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 1de2a75..3ebc857 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -399,9 +399,10 @@
       return expr.constant;
     }
     final constant = constantEvaluator.evaluate(expr);
-    if (constant == null) {
+    if (constant is UnevaluatedConstant &&
+        constant.expression is InvalidExpression) {
       // Compile-time error is already reported. Proceed with compilation
-      // in order to report as many errors as possible.
+      // in order to report errors in other constant expressions.
       hasErrors = true;
       return new NullConstant();
     }
diff --git a/pkg/vm/lib/constants_error_reporter.dart b/pkg/vm/lib/constants_error_reporter.dart
index def7f4c..0842add 100644
--- a/pkg/vm/lib/constants_error_reporter.dart
+++ b/pkg/vm/lib/constants_error_reporter.dart
@@ -26,28 +26,29 @@
   ForwardConstantEvaluationErrors(this.typeEnvironment);
 
   @override
-  void freeTypeParameter(List<TreeNode> context, TreeNode node, DartType type) {
+  String freeTypeParameter(
+      List<TreeNode> context, TreeNode node, DartType type) {
     final message =
         codes.templateConstEvalFreeTypeParameter.withArguments(type);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
+  String duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
     final message = codes.templateConstEvalDuplicateKey.withArguments(key);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
-      DartType expectedType) {
+  String invalidDartType(List<TreeNode> context, TreeNode node,
+      Constant receiver, DartType expectedType) {
     final message = codes.templateConstEvalInvalidType.withArguments(
         receiver, expectedType, receiver.getType(typeEnvironment));
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void invalidBinaryOperandType(
+  String invalidBinaryOperandType(
       List<TreeNode> context,
       TreeNode node,
       Constant receiver,
@@ -56,90 +57,91 @@
       DartType actualType) {
     final message = codes.templateConstEvalInvalidBinaryOperandType
         .withArguments(op, receiver, expectedType, actualType);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void invalidMethodInvocation(
+  String invalidMethodInvocation(
       List<TreeNode> context, TreeNode node, Constant receiver, String op) {
     final message = codes.templateConstEvalInvalidMethodInvocation
         .withArguments(op, receiver);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void invalidStaticInvocation(
+  String invalidStaticInvocation(
       List<TreeNode> context, TreeNode node, Member target) {
     final message = codes.templateConstEvalInvalidStaticInvocation
         .withArguments(target.name.toString());
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void invalidStringInterpolationOperand(
+  String invalidStringInterpolationOperand(
       List<TreeNode> context, TreeNode node, Constant constant) {
     final message = codes.templateConstEvalInvalidStringInterpolationOperand
         .withArguments(constant);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void invalidSymbolName(
+  String invalidSymbolName(
       List<TreeNode> context, TreeNode node, Constant constant) {
     final message =
         codes.templateConstEvalInvalidSymbolName.withArguments(constant);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void zeroDivisor(
+  String zeroDivisor(
       List<TreeNode> context, TreeNode node, IntConstant receiver, String op) {
     final message = codes.templateConstEvalZeroDivisor
         .withArguments(op, '${receiver.value}');
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void negativeShift(List<TreeNode> context, TreeNode node,
+  String negativeShift(List<TreeNode> context, TreeNode node,
       IntConstant receiver, String op, IntConstant argument) {
     final message = codes.templateConstEvalNegativeShift
         .withArguments(op, '${receiver.value}', '${argument.value}');
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
+  String nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
     final message =
         codes.templateConstEvalNonConstantLiteral.withArguments(klass);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void failedAssertion(List<TreeNode> context, TreeNode node, String string) {
+  String failedAssertion(List<TreeNode> context, TreeNode node, String string) {
     final message = string == null
         ? codes.messageConstEvalFailedAssertion
         : codes.templateConstEvalFailedAssertionWithMessage
             .withArguments(string);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void nonConstantVariableGet(
+  String nonConstantVariableGet(
       List<TreeNode> context, TreeNode node, String variableName) {
     final message = codes.templateConstEvalNonConstantVariableGet
         .withArguments(variableName);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
   @override
-  void deferredLibrary(
+  String deferredLibrary(
       List<TreeNode> context, TreeNode node, String importName) {
     final message =
         codes.templateConstEvalDeferredLibrary.withArguments(importName);
-    reportIt(context, message, node);
+    return reportIt(context, message, node);
   }
 
-  void reportIt(List<TreeNode> context, codes.Message message, TreeNode node) {
+  String reportIt(
+      List<TreeNode> context, codes.Message message, TreeNode node) {
     final Uri uri = getFileUri(node);
     final int fileOffset = getFileOffset(node);
 
@@ -156,5 +158,6 @@
 
     compilerContext.options
         .report(locatedMessage, Severity.error, context: contextMessages);
+    return locatedMessage.message;
   }
 }
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index f98b2af..8ac315e 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -60,17 +60,13 @@
 LanguageFeatures/Constant_update2018/NewOperators_A01_t01: Crash
 LanguageFeatures/Constant_update2018/NewOperators_A01_t02: Crash
 LanguageFeatures/Constant_update2018/NewOperators_A02_t01: CompileTimeError
-LanguageFeatures/Constant_update2018/NewOperators_A02_t02: Crash
-LanguageFeatures/Constant_update2018/NewOperators_A02_t03: Crash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t02: CompileTimeError
 LanguageFeatures/Constant_update2018/NewOperators_A02_t04: CompileTimeError
-LanguageFeatures/Constant_update2018/NewOperators_A02_t05: Crash
-LanguageFeatures/Constant_update2018/NewOperators_A02_t06: Crash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t05: CompileTimeError
 LanguageFeatures/Constant_update2018/NewOperators_A02_t07: CompileTimeError
-LanguageFeatures/Constant_update2018/NewOperators_A02_t08: Crash
-LanguageFeatures/Constant_update2018/NewOperators_A02_t09: Crash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t08: CompileTimeError
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t02: Crash
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t05: Crash
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t02: Crash
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t05: Crash
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t03: Crash
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t04: Crash
@@ -847,17 +843,13 @@
 LanguageFeatures/Constant_update2018/NewOperators_A01_t01: DartkCrash
 LanguageFeatures/Constant_update2018/NewOperators_A01_t02: DartkCrash
 LanguageFeatures/Constant_update2018/NewOperators_A02_t01: Fail
-LanguageFeatures/Constant_update2018/NewOperators_A02_t02: DartkCrash
-LanguageFeatures/Constant_update2018/NewOperators_A02_t03: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t02: CompileTimeError
 LanguageFeatures/Constant_update2018/NewOperators_A02_t04: Fail
-LanguageFeatures/Constant_update2018/NewOperators_A02_t05: DartkCrash
-LanguageFeatures/Constant_update2018/NewOperators_A02_t06: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t05: CompileTimeError
 LanguageFeatures/Constant_update2018/NewOperators_A02_t07: Fail
-LanguageFeatures/Constant_update2018/NewOperators_A02_t08: DartkCrash
-LanguageFeatures/Constant_update2018/NewOperators_A02_t09: DartkCrash
+LanguageFeatures/Constant_update2018/NewOperators_A02_t08: CompileTimeError
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t02: DartkCrash
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t05: DartkCrash
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t02: DartkCrash
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t05: DartkCrash
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t05: DartkCrash
 LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t06: DartkCrash