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

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

Issue 1182563003: Handle most qualified sends. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Handle qualified access of ambiguous static members. 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 61011b60178eb4c793dacad38fb70dd09fc4fa15..a647bdda9f96d64ca6314101ee0af41a5937327a 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -540,9 +540,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
Element target;
String name = node.selector.asIdentifier().source;
if (identical(name, 'this')) {
- // TODO(ahe): Why is this using GENERIC?
- error(node.selector, MessageKind.GENERIC,
- {'text': "expected an identifier"});
+ error(node.selector, MessageKind.THIS_PROPERTY);
return const NoneResult();
} else if (node.isSuperCall) {
if (node.isOperator) {
@@ -957,7 +955,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return computeSuperAccessSemantics(node, target);
}
- /// Resolve [node] as subexpression that is _not_ the prefix of a member
+ /// Resolve [node] as a subexpression that is _not_ the prefix of a member
/// access. For instance `a` in `a + b`, as opposed to `a` in `a.b`.
ResolutionResult visitExpression(Node node) {
bool oldSendIsMemberAccess = sendIsMemberAccess;
@@ -967,6 +965,39 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return result;
}
+ /// Resolve [node] as a subexpression that _is_ the prefix of a member access.
+ /// For instance `a` in `a.b`, as opposed to `a` in `a + b`.
+ ResolutionResult visitExpressionPrefix(Node node) {
+ int oldAllowedCategory = allowedCategory;
+ bool oldSendIsMemberAccess = sendIsMemberAccess;
+ allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER;
+ sendIsMemberAccess = true;
+ ResolutionResult result = visit(node);
+ sendIsMemberAccess = oldSendIsMemberAccess;
+ allowedCategory = oldAllowedCategory;
+ return result;
+ }
+
+ /// Resolved [node] as a subexpression that is the prefix of a conditional
+ /// access. For instance `a` in `a?.b`.
+ // TODO(johnniwinther): Is this equivalent to [visitExpression]?
+ ResolutionResult visitConditionalPrefix(Node node) {
+ // Conditional sends like `e?.foo` treat the receiver as an expression. So
+ // `C?.foo` needs to be treated like `(C).foo`, not like C.foo. Prefixes and
+ // super are not allowed on their own in that context.
+ int oldAllowedCategory = allowedCategory;
+ bool oldSendIsMemberAccess = sendIsMemberAccess;
+ sendIsMemberAccess = false;
+ allowedCategory =
+ ElementCategory.VARIABLE |
+ ElementCategory.FUNCTION |
+ ElementCategory.IMPLIES_TYPE;
+ ResolutionResult result = visit(node);
+ sendIsMemberAccess = oldSendIsMemberAccess;
+ allowedCategory = oldAllowedCategory;
+ return result;
+ }
+
/// Handle a type test expression, like `a is T` and `a is! T`.
ResolutionResult handleIs(Send node) {
Node expression = node.receiver;
@@ -1389,26 +1420,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
/// Handle access of a property of [name] on `this`, like `this.name` and
/// `this.name()`, or `name` and `name()` in instance context.
ResolutionResult handleThisPropertyAccess(Send node, Name name) {
- AccessSemantics accessSemantics = new AccessSemantics.thisProperty();
- SendStructure sendStructure;
- Selector selector;
- if (node.isCall) {
- CallStructure callStructure = resolveArguments(node.argumentsNode);
- selector = new Selector(SelectorKind.CALL, name, callStructure);
- registry.registerDynamicInvocation(selector);
- sendStructure = new InvokeStructure(accessSemantics, selector);
- } else {
- assert(invariant(node, node.isPropertyAccess));
- selector = new Selector(
- SelectorKind.GETTER, name, CallStructure.NO_ARGS);
- registry.registerDynamicGetter(selector);
- sendStructure = new GetStructure(accessSemantics, selector);
- }
- registry.registerSendStructure(node, sendStructure);
- // TODO(johnniwinther): Remove this when all information goes through
- // the [SendStructure].
- registry.setSelector(node, selector);
- return const NoneResult();
+ AccessSemantics semantics = new AccessSemantics.thisProperty();
+ return handleDynamicAccessSemantics(node, name, semantics);
}
/// Handle access on `this`, like `this()` and `this` when it is parsed as a
@@ -1576,12 +1589,179 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
+ /// Handle qualified access to an unresolved static class member, like `a.b`
+ /// or `a.b()` where `a` is a class and `b` is unresolved.
+ ResolutionResult handleUnresolvedStaticMemberAccess(
+ Send node, Name name, ClassElement receiverClass) {
+ // TODO(johnniwinther): Share code with [handleStaticInstanceMemberAccess]
+ // and [handlePrivateStaticMemberAccess].
+ registry.registerThrowNoSuchMethod();
+ // TODO(johnniwinther): Produce a different error if [name] is resolves to
+ // a constructor.
+
+ // TODO(johnniwinther): With the simplified [TreeElements] invariant,
+ // try to resolve injected elements if [currentClass] is in the patch
+ // library of [receiverClass].
+
+ // TODO(karlklose): this should be reported by the caller of
+ // [resolveSend] to select better warning messages for getters and
+ // setters.
+ ErroneousElement error = reportAndCreateErroneousElement(
+ node, name.text, MessageKind.MEMBER_NOT_FOUND,
+ {'className': receiverClass.name, 'memberName': name.text});
+ // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static
+ // member access.
+ return handleErroneousAccess(
+ node, name, error, new StaticAccess.unresolved(error));
+ }
+
+ /// Handle qualified access of an instance member, like `a.b` or `a.b()` where
+ /// `a` is a class and `b` is a non-static member.
+ ResolutionResult handleStaticInstanceMemberAccess(
+ Send node, Name name, ClassElement receiverClass, Element member) {
+
+ registry.registerThrowNoSuchMethod();
+ // TODO(johnniwinther): With the simplified [TreeElements] invariant,
+ // try to resolve injected elements if [currentClass] is in the patch
+ // library of [receiverClass].
+
+ // TODO(karlklose): this should be reported by the caller of
+ // [resolveSend] to select better warning messages for getters and
+ // setters.
+ ErroneousElement error = reportAndCreateErroneousElement(
+ node, name.text, MessageKind.MEMBER_NOT_STATIC,
+ {'className': receiverClass.name, 'memberName': name});
+
+ // TODO(johnniwinther): Add an [AccessSemantics] for statically accessed
+ // instance members.
+ return handleErroneousAccess(
+ node, name, error, new StaticAccess.unresolved(error));
+ }
+
+ /// Handle qualified access of an inaccessible private static class member,
+ /// like `a._b` or `a.b()` where `a` is class, `_b` is static member of `a`
+ /// but `a` is not defined in the current library.
+ ResolutionResult handlePrivateStaticMemberAccess(
+ Send node, Name name, ClassElement receiverClass, Element member) {
+ registry.registerThrowNoSuchMethod();
+ ErroneousElement error = reportAndCreateErroneousElement(
+ node, name.text, MessageKind.PRIVATE_ACCESS,
+ {'libraryName': member.library.getLibraryOrScriptName(),
+ 'name': name});
+ // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static
+ // member access.
+ return handleErroneousAccess(
+ node, name, error, new StaticAccess.unresolved(error));
+ }
+
+ /// Handle qualified access to a static member, like `a.b` or `a.b()` where
+ /// `a` is a class and `b` is a static member of `a`.
+ ResolutionResult handleStaticMemberAccess(
+ Send node, Name memberName, ClassElement receiverClass) {
+ String name = memberName.text;
+ receiverClass.ensureResolved(compiler);
+ if (node.isOperator) {
+ // When the resolved receiver is a class, we can have two cases:
+ // 1) a static send: C.foo, or
+ // 2) an operator send, where the receiver is a class literal: 'C + 1'.
+ // 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 const NoneResult();
+ }
+ MembersCreator.computeClassMembersByName(
+ compiler, receiverClass.declaration, name);
+ Element member = receiverClass.lookupLocalMember(name);
+ if (member == null) {
+ return handleUnresolvedStaticMemberAccess(
+ node, memberName, receiverClass);
+ } else if (member.isAmbiguous) {
+ return handleAmbiguousSend(node, memberName, member);
+ } else if (member.isInstanceMember) {
+ return handleStaticInstanceMemberAccess(
+ node, memberName, receiverClass, member);
+ } else if (memberName.isPrivate && memberName.library != member.library) {
+ return handlePrivateStaticMemberAccess(
+ node, memberName, receiverClass, member);
+ } else {
+ return handleStaticOrTopLevelAccess(node, memberName, member);
+ }
+ }
+
+ /// 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) {
+ if (element.isPrefix) {
+ return oldVisitSend(node);
+ } else if (element.isClass) {
+ return handleStaticMemberAccess(node, name, element);
+ }
+ return oldVisitSend(node);
+ }
+
+ /// Handle dynamic access of [semantics].
+ ResolutionResult handleDynamicAccessSemantics(
+ Send node, Name name, AccessSemantics semantics) {
+ SendStructure sendStructure;
+ Selector selector;
+ if (node.isCall) {
+ CallStructure callStructure = resolveArguments(node.argumentsNode);
+ selector = new Selector(SelectorKind.CALL, name, callStructure);
+ registry.registerDynamicInvocation(selector);
+ sendStructure = new InvokeStructure(semantics, selector);
+ } else {
+ assert(invariant(node, node.isPropertyAccess));
+ selector = new Selector(
+ SelectorKind.GETTER, name, CallStructure.NO_ARGS);
+ registry.registerDynamicGetter(selector);
+ sendStructure = new GetStructure(semantics, selector);
+ }
+ registry.registerSendStructure(node, sendStructure);
+ // TODO(johnniwinther): Remove this when all information goes through
+ // the [SendStructure].
+ registry.setSelector(node, selector);
+ return const NoneResult();
+ }
+
+ /// Handle dynamic property access, like `a.b` or `a.b()` where `a` is not a
+ /// prefix or class.
+ ResolutionResult handleDynamicPropertyAccess(Send node, Name name) {
+ AccessSemantics semantics =
+ new DynamicAccess.dynamicProperty(node.receiver);
+ return handleDynamicAccessSemantics(node, name, semantics);
+ }
+
+ /// Handle conditional access, like `a?.b` or `a?.b()`.
+ ResolutionResult handleConditionalAccess(Send node, Name name) {
+ Node receiver = node.receiver;
+ visitConditionalPrefix(receiver);
+ AccessSemantics semantics =
+ new DynamicAccess.ifNotNullProperty(receiver);
+ return handleDynamicAccessSemantics(node, name, semantics);
+ }
+
+ /// Handle `this` as a qualified property, like `a.this`.
+ ResolutionResult handleQualifiedThisAccess(Send node, Name name) {
+ ErroneousElement error = reportAndCreateErroneousElement(
+ node.selector,
+ name.text,
+ MessageKind.THIS_PROPERTY, {},
+ isError: true);
+ // TODO(johnniwinther): Support `this` as property as an [AccessSemantics].
+ AccessSemantics accessSemantics = new StaticAccess.unresolved(error);
+ return handleErroneousAccess(node, name, error, accessSemantics);
+ }
+
/// Handle a qualified [Send], that is where the receiver is non-null, like
/// `a.b`, `a.b()`, `this.a()` and `super.a()`.
ResolutionResult handleQualifiedSend(Send node) {
Identifier selector = node.selector.asIdentifier();
- Name name = new Name(selector.source, enclosingElement.library);
- if (node.isSuperCall) {
+ String text = selector.source;
+ Name name = new Name(text, enclosingElement.library);
+ if (text == 'this') {
+ return handleQualifiedThisAccess(node, name);
+ } else if (node.isSuperCall) {
return handleSuperPropertyAccess(node, name);
} else if (node.receiver.isThis()) {
if (checkThisAccess(node)) {
@@ -1590,9 +1770,15 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// TODO(johnniwinther): Handle invalid this access as an
// [AccessSemantics].
return const NoneResult();
+ } else if (node.isConditional) {
+ return handleConditionalAccess(node, name);
+ }
+ ResolutionResult result = visitExpressionPrefix(node.receiver);
+ if (result.element != null) {
+ return handleResolvedQualifiedSend(node, name, result.element);
+ } else {
+ return handleDynamicPropertyAccess(node, name);
}
- // TODO(johnniwinther): Handle remaining qualified sends.
- return oldVisitSend(node);
}
/// Handle access unresolved access to [name] in a non-instance context.
@@ -2464,8 +2650,10 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
bool oldSendIsMemberAccess = sendIsMemberAccess;
sendIsMemberAccess = false;
var oldCategory = allowedCategory;
- allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
- | ElementCategory.IMPLIES_TYPE;
+ allowedCategory =
+ ElementCategory.VARIABLE |
+ ElementCategory.FUNCTION |
+ ElementCategory.IMPLIES_TYPE;
ResolutionResult result = visit(node.expression);
allowedCategory = oldCategory;
sendIsMemberAccess = oldSendIsMemberAccess;
« no previous file with comments | « pkg/compiler/lib/src/resolution/access_semantics.dart ('k') | pkg/compiler/lib/src/resolution/resolution_common.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698