Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Unified Diff: pkg/compiler/lib/src/resolution/members.dart

Issue 1559233002: WIP: Compute constant expressions in resolution. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/resolution/constructors.dart ('k') | pkg/compiler/lib/src/resolution/resolution.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/resolution/members.dart
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 90f536553150628ae9a9f676416195b3666297a0..cda8e96a42b70df8ef37f2d47dabab98534ddcda 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -10,7 +10,11 @@ import '../common/names.dart' show
import '../compiler.dart' show
Compiler;
import '../constants/constructors.dart' show
+ ErroneousConstantConstructor,
RedirectingFactoryConstantConstructor;
+import '../constants/evaluation.dart' show
+ ConstantTypeChecker,
+ ConstantTypeInfo;
import '../constants/expressions.dart';
import '../constants/values.dart';
import '../core_types.dart';
@@ -67,21 +71,82 @@ import 'variables.dart' show
VariableDefinitionsVisitor;
/// The state of constants in resolutions.
-enum ConstantState {
- /// Expressions are not required to be constants.
- NON_CONSTANT,
+abstract class ConstantState {
- /// Expressions are required to be constants.
+ /// `true` if expressions are required to be constant.
+ bool get requiresConstant;
+
+ /// `true` if parameter references are considered constant. This is the case
+ /// in const constructor initializers.
+ bool get parameterReferenceIsConstant;
+
+ /// Returns the constant state corresponding to this state but where
+ /// expression are required to be constants.
+ ConstantState get requireConstant;
+
+ /// Constant state where expressions are not required to be constants.
+ static const ConstantState NON_CONSTANT = const _NoneConstantState();
+
+ /// Constant state where expressions are required to be constants.
///
/// For instance the values of a constant list literal.
- CONSTANT,
+ static const ConstantState CONSTANT = const _RequiredConstantState();
- /// Expressions are required to be constants and parameter references are
- /// also considered constant.
+ /// Constant state where expressions are required to be constants and
+ /// parameter references are also considered constant.
///
/// This is used for resolving constructor initializers of constant
/// constructors.
- CONSTANT_INITIALIZER,
+ static const ConstantState CONSTANT_INITIALIZER =
+ const _ConstantInitializerState();
+}
+
+/// Constant state where expressions are not required to be constants.
+class _NoneConstantState implements ConstantState {
+ const _NoneConstantState();
+
+ @override
+ bool get requiresConstant => false;
+
+ @override
+ bool get parameterReferenceIsConstant => false;
+
+ @override
+ ConstantState get requireConstant => ConstantState.CONSTANT;
+}
+
+/// Constant state where expressions are required to be constants.
+///
+/// For instance the values of a constant list literal.
+class _RequiredConstantState implements ConstantState {
+ const _RequiredConstantState();
+
+ @override
+ bool get requiresConstant => true;
+
+ @override
+ bool get parameterReferenceIsConstant => false;
+
+ @override
+ ConstantState get requireConstant => this;
+}
+
+/// Constant state where expressions are required to be constants and parameter
+/// references are also considered constant.
+///
+/// This is used for resolving constructor initializers of constant
+/// constructors.
+class _ConstantInitializerState implements ConstantState {
+ const _ConstantInitializerState();
+
+ @override
+ bool get requiresConstant => true;
+
+ @override
+ bool get parameterReferenceIsConstant => true;
+
+ @override
+ ConstantState get requireConstant => this;
}
/**
@@ -104,6 +169,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
bool inCheckContext;
bool inCatchBlock;
ConstantState constantState;
+ final ConstantNodeChecker constantExpressionChecker;
+ final ConstantNodeChecker constantExpressionValidator;
Scope scope;
ClassElement currentClass;
@@ -182,10 +249,22 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
inCatchBlock = false,
constantState = element.isConst
? ConstantState.CONSTANT : ConstantState.NON_CONSTANT,
+ constantExpressionChecker = new ConstantNodeChecker(
+ compiler, constantIsRequired: true),
+ constantExpressionValidator = new ConstantNodeChecker(
+ compiler, constantIsRequired: false),
super(compiler, registry);
CoreTypes get coreTypes => compiler.coreTypes;
+ ConstantNodeChecker get constantChecker {
+ if (constantState.requiresConstant) {
+ return constantExpressionChecker;
+ } else {
+ return constantExpressionValidator;
+ }
+ }
+
AsyncMarker get currentAsyncMarker {
if (enclosingElement is FunctionElement) {
FunctionElement function = enclosingElement;
@@ -264,18 +343,33 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
inConstantInitializer: inConstantInitializer);
}
+ /// Execute [action] where the constant state is `ConstantState.NON_CONSTANT`.
+ inNonConstantContext(action()) {
+ ConstantState oldConstantState = constantState;
+ constantState = ConstantState.NON_CONSTANT;
+ var result = action();
+ constantState = oldConstantState;
+ return result;
+ }
+
/// Execute [action] where the constant state is `ConstantState.CONSTANT` if
/// not already `ConstantState.CONSTANT_INITIALIZER`.
inConstantContext(action()) {
ConstantState oldConstantState = constantState;
- if (constantState != ConstantState.CONSTANT_INITIALIZER) {
- constantState = ConstantState.CONSTANT;
- }
+ constantState = constantState.requireConstant;
var result = action();
constantState = oldConstantState;
return result;
}
+ bool checkConstantInvariant(Node node, ResolutionResult result) {
+ return invariant(
+ node,
+ !constantState.requiresConstant || result.isConstant,
+ message: "No constant computed for expression.");
+ }
+
+
/// Visit [node] where the constant state is `ConstantState.CONSTANT` if
/// not already `ConstantState.CONSTANT_INITIALIZER`.
ResolutionResult visitInConstantContext(Node node) {
@@ -463,9 +557,9 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (element.isOptional) {
if (element.initializer != null) {
ResolutionResult result = visitInConstantContext(element.initializer);
- if (result.isConstant) {
- element.constant = result.constant;
- }
+ assert(invariant(element, result.isConstant,
+ message: "No default value computed for $element."));
+ element.constant = result.constant;
} else {
element.constant = new NullConstantExpression();
}
@@ -632,7 +726,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// Run the body in a fresh statement scope.
StatementScope oldStatementScope = statementScope;
statementScope = new StatementScope();
- visit(node.body);
+ inNonConstantContext(() => visit(node.body));
statementScope = oldStatementScope;
scope = oldScope;
@@ -640,7 +734,17 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerClosure(function);
registry.registerInstantiatedClass(compiler.functionClass);
- return const NoneResult();
+ return ensureConstantResult(node, const NoneResult());
+ }
+
+ ResolutionResult ensureConstantResult(Node node, ResolutionResult result) {
+ if (constantState.requiresConstant && !result.isConstant) {
+ reporter.reportErrorMessage(
+ node, MessageKind.NOT_A_COMPILE_TIME_CONSTANT);
+ return new ConstantResult(
+ node, new ErroneousConstantExpression(), element: result.element);
+ }
+ return result;
}
ResolutionResult visitIf(If node) {
@@ -741,6 +845,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) {
Expression argument = link.head;
ResolutionResult result = visit(argument);
+ assert(checkConstantInvariant(argument, result));
if (!result.isConstant) {
isValidAsConstant = false;
}
@@ -1227,37 +1332,29 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
} else {
ResolutionResult expressionResult = visitExpression(expression);
+ assert(checkConstantInvariant(expression, expressionResult));
semantics = const DynamicAccess.expression();
registry.registerDynamicInvocation(new UniverseSelector(selector, null));
+ ConstantExpression constant;
if (expressionResult.isConstant) {
- bool isValidConstant;
- ConstantExpression expressionConstant = expressionResult.constant;
- DartType knownExpressionType =
- expressionConstant.getKnownType(coreTypes);
- switch (operator.kind) {
- case UnaryOperatorKind.COMPLEMENT:
- isValidConstant =
- knownExpressionType == coreTypes.intType;
- break;
- case UnaryOperatorKind.NEGATE:
- isValidConstant =
- knownExpressionType == coreTypes.intType ||
- knownExpressionType == coreTypes.doubleType;
- break;
- case UnaryOperatorKind.NOT:
- reporter.internalError(node,
- "Unexpected user definable unary operator: $operator");
- }
- if (isValidConstant) {
- // TODO(johnniwinther): Handle potentially invalid constant
- // expressions.
- ConstantExpression constant =
- new UnaryConstantExpression(operator, expressionConstant);
- registry.setConstant(node, constant);
- result = new ConstantResult(node, constant);
+ bool isValidAsConstant =
+ !expressionResult.constant.isErroneous &&
+ constantChecker.checkUnary(
+ operator,
+ constantChecker.createInfo(expressionResult));
+ if (isValidAsConstant) {
+ constant =
+ new UnaryConstantExpression(operator, expressionResult.constant);
}
}
+ if (constant == null && constantState.requiresConstant) {
+ constant = new ErroneousConstantExpression();
+ }
+ if (constant != null) {
+ registry.setConstant(node, constant);
+ result = new ConstantResult(node, constant);
+ }
}
if (semantics != null) {
registry.registerSendStructure(node,
@@ -1271,20 +1368,26 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
assert(invariant(node, operator.kind == UnaryOperatorKind.NOT));
Node expression = node.receiver;
- ResolutionResult result = visitExpression(expression);
+ ResolutionResult expressionResult = visitExpression(expression);
registry.registerSendStructure(node, const NotStructure());
- if (result.isConstant) {
- ConstantExpression expressionConstant = result.constant;
- if (expressionConstant.getKnownType(coreTypes) == coreTypes.boolType) {
- // TODO(johnniwinther): Handle potentially invalid constant expressions.
- ConstantExpression constant =
- new UnaryConstantExpression(operator, expressionConstant);
- registry.setConstant(node, constant);
- return new ConstantResult(node, constant);
+ ConstantExpression constant;
+ if (expressionResult.isConstant) {
+ bool isValidAsConstant = constantChecker.checkUnary(
+ operator,
+ constantChecker.createInfo(expressionResult));
+ if (isValidAsConstant) {
+ constant =
+ new UnaryConstantExpression(operator, expressionResult.constant);
}
}
-
+ if (constant == null && constantState.requiresConstant) {
+ constant = new ErroneousConstantExpression();
+ }
+ if (constant != null) {
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
return const NoneResult();
}
@@ -1298,21 +1401,27 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
doInPromotionScope(right, () => visitExpression(right));
registry.registerSendStructure(node, const LogicalAndStructure());
+ ConstantExpression constant;
if (leftResult.isConstant && rightResult.isConstant) {
- ConstantExpression leftConstant = leftResult.constant;
- ConstantExpression rightConstant = rightResult.constant;
- if (leftConstant.getKnownType(coreTypes) == coreTypes.boolType &&
- rightConstant.getKnownType(coreTypes) == coreTypes.boolType) {
- // TODO(johnniwinther): Handle potentially invalid constant expressions.
- ConstantExpression constant = new BinaryConstantExpression(
- leftConstant,
+ bool isValidAsConstant = constantChecker.checkBinaryExpression(
+ node,
+ constantChecker.createInfo(leftResult),
+ BinaryOperator.LOGICAL_AND,
+ constantChecker.createInfo(rightResult));
+ if (isValidAsConstant) {
+ constant = new BinaryConstantExpression(
+ leftResult.constant,
BinaryOperator.LOGICAL_AND,
- rightConstant);
- registry.setConstant(node, constant);
- return new ConstantResult(node, constant);
+ rightResult.constant);
}
}
-
+ if (constant == null && constantState.requiresConstant) {
+ constant = new ErroneousConstantExpression();
+ }
+ if (constant != null) {
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
return const NoneResult();
}
@@ -1324,20 +1433,27 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ResolutionResult rightResult = visitExpression(right);
registry.registerSendStructure(node, const LogicalOrStructure());
+ ConstantExpression constant;
if (leftResult.isConstant && rightResult.isConstant) {
- ConstantExpression leftConstant = leftResult.constant;
- ConstantExpression rightConstant = rightResult.constant;
- if (leftConstant.getKnownType(coreTypes) == coreTypes.boolType &&
- rightConstant.getKnownType(coreTypes) == coreTypes.boolType) {
- // TODO(johnniwinther): Handle potentially invalid constant expressions.
- ConstantExpression constant = new BinaryConstantExpression(
- leftConstant,
+ bool isValidAsConstant = constantChecker.checkBinaryExpression(
+ node,
+ constantChecker.createInfo(leftResult),
+ BinaryOperator.LOGICAL_OR,
+ constantChecker.createInfo(rightResult));
+ if (isValidAsConstant) {
+ constant = new BinaryConstantExpression(
+ leftResult.constant,
BinaryOperator.LOGICAL_OR,
- rightConstant);
- registry.setConstant(node, constant);
- return new ConstantResult(node, constant);
+ rightResult.constant);
}
}
+ if (constant == null && constantState.requiresConstant) {
+ constant = new ErroneousConstantExpression();
+ }
+ if (constant != null) {
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
return const NoneResult();
}
@@ -1348,7 +1464,14 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
visitExpression(left);
visitExpression(right);
registry.registerSendStructure(node, const IfNullStructure());
- return const NoneResult();
+ ResolutionResult result = const NoneResult();
+ if (constantState.requiresConstant) {
+ ConstantExpression constant = new ErroneousConstantExpression();
+ reporter.reportErrorMessage(node, MessageKind.INVALID_CONSTANT_IF_NULL);
+ registry.setConstant(node, constant);
+ result = new ConstantResult(node, constant);
+ }
+ return result;
}
/// Handle the binary expression of an unresolved binary operator [text], like
@@ -1404,81 +1527,28 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerDynamicInvocation(new UniverseSelector(selector, null));
semantics = const DynamicAccess.expression();
+ ConstantExpression constant;
if (leftResult.isConstant && rightResult.isConstant) {
- bool isValidConstant;
- ConstantExpression leftConstant = leftResult.constant;
- ConstantExpression rightConstant = rightResult.constant;
- DartType knownLeftType = leftConstant.getKnownType(coreTypes);
- DartType knownRightType = rightConstant.getKnownType(coreTypes);
- switch (operator.kind) {
- case BinaryOperatorKind.EQ:
- case BinaryOperatorKind.NOT_EQ:
- isValidConstant =
- (knownLeftType == coreTypes.intType ||
- knownLeftType == coreTypes.doubleType ||
- knownLeftType == coreTypes.stringType ||
- knownLeftType == coreTypes.boolType ||
- knownLeftType == coreTypes.nullType) &&
- (knownRightType == coreTypes.intType ||
- knownRightType == coreTypes.doubleType ||
- knownRightType == coreTypes.stringType ||
- knownRightType == coreTypes.boolType ||
- knownRightType == coreTypes.nullType);
- break;
- case BinaryOperatorKind.ADD:
- isValidConstant =
- (knownLeftType == coreTypes.intType ||
- knownLeftType == coreTypes.doubleType ||
- knownLeftType == coreTypes.stringType) &&
- (knownRightType == coreTypes.intType ||
- knownRightType == coreTypes.doubleType ||
- knownRightType == coreTypes.stringType);
- break;
- case BinaryOperatorKind.SUB:
- case BinaryOperatorKind.MUL:
- case BinaryOperatorKind.DIV:
- case BinaryOperatorKind.IDIV:
- case BinaryOperatorKind.MOD:
- case BinaryOperatorKind.GTEQ:
- case BinaryOperatorKind.GT:
- case BinaryOperatorKind.LTEQ:
- case BinaryOperatorKind.LT:
- isValidConstant =
- (knownLeftType == coreTypes.intType ||
- knownLeftType == coreTypes.doubleType) &&
- (knownRightType == coreTypes.intType ||
- knownRightType == coreTypes.doubleType);
- break;
- case BinaryOperatorKind.SHL:
- case BinaryOperatorKind.SHR:
- case BinaryOperatorKind.AND:
- case BinaryOperatorKind.OR:
- case BinaryOperatorKind.XOR:
- isValidConstant =
- knownLeftType == coreTypes.intType &&
- knownRightType == coreTypes.intType;
- break;
- case BinaryOperatorKind.INDEX:
- isValidConstant = false;
- break;
- case BinaryOperatorKind.LOGICAL_AND:
- case BinaryOperatorKind.LOGICAL_OR:
- case BinaryOperatorKind.IF_NULL:
- reporter.internalError(
- node, "Unexpected binary operator '${operator}'.");
- break;
- }
- if (isValidConstant) {
- // TODO(johnniwinther): Handle potentially invalid constant
- // expressions.
- ConstantExpression constant = new BinaryConstantExpression(
+ //reportHere(compiler, node, 'left=${leftResult.constant.getText()},right=${rightResult.constant.getText()}');
+ bool isValidAsConstant = constantChecker.checkBinaryExpression(
+ node,
+ constantChecker.createInfo(leftResult),
+ operator,
+ constantChecker.createInfo(rightResult));
+ if (isValidAsConstant) {
+ constant = new BinaryConstantExpression(
leftResult.constant,
operator,
rightResult.constant);
- registry.setConstant(node, constant);
- result = new ConstantResult(node, constant);
}
}
+ if (constant == null && constantState.requiresConstant) {
+ constant = new ErroneousConstantExpression();
+ }
+ if (constant != null) {
+ registry.setConstant(node, constant);
+ result = new ConstantResult(node, constant);
+ }
}
if (semantics != null) {
@@ -1546,7 +1616,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
/// `this.name()`, or `name` and `name()` in instance context.
ResolutionResult handleThisPropertyAccess(Send node, Name name) {
AccessSemantics semantics = new DynamicAccess.thisProperty(name);
- return handleDynamicAccessSemantics(node, name, semantics);
+ return handleDynamicAccessSemantics(
+ node, const NoneResult(), name, semantics);
}
/// Handle update of a property of [name] on `this`, like `this.name = b` and
@@ -2059,7 +2130,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ConstantAccess semantics) {
// TODO(johnniwinther): Remove this when all constants are evaluated.
- compiler.resolver.constantCompiler.evaluate(semantics.constant);
+ compiler.resolver.constantCompiler.evaluate(node, semantics.constant);
ErroneousElement error;
if (node.isIfNullAssignment) {
@@ -2131,6 +2202,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ConstantExpression constant =
new TypeConstantExpression(const DynamicType());
AccessSemantics semantics = new ConstantAccess.dynamicTypeLiteral(constant);
+ // TODO(johnniwinther): Remove this when all constants are evaluated.
+ compiler.resolver.constantCompiler.evaluate(node, constant);
return handleConstantTypeLiteralUpdate(
node, const PublicName('dynamic'), compiler.typeClass, type, semantics);
}
@@ -2326,7 +2399,11 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
/// Handle dynamic access of [semantics].
ResolutionResult handleDynamicAccessSemantics(
- Send node, Name name, AccessSemantics semantics) {
+ Send node,
+ ResolutionResult receiverResult,
+ Name name,
+ AccessSemantics semantics) {
+ ResolutionResult result = const NoneResult();
SendStructure sendStructure;
Selector selector;
if (node.isCall) {
@@ -2341,13 +2418,22 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
selector = new Selector.getter(name);
registry.registerDynamicGetter(
new UniverseSelector(selector, null));
+ if (receiverResult.isConstant && name == const PublicName("length")) {
+ if (constantChecker.isStringOrNull(
+ receiverResult.constant.getKnownType(coreTypes))) {
+ ConstantExpression constant =
+ new StringLengthConstantExpression(receiverResult.constant);
+ registry.setConstant(node, constant);
+ result = new ConstantResult(node, constant);
+ }
+ }
sendStructure = new GetStructure(semantics);
}
registry.registerSendStructure(node, sendStructure);
// TODO(23998): Remove this when all information goes through
// the [SendStructure].
registry.setSelector(node, selector);
- return const NoneResult();
+ return result;
}
/// Handle dynamic update of [semantics].
@@ -2418,13 +2504,15 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return handlePrefixSend(node, name, result);
} else if (node.isConditional) {
return handleDynamicAccessSemantics(
- node, name, new DynamicAccess.ifNotNullProperty(name));
+ node, result,
+ name, new DynamicAccess.ifNotNullProperty(name));
} else {
// Handle dynamic property access, like `a.b` or `a.b()` where `a` is not
// a prefix or class.
// TODO(johnniwinther): Use the `element` of [result].
return handleDynamicAccessSemantics(
- node, name, new DynamicAccess.dynamicProperty(name));
+ node, result,
+ name, new DynamicAccess.dynamicProperty(name));
}
}
@@ -2591,7 +2679,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
break;
case AccessKind.PARAMETER:
case AccessKind.FINAL_PARAMETER:
- if (constantState == ConstantState.CONSTANT_INITIALIZER) {
+ if (constantState.parameterReferenceIsConstant) {
ParameterElement parameter = element;
if (parameter.isNamed) {
result = new ConstantResult(
@@ -2782,18 +2870,33 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
switch (semantics.kind) {
case AccessKind.STATIC_METHOD:
case AccessKind.TOPLEVEL_METHOD:
+ MethodElement method = member;
// TODO(johnniwinther): Method this should be registered as a
// closurization.
registry.registerStaticUse(semantics.element);
registry.registerGetOfStaticFunction(semantics.element);
+ result = new ConstantResult(
+ node,
+ new FunctionConstantExpression(method),
+ element: method);
break;
case AccessKind.STATIC_FIELD:
case AccessKind.FINAL_STATIC_FIELD:
- case AccessKind.STATIC_GETTER:
case AccessKind.TOPLEVEL_FIELD:
case AccessKind.FINAL_TOPLEVEL_FIELD:
+ FieldElement field = member;
+ if (field.isConst) {
+ result = new ConstantResult(
+ node, new VariableConstantExpression(field), element: field);
+ } else {
+ result = new ElementResult(field);
+ }
+ registry.registerStaticUse(semantics.element);
+ break;
+ case AccessKind.STATIC_GETTER:
case AccessKind.TOPLEVEL_GETTER:
registry.registerStaticUse(semantics.element);
+ result = new ElementResult(member);
break;
case AccessKind.STATIC_SETTER:
case AccessKind.TOPLEVEL_SETTER:
@@ -2802,6 +2905,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
member = reportAndCreateErroneousElement(
node.selector, name.text,
MessageKind.CANNOT_RESOLVE_GETTER, const {});
+ result = new ElementResult(member);
break;
default:
reporter.internalError(node,
@@ -2813,6 +2917,10 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
FieldElement field = member;
result = new ConstantResult(
node, new VariableConstantExpression(field), element: field);
+ } else if (member.isFunction) {
+ MethodElement function = member;
+ result = new ConstantResult(
+ node, new FunctionConstantExpression(function), element: function);
} else {
result = new ElementResult(member);
}
@@ -3068,16 +3176,21 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
ResolutionResult visitSend(Send node) {
+ ResolutionResult result;
if (node.isOperator) {
// `a && b`, `a + b`, `-a`, or `a is T`.
- return handleOperatorSend(node);
+ result = handleOperatorSend(node);
} else if (node.receiver != null) {
// `a.b`.
- return handleQualifiedSend(node);
+ result = handleQualifiedSend(node);
} else {
// `a`.
- return handleUnqualifiedSend(node);
+ result = handleUnqualifiedSend(node);
}
+ if (result.kind == ResultKind.PREFIX) {
+ return result;
+ }
+ return ensureConstantResult(node, result);
}
/// Register read access of [target] inside a closure.
@@ -3629,6 +3742,9 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.setRedirectingTargetConstructor(node, redirectionTarget);
if (Elements.isUnresolved(redirectionTarget)) {
registry.registerThrowNoSuchMethod();
+ if (isConstConstructor) {
+ constructor.constantConstructor = const ErroneousConstantConstructor();
+ }
return const NoneResult();
} else {
if (isConstConstructor &&
@@ -3709,6 +3825,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
redirectionTarget,
callStructure,
arguments));
+ } else if (isConstConstructor) {
+ constructor.constantConstructor = const ErroneousConstantConstructor();
}
return const NoneResult();
}
@@ -3716,7 +3834,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ResolutionResult visitThrow(Throw node) {
registry.registerThrowExpression();
visit(node.expression);
- return const NoneResult();
+ return ensureConstantResult(node, const NoneResult());
}
ResolutionResult visitAwait(Await node) {
@@ -3799,7 +3917,9 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ResolutionResult visitNewExpression(NewExpression node) {
bool isValidAsConstant = true;
- ConstructorElement constructor = resolveConstructor(node).element;
+ ConstructorResult result = resolveConstructor(node);
+ //reportHere(reporter, node, '$result');
+ ConstructorElement constructor = result.element;
final bool isSymbolConstructor = constructor == compiler.symbolConstructor;
final bool isMirrorsUsedConstant =
node.isConst && (constructor == compiler.mirrorsUsedConstructor);
@@ -3811,13 +3931,26 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
} else {
argumentsResult = resolveArguments(node.send.argumentsNode);
}
+
registry.useElement(node.send, constructor);
if (Elements.isUnresolved(constructor)) {
- return new ResolutionResult.forElement(constructor);
+ if (node.isConst) {
+ ConstantExpression constant = new ErroneousConstantExpression();
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant, element: constructor);
+ }
+ return ensureConstantResult(node,
+ new ResolutionResult.forElement(constructor));
}
constructor.computeType(resolution);
if (!callSelector.applies(constructor, compiler.world)) {
registry.registerThrowNoSuchMethod();
+ if (node.isConst) {
+ // TODO(johnniwinther): Provide a better message.
+ reporter.reportErrorMessage(
+ node, MessageKind.NOT_A_COMPILE_TIME_CONSTANT);
+ }
+ isValidAsConstant = false;
}
// [constructor] might be the implementation element
@@ -3877,6 +4010,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
} else if (isMirrorsUsedConstant) {
compiler.mirrorUsageAnalyzerTask.validate(node, registry.mapping);
}
+
+ ConstantExpression constant;
if (node.isConst) {
analyzeConstantDeferred(node);
@@ -3898,18 +4033,57 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
constructor.isConst &&
argumentsResult.isValidAsConstant) {
CallStructure callStructure = argumentsResult.callStructure;
- List<ConstantExpression> arguments = argumentsResult.constantArguments;
- ConstructedConstantExpression constant =
- new ConstructedConstantExpression(
- type,
- constructor,
- callStructure,
- arguments);
- return new ConstantResult(node, constant);
+ List<ConstantExpression> arguments =
+ argumentsResult.constantArguments;
+ if (constructor.isFromEnvironmentConstructor) {
+ ConstantResult nameResult = argumentsResult.argumentResults[0];
+ ConstantResult defaultValueResult;
+ ConstantExpression defaultValueConstant;
+ if (arguments.length > 1) {
+ defaultValueResult = argumentsResult.argumentResults[1];
+ defaultValueConstant = defaultValueResult.constant;
+ }
+ if (type == coreTypes.boolType) {
+ isValidAsConstant = constantChecker.checkBoolFromEnvironment(
+ constantChecker.createInfo(nameResult),
+ constantChecker.createInfo(defaultValueResult));
+ if (isValidAsConstant) {
+ constant = new BoolFromEnvironmentConstantExpression(
+ nameResult.constant, defaultValueConstant);
+ }
+ } else if (type == coreTypes.intType) {
+ isValidAsConstant = constantChecker.checkIntFromEnvironment(
+ constantChecker.createInfo(nameResult),
+ constantChecker.createInfo(defaultValueResult));
+ if (isValidAsConstant) {
+ constant = new IntFromEnvironmentConstantExpression(
+ nameResult.constant, defaultValueConstant);
+ }
+ } else {
+ assert(type == coreTypes.stringType);
+ isValidAsConstant = constantChecker.checkStringFromEnvironment(
+ constantChecker.createInfo(nameResult),
+ constantChecker.createInfo(defaultValueResult));
+ if (isValidAsConstant) {
+ constant = new StringFromEnvironmentConstantExpression(
+ nameResult.constant, defaultValueConstant);
+ }
+ }
+ } else {
+ constant = new ConstructedConstantExpression(
+ type, constructor, callStructure, arguments);
+ }
+ }
+ if (constant == null) {
+ constant = new ErroneousConstantExpression();
}
}
-
- return const NoneResult();
+ if (constant != null) {
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ } else {
+ return ensureConstantResult(node, const NoneResult());
+ }
}
void checkConstMapKeysDontOverrideEquals(Spannable spannable,
@@ -4054,12 +4228,14 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
});
analyzeConstantDeferred(node);
sendIsMemberAccess = false;
+ ConstantExpression constant;
if (isValidAsConstant) {
- ConstantExpression constant =
- new ListConstantExpression(listType, constantExpressions);
- registry.setConstant(node, constant);
- return new ConstantResult(node, constant);
+ constant = new ListConstantExpression(listType, constantExpressions);
+ } else {
+ constant = new ErroneousConstantExpression();
}
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
} else {
visit(node.elements);
sendIsMemberAccess = false;
@@ -4071,16 +4247,33 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ResolutionResult visitConditional(Conditional node) {
ResolutionResult conditionResult =
doInPromotionScope(node.condition, () => visit(node.condition));
+ assert(checkConstantInvariant(node.condition, conditionResult));
+
ResolutionResult thenResult =
- doInPromotionScope(node.thenExpression, () => visit(node.thenExpression));
+ doInPromotionScope(node.thenExpression,
+ () => visit(node.thenExpression));
+ assert(checkConstantInvariant(node.thenExpression, thenResult));
+
ResolutionResult elseResult = visit(node.elseExpression);
+ assert(checkConstantInvariant(node.elseExpression, elseResult));
+
+ ConstantExpression constant;
if (conditionResult.isConstant &&
thenResult.isConstant &&
elseResult.isConstant) {
- ConstantExpression constant = new ConditionalConstantExpression(
- conditionResult.constant,
- thenResult.constant,
- elseResult.constant);
+ bool isValidAsConstant = constantChecker.checkConditional(
+ constantChecker.createInfo(conditionResult));
+ if (isValidAsConstant) {
+ constant = new ConditionalConstantExpression(
+ conditionResult.constant,
+ thenResult.constant,
+ elseResult.constant);
+ }
+ }
+ if (constant == null && constantState.requiresConstant) {
+ constant = new ErroneousConstantExpression();
+ }
+ if (constant != null) {
registry.setConstant(node, constant);
return new ConstantResult(node, constant);
}
@@ -4095,12 +4288,17 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
bool isValidAsConstant = true;
List<ConstantExpression> parts = <ConstantExpression>[];
+ ConstantExpression constant;
void resolvePart(Node subnode) {
ResolutionResult result = visit(subnode);
- if (isValidAsConstant && result.isConstant) {
- parts.add(result.constant);
- } else {
- isValidAsConstant = false;
+ if (result.isConstant) {
+ bool isPartTypeValid = constantChecker.checkConcatenate(
+ constantChecker.createInfo(result));
+ if (isPartTypeValid) {
+ parts.add(result.constant);
+ } else {
+ isValidAsConstant = false;
+ }
}
}
@@ -4109,9 +4307,12 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
resolvePart(part.expression);
resolvePart(part.string);
}
-
if (isValidAsConstant) {
- ConstantExpression constant = new ConcatenateConstantExpression(parts);
+ constant = new ConcatenateConstantExpression(parts);
+ } else if (constantState.requiresConstant) {
+ constant = new ErroneousConstantExpression();
+ }
+ if (constant != null) {
registry.setConstant(node, constant);
return new ConstantResult(node, constant);
}
@@ -4371,7 +4572,9 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
inConstantContext(() {
for (LiteralMapEntry entry in node.entries) {
ResolutionResult keyResult = visit(entry.key);
+ assert(checkConstantInvariant(entry.key, keyResult));
ResolutionResult valueResult = visit(entry.value);
+ assert(checkConstantInvariant(entry.value, valueResult));
if (isValidAsConstant &&
keyResult.isConstant &&
valueResult.isConstant) {
@@ -4384,12 +4587,15 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
});
analyzeConstantDeferred(node);
sendIsMemberAccess = false;
+ ConstantExpression constant;
if (isValidAsConstant) {
- ConstantExpression constant = new MapConstantExpression(
+ constant = new MapConstantExpression(
mapType, keyExpressions, valueExpressions);
- registry.setConstant(node, constant);
- return new ConstantResult(node, constant);
+ } else {
+ constant = new ErroneousConstantExpression();
}
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
} else {
node.visitChildren(this);
sendIsMemberAccess = false;
@@ -4689,3 +4895,45 @@ Element lookupInScope(DiagnosticReporter reporter, Node node,
Scope scope, String name) {
return Elements.unwrap(scope.lookup(name), reporter, node);
}
+
+class ConstantNodeChecker extends ConstantTypeChecker<Spannable> {
+ final Compiler compiler;
+ final bool constantIsRequired;
+
+ ConstantNodeChecker(this.compiler, {this.constantIsRequired});
+
+ @override
+ bool get allowUnknown => constantIsRequired;
+
+ @override
+ CoreTypes get coreTypes => compiler.coreTypes;
+
+ @override
+ bool get isRequired => constantIsRequired;
+
+ @override
+ void reportError(Spannable position, MessageKind messageKind, Map arguments) {
+ if (constantIsRequired) {
+ compiler.reporter.reportErrorMessage(position, messageKind, arguments);
+ }
+ }
+
+ ConstantTypeInfo createInfo(ResolutionResult result) {
+ if (result == null) return null;
+ return new NodeConstantTypeInfo(
+ result.node, result.constant, result.constant.getKnownType(coreTypes));
+ }
+}
+
+class NodeConstantTypeInfo implements ConstantTypeInfo<Spannable> {
+ final Spannable position;
+ final ConstantExpression constant;
+ final DartType type;
+
+ NodeConstantTypeInfo(this.position, this.constant, this.type);
+
+ String toString() {
+ return 'NodeConstantTypeInfo['
+ 'position=$position,constant=${constant.getText()},type=$type]';
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/resolution/constructors.dart ('k') | pkg/compiler/lib/src/resolution/resolution.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698