[vm/kernel] Enable kernel2kernel "constants" transformation in AOT mode (after running TFA)

This CL also uses the newer `onProblem` error reporting mechanism, which supports contexts.

The errors by the constant evaluator are formatted e.g. like this:

    .../language_2/compile_time_constant_o_test_01.dart:14:8: Error: Duplicate keys are not allowed in constant maps (found duplicate key "StringConstant(foo)").
      "foo": 499
       ^
    .../language_2/compile_time_constant_o_test_01.dart:32:24: Context: While analyzing:
      Expect.identical(m1, m3);

Change-Id: I463416e14686e218b0f08903bd6aa0bca7392260
Reviewed-on: https://dart-review.googlesource.com/53021
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Martin Kustermann 2018-05-09 09:00:02 +00:00 committed by commit-bot@chromium.org
parent 2f781e46b0
commit 039e8a1755
12 changed files with 766 additions and 195 deletions

View file

@ -4,7 +4,7 @@
library fasta.codes;
import 'package:kernel/ast.dart' show DartType;
import 'package:kernel/ast.dart' show Constant, DartType;
import 'package:kernel/text/ast_to_text.dart' show NameSystem, Printer;

View file

@ -725,6 +725,257 @@ const MessageCode messageConstConstructorWithBody = const MessageCode(
message: r"""A const constructor can't have a body.""",
tip: r"""Try removing either the 'const' keyword or the body.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeConstEvalContext = messageConstEvalContext;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageConstEvalContext =
const MessageCode("ConstEvalContext", message: r"""While analyzing:""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
Constant
constant)> templateConstEvalDuplicateKey = const Template<
Message Function(Constant constant)>(
messageTemplate:
r"""The key '#constant' conflicts with another existing key in the map.""",
withArguments: _withArgumentsConstEvalDuplicateKey);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(Constant constant)> codeConstEvalDuplicateKey =
const Code<Message Function(Constant constant)>(
"ConstEvalDuplicateKey", templateConstEvalDuplicateKey,
analyzerCode: "EQUAL_KEYS_IN_MAP");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsConstEvalDuplicateKey(Constant constant) {
return new Message(codeConstEvalDuplicateKey,
message:
"""The key '$constant' conflicts with another existing key in the map.""",
arguments: {'constant': constant});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeConstEvalFailedAssertion = messageConstEvalFailedAssertion;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageConstEvalFailedAssertion = const MessageCode(
"ConstEvalFailedAssertion",
analyzerCode: "CONST_EVAL_THROWS_EXCEPTION",
message: r"""This assertion failed.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String string)>
templateConstEvalFailedAssertionWithMessage =
const Template<Message Function(String string)>(
messageTemplate: r"""This assertion failed with message: #string""",
withArguments: _withArgumentsConstEvalFailedAssertionWithMessage);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String string)>
codeConstEvalFailedAssertionWithMessage =
const Code<Message Function(String string)>(
"ConstEvalFailedAssertionWithMessage",
templateConstEvalFailedAssertionWithMessage,
analyzerCode: "CONST_EVAL_THROWS_EXCEPTION");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsConstEvalFailedAssertionWithMessage(String string) {
return new Message(codeConstEvalFailedAssertionWithMessage,
message: """This assertion failed with message: $string""",
arguments: {'string': string});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String string,
Constant constant,
DartType _type,
DartType
_type2)> templateConstEvalInvalidBinaryOperandType = const Template<
Message Function(String string, Constant constant, DartType _type,
DartType _type2)>(
messageTemplate:
r"""Binary operator '#string' on '#constant' requires operand of type '#type', but was of type '#type2'.""",
withArguments: _withArgumentsConstEvalInvalidBinaryOperandType);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<
Message Function(
String string, Constant constant, DartType _type, DartType _type2)>
codeConstEvalInvalidBinaryOperandType = const Code<
Message Function(
String string, Constant constant, DartType _type, DartType _type2)>(
"ConstEvalInvalidBinaryOperandType",
templateConstEvalInvalidBinaryOperandType,
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsConstEvalInvalidBinaryOperandType(
String string, Constant constant, DartType _type, DartType _type2) {
NameSystem nameSystem = new NameSystem();
StringBuffer buffer = new StringBuffer();
new Printer(buffer, syntheticNames: nameSystem).writeNode(_type);
String type = '$buffer';
buffer = new StringBuffer();
new Printer(buffer, syntheticNames: nameSystem).writeNode(_type2);
String type2 = '$buffer';
return new Message(codeConstEvalInvalidBinaryOperandType,
message:
"""Binary operator '$string' on '$constant' requires operand of type '$type', but was of type '$type2'.""",
arguments: {
'string': string,
'constant': constant,
'type': _type,
'type2': _type2
});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String string,
Constant
constant)> templateConstEvalInvalidMethodInvocation = const Template<
Message Function(String string, Constant constant)>(
messageTemplate:
r"""The method '#string' can't be invoked on '#constant' within a const context.""",
withArguments: _withArgumentsConstEvalInvalidMethodInvocation);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String string, Constant constant)>
codeConstEvalInvalidMethodInvocation =
const Code<Message Function(String string, Constant constant)>(
"ConstEvalInvalidMethodInvocation",
templateConstEvalInvalidMethodInvocation,
analyzerCode: "UNDEFINED_OPERATOR");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsConstEvalInvalidMethodInvocation(
String string, Constant constant) {
return new Message(codeConstEvalInvalidMethodInvocation,
message:
"""The method '$string' can't be invoked on '$constant' within a const context.""",
arguments: {'string': string, 'constant': constant});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String
name)> templateConstEvalInvalidStaticInvocation = const Template<
Message Function(String name)>(
messageTemplate:
r"""The invocation of '#name' is not allowed within a const context.""",
withArguments: _withArgumentsConstEvalInvalidStaticInvocation);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String name)> codeConstEvalInvalidStaticInvocation =
const Code<Message Function(String name)>(
"ConstEvalInvalidStaticInvocation",
templateConstEvalInvalidStaticInvocation,
analyzerCode: "CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsConstEvalInvalidStaticInvocation(String name) {
return new Message(codeConstEvalInvalidStaticInvocation,
message:
"""The invocation of '$name' is not allowed within a const context.""",
arguments: {'name': name});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(Constant constant)>
templateConstEvalInvalidStringInterpolationOperand =
const Template<Message Function(Constant constant)>(
messageTemplate:
r"""The '#constant' can't be used as part of a string interpolation within a const context, only values of type 'null', 'bool', 'int', 'double', or 'String' can be used.""",
withArguments:
_withArgumentsConstEvalInvalidStringInterpolationOperand);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(Constant constant)>
codeConstEvalInvalidStringInterpolationOperand =
const Code<Message Function(Constant constant)>(
"ConstEvalInvalidStringInterpolationOperand",
templateConstEvalInvalidStringInterpolationOperand,
analyzerCode: "CONST_EVAL_TYPE_BOOL_NUM_STRING");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsConstEvalInvalidStringInterpolationOperand(
Constant constant) {
return new Message(codeConstEvalInvalidStringInterpolationOperand,
message:
"""The '$constant' can't be used as part of a string interpolation within a const context, only values of type 'null', 'bool', 'int', 'double', or 'String' can be used.""",
arguments: {'constant': constant});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
Constant constant,
DartType _type,
DartType
_type2)> templateConstEvalInvalidType = const Template<
Message Function(Constant constant, DartType _type, DartType _type2)>(
messageTemplate:
r"""Expected constant '#constant' to be of type '#type', but was of type '#type2'.""",
withArguments: _withArgumentsConstEvalInvalidType);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(Constant constant, DartType _type, DartType _type2)>
codeConstEvalInvalidType = const Code<
Message Function(Constant constant, DartType _type, DartType _type2)>(
"ConstEvalInvalidType",
templateConstEvalInvalidType,
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsConstEvalInvalidType(
Constant constant, DartType _type, DartType _type2) {
NameSystem nameSystem = new NameSystem();
StringBuffer buffer = new StringBuffer();
new Printer(buffer, syntheticNames: nameSystem).writeNode(_type);
String type = '$buffer';
buffer = new StringBuffer();
new Printer(buffer, syntheticNames: nameSystem).writeNode(_type2);
String type2 = '$buffer';
return new Message(codeConstEvalInvalidType,
message:
"""Expected constant '$constant' to be of type '$type', but was of type '$type2'.""",
arguments: {'constant': constant, 'type': _type, 'type2': _type2});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String
string)> templateConstEvalNonConstantLiteral = const Template<
Message Function(String string)>(
messageTemplate:
r"""Can't have a non-constant #string literal within a const context.""",
withArguments: _withArgumentsConstEvalNonConstantLiteral);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String string)> codeConstEvalNonConstantLiteral =
const Code<Message Function(String string)>(
"ConstEvalNonConstantLiteral", templateConstEvalNonConstantLiteral,
analyzerCode: "NON_CONSTANT_DEFAULT_VALUE");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsConstEvalNonConstantLiteral(String string) {
return new Message(codeConstEvalNonConstantLiteral,
message:
"""Can't have a non-constant $string literal within a const context.""",
arguments: {'string': string});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeConstFactory = messageConstFactory;

View file

@ -61,6 +61,26 @@ ConstAndFinal/script1: Fail
ConstAndVar/script1: Fail
ConstConstructorNonFinalField/analyzerCode: Fail
ConstConstructorNonFinalField/example: Fail
ConstEvalContext/analyzerCode: Fail # This is just used for displaying the context.
ConstEvalContext/example: Fail # This is just used for displaying the context.
ConstEvalDuplicateKey/dart2jsCode: Fail
ConstEvalDuplicateKey/example: Fail
ConstEvalFailedAssertion/dart2jsCode: Fail
ConstEvalFailedAssertion/example: Fail
ConstEvalFailedAssertionWithMessage/dart2jsCode: Fail
ConstEvalFailedAssertionWithMessage/example: Fail
ConstEvalInvalidBinaryOperandType/analyzerCode: Fail # CONST_EVAL_TYPE_NUM / CONST_EVAL_TYPE_BOOL
ConstEvalInvalidBinaryOperandType/example: Fail
ConstEvalInvalidMethodInvocation/dart2jsCode: Fail
ConstEvalInvalidMethodInvocation/example: Fail
ConstEvalInvalidStaticInvocation/dart2jsCode: Fail
ConstEvalInvalidStaticInvocation/example: Fail
ConstEvalInvalidStringInterpolationOperand/dart2jsCode: Fail
ConstEvalInvalidStringInterpolationOperand/example: Fail
ConstEvalInvalidType/analyzerCode: Fail # CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH / CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH / CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH / ...
ConstEvalInvalidType/example: Fail
ConstEvalNonConstantLiteral/dart2jsCode: Fail
ConstEvalNonConstantLiteral/example: Fail
ConstFieldWithoutInitializer/example: Fail
ConstructorHasNoSuchNamedParameter/analyzerCode: Fail
ConstructorHasNoSuchNamedParameter/example: Fail

View file

@ -72,6 +72,43 @@ AsciiControlCharacter:
analyzerCode: ILLEGAL_CHARACTER
expression: "\x1b 1"
ConstEvalContext:
template: "While analyzing:"
ConstEvalDuplicateKey:
template: "The key '#constant' conflicts with another existing key in the map."
analyzerCode: EQUAL_KEYS_IN_MAP
ConstEvalNonConstantLiteral:
template: "Can't have a non-constant #string literal within a const context."
analyzerCode: NON_CONSTANT_DEFAULT_VALUE
ConstEvalInvalidType:
template: "Expected constant '#constant' to be of type '#type', but was of type '#type2'."
ConstEvalInvalidBinaryOperandType:
template: "Binary operator '#string' on '#constant' requires operand of type '#type', but was of type '#type2'."
ConstEvalInvalidMethodInvocation:
template: "The method '#string' can't be invoked on '#constant' within a const context."
analyzerCode: UNDEFINED_OPERATOR
ConstEvalInvalidStringInterpolationOperand:
template: "The '#constant' can't be used as part of a string interpolation within a const context, only values of type 'null', 'bool', 'int', 'double', or 'String' can be used."
analyzerCode: CONST_EVAL_TYPE_BOOL_NUM_STRING
ConstEvalInvalidStaticInvocation:
template: "The invocation of '#name' is not allowed within a const context."
analyzerCode: CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
ConstEvalFailedAssertion:
template: "This assertion failed."
analyzerCode: CONST_EVAL_THROWS_EXCEPTION
ConstEvalFailedAssertionWithMessage:
template: "This assertion failed with message: #string"
analyzerCode: CONST_EVAL_THROWS_EXCEPTION
NonAsciiIdentifier:
template: "The non-ASCII character '#character' (#unicode) can't be used in identifiers, only in strings and comments."
tip: "Try using an US-ASCII letter, a digit, '_' (an underscore), or '$' (a dollar sign)."

View file

@ -172,6 +172,11 @@ String type2 = '$buffer';
arguments.add("'count2': count2");
break;
case "#constant":
parameters.add("Constant constant");
arguments.add("'constant': constant");
break;
default:
throw "Unhandled placeholder in template: ${match[0]}";
}

View file

@ -409,9 +409,7 @@ class ConstantEvaluator extends RecursiveVisitor {
defaultTreeNode(Node node) {
// Only a subset of the expression language is valid for constant
// evaluation.
errorReporter.unimplemented(contextChain, node,
'Constant evaluation has no support for ${node.runtimeType} yet!');
throw const _AbortCurrentEvaluation();
throw 'Constant evaluation has no support for ${node.runtimeType} yet!';
}
visitNullLiteral(NullLiteral node) => nullConstant;
@ -449,7 +447,7 @@ class ConstantEvaluator extends RecursiveVisitor {
visitListLiteral(ListLiteral node) {
if (!node.isConst) {
errorReporter.nonConstantLiteral(contextChain, node, 'List');
errorReporter.nonConstLiteral(contextChain, node, 'List');
throw const _AbortCurrentEvaluation();
}
final List<Constant> entries = new List<Constant>(node.expressions.length);
@ -463,7 +461,7 @@ class ConstantEvaluator extends RecursiveVisitor {
visitMapLiteral(MapLiteral node) {
if (!node.isConst) {
errorReporter.nonConstantLiteral(contextChain, node, 'Map');
errorReporter.nonConstLiteral(contextChain, node, 'Map');
throw const _AbortCurrentEvaluation();
}
final Set<Constant> usedKeys = new Set<Constant>();
@ -473,6 +471,9 @@ class ConstantEvaluator extends RecursiveVisitor {
final key = node.entries[i].key.accept(this);
final value = node.entries[i].value.accept(this);
if (!usedKeys.add(key)) {
// 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();
}
@ -485,23 +486,24 @@ class ConstantEvaluator extends RecursiveVisitor {
return canonicalize(backend.lowerMapConstant(mapConstant));
}
visitFunctionExpression(FunctionExpression node) {
errorReporter.nonConstLiteral(contextChain, node, 'Function');
throw const _AbortCurrentEvaluation();
}
visitConstructorInvocation(ConstructorInvocation node) {
final Constructor constructor = node.target;
final Class klass = constructor.enclosingClass;
if (!constructor.isConst) {
errorReporter.nonConstConstructorInvocation(
contextChain, node, constructor);
throw const _AbortCurrentEvaluation();
throw 'The front-end should ensure we do not encounter a '
'constructor invocation of a non-const constructor.';
}
if (constructor.function.body is! EmptyStatement) {
errorReporter.unreachable(contextChain, node,
'Constructor "$node" has non-trivial body "${constructor.function.body.runtimeType}".');
throw const _AbortCurrentEvaluation();
if (constructor.function.body != null &&
constructor.function.body is! EmptyStatement) {
throw 'Constructor "$node" has non-trivial body "${constructor.function.body.runtimeType}".';
}
if (klass.isAbstract) {
errorReporter.unreachable(contextChain, node,
'Constructor "$node" belongs to abstract class "${klass}".');
throw const _AbortCurrentEvaluation();
throw 'Constructor "$node" belongs to abstract class "${klass}".';
}
final typeArguments = evaluateTypeArguments(node.arguments);
@ -587,20 +589,34 @@ class ConstantEvaluator extends RecursiveVisitor {
if (condition is BoolConstant) {
if (!condition.value) {
final Constant message = init.statement.message?.accept(this);
errorReporter.failedAssertion(
contextChain, init.statement.condition, message);
if (message == null) {
errorReporter.failedAssertion(
contextChain, init.statement.condition, null);
throw const _AbortCurrentEvaluation();
} else if (message is StringConstant) {
errorReporter.failedAssertion(
contextChain, init.statement.condition, message.value);
throw const _AbortCurrentEvaluation();
}
errorReporter.invalidDartType(
contextChain,
init.statement.message,
message,
typeEnvironment.stringType);
throw const _AbortCurrentEvaluation();
}
} else {
errorReporter.invalidType(
contextChain, init.statement.condition, condition, 'bool');
errorReporter.invalidDartType(
contextChain,
init.statement.condition,
condition,
typeEnvironment.boolType);
throw const _AbortCurrentEvaluation();
}
}
} else {
errorReporter.unimplemented(contextChain, init,
throw new Exception(
'No support for handling initializer of type "${init.runtimeType}".');
throw const _AbortCurrentEvaluation();
}
}
});
@ -615,21 +631,16 @@ class ConstantEvaluator extends RecursiveVisitor {
final List<Constant> arguments =
evaluatePositionalArguments(node.arguments);
// TODO(http://dartbug.com/31799): Ensure we only invoke ==/!= on
// null/bool/int/double/String objects.
// Handle == and != first (it's common between all types).
if (arguments.length == 1 && node.name.name == '==') {
// TODO(http://dartbug.com/31799): Re-enable these checks.
//ensurePrimitiveConstant(receiver);
final right = arguments[0];
// TODO(http://dartbug.com/31799): Re-enable these checks.
//ensurePrimitiveConstant(right);
return receiver == right ? trueConstant : falseConstant;
}
if (arguments.length == 1 && node.name.name == '!=') {
// TODO(http://dartbug.com/31799): Re-enable these checks.
//ensurePrimitiveConstant(receiver);
final right = arguments[0];
// TODO(http://dartbug.com/31799): Re-enable these checks.
//ensurePrimitiveConstant(right);
return receiver != right ? trueConstant : falseConstant;
}
@ -644,7 +655,12 @@ class ConstantEvaluator extends RecursiveVisitor {
new StringConstant(receiver.value + other.value));
}
errorReporter.invalidBinaryOperandType(
contextChain, node, 'String', '+', 'String', '$other');
contextChain,
node,
receiver,
'+',
typeEnvironment.stringType,
other.getType(typeEnvironment));
throw const _AbortCurrentEvaluation();
}
}
@ -669,7 +685,12 @@ class ConstantEvaluator extends RecursiveVisitor {
}
}
errorReporter.invalidBinaryOperandType(
contextChain, node, 'bool', '${node.name.name}', 'bool', '$right');
contextChain,
node,
receiver,
'${node.name.name}',
typeEnvironment.boolType,
right.getType(typeEnvironment));
throw const _AbortCurrentEvaluation();
}
} else if (receiver is IntConstant) {
@ -710,8 +731,13 @@ class ConstantEvaluator extends RecursiveVisitor {
node.name.name, receiver.value, value, node);
}
errorReporter.invalidBinaryOperandType(contextChain, node, 'int',
'${node.name.name}', 'int/double', '$other');
errorReporter.invalidBinaryOperandType(
contextChain,
node,
receiver,
'${node.name.name}',
typeEnvironment.numType,
other.getType(typeEnvironment));
throw const _AbortCurrentEvaluation();
}
} else if (receiver is DoubleConstant) {
@ -730,8 +756,13 @@ class ConstantEvaluator extends RecursiveVisitor {
return evaluateBinaryNumericOperation(
node.name.name, receiver.value, value, node);
}
errorReporter.invalidBinaryOperandType(contextChain, node, 'double',
'${node.name.name}', 'int/double', '$other');
errorReporter.invalidBinaryOperandType(
contextChain,
node,
receiver,
'${node.name.name}',
typeEnvironment.numType,
other.getType(typeEnvironment));
throw const _AbortCurrentEvaluation();
}
}
@ -752,7 +783,12 @@ class ConstantEvaluator extends RecursiveVisitor {
return right;
}
errorReporter.invalidBinaryOperandType(
contextChain, node, 'bool', '${node.operator}', 'bool', '$right');
contextChain,
node,
left,
'${node.operator}',
typeEnvironment.boolType,
right.getType(typeEnvironment));
throw const _AbortCurrentEvaluation();
}
errorReporter.invalidMethodInvocation(
@ -767,7 +803,12 @@ class ConstantEvaluator extends RecursiveVisitor {
return right;
}
errorReporter.invalidBinaryOperandType(
contextChain, node, 'bool', '${node.operator}', 'bool', '$right');
contextChain,
node,
left,
'${node.operator}',
typeEnvironment.boolType,
right.getType(typeEnvironment));
throw const _AbortCurrentEvaluation();
}
errorReporter.invalidMethodInvocation(
@ -789,7 +830,8 @@ class ConstantEvaluator extends RecursiveVisitor {
} else if (constant == falseConstant) {
return evaluate(node.otherwise);
} else {
errorReporter.invalidType(contextChain, node, constant, 'bool');
errorReporter.invalidDartType(
contextChain, node, constant, typeEnvironment.boolType);
throw const _AbortCurrentEvaluation();
}
}
@ -834,8 +876,8 @@ class ConstantEvaluator extends RecursiveVisitor {
if (!variable.isConst &&
!_isFormalParameter(variable) &&
variable.parent is! Let) {
errorReporter.nonConstantVariableGet(contextChain, node);
throw const _AbortCurrentEvaluation();
throw new Exception('The front-end should ensure we do not encounter a '
'variable get of a non-const variable.');
}
return env.lookupVariable(node.variable);
}
@ -854,9 +896,8 @@ class ConstantEvaluator extends RecursiveVisitor {
errorReporter.invalidStaticInvocation(contextChain, node, target);
throw const _AbortCurrentEvaluation();
} else {
errorReporter.unreachable(contextChain, node,
throw new Exception(
'No support for ${target.runtimeType} in a static-get.');
throw const _AbortCurrentEvaluation();
}
});
}
@ -903,11 +944,7 @@ class ConstantEvaluator extends RecursiveVisitor {
if (parent is Library && parent == coreTypes.coreLibrary) {
final positionalArguments = evaluatePositionalArguments(node.arguments);
final Constant left = positionalArguments[0];
// TODO(http://dartbug.com/31799): Re-enable these checks.
//ensurePrimitiveConstant(left, node);
final Constant right = positionalArguments[1];
// TODO(http://dartbug.com/31799): Re-enable these checks.
//ensurePrimitiveConstant(right, node);
// Since we canonicalize constants during the evaluation, we can use
// identical here.
assert(left == right);
@ -929,7 +966,8 @@ class ConstantEvaluator extends RecursiveVisitor {
if (constant is BoolConstant) {
return constant == trueConstant ? falseConstant : trueConstant;
}
errorReporter.invalidType(contextChain, node, constant, 'bool');
errorReporter.invalidDartType(
contextChain, node, constant, typeEnvironment.boolType);
throw const _AbortCurrentEvaluation();
}
@ -946,16 +984,12 @@ class ConstantEvaluator extends RecursiveVisitor {
return canonicalize(
new PartialInstantiationConstant(constant, node.typeArguments));
}
errorReporter.unreachable(
contextChain,
node,
throw new Exception(
'The number of type arguments supplied in the partial instantiation '
'does not match the number of type arguments of the $constant.');
throw const _AbortCurrentEvaluation();
}
errorReporter.unreachable(contextChain, node,
throw new Exception(
'Only tear-off constants can be partially instantiated.');
throw const _AbortCurrentEvaluation();
}
// Helper methods:
@ -985,13 +1019,11 @@ class ConstantEvaluator extends RecursiveVisitor {
} else if (constant is TypeLiteralConstant) {
constantType = new InterfaceType(coreTypes.typeClass);
} else {
errorReporter.unreachable(contextChain, node,
'No support for ${constant.runtimeType}.runtimeType');
throw const _AbortCurrentEvaluation();
throw new Exception('No support for ${constant.runtimeType}.runtimeType');
}
if (!typeEnvironment.isSubtypeOf(constantType, type)) {
errorReporter.invalidType(contextChain, node, constant, '$type');
errorReporter.invalidDartType(contextChain, node, constant, type);
throw const _AbortCurrentEvaluation();
}
}
@ -1015,7 +1047,7 @@ class ConstantEvaluator extends RecursiveVisitor {
List<Constant> evaluatePositionalArguments(Arguments arguments) {
return arguments.positional.map((Expression node) {
return node.accept(this);
return node.accept(this) as Constant;
}).toList();
}
@ -1053,18 +1085,6 @@ class ConstantEvaluator extends RecursiveVisitor {
}
}
ensurePrimitiveConstant(Constant value, TreeNode node) {
if (value is! NullConstant &&
value is! BoolConstant &&
value is! IntConstant &&
value is! DoubleConstant &&
value is! StringConstant) {
errorReporter.invalidType(
contextChain, node, value, 'bool/int/double/Null/String');
throw const _AbortCurrentEvaluation();
}
}
evaluateBinaryNumericOperation(String op, num a, num b, TreeNode node) {
num result;
switch (op) {
@ -1105,8 +1125,7 @@ class ConstantEvaluator extends RecursiveVisitor {
return a > b ? trueConstant : falseConstant;
}
errorReporter.invalidBinaryMethodInvocation(contextChain, node, op);
throw const _AbortCurrentEvaluation();
throw new Exception("Unexpected binary numeric operation '$op'.");
}
int _wrapAroundInteger(int value) {
@ -1211,32 +1230,23 @@ class _AbortCurrentEvaluation {
abstract class ErrorReporter {
const ErrorReporter();
invalidType(List<TreeNode> context, TreeNode node, Constant receiver,
String expectedType);
invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
DartType expectedType);
invalidBinaryOperandType(List<TreeNode> context, TreeNode node,
String receiverType, String op, String expectedType, String actualType);
invalidBinaryMethodInvocation(
List<TreeNode> context, TreeNode node, String op);
Constant receiver, String op, DartType expectedType, DartType actualType);
invalidMethodInvocation(
List<TreeNode> context, TreeNode node, Constant receiver, String op);
invalidStaticInvocation(
List<TreeNode> context, TreeNode node, Procedure target);
invalidStringInterpolationOperand(
List<TreeNode> context, TreeNode node, Constant constant);
nonConstLiteral(List<TreeNode> context, TreeNode node, String klass);
duplicateKey(List<TreeNode> context, TreeNode node, Constant key);
nonConstantLiteral(List<TreeNode> context, TreeNode node, String literalType);
nonConstantVariableGet(List<TreeNode> context, VariableGet node);
nonConstConstructorInvocation(
List<TreeNode> context, TreeNode node, Constructor target);
failedAssertion(List<TreeNode> context, TreeNode node, Constant message);
unimplemented(List<TreeNode> context, TreeNode node, String message);
unreachable(List<TreeNode> context, TreeNode node, String message);
failedAssertion(List<TreeNode> context, TreeNode node, String message);
}
abstract class ErrorReporterBase implements ErrorReporter {
const ErrorReporterBase();
report(List<TreeNode> context, String message, TreeNode node);
class _SimpleErrorReporter implements ErrorReporter {
const _SimpleErrorReporter();
getFileUri(TreeNode node) {
while (node is! FileUriNode) {
@ -1252,28 +1262,28 @@ abstract class ErrorReporterBase implements ErrorReporter {
return node == null ? TreeNode.noOffset : node.fileOffset;
}
invalidType(List<TreeNode> context, TreeNode node, Constant receiver,
String expectedType) {
invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
DartType expectedType) {
report(
context,
'Expected expression to evaluate to "$expectedType" but got "$receiver.',
node);
}
invalidBinaryOperandType(List<TreeNode> context, TreeNode node,
String receiverType, String op, String expectedType, String actualType) {
invalidBinaryOperandType(
List<TreeNode> context,
TreeNode node,
Constant receiver,
String op,
DartType expectedType,
DartType actualType) {
report(
context,
'Calling "$op" on "$receiverType" needs operand of type '
'Calling "$op" on "$receiver" needs operand of type '
'"$expectedType" (but got "$actualType")',
node);
}
invalidBinaryMethodInvocation(
List<TreeNode> context, TreeNode node, String op) {
report(context, 'Cannot call "$op" on a numeric constant receiver', node);
}
invalidMethodInvocation(
List<TreeNode> context, TreeNode node, Constant receiver, String op) {
report(context, 'Cannot call "$op" on "$receiver" in constant expression',
@ -1295,6 +1305,13 @@ abstract class ErrorReporterBase implements ErrorReporter {
node);
}
nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
report(
context,
'Cannot have a non-constant $klass literal within a const context.',
node);
}
duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
report(
context,
@ -1302,52 +1319,13 @@ abstract class ErrorReporterBase implements ErrorReporter {
node);
}
nonConstantLiteral(
List<TreeNode> context, TreeNode node, String literalType) {
report(
context,
'"$literalType" literals inside constant expressions are required to '
'be constant.',
node);
}
nonConstantVariableGet(List<TreeNode> context, VariableGet node) {
report(
context,
'The variable "${node.variable.name}" is non-const and '
'can therefore not be used inside a constant expression.'
' (${node}, ${node.parent.parent}, )',
node);
}
nonConstConstructorInvocation(
List<TreeNode> context, TreeNode node, Constructor target) {
report(
context,
'The non-const constructor "$target" cannot be called inside a '
'constant expression',
node);
}
failedAssertion(List<TreeNode> context, TreeNode node, Constant message) {
failedAssertion(List<TreeNode> context, TreeNode node, String message) {
report(
context,
'The assertion condition evaluated to "false" with message "$message"',
node);
}
unimplemented(List<TreeNode> context, TreeNode node, String message) {
report(context, 'Unimplemented: $message', node);
}
unreachable(List<TreeNode> context, TreeNode node, String message) {
report(context, 'Unreachable: $message', node);
}
}
class _SimpleErrorReporter extends ErrorReporterBase {
const _SimpleErrorReporter();
report(List<TreeNode> context, String message, TreeNode node) {
io.exitCode = 42;
final Uri uri = getFileUri(node);

View file

@ -8,14 +8,14 @@ import 'dart:io';
import 'package:args/args.dart' show ArgParser, ArgResults;
import 'package:front_end/src/api_prototype/front_end.dart';
import 'package:kernel/binary/ast_to_binary.dart';
import 'package:kernel/kernel.dart' show Component;
import 'package:kernel/src/tool/batch_util.dart' as batch_util;
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/target/vm.dart' show VmTarget;
import 'package:kernel/text/ast_to_text.dart'
show globalDebuggingNames, NameSystem;
import 'package:vm/bytecode/gen_bytecode.dart' show isKernelBytecodeEnabled;
import 'package:vm/kernel_front_end.dart' show compileToKernel, ErrorDetector;
import 'package:vm/kernel_front_end.dart'
show compileToKernel, ErrorDetector, ErrorPrinter;
final ArgParser _argParser = new ArgParser(allowTrailingOptions: true)
..addOption('platform',
@ -36,6 +36,14 @@ final ArgParser _argParser = new ArgParser(allowTrailingOptions: true)
help:
'Enable global type flow analysis and related transformations in AOT mode.',
defaultsTo: true)
..addMultiOption('define',
abbr: 'D',
help: 'The values for the environment constants (e.g. -Dkey=value).')
..addFlag('enable-asserts',
help: 'Whether asserts will be enabled.', defaultsTo: false)
..addFlag('enable-constant-evaluation',
help: 'Whether kernel constant evaluation will be enabled.',
defaultsTo: true)
..addMultiOption('entry-points',
help: 'Path to JSON file with the list of entry points')
..addFlag('gen-bytecode',
@ -77,6 +85,13 @@ Future<int> compile(List<String> arguments) async {
final bool syncAsync = options['sync-async'];
final bool tfa = options['tfa'];
final bool genBytecode = options['gen-bytecode'];
final bool enableAsserts = options['enable-asserts'];
final bool enableConstantEvaluation = options['enable-constant-evaluation'];
final Map<String, String> environmentDefines = {};
if (!_parseDefines(options['define'], environmentDefines)) {
return _badUsageExitCode;
}
final List<String> entryPoints = options['entry-points'] ?? <String>[];
if (entryPoints.isEmpty) {
@ -87,7 +102,8 @@ Future<int> compile(List<String> arguments) async {
]);
}
ErrorDetector errorDetector = new ErrorDetector();
final errorPrinter = new ErrorPrinter();
final errorDetector = new ErrorDetector(previousErrorHandler: errorPrinter);
final CompilerOptions compilerOptions = new CompilerOptions()
..strongMode = strongMode
@ -99,15 +115,21 @@ Future<int> compile(List<String> arguments) async {
..packagesFileUri =
packages != null ? Uri.base.resolveUri(new Uri.file(packages)) : null
..reportMessages = true
..onError = errorDetector
..onProblem = errorDetector
..embedSourceText = options['embed-sources'];
Component component = await compileToKernel(
Uri.base.resolveUri(new Uri.file(filename)), compilerOptions,
final inputUri = new Uri.file(filename);
final component = await compileToKernel(
Uri.base.resolveUri(inputUri), compilerOptions,
aot: aot,
useGlobalTypeFlowAnalysis: tfa,
entryPoints: entryPoints,
genBytecode: genBytecode);
environmentDefines: environmentDefines,
genBytecode: genBytecode,
enableAsserts: enableAsserts,
enableConstantEvaluation: enableConstantEvaluation);
errorPrinter.printCompilationMessages(inputUri);
if (errorDetector.hasCompilationErrors || (component == null)) {
return _compileTimeErrorExitCode;
@ -152,3 +174,22 @@ Future runBatchModeCompiler() async {
}
});
}
bool _parseDefines(
List<String> dFlags, Map<String, String> environmentDefines) {
for (final String dflag in dFlags) {
final equalsSignIndex = dflag.indexOf('=');
if (equalsSignIndex < 0) {
environmentDefines[dflag] = '';
} else if (equalsSignIndex > 0) {
final key = dflag.substring(0, equalsSignIndex);
final value = dflag.substring(equalsSignIndex + 1);
environmentDefines[key] = value;
} else {
print('The environment constant options must have a key (was: "$dflag")');
print(_usage);
return false;
}
}
return true;
}

View file

@ -7,16 +7,34 @@ library vm.kernel_front_end;
import 'dart:async';
import 'package:front_end/src/base/processed_options.dart'
show ProcessedOptions;
import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
import 'package:front_end/src/fasta/fasta_codes.dart' as codes;
import 'package:front_end/src/api_prototype/compiler_options.dart'
show CompilerOptions, ErrorHandler;
show CompilerOptions, ProblemHandler;
import 'package:front_end/src/api_prototype/kernel_generator.dart'
show kernelForProgram;
import 'package:front_end/src/api_prototype/compilation_message.dart'
show CompilationMessage, Severity;
import 'package:front_end/src/fasta/severity.dart' show Severity;
import 'package:kernel/ast.dart' show Component, StaticGet, Field;
show Severity;
import 'package:kernel/type_environment.dart' show TypeEnvironment;
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
import 'package:kernel/ast.dart'
show
Component,
Constant,
DartType,
Field,
FileUriNode,
Procedure,
StaticGet,
TreeNode;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:vm/bytecode/gen_bytecode.dart' show generateBytecode;
import 'package:kernel/transformations/constants.dart' as constants;
import 'package:kernel/vm/constants_native_effects.dart' as vm_constants;
import 'bytecode/gen_bytecode.dart' show generateBytecode;
import 'transformations/devirtualization.dart' as devirtualization
show transformComponent;
@ -36,23 +54,35 @@ Future<Component> compileToKernel(Uri source, CompilerOptions options,
{bool aot: false,
bool useGlobalTypeFlowAnalysis: false,
List<String> entryPoints,
bool genBytecode: false}) async {
Map<String, String> environmentDefines,
bool genBytecode: false,
bool enableAsserts: false,
bool enableConstantEvaluation: true}) async {
// Replace error handler to detect if there are compilation errors.
final errorDetector =
new ErrorDetector(previousErrorHandler: options.onError);
options.onError = errorDetector;
new ErrorDetector(previousErrorHandler: options.onProblem);
options.onProblem = errorDetector;
final component = await kernelForProgram(source, options);
// Restore error handler (in case 'options' are reused).
options.onError = errorDetector.previousErrorHandler;
// Run global transformations only if component is correct.
if (aot && (component != null) && !errorDetector.hasCompilationErrors) {
_runGlobalTransformations(
component, options.strongMode, useGlobalTypeFlowAnalysis, entryPoints);
if (aot && component != null) {
await _runGlobalTransformations(
source,
options,
component,
options.strongMode,
useGlobalTypeFlowAnalysis,
entryPoints,
environmentDefines,
enableAsserts,
enableConstantEvaluation,
errorDetector);
}
// Restore error handler (in case 'options' are reused).
options.onProblem = errorDetector.previousErrorHandler;
if (genBytecode && component != null) {
generateBytecode(component, strongMode: options.strongMode);
}
@ -60,11 +90,21 @@ Future<Component> compileToKernel(Uri source, CompilerOptions options,
return component;
}
_runGlobalTransformations(Component component, bool strongMode,
bool useGlobalTypeFlowAnalysis, List<String> entryPoints) {
Future _runGlobalTransformations(
Uri source,
CompilerOptions compilerOptions,
Component component,
bool strongMode,
bool useGlobalTypeFlowAnalysis,
List<String> entryPoints,
Map<String, String> environmentDefines,
bool enableAsserts,
bool enableConstantEvaluation,
ErrorDetector errorDetector) async {
if (strongMode) {
final coreTypes = new CoreTypes(component);
if (errorDetector.hasCompilationErrors) return;
final coreTypes = new CoreTypes(component);
_patchVmConstants(coreTypes);
// TODO(alexmarkov, dmitryas): Consider doing canonicalization of identical
@ -81,10 +121,56 @@ _runGlobalTransformations(Component component, bool strongMode,
devirtualization.transformComponent(coreTypes, component);
}
if (enableConstantEvaluation) {
await _performConstantEvaluation(source, compilerOptions, component,
coreTypes, environmentDefines, strongMode, enableAsserts);
if (errorDetector.hasCompilationErrors) return;
}
no_dynamic_invocations_annotator.transformComponent(component);
}
}
Future _performConstantEvaluation(
Uri source,
CompilerOptions compilerOptions,
Component component,
CoreTypes coreTypes,
Map<String, String> environmentDefines,
bool strongMode,
bool enableAsserts) async {
final vmConstants =
new vm_constants.VmConstantsBackend(environmentDefines, coreTypes);
final processedOptions =
new ProcessedOptions(compilerOptions, false, [source]);
// Run within the context, so we have uri source tokens...
await CompilerContext.runWithOptions(processedOptions,
(CompilerContext context) async {
// To make the fileUri/fileOffset -> line/column mapping, we need to
// pre-fill the map.
context.uriToSource.addAll(component.uriToSource);
final hierarchy = new ClassHierarchy(component);
final typeEnvironment =
new TypeEnvironment(coreTypes, hierarchy, strongMode: strongMode);
// NOTE: Currently we keep fields, because there are certain constant
// fields which the VM accesses (e.g. `_Random._A` needs to be preserved).
// TODO(kustermann): We should use the entrypoints manifest to find out
// which fields need to be preserved and remove the rest.
constants.transformComponent(component, vmConstants,
keepFields: true,
strongMode: true,
evaluateAnnotations: false,
enableAsserts: enableAsserts,
errorReporter:
new ForwardConstantEvaluationErrors(context, typeEnvironment));
});
}
void _patchVmConstants(CoreTypes coreTypes) {
// Fix Endian.host to be a const field equal to Endial.little instead of
// a final field. VM does not support big-endian architectures at the
@ -101,16 +187,147 @@ void _patchVmConstants(CoreTypes coreTypes) {
}
class ErrorDetector {
final ErrorHandler previousErrorHandler;
final ProblemHandler previousErrorHandler;
bool hasCompilationErrors = false;
ErrorDetector({this.previousErrorHandler});
void call(CompilationMessage message) {
if (message.severity == Severity.error) {
void call(codes.FormattedMessage problem, Severity severity,
List<codes.FormattedMessage> context) {
if (severity == Severity.error) {
hasCompilationErrors = true;
}
previousErrorHandler?.call(message);
previousErrorHandler?.call(problem, severity, context);
}
}
class ErrorPrinter {
final ProblemHandler previousErrorHandler;
final compilationMessages = <Uri, List<List>>{};
ErrorPrinter({this.previousErrorHandler});
void call(codes.FormattedMessage problem, Severity severity,
List<codes.FormattedMessage> context) {
final sourceUri = problem.locatedMessage.uri;
compilationMessages.putIfAbsent(sourceUri, () => [])
..add([problem, context]);
previousErrorHandler?.call(problem, severity, context);
}
void printCompilationMessages(Uri baseUri) {
final sortedUris = compilationMessages.keys.toList()
..sort((a, b) => '$a'.compareTo('$b'));
for (final Uri sourceUri in sortedUris) {
for (final List errorTuple in compilationMessages[sourceUri]) {
final codes.FormattedMessage message = errorTuple.first;
print(message.formatted);
final List context = errorTuple.last;
for (final codes.FormattedMessage message in context?.reversed) {
print(message.formatted);
}
}
}
}
}
class ForwardConstantEvaluationErrors implements constants.ErrorReporter {
final CompilerContext compilerContext;
final TypeEnvironment typeEnvironment;
ForwardConstantEvaluationErrors(this.compilerContext, this.typeEnvironment);
duplicateKey(List<TreeNode> context, TreeNode node, Constant key) {
final message = codes.templateConstEvalDuplicateKey.withArguments(key);
reportIt(context, message, node);
}
invalidDartType(List<TreeNode> context, TreeNode node, Constant receiver,
DartType expectedType) {
final message = codes.templateConstEvalInvalidType.withArguments(
receiver, expectedType, receiver.getType(typeEnvironment));
reportIt(context, message, node);
}
invalidBinaryOperandType(
List<TreeNode> context,
TreeNode node,
Constant receiver,
String op,
DartType expectedType,
DartType actualType) {
final message = codes.templateConstEvalInvalidBinaryOperandType
.withArguments(op, receiver, expectedType, actualType);
reportIt(context, message, node);
}
invalidMethodInvocation(
List<TreeNode> context, TreeNode node, Constant receiver, String op) {
final message = codes.templateConstEvalInvalidMethodInvocation
.withArguments(op, receiver);
reportIt(context, message, node);
}
invalidStaticInvocation(
List<TreeNode> context, TreeNode node, Procedure target) {
final message = codes.templateConstEvalInvalidStaticInvocation
.withArguments(target.name.toString());
reportIt(context, message, node);
}
invalidStringInterpolationOperand(
List<TreeNode> context, TreeNode node, Constant constant) {
final message = codes.templateConstEvalInvalidStringInterpolationOperand
.withArguments(constant);
reportIt(context, message, node);
}
nonConstLiteral(List<TreeNode> context, TreeNode node, String klass) {
final message =
codes.templateConstEvalNonConstantLiteral.withArguments(klass);
reportIt(context, message, node);
}
failedAssertion(List<TreeNode> context, TreeNode node, String string) {
final message = string == null
? codes.messageConstEvalFailedAssertion
: codes.templateConstEvalFailedAssertionWithMessage
.withArguments(string);
reportIt(context, message, node);
}
reportIt(List<TreeNode> context, codes.Message message, TreeNode node) {
final Uri uri = getFileUri(node);
final int fileOffset = getFileOffset(node);
final contextMessages = <codes.LocatedMessage>[];
for (final TreeNode node in context) {
final Uri uri = getFileUri(node);
final int fileOffset = getFileOffset(node);
contextMessages.add(codes.messageConstEvalContext
.withLocation(uri, fileOffset, codes.noLength));
}
final locatedMessage =
message.withLocation(uri, fileOffset, codes.noLength);
compilerContext.options
.report(locatedMessage, Severity.error, context: contextMessages);
}
getFileUri(TreeNode node) {
while (node is! FileUriNode) {
node = node.parent;
}
return (node as FileUriNode).fileUri;
}
getFileOffset(TreeNode node) {
while (node.fileOffset == TreeNode.noOffset) {
node = node.parent;
}
return node == null ? TreeNode.noOffset : node.fileOffset;
}
}

View file

@ -24,10 +24,15 @@ for arg in "$@"; do
--packages=*)
PACKAGES="$arg"
;;
--enable-asserts)
GEN_KERNEL_OPTIONS+=("$arg")
OPTIONS+=("$arg")
;;
--sync-async | \
--no-sync-async | \
--tfa | \
--no-tfa )
--no-tfa | \
-D* )
GEN_KERNEL_OPTIONS+=("$arg")
;;
--*)

View file

@ -2712,6 +2712,7 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
CollectImmediateSuperInterfaces(cls, &cids);
RemoveCHAOptimizedCode(cls, cids);
}
if (cls.is_enum_class()) {
AllocateEnumValues(cls);
}
@ -2765,11 +2766,15 @@ void ClassFinalizer::AllocateEnumValues(const Class& enum_cls) {
(sentinel.raw() == field.raw())) {
continue;
}
field.SetStaticValue(Object::transition_sentinel());
result = Compiler::EvaluateStaticInitializer(field);
ASSERT(!result.IsError());
field.SetStaticValue(Instance::Cast(result), true);
field.RecordStore(Instance::Cast(result));
// The eager evaluation of the enum values is required for hot-reload (see
// commit e3ecc87).
if (!FLAG_precompiled_mode) {
field.SetStaticValue(Object::transition_sentinel());
result = Compiler::EvaluateStaticInitializer(field);
ASSERT(!result.IsError());
field.SetStaticValue(Instance::Cast(result), true);
field.RecordStore(Instance::Cast(result));
}
}
} else {
const String& name_prefix =

View file

@ -68,11 +68,8 @@ bad_override_test/02: MissingCompileTimeError
call_non_method_field_test/01: MissingCompileTimeError
call_non_method_field_test/02: MissingCompileTimeError
check_member_static_test/01: MissingCompileTimeError
compile_time_constant_o_test/01: MissingCompileTimeError
compile_time_constant_o_test/02: MissingCompileTimeError
const_cast2_test/01: CompileTimeError
const_cast2_test/none: CompileTimeError
const_dynamic_type_literal_test/02: MissingCompileTimeError
const_instance_field_test/01: MissingCompileTimeError # Fasta bug: Const instance field. Issue 32326.
const_map2_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
const_map3_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
@ -104,10 +101,6 @@ generic_methods_bounds_test/01: MissingCompileTimeError
generic_methods_overriding_test/01: MissingCompileTimeError
generic_methods_recursive_bound_test/02: MissingCompileTimeError
getter_override_test/03: MissingCompileTimeError
identical_const_test/01: MissingCompileTimeError
identical_const_test/02: MissingCompileTimeError
identical_const_test/03: MissingCompileTimeError
identical_const_test/04: MissingCompileTimeError
issue31596_override_test/07: MissingCompileTimeError
issue31596_override_test/08: MissingCompileTimeError
issue31596_super_test/02: MissingCompileTimeError
@ -448,10 +441,15 @@ export_ambiguous_main_test: MissingCompileTimeError
[ $compiler != dart2js && $compiler != dartk && $compiler != dartkp && $fasta ]
const_optional_args_test/01: MissingCompileTimeError
[ $compiler != dart2js && $fasta ]
# The precomilation configuration uses a kernel2kernel constants evaluator
# which is is more correct than fasta/vm in JIT mode (i.e. it catches more
# compile-time errors).
[ $compiler != dart2js && $compiler != dartkp && $fasta ]
compile_time_constant_c_test/02: MissingCompileTimeError
const_constructor_nonconst_field_test/01: MissingCompileTimeError
const_syntax_test/05: MissingCompileTimeError
[ $compiler != dart2js && $fasta ]
mixin_super_2_test/01: MissingCompileTimeError
mixin_super_2_test/03: MissingCompileTimeError
mixin_supertype_subclass_test/02: MissingCompileTimeError
@ -857,11 +855,6 @@ check_member_static_test/02: MissingCompileTimeError # Issue 32613: override che
checked_setter3_test/01: MissingCompileTimeError
checked_setter3_test/02: MissingCompileTimeError
checked_setter3_test/03: MissingCompileTimeError
compile_time_constant_k_test/01: MissingCompileTimeError
compile_time_constant_k_test/02: MissingCompileTimeError
compile_time_constant_k_test/03: MissingCompileTimeError
compile_time_constant_o_test/01: RuntimeError # KernelVM bug: Constant map duplicated key.
compile_time_constant_o_test/02: RuntimeError # KernelVM bug: Constant map duplicated key.
compile_time_constant_static5_test/11: CompileTimeError # Issue 31537
compile_time_constant_static5_test/16: CompileTimeError # Issue 31537
compile_time_constant_static5_test/21: CompileTimeError # Issue 31537
@ -870,11 +863,9 @@ conditional_import_string_test: CompileTimeError # KernelVM bug: Deferred loadin
conditional_import_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
config_import_corelib_test: CompileTimeError # Issue 31533
config_import_test: RuntimeError # KernelVM bug: Configurable imports.
const_dynamic_type_literal_test/02: RuntimeError # KernelVM bug: Constant map duplicated key.
const_evaluation_test: SkipByDesign
const_list_test: RuntimeError
const_map4_test: RuntimeError
const_nested_test: RuntimeError # KernelVM bug: Constant evaluation.
constructor12_test: RuntimeError
constructor3_test: Fail, OK, Pass
ct_const2_test: Skip # Incompatible flag: --compile_all
@ -974,8 +965,6 @@ local_function_test/none: RuntimeError
main_not_a_function_test: Skip
main_test/03: RuntimeError
many_overridden_no_such_method_test: SkipByDesign
map_literal3_test/01: MissingCompileTimeError
map_literal3_test/02: MissingCompileTimeError
map_literal3_test/03: MissingCompileTimeError
method_override4_test/01: MissingCompileTimeError
method_override4_test/02: MissingCompileTimeError
@ -1103,6 +1092,28 @@ recursive_generic_test: RuntimeError # Compares a (dynamic) toString call to 'C<
tearoff_dynamic_test: RuntimeError # Compares call to "foo" (noSuchMethod) with string "foo"
type_variable_promotion_test: RuntimeError # Compares runtime type to the string "List<B>"
# The precomilation configuration uses a kernel2kernel constants evaluator
# which is is more correct than fasta/vm in JIT mode (i.e. it catches more
# compile-time errors).
[ $compiler != dartkp && $fasta ]
compile_time_constant_o_test/01: MissingCompileTimeError
compile_time_constant_o_test/02: MissingCompileTimeError
const_dynamic_type_literal_test/02: MissingCompileTimeError
identical_const_test/01: MissingCompileTimeError
identical_const_test/02: MissingCompileTimeError
identical_const_test/03: MissingCompileTimeError
identical_const_test/04: MissingCompileTimeError
# The precomilation configuration uses a kernel2kernel constants evaluator
# which is is more correct than fasta/vm in JIT mode (i.e. it catches more
# compile-time errors).
[ $compiler != dartkp && $fasta && $strong ]
compile_time_constant_k_test/01: MissingCompileTimeError
compile_time_constant_k_test/02: MissingCompileTimeError
compile_time_constant_k_test/03: MissingCompileTimeError
map_literal3_test/01: MissingCompileTimeError
map_literal3_test/02: MissingCompileTimeError
[ $compiler == fasta && $strong ]
bad_override_test/03: MissingCompileTimeError
check_member_static_test/02: MissingCompileTimeError
@ -1296,16 +1307,11 @@ setter_override2_test/02: MissingCompileTimeError
variable_shadow_class_test/01: MissingCompileTimeError
[ $fasta && $strong ]
compile_time_constant_k_test/01: MissingCompileTimeError
compile_time_constant_k_test/02: MissingCompileTimeError
compile_time_constant_k_test/03: MissingCompileTimeError
compile_time_constant_static2_test/04: MissingCompileTimeError
compile_time_constant_static3_test/04: MissingCompileTimeError
initializing_formal_type_annotation_test/01: MissingCompileTimeError
initializing_formal_type_annotation_test/02: MissingCompileTimeError
issue18628_2_test/01: MissingCompileTimeError
map_literal3_test/01: MissingCompileTimeError
map_literal3_test/02: MissingCompileTimeError
map_literal3_test/03: MissingCompileTimeError
redirecting_factory_infinite_steps_test/01: MissingCompileTimeError
redirecting_factory_malbounded_test/01: MissingCompileTimeError

View file

@ -1062,6 +1062,8 @@ abstract class VMKernelCompilerMixin {
bool get _useSdk;
bool get _isStrong;
bool get _isAot;
bool get _isChecked;
bool get _useEnableAsserts;
String get executableScriptSuffix;
@ -1107,6 +1109,10 @@ abstract class VMKernelCompilerMixin {
}
args.add(arguments.where((name) => name.endsWith('.dart')).single);
args.addAll(arguments.where((name) => name.startsWith('-D')));
if (_isChecked || _useEnableAsserts) {
args.add('--enable_asserts');
}
// Pass environment variable to the gen_kernel script as
// arguments are not passed if gen_kernel runs in batch mode.