[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