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(); |
} |
} |