mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 21:30:17 +00:00
[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:
parent
2f781e46b0
commit
039e8a1755
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)."
|
||||
|
|
|
@ -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]}";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
;;
|
||||
--*)
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue