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

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

Issue 1149403009: Refactoring resolution of local access and unqualified access of statics (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Fix after rebase 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 fb0d246658580d7499c3d75516d40ca3d644c2e8..27dda38d8150b044756529368e0c2db331daabea 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -813,7 +813,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
/// Compute the [AccessSemantics] corresponding to a super access of [target].
- AccessSemantics computeSuperAccess(Spannable node, Element target) {
+ AccessSemantics computeSuperAccessSemantics(Spannable node, Element target) {
if (target.isErroneous) {
return new StaticAccess.unresolvedSuper(target);
} else if (target.isGetter) {
@@ -821,7 +821,11 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
} else if (target.isSetter) {
return new StaticAccess.superSetter(target);
} else if (target.isField) {
- return new StaticAccess.superField(target);
+ if (target.isFinal) {
+ return new StaticAccess.superFinalField(target);
+ } else {
+ return new StaticAccess.superField(target);
+ }
} else {
assert(invariant(node, target.isFunction,
message: "Unexpected super target '$target'."));
@@ -829,6 +833,78 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
+ /// Compute the [AccessSemantics] corresponding to a local access of [target].
+ AccessSemantics computeLocalAccessSemantics(Spannable node,
+ LocalElement target) {
+ if (target.isParameter) {
+ if (target.isFinal || target.isConst) {
+ return new StaticAccess.finalParameter(target);
+ } else {
+ return new StaticAccess.parameter(target);
+ }
+ } else if (target.isVariable) {
+ if (target.isFinal || target.isConst) {
+ return new StaticAccess.finalLocalVariable(target);
+ } else {
+ return new StaticAccess.localVariable(target);
+ }
+ } else {
+ assert(invariant(node, target.isFunction,
+ message: "Unexpected local target '$target'."));
+ return new StaticAccess.localFunction(target);
+ }
+ }
+
+ /// Compute the [AccessSemantics] corresponding to a static or toplevel access
+ /// of [target].
+ AccessSemantics computeStaticOrTopLevelAccessSemantics(
+ Spannable node,
+ Element target) {
+
+ target = target.declaration;
+ if (target.isErroneous) {
+ // This handles elements with parser errors.
+ // TODO(johnniwinther): Elements with parse error should not set
+ // [isErroneous] to `true`.
+ return new StaticAccess.unresolved(target);
+ }
+ if (target.isStatic) {
+ if (target.isGetter) {
+ return new StaticAccess.staticGetter(target);
+ } else if (target.isSetter) {
+ return new StaticAccess.staticSetter(target);
+ } else if (target.isField) {
+ if (target.isFinal || target.isConst) {
+ return new StaticAccess.finalStaticField(target);
+ } else {
+ return new StaticAccess.staticField(target);
+ }
+ } else {
+ assert(invariant(node, target.isFunction,
+ message: "Unexpected static target '$target'."));
+ return new StaticAccess.staticMethod(target);
+ }
+ } else {
+ assert(invariant(node, target.isTopLevel,
+ message: "Unexpected statically resolved target '$target'."));
+ if (target.isGetter) {
+ return new StaticAccess.topLevelGetter(target);
+ } else if (target.isSetter) {
+ return new StaticAccess.topLevelSetter(target);
+ } else if (target.isField) {
+ if (target.isFinal) {
+ return new StaticAccess.finalTopLevelField(target);
+ } else {
+ return new StaticAccess.topLevelField(target);
+ }
+ } else {
+ assert(invariant(node, target.isFunction,
+ message: "Unexpected top level target '$target'."));
+ return new StaticAccess.topLevelMethod(target);
+ }
+ }
+ }
+
/// Compute the [AccessSemantics] for accessing the name of [selector] on the
/// super class.
///
@@ -845,9 +921,11 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
/// foo => super.name; // Access to the setter.
/// }
///
- AccessSemantics computeSuperSemantics(Spannable node,
- Selector selector,
- {Name alternateName}) {
+ AccessSemantics computeSuperAccessSemanticsForSelector(
+ Spannable node,
+ Selector selector,
+ {Name alternateName}) {
+
Name name = selector.memberName;
// TODO(johnniwinther): Ensure correct behavior if currentClass is a
// patch.
@@ -869,7 +947,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerDynamicInvocation(selector);
registry.registerSuperNoSuchMethod();
}
- return computeSuperAccess(node, target);
+ return computeSuperAccessSemantics(node, target);
}
/// Resolve [node] as subexpression that is _not_ the prefix of a member
@@ -948,7 +1026,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
AccessSemantics semantics;
if (node.isSuperCall) {
if (checkSuperAccess(node)) {
- semantics = computeSuperSemantics(node, selector);
+ semantics = computeSuperAccessSemanticsForSelector(node, selector);
// TODO(johnniwinther): Add information to [AccessSemantics] about
// whether it is erroneous.
if (semantics.kind == AccessKind.SUPER_METHOD) {
@@ -1122,7 +1200,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (node.isSuperCall) {
if (checkSuperAccess(node)) {
- semantics = computeSuperSemantics(node, selector);
+ semantics = computeSuperAccessSemanticsForSelector(node, selector);
// TODO(johnniwinther): Add information to [AccessSemantics] about
// whether it is erroneous.
if (semantics.kind == AccessKind.SUPER_METHOD) {
@@ -1362,7 +1440,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
selector = new Selector(SelectorKind.GETTER, name, callStructure);
}
if (checkSuperAccess(node)) {
- AccessSemantics semantics = computeSuperSemantics(
+ AccessSemantics semantics = computeSuperAccessSemanticsForSelector(
node, selector, alternateName: name.setter);
if (node.isCall) {
bool isIncompatibleInvoke = false;
@@ -1380,6 +1458,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
break;
case AccessKind.SUPER_FIELD:
+ case AccessKind.SUPER_FINAL_FIELD:
case AccessKind.SUPER_GETTER:
registry.registerStaticUse(semantics.element);
selector = callStructure.callSelector;
@@ -1405,6 +1484,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
registry.registerStaticUse(semantics.element);
break;
case AccessKind.SUPER_FIELD:
+ case AccessKind.SUPER_FINAL_FIELD:
case AccessKind.SUPER_GETTER:
registry.registerStaticUse(semantics.element);
break;
@@ -1514,6 +1594,12 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// TODO(johnniwinther): Support unresolved top level access as an
// [AccessSemantics].
AccessSemantics accessSemantics = new StaticAccess.unresolved(element);
+ return handleErroneousAccess(node, name, element, accessSemantics);
+ }
+
+ /// Handle erroneous access of [element] of the given [accessSemantics].
+ ResolutionResult handleErroneousAccess(
+ Send node, Name name, Element element, AccessSemantics accessSemantics) {
SendStructure sendStructure;
Selector selector;
if (node.isCall) {
@@ -1536,6 +1622,247 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return const NoneResult();
}
+ /// Handle access to an ambiguous element, that is, a name imported twice.
+ ResolutionResult handleAmbiguousSend(
+ Send node,
+ Name name,
+ AmbiguousElement element) {
+
+ compiler.reportError(
+ node, element.messageKind, element.messageArguments);
+ element.diagnose(enclosingElement, compiler);
+
+ ErroneousElement error = new ErroneousElementX(
+ element.messageKind,
+ element.messageArguments,
+ name.text,
+ enclosingElement);
+
+ // TODO(johnniwinther): Support ambiguous access as an [AccessSemantics].
+ AccessSemantics accessSemantics = new StaticAccess.unresolved(error);
+ return handleErroneousAccess(node, name, error, accessSemantics);
+ }
+
+ /// Handle access of an instance [member] from a non-instance context.
+ ResolutionResult handleStaticInstanceSend(
+ Send node, Name name, MemberElement member) {
+ compiler.reportError(
+ node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': member.name});
+ ErroneousElement error = new ErroneousElementX(
+ MessageKind.NO_INSTANCE_AVAILABLE,
+ {'name': name},
+ name.text,
+ enclosingElement);
+
+ // TODO(johnniwinther): Support static instance access as an
+ // [AccessSemantics].
+ AccessSemantics accessSemantics = new StaticAccess.unresolved(error);
+ return handleErroneousAccess(node, name, error, accessSemantics);
+ }
+
+ /// Handle access of a parameter, local variable or local function.
+ ResolutionResult handleLocalAccess(Send node, Name name, Element element) {
+ AccessSemantics semantics = computeLocalAccessSemantics(node, element);
+ Selector selector;
+ CallStructure callStructure = CallStructure.NO_ARGS;
+ if (node.isCall) {
+ callStructure = resolveArguments(node.argumentsNode);
+ selector = new Selector(SelectorKind.CALL, name, callStructure);
+ } else {
+ selector = new Selector(SelectorKind.GETTER, name, callStructure);
+ }
+ if (node.isCall) {
+ bool isIncompatibleInvoke = false;
+ switch (semantics.kind) {
+ case AccessKind.LOCAL_FUNCTION:
+ LocalFunctionElementX function = semantics.element;
+ function.computeSignature(compiler);
+ if (!callStructure.signatureApplies(function)) {
+ registry.registerThrowNoSuchMethod();
+ registry.registerDynamicInvocation(selector);
+ isIncompatibleInvoke = true;
+ }
+ break;
+ case AccessKind.PARAMETER:
+ case AccessKind.FINAL_PARAMETER:
+ case AccessKind.LOCAL_VARIABLE:
+ case AccessKind.FINAL_LOCAL_VARIABLE:
+ selector = callStructure.callSelector;
+ registry.registerDynamicInvocation(selector);
+ break;
+ default:
+ internalError(node,
+ "Unexpected local access $semantics.");
+ break;
+ }
+ registry.registerSendStructure(node,
+ isIncompatibleInvoke
+ ? new IncompatibleInvokeStructure(semantics, selector)
+ : new InvokeStructure(semantics, selector));
+ } else {
+ registry.registerSendStructure(node,
+ new GetStructure(semantics, selector));
+ }
+
+ // TODO(johnniwinther): Remove these when all information goes through
+ // the [SendStructure].
+ registry.useElement(node, element);
+ registry.setSelector(node, selector);
+
+ registerPotentialAccessInClosure(node, element);
+
+ return node.isPropertyAccess
+ ? new ElementResult(element) : const NoneResult();
+ }
+
+ /// Handle access of a static or top level [element].
+ ResolutionResult handleStaticOrTopLevelAccess(
+ Send node, Name name, Element element) {
+
+ if (element.isAbstractField) {
+ AbstractFieldElement abstractField = element;
+ if (abstractField.getter != null) {
+ element = abstractField.getter;
+ } else {
+ element = abstractField.setter;
+ }
+ }
+ // TODO(johnniwinther): Needed to provoke a parsing and with it discovery
+ // of parse errors to make [element] erroneous. Fix this!
+ element.computeType(compiler);
+
+ Selector selector;
+ CallStructure callStructure = CallStructure.NO_ARGS;
+ if (node.isCall) {
+ callStructure = resolveArguments(node.argumentsNode);
+ selector = new Selector(SelectorKind.CALL, name, callStructure);
+ } else {
+ selector = new Selector(SelectorKind.GETTER, name, callStructure);
+ }
+ AccessSemantics semantics =
+ computeStaticOrTopLevelAccessSemantics(node, element);
+ if (node.isCall) {
+ bool isIncompatibleInvoke = false;
+ switch (semantics.kind) {
+ case AccessKind.STATIC_METHOD:
+ case AccessKind.TOPLEVEL_METHOD:
+ MethodElementX method = semantics.element;
+ method.computeSignature(compiler);
+ if (!callStructure.signatureApplies(method)) {
+ registry.registerThrowNoSuchMethod();
+ registry.registerDynamicInvocation(selector);
+ isIncompatibleInvoke = true;
+ } else {
+ registry.registerStaticUse(semantics.element);
+ handleForeignCall(node, semantics.element, selector);
+ }
+ break;
+ case AccessKind.STATIC_FIELD:
+ case AccessKind.FINAL_STATIC_FIELD:
+ case AccessKind.STATIC_GETTER:
+ case AccessKind.TOPLEVEL_FIELD:
+ case AccessKind.FINAL_TOPLEVEL_FIELD:
+ case AccessKind.TOPLEVEL_GETTER:
+ registry.registerStaticUse(semantics.element);
+ selector = callStructure.callSelector;
+ registry.registerDynamicInvocation(selector);
+ break;
+ case AccessKind.STATIC_SETTER:
+ case AccessKind.TOPLEVEL_SETTER:
+ case AccessKind.UNRESOLVED:
+ registry.registerThrowNoSuchMethod();
+ element = reportAndCreateErroneousElement(
+ node.selector, name.text,
+ MessageKind.CANNOT_RESOLVE_GETTER, const {});
+ break;
+ default:
+ internalError(node,
+ "Unexpected statically resolved access $semantics.");
+ break;
+ }
+ registry.registerSendStructure(node,
+ isIncompatibleInvoke
+ ? new IncompatibleInvokeStructure(semantics, selector)
+ : new InvokeStructure(semantics, selector));
+ } else {
+ switch (semantics.kind) {
+ case AccessKind.STATIC_METHOD:
+ case AccessKind.TOPLEVEL_METHOD:
+ // TODO(johnniwinther): Method this should be registered as a
+ // closurization.
+ registry.registerStaticUse(semantics.element);
+ registry.registerGetOfStaticFunction(semantics.element);
+ break;
+ case AccessKind.STATIC_FIELD:
+ case AccessKind.FINAL_STATIC_FIELD:
+ case AccessKind.STATIC_GETTER:
+ case AccessKind.TOPLEVEL_FIELD:
+ case AccessKind.FINAL_TOPLEVEL_FIELD:
+ case AccessKind.TOPLEVEL_GETTER:
+ registry.registerStaticUse(semantics.element);
+ break;
+ case AccessKind.STATIC_SETTER:
+ case AccessKind.TOPLEVEL_SETTER:
+ case AccessKind.UNRESOLVED:
+ registry.registerThrowNoSuchMethod();
+ element = reportAndCreateErroneousElement(
+ node.selector, name.text,
+ MessageKind.CANNOT_RESOLVE_GETTER, const {});
+ break;
+ default:
+ internalError(node,
+ "Unexpected statically resolved access $semantics.");
+ break;
+ }
+ registry.registerSendStructure(node,
+ new GetStructure(semantics, selector));
+ }
+
+ // TODO(johnniwinther): Remove these when all information goes through
+ // the [SendStructure].
+ registry.useElement(node, element);
+ registry.setSelector(node, selector);
+
+ return node.isPropertyAccess
+ ? new ElementResult(element) : const NoneResult();
+ }
+
+ /// Handle access to resolved [element].
+ ResolutionResult handleResolvedSend(Send node, Name name, Element element) {
+ if (element.isAmbiguous) {
+ return handleAmbiguousSend(node, name, element);
+ }
+ if (element.isErroneous) {
+ // This handles elements with parser errors.
+ // TODO(johnniwinther): Elements with parse error should not set
+ // [isErroneous] to `true`.
+ assert(invariant(node, element is! ErroneousElement,
+ message: "Unexpected erroneous element $element."));
+ return handleErroneousAccess(node, name, element,
+ new StaticAccess.unresolved(element));
+ }
+ if (element.isInstanceMember) {
+ if (inInstanceContext) {
+ // TODO(johnniwinther): Maybe use the found [element].
+ return handleThisPropertyAccess(node, name);
+ } else {
+ return handleStaticInstanceSend(node, name, element);
+ }
+ }
+ if (element.isClass || element.isTypedef) {
+ return oldVisitSend(node);
+ } else if (element.isTypeVariable) {
+ return oldVisitSend(node);
+ } else if (element.isPrefix) {
+ return oldVisitSend(node);
+ } else if (element.isLocal) {
+ return handleLocalAccess(node, name, element);
+ } else if (element.isStatic || element.isTopLevel) {
+ return handleStaticOrTopLevelAccess(node, name, element);
+ }
+ return internalError(node, "Unexpected resolved send: $element");
+ }
+
/// Handle an unqualified [Send], that is where the `node.receiver` is null,
/// like `a`, `a()`, `this()`, `assert()`, and `(){}()`.
ResolutionResult handleUnqualifiedSend(Send node) {
@@ -1568,19 +1895,33 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ErroneousElement error = reportCannotResolve(node, text);
return handleUnresolvedAccess(node, name, error);
}
+ } else {
+ return handleResolvedSend(node, name, element);
}
- return oldVisitSend(node);
}
ResolutionResult visitSend(Send node) {
if (node.isOperator) {
+ // `a && b`, `a + b`, `-a`, or `a is T`.
return handleOperatorSend(node);
} else if (node.receiver != null) {
+ // `a.b`.
return handleQualifiedSend(node);
} else {
+ // `a`.
return handleUnqualifiedSend(node);
}
- return oldVisitSend(node);
+ }
+
+ /// Regigster read access of [target] inside a closure.
+ void registerPotentialAccessInClosure(Send node, Element target) {
+ if (isPotentiallyMutableTarget(target)) {
+ if (enclosingElement != target.enclosingElement) {
+ for (Node scope in promotionScope) {
+ registry.setAccessedByClosureIn(scope, target, node);
+ }
+ }
+ }
}
ResolutionResult oldVisitSend(Send node) {
@@ -1628,13 +1969,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
} else if (target.impliesType && (!sendIsMemberAccess || node.isCall)) {
registerTypeLiteralAccess(node, target);
}
- if (isPotentiallyMutableTarget(target)) {
- if (enclosingElement != target.enclosingElement) {
- for (Node scope in promotionScope) {
- registry.setAccessedByClosureIn(scope, target, node);
- }
- }
- }
+ registerPotentialAccessInClosure(node, target);
}
bool resolvedArguments = false;
@@ -1672,23 +2007,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
- if (target != null && compiler.backend.isForeign(target)) {
- if (selector.name == 'JS') {
- registry.registerJsCall(node, this);
- } else if (selector.name == 'JS_EMBEDDED_GLOBAL') {
- registry.registerJsEmbeddedGlobalCall(node, this);
- } else if (selector.name == 'JS_BUILTIN') {
- registry.registerJsBuiltinCall(node, this);
- } else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') {
- if (!node.argumentsNode.isEmpty) {
- Node argument = node.argumentsNode.nodes.head;
- if (argumentsToJsInterceptorConstant == null) {
- argumentsToJsInterceptorConstant = new Set<Node>();
- }
- argumentsToJsInterceptorConstant.add(argument);
- }
- }
- }
+ handleForeignCall(node, target, selector);
}
registry.useElement(node, target);
@@ -1700,6 +2019,27 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
? new ResolutionResult.forElement(target) : const NoneResult();
}
+ // TODO(johnniwinther): Move this to the backend resolution callbacks.
+ void handleForeignCall(Send node, Element target, Selector selector) {
+ if (target != null && compiler.backend.isForeign(target)) {
+ if (selector.name == 'JS') {
+ registry.registerJsCall(node, this);
+ } else if (selector.name == 'JS_EMBEDDED_GLOBAL') {
+ registry.registerJsEmbeddedGlobalCall(node, this);
+ } else if (selector.name == 'JS_BUILTIN') {
+ registry.registerJsBuiltinCall(node, this);
+ } else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') {
+ if (!node.argumentsNode.isEmpty) {
+ Node argument = node.argumentsNode.nodes.head;
+ if (argumentsToJsInterceptorConstant == null) {
+ argumentsToJsInterceptorConstant = new Set<Node>();
+ }
+ argumentsToJsInterceptorConstant.add(argument);
+ }
+ }
+ }
+ }
+
/// Callback for native enqueuer to parse a type. Returns [:null:] on error.
DartType resolveTypeFromString(Node node, String typeName) {
Element element = lookupInScope(compiler, node, scope, typeName);
« no previous file with comments | « pkg/compiler/lib/src/inferrer/simple_types_inferrer.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