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

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

Issue 1170673002: Begin to compute constant expressions in resolution. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Fix BinaryConstantExpression.getKnownType Created 5 years, 6 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
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 6069d4cebddd98b67bb58ae935ed13eebc690f1b..fb0d246658580d7499c3d75516d40ca3d644c2e8 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -102,6 +102,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
inCatchBlock = false,
super(compiler, registry);
+ CoreTypes get coreTypes => compiler.coreTypes;
+
AsyncMarker get currentAsyncMarker {
if (enclosingElement is FunctionElement) {
FunctionElement function = enclosingElement;
@@ -166,8 +168,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return result;
}
- visitInStaticContext(Node node) {
- inStaticContext(() => visit(node));
+ ResolutionResult visitInStaticContext(Node node) {
+ return inStaticContext(() => visit(node));
}
ErroneousElement reportAndCreateErroneousElement(
@@ -230,7 +232,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (!inInstanceContext) {
error(node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': node});
}
- return null;
+ return const NoneResult();
} else if (node.isSuper()) {
if (!inInstanceContext) {
error(node, MessageKind.NO_SUPER_IN_STATIC);
@@ -238,7 +240,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if ((ElementCategory.SUPER & allowedCategory) == 0) {
error(node, MessageKind.INVALID_USE_OF_SUPER);
}
- return null;
+ return const NoneResult();
} else {
String name = node.source;
Element element = lookupInScope(compiler, node, scope, name);
@@ -272,7 +274,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
- ResolutionResult visitTypeAnnotation(TypeAnnotation node) {
+ TypeResult visitTypeAnnotation(TypeAnnotation node) {
DartType type = resolveTypeAnnotation(node);
if (inCheckContext) {
registry.registerIsCheck(type);
@@ -358,19 +360,17 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
- visitCascade(Cascade node) {
+ ResolutionResult visitCascade(Cascade node) {
visit(node.expression);
+ return const NoneResult();
}
- visitCascadeReceiver(CascadeReceiver node) {
+ ResolutionResult visitCascadeReceiver(CascadeReceiver node) {
visit(node.expression);
+ return const NoneResult();
}
- visitClassNode(ClassNode node) {
- internalError(node, "shouldn't be called");
- }
-
- visitIn(Node node, Scope nestedScope) {
+ ResolutionResult visitIn(Node node, Scope nestedScope) {
Scope oldScope = scope;
scope = nestedScope;
ResolutionResult result = visit(node);
@@ -382,7 +382,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
* Introduces new default targets for break and continue
* before visiting the body of the loop
*/
- visitLoopBodyIn(Loop loop, Node body, Scope bodyScope) {
+ void visitLoopBodyIn(Loop loop, Node body, Scope bodyScope) {
JumpTarget element = getOrDefineTarget(loop);
statementScope.enterLoop(element);
visitIn(body, bodyScope);
@@ -392,35 +392,42 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
- visitBlock(Block node) {
+ ResolutionResult visitBlock(Block node) {
visitIn(node.statements, new BlockScope(scope));
+ return const NoneResult();
}
- visitDoWhile(DoWhile node) {
+ ResolutionResult visitDoWhile(DoWhile node) {
visitLoopBodyIn(node, node.body, new BlockScope(scope));
visit(node.condition);
+ return const NoneResult();
}
- visitEmptyStatement(EmptyStatement node) { }
+ ResolutionResult visitEmptyStatement(EmptyStatement node) {
+ return const NoneResult();
+ }
- visitExpressionStatement(ExpressionStatement node) {
+ ResolutionResult visitExpressionStatement(ExpressionStatement node) {
ExpressionStatement oldExpressionStatement = currentExpressionStatement;
currentExpressionStatement = node;
visit(node.expression);
currentExpressionStatement = oldExpressionStatement;
+ return const NoneResult();
}
- visitFor(For node) {
+ ResolutionResult visitFor(For node) {
Scope blockScope = new BlockScope(scope);
visitIn(node.initializer, blockScope);
visitIn(node.condition, blockScope);
visitIn(node.update, blockScope);
visitLoopBodyIn(node, node.body, blockScope);
+ return const NoneResult();
}
- visitFunctionDeclaration(FunctionDeclaration node) {
+ ResolutionResult visitFunctionDeclaration(FunctionDeclaration node) {
assert(node.function.name != null);
visitFunctionExpression(node.function, inFunctionDeclaration: true);
+ return const NoneResult();
}
@@ -431,8 +438,9 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
///
/// This is used to distinguish local function declarations from anonymous
/// function expressions.
- visitFunctionExpression(FunctionExpression node,
- {bool inFunctionDeclaration: false}) {
+ ResolutionResult visitFunctionExpression(
+ FunctionExpression node,
+ {bool inFunctionDeclaration: false}) {
bool doAddToScope = inFunctionDeclaration;
if (!inFunctionDeclaration && node.name != null) {
compiler.reportError(
@@ -480,13 +488,15 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerClosure(function);
registry.registerInstantiatedClass(compiler.functionClass);
+ return const NoneResult();
}
- visitIf(If node) {
+ ResolutionResult visitIf(If node) {
doInPromotionScope(node.condition.expression, () => visit(node.condition));
doInPromotionScope(node.thenPart,
() => visitIn(node.thenPart, new BlockScope(scope)));
visitIn(node.elsePart, new BlockScope(scope));
+ return const NoneResult();
}
ResolutionResult resolveSend(Send node) {
@@ -533,26 +543,26 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// TODO(ahe): Why is this using GENERIC?
error(node.selector, MessageKind.GENERIC,
{'text': "expected an identifier"});
- return null;
+ return const NoneResult();
} else if (node.isSuperCall) {
if (node.isOperator) {
if (isUserDefinableOperator(name)) {
name = selector.name;
} else {
error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name});
- return null;
+ return const NoneResult();
}
}
if (!inInstanceContext) {
error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name});
- return null;
+ return const NoneResult();
}
if (currentClass.supertype == null) {
// This is just to guard against internal errors, so no need
// for a real error message.
error(node.receiver, MessageKind.GENERIC,
{'text': "Object has no superclass"});
- return null;
+ return const NoneResult();
}
// TODO(johnniwinther): Ensure correct behavior if currentClass is a
// patch.
@@ -569,9 +579,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerDynamicInvocation(selector);
registry.registerSuperNoSuchMethod();
}
- } else if (resolvedReceiver == null ||
- Elements.isUnresolved(resolvedReceiver.element)) {
- return null;
+ } else if (Elements.isUnresolved(resolvedReceiver.element)) {
+ return const NoneResult();
} else if (resolvedReceiver.element.isClass) {
ClassElement receiverClass = resolvedReceiver.element;
receiverClass.ensureResolved(compiler);
@@ -582,7 +591,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// The following code that looks up the selector on the resolved
// receiver will treat the second as the invocation of a static operator
// if the resolved receiver is not null.
- return null;
+ return const NoneResult();
}
MembersCreator.computeClassMembersByName(
compiler, receiverClass.declaration, name);
@@ -630,7 +639,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
classElement.ensureResolved(compiler);
}
}
- return new ElementResult(target);
+ return new ResolutionResult.forElement(target);
}
static Selector computeSendSelector(Send node,
@@ -897,7 +906,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
registry.registerIsCheck(type);
registry.registerSendStructure(node, sendStructure);
- return null;
+ return const NoneResult();
}
/// Handle a type cast expression, like `a as T`.
@@ -909,7 +918,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
DartType type = resolveTypeAnnotation(typeNode);
registry.registerAsCheck(type);
registry.registerSendStructure(node, new AsStructure(type));
- return null;
+ return const NoneResult();
}
/// Handle the unary expression of an unresolved unary operator [text], like
@@ -923,12 +932,13 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
registry.registerSendStructure(node, const InvalidUnaryStructure());
- return null;
+ return const NoneResult();
}
/// Handle the unary expression of a user definable unary [operator], like
/// `-a`, and `-super`.
ResolutionResult handleUserDefinableUnary(Send node, UnaryOperator operator) {
+ ResolutionResult result = const NoneResult();
Node expression = node.receiver;
Selector selector = operator.selector;
// TODO(johnniwinther): Remove this when all information goes through the
@@ -949,9 +959,38 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.useElement(node, semantics.element);
}
} else {
- visitExpression(expression);
+ ResolutionResult expressionResult = visitExpression(expression);
semantics = new DynamicAccess.dynamicProperty(expression);
registry.registerDynamicInvocation(selector);
+
+ 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:
+ 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);
+ }
+ }
}
if (semantics != null) {
// TODO(johnniwinther): Support invalid super access as an
@@ -959,7 +998,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerSendStructure(node,
new UnaryStructure(semantics, operator));
}
- return null;
+ return result;
}
/// Handle a not expression, like `!a`.
@@ -967,30 +1006,75 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
assert(invariant(node, operator.kind == UnaryOperatorKind.NOT));
Node expression = node.receiver;
- visitExpression(expression);
+ ResolutionResult result = visitExpression(expression);
registry.registerSendStructure(node,
new NotStructure(new DynamicAccess.dynamicProperty(expression)));
- return null;
+
+ 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);
+ }
+ }
+
+ return const NoneResult();
}
/// Handle a logical and expression, like `a && b`.
ResolutionResult handleLogicalAnd(Send node) {
Node left = node.receiver;
Node right = node.arguments.head;
- doInPromotionScope(left, () => visitExpression(left));
- doInPromotionScope(right, () => visitExpression(right));
+ ResolutionResult leftResult =
+ doInPromotionScope(left, () => visitExpression(left));
+ ResolutionResult rightResult =
+ doInPromotionScope(right, () => visitExpression(right));
registry.registerSendStructure(node, const LogicalAndStructure());
- return null;
+
+ 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,
+ BinaryOperator.LOGICAL_AND,
+ rightConstant);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
+ }
+
+ return const NoneResult();
}
/// Handle a logical or expression, like `a || b`.
ResolutionResult handleLogicalOr(Send node) {
Node left = node.receiver;
Node right = node.arguments.head;
- visitExpression(left);
- visitExpression(right);
+ ResolutionResult leftResult = visitExpression(left);
+ ResolutionResult rightResult = visitExpression(right);
registry.registerSendStructure(node, const LogicalOrStructure());
- return null;
+
+ 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,
+ BinaryOperator.LOGICAL_OR,
+ rightConstant);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
+ }
+ return const NoneResult();
}
/// Handle an if-null expression, like `a ?? b`.
@@ -1000,7 +1084,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
visitExpression(left);
visitExpression(right);
registry.registerSendStructure(node, const IfNullStructure());
- return null;
+ return const NoneResult();
}
/// Handle the binary expression of an unresolved binary operator [text], like
@@ -1015,13 +1099,14 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
visitExpression(right);
registry.registerSendStructure(node, const InvalidBinaryStructure());
- return null;
+ return const NoneResult();
}
/// Handle the binary expression of a user definable binary [operator], like
/// `a + b`, `super + b`, `a == b` and `a != b`.
ResolutionResult handleUserDefinableBinary(Send node,
BinaryOperator operator) {
+ ResolutionResult result = const NoneResult();
Node left = node.receiver;
Node right = node.arguments.head;
AccessSemantics semantics;
@@ -1047,12 +1132,88 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// the [SendStructure].
registry.useElement(node, semantics.element);
}
+ visitExpression(right);
} else {
- visitExpression(left);
+ ResolutionResult leftResult = visitExpression(left);
+ ResolutionResult rightResult = visitExpression(right);
registry.registerDynamicInvocation(selector);
semantics = new DynamicAccess.dynamicProperty(left);
+
+ if (leftResult.isConstant && rightResult.isConstant) {
+ bool isValidConstant;
+ ConstantExpression leftConstant = leftResult.constant;
+ ConstantExpression rightConstant = leftResult.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:
+ internalError(node, "Unexpected binary operator '${operator}'.");
+ break;
+ }
+ if (isValidConstant) {
+ // TODO(johnniwinther): Handle potentially invalid constant
+ // expressions.
+ ConstantExpression constant = new BinaryConstantExpression(
+ leftResult.constant,
+ operator,
+ rightResult.constant);
+ registry.setConstant(node, constant);
+ result = new ConstantResult(node, constant);
+ }
+ }
}
- visitExpression(right);
if (semantics != null) {
// TODO(johnniwinther): Support invalid super access as an
@@ -1093,7 +1254,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
registry.registerSendStructure(node, sendStructure);
}
- return null;
+ return result;
}
/// Handle an invocation of an expression, like `(){}()` or `(foo)()`.
@@ -1110,7 +1271,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerDynamicInvocation(selector);
registry.registerSendStructure(node,
new InvokeStructure(new AccessSemantics.expression(), selector));
- return null;
+ return const NoneResult();
}
/// Handle a, possibly invalid, assertion, like `assert(cond)` or `assert()`.
@@ -1162,7 +1323,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// TODO(johnniwinther): Remove this when all information goes through
// the [SendStructure].
registry.setSelector(node, selector);
- return null;
+ return const NoneResult();
}
/// Handle access on `this`, like `this()` and `this` when it is parsed as a
@@ -1186,7 +1347,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// TODO(johnniwinther): Handle get of `this` when it is a [Send] node.
internalError(node, "Unexpected node '$node'.");
}
- return null;
+ return const NoneResult();
}
/// Handle access of a super property, like `super.foo` and `super.foo()`.
@@ -1265,7 +1426,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// the [SendStructure].
registry.useElement(node, target);
registry.setSelector(node, selector);
- return null;
+ return const NoneResult();
}
/// Handle a [Send] whose selector is an [Operator], like `a && b`, `a is T`,
@@ -1341,7 +1502,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
// TODO(johnniwinther): Handle invalid this access as an
// [AccessSemantics].
- return null;
+ return const NoneResult();
}
// TODO(johnniwinther): Handle remaining qualified sends.
return oldVisitSend(node);
@@ -1372,7 +1533,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.setSelector(node, selector);
registry.useElement(node, element);
registry.registerSendStructure(node, sendStructure);
- return null;
+ return const NoneResult();
}
/// Handle an unqualified [Send], that is where the `node.receiver` is null,
@@ -1429,7 +1590,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ResolutionResult result = resolveSend(node);
sendIsMemberAccess = oldSendIsMemberAccess;
- Element target = result != null ? result.element : null;
+ Element target = result.element;
if (target != null
&& target == compiler.mirrorSystemGetNameFunction
@@ -1482,7 +1643,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// If the selector is null, it means that we will not be generating
// code for this as a send.
Selector selector = registry.getSelector(node);
- if (selector == null) return null;
+ if (selector == null) return const NoneResult();
if (node.isCall) {
if (Elements.isUnresolved(target) ||
@@ -1535,7 +1696,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (node.isPropertyAccess && Elements.isStaticOrTopLevelFunction(target)) {
registry.registerGetOfStaticFunction(target.declaration);
}
- return node.isPropertyAccess ? new ElementResult(target) : null;
+ return node.isPropertyAccess
+ ? new ResolutionResult.forElement(target) : const NoneResult();
}
/// Callback for native enqueuer to parse a type. Returns [:null:] on error.
@@ -1553,7 +1715,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
sendIsMemberAccess = node.isPropertyAccess || node.isCall;
ResolutionResult result = resolveSend(node);
sendIsMemberAccess = oldSendIsMemberAccess;
- Element target = result != null ? result.element : null;
+ Element target = result.element;
Element setter = target;
Element getter = target;
String operatorName = node.assignmentOperator.source;
@@ -1677,7 +1839,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
registerSend(selector, setter);
- return new ElementResult(registry.useElement(node, setter));
+ return new ResolutionResult.forElement(registry.useElement(node, setter));
}
void registerSend(Selector selector, Element target) {
@@ -1700,60 +1862,90 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
- visitLiteralInt(LiteralInt node) {
- registry.registerInstantiatedClass(compiler.intClass);
+ ConstantResult visitLiteralInt(LiteralInt node) {
+ registry.registerInstantiatedType(coreTypes.intType);
+ ConstantExpression constant = new IntConstantExpression(node.value);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
}
- visitLiteralDouble(LiteralDouble node) {
- registry.registerInstantiatedClass(compiler.doubleClass);
+ ConstantResult visitLiteralDouble(LiteralDouble node) {
+ registry.registerInstantiatedType(coreTypes.doubleType);
+ ConstantExpression constant = new DoubleConstantExpression(node.value);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
}
- visitLiteralBool(LiteralBool node) {
- registry.registerInstantiatedClass(compiler.boolClass);
+ ConstantResult visitLiteralBool(LiteralBool node) {
+ registry.registerInstantiatedType(coreTypes.boolType);
+ ConstantExpression constant = new BoolConstantExpression(node.value);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
}
- visitLiteralString(LiteralString node) {
- registry.registerInstantiatedClass(compiler.stringClass);
+ ResolutionResult visitLiteralString(LiteralString node) {
+ registry.registerInstantiatedType(coreTypes.stringType);
+ if (node.dartString != null) {
+ // [dartString] might be null on parser errors.
+ ConstantExpression constant =
+ new StringConstantExpression(node.dartString.slowToString());
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
+ return const NoneResult();
}
- visitLiteralNull(LiteralNull node) {
- registry.registerInstantiatedClass(compiler.nullClass);
+ ConstantResult visitLiteralNull(LiteralNull node) {
+ registry.registerInstantiatedType(coreTypes.nullType);
+ ConstantExpression constant = new NullConstantExpression();
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
}
- visitLiteralSymbol(LiteralSymbol node) {
+ ConstantResult visitLiteralSymbol(LiteralSymbol node) {
registry.registerInstantiatedClass(compiler.symbolClass);
registry.registerStaticUse(compiler.symbolConstructor.declaration);
- registry.registerConstSymbol(node.slowNameString);
- if (!validateSymbol(node, node.slowNameString, reportError: false)) {
+ String name = node.slowNameString;
+ registry.registerConstSymbol(name);
+ if (!validateSymbol(node, name, reportError: false)) {
compiler.reportError(node,
MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
- {'value': node.slowNameString});
+ {'value': name});
}
analyzeConstantDeferred(node);
+ ConstantExpression constant = new SymbolConstantExpression(name);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
}
- visitStringJuxtaposition(StringJuxtaposition node) {
- registry.registerInstantiatedClass(compiler.stringClass);
- node.visitChildren(this);
+ ResolutionResult visitStringJuxtaposition(StringJuxtaposition node) {
+ registry.registerInstantiatedType(coreTypes.stringType);
+ ResolutionResult first = visit(node.first);
+ ResolutionResult second = visit(node.second);
+ if (first.isConstant && second.isConstant) {
+ ConstantExpression constant = new ConcatenateConstantExpression(
+ <ConstantExpression>[first.constant, second.constant]);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
+ return const NoneResult();
}
- visitNodeList(NodeList node) {
+ ResolutionResult visitNodeList(NodeList node) {
for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
visit(link.head);
}
+ return const NoneResult();
}
- visitOperator(Operator node) {
- internalError(node, 'operator');
- }
-
- visitRethrow(Rethrow node) {
+ ResolutionResult visitRethrow(Rethrow node) {
if (!inCatchBlock) {
error(node, MessageKind.THROW_WITHOUT_EXPRESSION);
}
+ return const NoneResult();
}
- visitReturn(Return node) {
+ ResolutionResult visitReturn(Return node) {
Node expression = node.expression;
if (expression != null) {
if (enclosingElement.isGenerativeConstructor) {
@@ -1770,15 +1962,17 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
visit(node.expression);
+ return const NoneResult();
}
- visitYield(Yield node) {
+ ResolutionResult visitYield(Yield node) {
compiler.streamClass.ensureResolved(compiler);
compiler.iterableClass.ensureResolved(compiler);
visit(node.expression);
+ return const NoneResult();
}
- visitRedirectingFactoryBody(RedirectingFactoryBody node) {
+ ResolutionResult visitRedirectingFactoryBody(RedirectingFactoryBody node) {
final isSymbolConstructor = enclosingElement == compiler.symbolConstructor;
if (!enclosingElement.isFactoryConstructor) {
compiler.reportError(
@@ -1802,7 +1996,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.setRedirectingTargetConstructor(node, redirectionTarget);
if (Elements.isUnresolved(redirectionTarget)) {
registry.registerThrowNoSuchMethod();
- return;
+ return const NoneResult();
} else {
if (isConstConstructor &&
!redirectionTarget.isConst) {
@@ -1848,19 +2042,22 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (isSymbolConstructor) {
registry.registerSymbolConstructor();
}
+ return const NoneResult();
}
- visitThrow(Throw node) {
+ ResolutionResult visitThrow(Throw node) {
registry.registerThrowExpression();
visit(node.expression);
+ return const NoneResult();
}
- visitAwait(Await node) {
+ ResolutionResult visitAwait(Await node) {
compiler.futureClass.ensureResolved(compiler);
visit(node.expression);
+ return const NoneResult();
}
- visitVariableDefinitions(VariableDefinitions node) {
+ ResolutionResult visitVariableDefinitions(VariableDefinitions node) {
DartType type;
if (node.type != null) {
type = resolveTypeAnnotation(node.type);
@@ -1905,22 +2102,28 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
compiler.resolver.resolveMetadata(enclosingElement, node);
}
visitor.visit(node.definitions);
+ return const NoneResult();
}
- visitWhile(While node) {
+ ResolutionResult visitWhile(While node) {
visit(node.condition);
visitLoopBodyIn(node, node.body, new BlockScope(scope));
+ return const NoneResult();
}
- visitParenthesizedExpression(ParenthesizedExpression node) {
+ ResolutionResult visitParenthesizedExpression(ParenthesizedExpression node) {
bool oldSendIsMemberAccess = sendIsMemberAccess;
sendIsMemberAccess = false;
var oldCategory = allowedCategory;
allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
| ElementCategory.IMPLIES_TYPE;
- visit(node.expression);
+ ResolutionResult result = visit(node.expression);
allowedCategory = oldCategory;
sendIsMemberAccess = oldSendIsMemberAccess;
+ if (result.kind == ResultKind.CONSTANT) {
+ return result;
+ }
+ return const NoneResult();
}
ResolutionResult visitNewExpression(NewExpression node) {
@@ -1933,7 +2136,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
resolveArguments(node.send.argumentsNode);
registry.useElement(node.send, constructor);
if (Elements.isUnresolved(constructor)) {
- return new ElementResult(constructor);
+ return new ResolutionResult.forElement(constructor);
}
constructor.computeSignature(compiler);
if (!callSelector.applies(constructor, compiler.world)) {
@@ -1971,7 +2174,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
argumentNode, registry.mapping);
ConstantValue name = compiler.constants.getConstantValue(constant);
if (!name.isString) {
- DartType type = name.getType(compiler.coreTypes);
+ DartType type = name.getType(coreTypes);
compiler.reportError(argumentNode, MessageKind.STRING_EXPECTED,
{'type': type});
} else {
@@ -1997,7 +2200,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
analyzeConstantDeferred(node);
}
- return null;
+ return const NoneResult();
}
void checkConstMapKeysDontOverrideEquals(Spannable spannable,
@@ -2105,12 +2308,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return type;
}
- visitModifiers(Modifiers node) {
- internalError(node, 'modifiers');
- }
-
- visitLiteralList(LiteralList node) {
- bool oldSendIsMemberAccess = sendIsMemberAccess;
+ ResolutionResult visitLiteralList(LiteralList node) {
+ bool isValidAsConstant = true;
sendIsMemberAccess = false;
NodeList arguments = node.typeArguments;
@@ -2120,6 +2319,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (nodes.isEmpty) {
// The syntax [: <>[] :] is not allowed.
error(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
+ isValidAsConstant = false;
} else {
typeArgument = resolveTypeAnnotation(nodes.head);
for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
@@ -2133,47 +2333,98 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (node.isConst && typeArgument.containsTypeVariables) {
compiler.reportError(arguments.nodes.head,
MessageKind.TYPE_VARIABLE_IN_CONSTANT);
+ isValidAsConstant = false;
}
- listType = new InterfaceType(compiler.listClass, [typeArgument]);
+ listType = coreTypes.listType(typeArgument);
} else {
- compiler.listClass.computeType(compiler);
- listType = compiler.listClass.rawType;
+ listType = coreTypes.listType();
}
registry.setType(node, listType);
registry.registerInstantiatedType(listType);
registry.registerRequiredType(listType, enclosingElement);
- visit(node.elements);
if (node.isConst) {
+ List<ConstantExpression> constantExpressions = <ConstantExpression>[];
+ for (Node element in node.elements) {
+ ResolutionResult elementResult = visit(element);
+ if (isValidAsConstant && elementResult.isConstant) {
+ constantExpressions.add(elementResult.constant);
+ } else {
+ isValidAsConstant = false;
+ }
+ }
analyzeConstantDeferred(node);
+ sendIsMemberAccess = false;
+ if (isValidAsConstant) {
+ ConstantExpression constant =
+ new ListConstantExpression(listType, constantExpressions);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
+ } else {
+ visit(node.elements);
+ sendIsMemberAccess = false;
}
+ return const NoneResult();
- sendIsMemberAccess = false;
}
- visitConditional(Conditional node) {
- doInPromotionScope(node.condition, () => visit(node.condition));
- doInPromotionScope(node.thenExpression, () => visit(node.thenExpression));
- visit(node.elseExpression);
+ ResolutionResult visitConditional(Conditional node) {
+ ResolutionResult conditionResult =
+ doInPromotionScope(node.condition, () => visit(node.condition));
+ ResolutionResult thenResult =
+ doInPromotionScope(node.thenExpression, () => visit(node.thenExpression));
+ ResolutionResult elseResult = visit(node.elseExpression);
+ if (conditionResult.isConstant &&
+ thenResult.isConstant &&
+ elseResult.isConstant) {
+ ConstantExpression constant = new ConditionalConstantExpression(
+ conditionResult.constant,
+ thenResult.constant,
+ elseResult.constant);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
+ return const NoneResult();
}
- visitStringInterpolation(StringInterpolation node) {
- registry.registerInstantiatedClass(compiler.stringClass);
+ ResolutionResult visitStringInterpolation(StringInterpolation node) {
+ registry.registerInstantiatedType(coreTypes.stringType);
registry.registerStringInterpolation();
- node.visitChildren(this);
- }
-
- visitStringInterpolationPart(StringInterpolationPart node) {
registerImplicitInvocation('toString', 0);
- node.visitChildren(this);
+
+ bool isValidAsConstant = true;
+ List<ConstantExpression> parts = <ConstantExpression>[];
+
+ void resolvePart(Node subnode) {
+ ResolutionResult result = visit(subnode);
+ if (isValidAsConstant && result.isConstant) {
+ parts.add(result.constant);
+ } else {
+ isValidAsConstant = false;
+ }
+ }
+
+ resolvePart(node.string);
+ for (StringInterpolationPart part in node.parts) {
+ resolvePart(part.expression);
+ resolvePart(part.string);
+ }
+
+ if (isValidAsConstant) {
+ ConstantExpression constant = new ConcatenateConstantExpression(parts);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
+ return const NoneResult();
}
- visitBreakStatement(BreakStatement node) {
+ ResolutionResult visitBreakStatement(BreakStatement node) {
JumpTarget target;
if (node.target == null) {
target = statementScope.currentBreakTarget();
if (target == null) {
error(node, MessageKind.NO_BREAK_TARGET);
- return;
+ return const NoneResult();
}
target.isBreakTarget = true;
} else {
@@ -2181,26 +2432,27 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
LabelDefinition label = statementScope.lookupLabel(labelName);
if (label == null) {
error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
- return;
+ return const NoneResult();
}
target = label.target;
if (!target.statement.isValidBreakTarget()) {
error(node.target, MessageKind.INVALID_BREAK);
- return;
+ return const NoneResult();
}
label.setBreakTarget();
registry.useLabel(node, label);
}
registry.registerTargetOf(node, target);
+ return const NoneResult();
}
- visitContinueStatement(ContinueStatement node) {
+ ResolutionResult visitContinueStatement(ContinueStatement node) {
JumpTarget target;
if (node.target == null) {
target = statementScope.currentContinueTarget();
if (target == null) {
error(node, MessageKind.NO_CONTINUE_TARGET);
- return;
+ return const NoneResult();
}
target.isContinueTarget = true;
} else {
@@ -2208,7 +2460,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
LabelDefinition label = statementScope.lookupLabel(labelName);
if (label == null) {
error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
- return;
+ return const NoneResult();
}
target = label.target;
if (!target.statement.isValidContinueTarget()) {
@@ -2218,6 +2470,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.useLabel(node, label);
}
registry.registerTargetOf(node, target);
+ return const NoneResult();
}
registerImplicitInvocation(String name, int arity) {
@@ -2225,7 +2478,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerDynamicInvocation(selector);
}
- visitAsyncForIn(AsyncForIn node) {
+ ResolutionResult visitAsyncForIn(AsyncForIn node) {
registry.registerAsyncForIn(node);
registry.setCurrentSelector(node, compiler.currentSelector);
registry.registerDynamicGetter(compiler.currentSelector);
@@ -2237,9 +2490,10 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
Scope blockScope = new BlockScope(scope);
visitForInDeclaredIdentifierIn(node.declaredIdentifier, node, blockScope);
visitLoopBodyIn(node, node.body, blockScope);
+ return const NoneResult();
}
- visitSyncForIn(SyncForIn node) {
+ ResolutionResult visitSyncForIn(SyncForIn node) {
registry.registerSyncForIn(node);
registry.setIteratorSelector(node, compiler.iteratorSelector);
registry.registerDynamicGetter(compiler.iteratorSelector);
@@ -2253,10 +2507,13 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
Scope blockScope = new BlockScope(scope);
visitForInDeclaredIdentifierIn(node.declaredIdentifier, node, blockScope);
visitLoopBodyIn(node, node.body, blockScope);
+ return const NoneResult();
}
- visitForInDeclaredIdentifierIn(Node declaration, ForIn node,
- Scope blockScope) {
+ void visitForInDeclaredIdentifierIn(
+ Node declaration,
+ ForIn node,
+ Scope blockScope) {
LibraryElement library = enclosingElement.library;
bool oldAllowFinalWithoutInitializer = allowFinalWithoutInitializer;
@@ -2313,7 +2570,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// Labels are handled by their containing statements/cases.
}
- visitLabeledStatement(LabeledStatement node) {
+ ResolutionResult visitLabeledStatement(LabeledStatement node) {
Statement body = node.statement;
JumpTarget targetElement = getOrDefineTarget(body);
Map<String, LabelDefinition> labelElements = <String, LabelDefinition>{};
@@ -2337,9 +2594,11 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (!targetElement.isTarget) {
registry.undefineTarget(body);
}
+ return const NoneResult();
}
- visitLiteralMap(LiteralMap node) {
+ ResolutionResult visitLiteralMap(LiteralMap node) {
+ bool isValidAsConstant = true;
sendIsMemberAccess = false;
NodeList arguments = node.typeArguments;
@@ -2350,6 +2609,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (nodes.isEmpty) {
// The syntax [: <>{} :] is not allowed.
error(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
+ isValidAsConstant = false;
} else {
keyTypeArgument = resolveTypeAnnotation(nodes.head);
nodes = nodes.tail;
@@ -2366,32 +2626,54 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
DartType mapType;
if (valueTypeArgument != null) {
- mapType = new InterfaceType(compiler.mapClass,
- [keyTypeArgument, valueTypeArgument]);
+ mapType = coreTypes.mapType(keyTypeArgument, valueTypeArgument);
} else {
- compiler.mapClass.computeType(compiler);
- mapType = compiler.mapClass.rawType;
+ mapType = coreTypes.mapType();
}
if (node.isConst && mapType.containsTypeVariables) {
compiler.reportError(arguments,
MessageKind.TYPE_VARIABLE_IN_CONSTANT);
+ isValidAsConstant = false;
}
registry.registerMapLiteral(node, mapType, node.isConst);
registry.registerRequiredType(mapType, enclosingElement);
- node.visitChildren(this);
if (node.isConst) {
+ List<ConstantExpression> keyExpressions = <ConstantExpression>[];
+ List<ConstantExpression> valueExpressions = <ConstantExpression>[];
+ for (LiteralMapEntry entry in node.entries) {
+ ResolutionResult keyResult = visit(entry.key);
+ ResolutionResult valueResult = visit(entry.value);
+ if (isValidAsConstant &&
+ keyResult.isConstant &&
+ valueResult.isConstant) {
+ keyExpressions.add(keyResult.constant);
+ valueExpressions.add(valueResult.constant);
+ } else {
+ isValidAsConstant = false;
+ }
+ }
analyzeConstantDeferred(node);
+ sendIsMemberAccess = false;
+ if (isValidAsConstant) {
+ ConstantExpression constant = new MapConstantExpression(
+ mapType, keyExpressions, valueExpressions);
+ registry.setConstant(node, constant);
+ return new ConstantResult(node, constant);
+ }
+ } else {
+ node.visitChildren(this);
+ sendIsMemberAccess = false;
}
-
- sendIsMemberAccess = false;
+ return const NoneResult();
}
- visitLiteralMapEntry(LiteralMapEntry node) {
+ ResolutionResult visitLiteralMapEntry(LiteralMapEntry node) {
node.visitChildren(this);
+ return const NoneResult();
}
- visitNamedArgument(NamedArgument node) {
- visit(node.expression);
+ ResolutionResult visitNamedArgument(NamedArgument node) {
+ return visit(node.expression);
}
DartType typeOfConstant(ConstantValue constant) {
@@ -2476,7 +2758,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
- visitSwitchStatement(SwitchStatement node) {
+ ResolutionResult visitSwitchStatement(SwitchStatement node) {
node.expression.accept(this);
JumpTarget breakElement = getOrDefineTarget(node);
@@ -2547,27 +2829,31 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// TODO(15575): We should warn if we can detect a fall through
// error.
registry.registerFallThroughError();
+ return const NoneResult();
}
- visitSwitchCase(SwitchCase node) {
+ ResolutionResult visitSwitchCase(SwitchCase node) {
node.labelsAndCases.accept(this);
visitIn(node.statements, new BlockScope(scope));
+ return const NoneResult();
}
- visitCaseMatch(CaseMatch node) {
+ ResolutionResult visitCaseMatch(CaseMatch node) {
visit(node.expression);
+ return const NoneResult();
}
- visitTryStatement(TryStatement node) {
+ ResolutionResult visitTryStatement(TryStatement node) {
visit(node.tryBlock);
if (node.catchBlocks.isEmpty && node.finallyBlock == null) {
error(node.getEndToken().next, MessageKind.NO_CATCH_NOR_FINALLY);
}
visit(node.catchBlocks);
visit(node.finallyBlock);
+ return const NoneResult();
}
- visitCatchBlock(CatchBlock node) {
+ ResolutionResult visitCatchBlock(CatchBlock node) {
registry.registerCatchStatement();
// Check that if catch part is present, then
// it has one or two formal parameters.
@@ -2637,10 +2923,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerInstantiatedClass(compiler.stackTraceClass);
stackTraceElement.variables.type = compiler.stackTraceClass.rawType;
}
- }
-
- visitTypedef(Typedef node) {
- internalError(node, 'typedef');
+ return const NoneResult();
}
}
« no previous file with comments | « pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart ('k') | pkg/compiler/lib/src/resolution/registry.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698