Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/resolution/members.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart |
| index b60dfc7b65f51df030f7e8f797399c5906c96369..d724e81b3c202dec5d6dff813462cd719b265733 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart |
| @@ -1953,7 +1953,7 @@ abstract class MappingVisitor<T> extends CommonResolverVisitor<T> { |
| * Do not subclass or instantiate this class outside this library |
| * except for testing. |
| */ |
| -class ResolverVisitor extends MappingVisitor<Element> { |
| +class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| /** |
| * The current enclosing element for the visited AST nodes. |
| * |
| @@ -2109,7 +2109,7 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| return new ErroneousElementX(kind, arguments, name, enclosingElement); |
| } |
| - Element visitIdentifier(Identifier node) { |
| + ResolutionResult visitIdentifier(Identifier node) { |
| if (node.isThis()) { |
| if (!inInstanceContext) { |
| error(node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': node}); |
| @@ -2152,19 +2152,16 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| ClassElement classElement = element; |
| classElement.ensureResolved(compiler); |
| } |
| - return registry.useElement(node, element); |
| + return new ElementResult(registry.useElement(node, element)); |
| } |
| } |
| - Element visitTypeAnnotation(TypeAnnotation node) { |
| + ResolutionResult visitTypeAnnotation(TypeAnnotation node) { |
| DartType type = resolveTypeAnnotation(node); |
| - if (type != null) { |
| - if (inCheckContext) { |
| - registry.registerIsCheck(type); |
| - } |
| - return type.element; |
| + if (inCheckContext) { |
| + registry.registerIsCheck(type); |
| } |
| - return null; |
| + return new TypeResult(type); |
| } |
| bool isNamedConstructor(Send node) => node.receiver != null; |
| @@ -2254,9 +2251,9 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| visitIn(Node node, Scope nestedScope) { |
| Scope oldScope = scope; |
| scope = nestedScope; |
| - Element element = visit(node); |
| + ResolutionResult result = visit(node); |
| scope = oldScope; |
| - return element; |
| + return result; |
| } |
| /** |
| @@ -2348,7 +2345,7 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| visitIn(node.elsePart, new BlockScope(scope)); |
| } |
| - Element resolveSend(Send node) { |
| + ResolutionResult resolveSend(Send node) { |
| Selector selector = resolveSelector(node, null); |
| if (node.isSuperCall) registry.registerSuperUse(node); |
| @@ -2366,9 +2363,7 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| {'argumentCount': selector.namedArgumentCount}); |
| } |
| registry.registerAssert(node); |
| - // TODO(johnniwinther): Return a marker to indicated that this is |
| - // a call to assert. |
| - return null; |
| + return const AssertResult(); |
| } |
| return node.selector.accept(this); |
| @@ -2376,7 +2371,7 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| var oldCategory = allowedCategory; |
| allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER; |
| - Element resolvedReceiver = visit(node.receiver); |
| + ResolutionResult resolvedReceiver = visit(node.receiver); |
| allowedCategory = oldCategory; |
| Element target; |
|
karlklose
2014/07/03 08:36:04
Target could be a ResolutionResult.
Johnni Winther
2014/07/03 12:11:35
Not as easy as it looks. Will do it in a later CL.
|
| @@ -2418,10 +2413,11 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| registry.registerDynamicInvocation(selector); |
| registry.registerSuperNoSuchMethod(); |
| } |
| - } else if (Elements.isUnresolved(resolvedReceiver)) { |
| + } else if (resolvedReceiver == null || |
| + Elements.isUnresolved(resolvedReceiver.element)) { |
| return null; |
| - } else if (resolvedReceiver.isClass) { |
| - ClassElement receiverClass = resolvedReceiver; |
| + } else if (resolvedReceiver.element.isClass) { |
| + ClassElement receiverClass = resolvedReceiver.element; |
| receiverClass.ensureResolved(compiler); |
| if (node.isOperator) { |
| // When the resolved receiver is a class, we can have two cases: |
| @@ -2447,18 +2443,18 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| MessageKind kind = (target == null) |
| ? MessageKind.MEMBER_NOT_FOUND |
| : MessageKind.MEMBER_NOT_STATIC; |
| - return warnAndCreateErroneousElement(node, name, kind, |
| - {'className': receiverClass.name, |
| - 'memberName': name}); |
| + return new ElementResult(warnAndCreateErroneousElement( |
|
karlklose
2014/07/03 08:36:04
Change warnAndCreateErroneousElement to return the
Johnni Winther
2014/07/03 12:11:35
Not as easy as it looks. Will do it in a later CL.
|
| + node, name, kind, |
| + {'className': receiverClass.name, 'memberName': name})); |
| } |
| - } else if (identical(resolvedReceiver.kind, ElementKind.PREFIX)) { |
| - PrefixElement prefix = resolvedReceiver; |
| + } else if (resolvedReceiver.element.isPrefix) { |
| + PrefixElement prefix = resolvedReceiver.element; |
| target = prefix.lookupLocalMember(name); |
| if (Elements.isUnresolved(target)) { |
| registry.registerThrowNoSuchMethod(); |
| - return warnAndCreateErroneousElement( |
| + return new ElementResult(warnAndCreateErroneousElement( |
| node, name, MessageKind.NO_SUCH_LIBRARY_MEMBER, |
| - {'libraryName': prefix.name, 'memberName': name}); |
| + {'libraryName': prefix.name, 'memberName': name})); |
| } else if (target.isAmbiguous) { |
| registry.registerThrowNoSuchMethod(); |
| AmbiguousElement ambiguous = target; |
| @@ -2466,13 +2462,13 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| ambiguous.messageKind, |
| ambiguous.messageArguments); |
| ambiguous.diagnose(enclosingElement, compiler); |
| - return target; |
| + return new ElementResult(target); |
| } else if (target.kind == ElementKind.CLASS) { |
| ClassElement classElement = target; |
| classElement.ensureResolved(compiler); |
| } |
| } |
| - return target; |
| + return new ElementResult(target); |
| } |
| static Selector computeSendSelector(Send node, |
| @@ -2575,17 +2571,19 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| sendIsMemberAccess = oldSendIsMemberAccess; |
| } |
| - visitSend(Send node) { |
| + ResolutionResult visitSend(Send node) { |
| bool oldSendIsMemberAccess = sendIsMemberAccess; |
| sendIsMemberAccess = node.isPropertyAccess || node.isCall; |
| - Element target; |
| + ResolutionResult result; |
| if (node.isLogicalAnd) { |
| - target = doInPromotionScope(node.receiver, () => resolveSend(node)); |
| + result = doInPromotionScope(node.receiver, () => resolveSend(node)); |
| } else { |
| - target = resolveSend(node); |
| + result = resolveSend(node); |
| } |
| sendIsMemberAccess = oldSendIsMemberAccess; |
| + Element target = result != null ? result.element : null; |
| + |
| if (target != null |
| && target == compiler.mirrorSystemGetNameFunction |
| && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) { |
| @@ -2727,7 +2725,7 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| if (node.isPropertyAccess && Elements.isStaticOrTopLevelFunction(target)) { |
| registry.registerGetOfStaticFunction(target.declaration); |
| } |
| - return node.isPropertyAccess ? target : null; |
| + return node.isPropertyAccess ? new ElementResult(target) : null; |
| } |
| /// Callback for native enqueuer to parse a type. Returns [:null:] on error. |
| @@ -2741,17 +2739,18 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| return cls.computeType(compiler); |
| } |
| - visitSendSet(SendSet node) { |
| + ResolutionResult visitSendSet(SendSet node) { |
| bool oldSendIsMemberAccess = sendIsMemberAccess; |
| sendIsMemberAccess = node.isPropertyAccess || node.isCall; |
| - Element target = resolveSend(node); |
| + ResolutionResult result = resolveSend(node); |
| sendIsMemberAccess = oldSendIsMemberAccess; |
| + Element target = result != null ? result.element : null; |
| Element setter = target; |
| Element getter = target; |
| String operatorName = node.assignmentOperator.source; |
| String source = operatorName; |
| bool isComplex = !identical(source, '='); |
| - if (!(registry.isAssert(node) || Elements.isUnresolved(target))) { |
| + if (!(result is AssertResult || Elements.isUnresolved(target))) { |
| if (target.isAbstractField) { |
| AbstractFieldElement field = target; |
| setter = field.setter; |
| @@ -2838,7 +2837,7 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| } |
| registerSend(selector, setter); |
| - return registry.useElement(node, setter); |
| + return new ElementResult(registry.useElement(node, setter)); |
| } |
| void registerSend(Selector selector, Element target) { |
| @@ -3059,7 +3058,7 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| sendIsMemberAccess = oldSendIsMemberAccess; |
| } |
| - visitNewExpression(NewExpression node) { |
| + ResolutionResult visitNewExpression(NewExpression node) { |
| Node selector = node.send.selector; |
| FunctionElement constructor = resolveConstructor(node); |
| final bool isSymbolConstructor = constructor == compiler.symbolConstructor; |
| @@ -3068,7 +3067,9 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| Selector callSelector = resolveSelector(node.send, constructor); |
| resolveArguments(node.send.argumentsNode); |
| registry.useElement(node.send, constructor); |
| - if (Elements.isUnresolved(constructor)) return constructor; |
| + if (Elements.isUnresolved(constructor)) { |
| + return new ElementResult(constructor); |
| + } |
| if (!callSelector.applies(constructor, compiler)) { |
| registry.registerThrowNoSuchMethod(); |
| } |
| @@ -3202,7 +3203,7 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| } |
| ConstructorElement resolveRedirectingFactory(Return node, |
| - {bool inConstContext: false}) { |
| + {bool inConstContext: false}) { |
| return node.accept(new ConstructorResolver(compiler, this, |
| inConstContext: inConstContext)); |
| } |
| @@ -3213,7 +3214,6 @@ class ResolverVisitor extends MappingVisitor<Element> { |
| DartType type = typeResolver.resolveTypeAnnotation( |
| this, node, malformedIsError: malformedIsError, |
| deferredIsMalformed: deferredIsMalformed); |
| - if (type == null) return null; |
| if (inCheckContext) { |
| registry.registerIsCheck(type); |
| registry.registerRequiredType(type, enclosingElement); |
| @@ -4707,3 +4707,45 @@ abstract class AnalyzableElementX implements AnalyzableElement { |
| return _treeElements; |
| } |
| } |
| + |
| +/// The result of resolving a node. |
| +abstract class ResolutionResult { |
| + Element get element; |
| +} |
| + |
| +/// The result for the resolution of a node that points to an [Element]. |
| +class ElementResult implements ResolutionResult { |
| + final Element element; |
| + |
| + // TODO(johnniwinther): Remove this factory constructor when `null` is never |
| + // passed as an element result. |
| + factory ElementResult(Element element) { |
| + return element != null ? new ElementResult.internal(element) : null; |
| + } |
| + |
| + ElementResult.internal(this.element); |
| + |
| + String toString() => 'ElementResult($element)'; |
| +} |
| + |
| +/// The result for the resolution of a node that points to an [DartType]. |
| +class TypeResult implements ResolutionResult { |
| + final DartType type; |
| + |
| + TypeResult(this.type) { |
| + assert(type != null); |
| + } |
| + |
| + Element get element => type.element; |
| + |
| + String toString() => 'TypeResult($type)'; |
| +} |
| + |
| +/// The result for the resolution of the `assert` method. |
| +class AssertResult implements ResolutionResult { |
| + const AssertResult(); |
| + |
| + Element get element => null; |
| + |
| + String toString() => 'AssertResult()'; |
| +} |