| 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 96961f3d213ceb3e8fb10c8b5a040cf6468dc1dc..ea44ed2ca41fcd3f3e2761ab40d116fec0303f8c 100644
|
| --- a/pkg/compiler/lib/src/resolution/members.dart
|
| +++ b/pkg/compiler/lib/src/resolution/members.dart
|
| @@ -327,7 +327,16 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| ClassElement classElement = element;
|
| classElement.ensureResolved(compiler);
|
| }
|
| - return new ElementResult(registry.useElement(node, element));
|
| + if (element != null) {
|
| + registry.useElement(node, element);
|
| + if (element.isPrefix) {
|
| + return new PrefixResult(element, null);
|
| + } else if (element.isClass && sendIsMemberAccess) {
|
| + return new PrefixResult(null, element);
|
| + }
|
| + return new ElementResult(element);
|
| + }
|
| + return const NoneResult();
|
| }
|
| }
|
|
|
| @@ -1638,7 +1647,6 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| message: "Unexpected unary operator '${operator}'."));
|
| return handleUserDefinableUnary(node, operator);
|
| }
|
| - return handleUserDefinableUnary(node, operator);
|
| }
|
| } else {
|
| BinaryOperator operator = BinaryOperator.parse(operatorText);
|
| @@ -1907,29 +1915,60 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| cls.ensureResolved(compiler);
|
| if (sendIsMemberAccess) {
|
| registry.useElement(node, cls);
|
| - return new ElementResult(cls);
|
| + return new PrefixResult(null, cls);
|
| } else {
|
| // `C` or `C()` where 'C' is a class.
|
| return handleClassTypeLiteralAccess(node, name, cls);
|
| }
|
| }
|
|
|
| + /// Compute a [DeferredPrefixStructure] for [node].
|
| + ResolutionResult handleDeferredAccess(
|
| + Send node,
|
| + PrefixElement prefix,
|
| + ResolutionResult result) {
|
| + assert(invariant(node, prefix.isDeferred,
|
| + message: "Prefix $prefix is not deferred."));
|
| + SendStructure sendStructure = registry.getSendStructure(node);
|
| + assert(invariant(node, sendStructure != null,
|
| + message: "No SendStructure for $node."));
|
| + registry.registerSendStructure(node,
|
| + new DeferredPrefixStructure(prefix, sendStructure));
|
| + if (result.isConstant) {
|
| + ConstantExpression constant =
|
| + new DeferredConstantExpression(result.constant, prefix);
|
| + registry.setConstant(node, constant);
|
| + result = new ConstantResult(node, constant);
|
| + }
|
| + return result;
|
| + }
|
| +
|
| /// Handle qualified [Send] where the receiver resolves to a [prefix],
|
| /// like `prefix.toplevelFunction()` or `prefix.Class.staticField` where
|
| /// `prefix` is a library prefix.
|
| ResolutionResult handleLibraryPrefixSend(
|
| Send node, PrefixElement prefix, Name name) {
|
| + ResolutionResult result;
|
| Element member = prefix.lookupLocalMember(name.text);
|
| if (member == null) {
|
| registry.registerThrowNoSuchMethod();
|
| Element error = reportAndCreateErroneousElement(
|
| node, name.text, MessageKind.NO_SUCH_LIBRARY_MEMBER,
|
| {'libraryName': prefix.name, 'memberName': name});
|
| - registry.useElement(node, error);
|
| - return new ElementResult(error);
|
| + result = handleUnresolvedAccess(node, name, error);
|
| } else {
|
| - return handleResolvedSend(node, name, member);
|
| + result = handleResolvedSend(node, name, member);
|
| + }
|
| + if (result.kind == ResultKind.PREFIX) {
|
| + // [member] is a class prefix of a static access like `prefix.Class` of
|
| + // `prefix.Class.foo`. No need to call [handleDeferredAccess]; it will
|
| + // called on the parent `prefix.Class.foo` node.
|
| + result = new PrefixResult(prefix, result.element);
|
| + } else if (prefix.isDeferred &&
|
| + (member == null || !member.isDeferredLoaderGetter)) {
|
| + result = handleDeferredAccess(node, prefix, result);
|
| }
|
| + return result;
|
| }
|
|
|
| /// Handle a [Send] that resolves to a [prefix]. Like `prefix` in
|
| @@ -1952,20 +1991,24 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| registry.useElement(node.selector, prefix);
|
| }
|
| registry.useElement(node, prefix);
|
| - return new ElementResult(prefix);
|
| + return new PrefixResult(prefix, null);
|
| }
|
|
|
| /// Handle qualified [Send] where the receiver resolves to an [Element], like
|
| - /// `a.b` where `a` is a local, field, class, or prefix, etc.
|
| - ResolutionResult handleResolvedQualifiedSend(
|
| - Send node, Name name, Element element) {
|
| + /// `a.b` where `a` is a prefix or a class.
|
| + ResolutionResult handlePrefixSend(
|
| + Send node, Name name, PrefixResult prefixResult) {
|
| + Element element = prefixResult.element;
|
| if (element.isPrefix) {
|
| return handleLibraryPrefixSend(node, element, name);
|
| - } else if (element.isClass) {
|
| - return handleStaticMemberAccess(node, name, element);
|
| + } else {
|
| + assert(element.isClass);
|
| + ResolutionResult result = handleStaticMemberAccess(node, name, element);
|
| + if (prefixResult.isDeferred) {
|
| + result = handleDeferredAccess(node, prefixResult.prefix, result);
|
| + }
|
| + return result;
|
| }
|
| - // TODO(johnniwinther): Use the [element].
|
| - return handleDynamicPropertyAccess(node, name);
|
| }
|
|
|
| /// Handle dynamic access of [semantics].
|
| @@ -2045,9 +2088,10 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| return handleConditionalAccess(node, name);
|
| }
|
| ResolutionResult result = visitExpressionPrefix(node.receiver);
|
| - if (result.element != null) {
|
| - return handleResolvedQualifiedSend(node, name, result.element);
|
| + if (result.kind == ResultKind.PREFIX) {
|
| + return handlePrefixSend(node, name, result);
|
| } else {
|
| + // TODO(johnniwinther): Use the `element` of [result].
|
| return handleDynamicPropertyAccess(node, name);
|
| }
|
| }
|
| @@ -2448,7 +2492,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| }
|
| }
|
|
|
| - /// Regigster read access of [target] inside a closure.
|
| + /// Register read access of [target] inside a closure.
|
| void registerPotentialAccessInClosure(Send node, Element target) {
|
| if (isPotentiallyMutableTarget(target)) {
|
| if (enclosingElement != target.enclosingElement) {
|
|
|