| 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 dd9b62be3692cb532aad6294aab77d590c6ecad7..a67de982765a3d32aba6112e564844cae0388254 100644
|
| --- a/pkg/compiler/lib/src/resolution/members.dart
|
| +++ b/pkg/compiler/lib/src/resolution/members.dart
|
| @@ -874,26 +874,36 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| }
|
| }
|
|
|
| - /// Check that access to `super` is currently allowed.
|
| - bool checkSuperAccess(Send node) {
|
| + /// Check that access to `super` is currently allowed. Returns an
|
| + /// [AccessSemantics] in case of an error, `null` otherwise.
|
| + AccessSemantics checkSuperAccess(Send node) {
|
| if (!inInstanceContext) {
|
| - compiler.reportError(node, MessageKind.NO_SUPER_IN_STATIC);
|
| - return false;
|
| + return new StaticAccess.invalid(
|
| + reportAndCreateErroneousElement(
|
| + node, 'super',
|
| + MessageKind.NO_SUPER_IN_STATIC, {},
|
| + isError: true));
|
| }
|
| if (node.isConditional) {
|
| // `super?.foo` is not allowed.
|
| - compiler.reportError(node, MessageKind.INVALID_USE_OF_SUPER);
|
| - return false;
|
| + return new StaticAccess.invalid(
|
| + reportAndCreateErroneousElement(
|
| + node, 'super',
|
| + MessageKind.INVALID_USE_OF_SUPER, {},
|
| + isError: true));
|
| }
|
| if (currentClass.supertype == null) {
|
| // This is just to guard against internal errors, so no need
|
| // for a real error message.
|
| - compiler.reportError(node, MessageKind.GENERIC,
|
| - {'text': "Object has no superclass"});
|
| - return false;
|
| + return new StaticAccess.invalid(
|
| + reportAndCreateErroneousElement(
|
| + node, 'super',
|
| + MessageKind.GENERIC,
|
| + {'text': "Object has no superclass"},
|
| + isError: true));
|
| }
|
| registry.registerSuperUse(node);
|
| - return true;
|
| + return null;
|
| }
|
|
|
| /// Check that access to `this` is currently allowed.
|
| @@ -926,6 +936,78 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| }
|
| }
|
|
|
| + /// Compute the [AccessSemantics] corresponding to a compound super access
|
| + /// reading from [getter] and writing to [setter].
|
| + AccessSemantics computeCompoundSuperAccessSemantics(
|
| + Spannable node,
|
| + Element getter,
|
| + Element setter) {
|
| + if (getter.isErroneous) {
|
| + if (setter.isErroneous) {
|
| + return new StaticAccess.unresolvedSuper(getter);
|
| + } else if (setter.isFunction) {
|
| + assert(invariant(node, setter.name == '[]=',
|
| + message: "Unexpected super setter '$setter'."));
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.UNRESOLVED_SUPER_GETTER, getter, setter);
|
| + } else {
|
| + assert(invariant(node, setter.isSetter,
|
| + message: "Unexpected super setter '$setter'."));
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.UNRESOLVED_SUPER_GETTER, getter, setter);
|
| + }
|
| + } else if (getter.isField) {
|
| + if (setter.isField) {
|
| + if (getter == setter) {
|
| + return new StaticAccess.superField(getter);
|
| + } else {
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.SUPER_FIELD_FIELD, getter, setter);
|
| + }
|
| + } else {
|
| + // Either the field is accessible directly, or a setter shadows the
|
| + // setter access. If there was another instance member it would shadow
|
| + // the field.
|
| + assert(invariant(node, setter.isSetter,
|
| + message: "Unexpected super setter '$setter'."));
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.SUPER_FIELD_SETTER, getter, setter);
|
| + }
|
| + } else if (getter.isGetter) {
|
| + if (setter.isErroneous) {
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, setter);
|
| + } else if (setter.isField) {
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.SUPER_GETTER_FIELD, getter, setter);
|
| + } else {
|
| + assert(invariant(node, setter.isSetter,
|
| + message: "Unexpected super setter '$setter'."));
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.SUPER_GETTER_SETTER, getter, setter);
|
| + }
|
| + } else {
|
| + assert(invariant(node, getter.isFunction,
|
| + message: "Unexpected super getter '$getter'."));
|
| + if (setter.isErroneous) {
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, setter);
|
| + } else if (setter.isFunction) {
|
| + assert(invariant(node, getter.name == '[]',
|
| + message: "Unexpected super getter '$getter'."));
|
| + assert(invariant(node, setter.name == '[]=',
|
| + message: "Unexpected super setter '$setter'."));
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.SUPER_GETTER_SETTER, getter, setter);
|
| + } else {
|
| + assert(invariant(node, setter.isSetter,
|
| + message: "Unexpected super setter '$setter'."));
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.SUPER_METHOD_SETTER, getter, setter);
|
| + }
|
| + }
|
| + }
|
| +
|
| /// Compute the [AccessSemantics] corresponding to a local access of [target].
|
| AccessSemantics computeLocalAccessSemantics(Spannable node,
|
| LocalElement target) {
|
| @@ -1043,6 +1125,55 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| return computeSuperAccessSemantics(node, target);
|
| }
|
|
|
| + /// Compute the [AccessSemantics] for accessing the name of [selector] on the
|
| + /// super class.
|
| + ///
|
| + /// If no matching super member is found and error is reported and
|
| + /// `noSuchMethod` on `super` is registered. Furthermore, if [alternateName]
|
| + /// is provided, the [AccessSemantics] corresponding to the alternate name is
|
| + /// returned. For instance, the access of a super setter for an unresolved
|
| + /// getter:
|
| + ///
|
| + /// class Super {
|
| + /// set name(_) {}
|
| + /// }
|
| + /// class Sub extends Super {
|
| + /// foo => super.name; // Access to the setter.
|
| + /// }
|
| + ///
|
| + AccessSemantics computeSuperAccessSemanticsForSelectors(
|
| + Spannable node,
|
| + Selector getterSelector, Selector setterSelector) {
|
| +
|
| + // TODO(johnniwinther): Ensure correct behavior if currentClass is a
|
| + // patch.
|
| + Element getter = currentClass.lookupSuperByName(getterSelector.memberName);
|
| + // [target] may be null which means invoking noSuchMethod on super.
|
| + if (getter == null) {
|
| + getter = reportAndCreateErroneousElement(
|
| + node, getterSelector.name, MessageKind.NO_SUCH_SUPER_MEMBER,
|
| + {'className': currentClass.name, 'memberName': getterSelector.name});
|
| + // We still need to register the invocation, because we might
|
| + // call `super.noSuchMethod` which calls [JSInvocationMirror._invokeOn].
|
| + registry.registerDynamicInvocation(
|
| + new UniverseSelector(getterSelector, null));
|
| + registry.registerSuperNoSuchMethod();
|
| + }
|
| + Element setter = currentClass.lookupSuperByName(setterSelector.memberName);
|
| + // [target] may be null which means invoking noSuchMethod on super.
|
| + if (setter == null) {
|
| + setter = reportAndCreateErroneousElement(
|
| + node, setterSelector.name, MessageKind.NO_SUCH_SUPER_MEMBER,
|
| + {'className': currentClass.name, 'memberName': setterSelector.name});
|
| + // We still need to register the invocation, because we might
|
| + // call `super.noSuchMethod` which calls [JSInvocationMirror._invokeOn].
|
| + registry.registerDynamicInvocation(
|
| + new UniverseSelector(setterSelector, null));
|
| + registry.registerSuperNoSuchMethod();
|
| + }
|
| + return computeCompoundSuperAccessSemantics(node, getter, setter);
|
| + }
|
| +
|
| /// 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) {
|
| @@ -1151,7 +1282,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|
|
| AccessSemantics semantics;
|
| if (node.isSuperCall) {
|
| - if (checkSuperAccess(node)) {
|
| + semantics = checkSuperAccess(node);
|
| + if (semantics == null) {
|
| semantics = computeSuperAccessSemanticsForSelector(node, selector);
|
| // TODO(johnniwinther): Add information to [AccessSemantics] about
|
| // whether it is erroneous.
|
| @@ -1197,8 +1329,6 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| }
|
| }
|
| if (semantics != null) {
|
| - // TODO(johnniwinther): Support invalid super access as an
|
| - // [AccessSemantics].
|
| registry.registerSendStructure(node,
|
| new UnaryStructure(semantics, operator));
|
| }
|
| @@ -1325,7 +1455,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| registry.setSelector(node, selector);
|
|
|
| if (node.isSuperCall) {
|
| - if (checkSuperAccess(node)) {
|
| + semantics = checkSuperAccess(node);
|
| + if (semantics == null) {
|
| semantics = computeSuperAccessSemanticsForSelector(node, selector);
|
| // TODO(johnniwinther): Add information to [AccessSemantics] about
|
| // whether it is erroneous.
|
| @@ -1552,71 +1683,78 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| } else {
|
| selector = new Selector(SelectorKind.GETTER, name, callStructure);
|
| }
|
| - if (checkSuperAccess(node)) {
|
| - AccessSemantics semantics = computeSuperAccessSemanticsForSelector(
|
| + AccessSemantics semantics = checkSuperAccess(node);
|
| + if (semantics == null) {
|
| + semantics = computeSuperAccessSemanticsForSelector(
|
| node, selector, alternateName: name.setter);
|
| - if (node.isCall) {
|
| - bool isIncompatibleInvoke = false;
|
| - switch (semantics.kind) {
|
| - case AccessKind.SUPER_METHOD:
|
| - MethodElementX superMethod = semantics.element;
|
| - superMethod.computeSignature(compiler);
|
| - if (!callStructure.signatureApplies(
|
| - superMethod.functionSignature)) {
|
| - registry.registerThrowNoSuchMethod();
|
| - registry.registerDynamicInvocation(
|
| - new UniverseSelector(selector, null));
|
| - registry.registerSuperNoSuchMethod();
|
| - isIncompatibleInvoke = true;
|
| - } else {
|
| - registry.registerStaticInvocation(semantics.element);
|
| - }
|
| - break;
|
| - case AccessKind.SUPER_FIELD:
|
| - case AccessKind.SUPER_FINAL_FIELD:
|
| - case AccessKind.SUPER_GETTER:
|
| - registry.registerStaticUse(semantics.element);
|
| - selector = callStructure.callSelector;
|
| + }
|
| + if (node.isCall) {
|
| + bool isIncompatibleInvoke = false;
|
| + switch (semantics.kind) {
|
| + case AccessKind.SUPER_METHOD:
|
| + MethodElementX superMethod = semantics.element;
|
| + superMethod.computeSignature(compiler);
|
| + if (!callStructure.signatureApplies(
|
| + superMethod.functionSignature)) {
|
| + registry.registerThrowNoSuchMethod();
|
| registry.registerDynamicInvocation(
|
| new UniverseSelector(selector, null));
|
| - break;
|
| - case AccessKind.SUPER_SETTER:
|
| - case AccessKind.UNRESOLVED_SUPER:
|
| - // NoSuchMethod registered in [computeSuperSemantics].
|
| - break;
|
| - default:
|
| - internalError(node, "Unexpected super property access $semantics.");
|
| - break;
|
| - }
|
| - registry.registerSendStructure(node,
|
| - isIncompatibleInvoke
|
| - ? new IncompatibleInvokeStructure(semantics, selector)
|
| - : new InvokeStructure(semantics, selector));
|
| - } else {
|
| - switch (semantics.kind) {
|
| - case AccessKind.SUPER_METHOD:
|
| - // TODO(johnniwinther): Method this should be registered as a
|
| - // closurization.
|
| - registry.registerStaticUse(semantics.element);
|
| - break;
|
| - case AccessKind.SUPER_FIELD:
|
| - case AccessKind.SUPER_FINAL_FIELD:
|
| - case AccessKind.SUPER_GETTER:
|
| - registry.registerStaticUse(semantics.element);
|
| - break;
|
| - case AccessKind.SUPER_SETTER:
|
| - case AccessKind.UNRESOLVED_SUPER:
|
| - // NoSuchMethod registered in [computeSuperSemantics].
|
| - break;
|
| - default:
|
| - internalError(node, "Unexpected super property access $semantics.");
|
| - break;
|
| - }
|
| - registry.registerSendStructure(node,
|
| - new GetStructure(semantics, selector));
|
| + registry.registerSuperNoSuchMethod();
|
| + isIncompatibleInvoke = true;
|
| + } else {
|
| + registry.registerStaticInvocation(semantics.element);
|
| + }
|
| + break;
|
| + case AccessKind.SUPER_FIELD:
|
| + case AccessKind.SUPER_FINAL_FIELD:
|
| + case AccessKind.SUPER_GETTER:
|
| + registry.registerStaticUse(semantics.element);
|
| + selector = callStructure.callSelector;
|
| + registry.registerDynamicInvocation(
|
| + new UniverseSelector(selector, null));
|
| + break;
|
| + case AccessKind.SUPER_SETTER:
|
| + case AccessKind.UNRESOLVED_SUPER:
|
| + // NoSuchMethod registered in [computeSuperSemantics].
|
| + break;
|
| + case AccessKind.INVALID:
|
| + // 'super' is not allowed.
|
| + break;
|
| + default:
|
| + internalError(node, "Unexpected super property access $semantics.");
|
| + break;
|
| }
|
| - target = semantics.element;
|
| + registry.registerSendStructure(node,
|
| + isIncompatibleInvoke
|
| + ? new IncompatibleInvokeStructure(semantics, selector)
|
| + : new InvokeStructure(semantics, selector));
|
| + } else {
|
| + switch (semantics.kind) {
|
| + case AccessKind.SUPER_METHOD:
|
| + // TODO(johnniwinther): Method this should be registered as a
|
| + // closurization.
|
| + registry.registerStaticUse(semantics.element);
|
| + break;
|
| + case AccessKind.SUPER_FIELD:
|
| + case AccessKind.SUPER_FINAL_FIELD:
|
| + case AccessKind.SUPER_GETTER:
|
| + registry.registerStaticUse(semantics.element);
|
| + break;
|
| + case AccessKind.SUPER_SETTER:
|
| + case AccessKind.UNRESOLVED_SUPER:
|
| + // NoSuchMethod registered in [computeSuperSemantics].
|
| + break;
|
| + case AccessKind.INVALID:
|
| + // 'super' is not allowed.
|
| + break;
|
| + default:
|
| + internalError(node, "Unexpected super property access $semantics.");
|
| + break;
|
| + }
|
| + registry.registerSendStructure(node,
|
| + new GetStructure(semantics, selector));
|
| }
|
| + target = semantics.element;
|
|
|
| // TODO(johnniwinther): Remove these when all information goes through
|
| // the [SendStructure].
|
| @@ -2621,10 +2759,116 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
| }
|
| }
|
|
|
| + /// Handle super index operations like `super[a] = b`, `super[a] += b`, and
|
| + /// `super[a]++`.
|
| + // TODO(johnniwinther): Share code with [handleIndexSendSet].
|
| + ResolutionResult handleSuperIndexSendSet(SendSet node) {
|
| + String operatorText = node.assignmentOperator.source;
|
| + Node index = node.arguments.head;
|
| + visitExpression(index);
|
| + AccessSemantics semantics = checkSuperAccess(node);
|
| + if (node.isPrefix || node.isPostfix) {
|
| + // `super[a]++` or `++super[a]`.
|
| + IncDecOperator operator = IncDecOperator.parse(operatorText);
|
| + Selector getterSelector = new Selector.index();
|
| + Selector setterSelector = new Selector.indexSet();
|
| + Selector operatorSelector =
|
| + new Selector.binaryOperator(operator.selectorName);
|
| +
|
| + // TODO(johnniwinther): Remove these when selectors are only accessed
|
| + // through the send structure.
|
| + registry.setGetterSelectorInComplexSendSet(node, getterSelector);
|
| + registry.setSelector(node, setterSelector);
|
| + registry.setOperatorSelectorInComplexSendSet(node, operatorSelector);
|
| +
|
| + if (semantics == null) {
|
| + semantics = computeSuperAccessSemanticsForSelectors(
|
| + node, getterSelector, setterSelector);
|
| +
|
| + registry.registerStaticInvocation(semantics.getter);
|
| + registry.registerStaticInvocation(semantics.setter);
|
| +
|
| + // TODO(johnniwinther): Remove these when elements are only accessed
|
| + // through the send structure.
|
| + registry.useElement(node, semantics.setter);
|
| + registry.useElement(node.selector, semantics.getter);
|
| + }
|
| + registry.registerDynamicInvocation(
|
| + new UniverseSelector(operatorSelector, null));
|
| +
|
| + SendStructure sendStructure = node.isPrefix
|
| + ? new IndexPrefixStructure(
|
| + semantics, operator, getterSelector, setterSelector)
|
| + : new IndexPostfixStructure(
|
| + semantics, operator, getterSelector, setterSelector);
|
| + registry.registerSendStructure(node, sendStructure);
|
| + return const NoneResult();
|
| + } else {
|
| + Node rhs = node.arguments.tail.head;
|
| + visitExpression(rhs);
|
| +
|
| + AssignmentOperator operator = AssignmentOperator.parse(operatorText);
|
| + if (operator.kind == AssignmentOperatorKind.ASSIGN) {
|
| + // `super[a] = b`.
|
| + Selector setterSelector = new Selector.indexSet();
|
| + if (semantics == null) {
|
| + semantics =
|
| + computeSuperAccessSemanticsForSelector(node, setterSelector);
|
| +
|
| + // TODO(johnniwinther): Remove these when elements are only accessed
|
| + // through the send structure.
|
| + registry.useElement(node, semantics.setter);
|
| + }
|
| +
|
| + // TODO(johnniwinther): Remove this when selectors are only accessed
|
| + // through the send structure.
|
| + registry.setSelector(node, setterSelector);
|
| + registry.registerStaticInvocation(semantics.setter);
|
| +
|
| + SendStructure sendStructure =
|
| + new IndexSetStructure(semantics, setterSelector);
|
| + registry.registerSendStructure(node, sendStructure);
|
| + return const NoneResult();
|
| + } else {
|
| + // `super[a] += b`.
|
| + Selector getterSelector = new Selector.index();
|
| + Selector setterSelector = new Selector.indexSet();
|
| + Selector operatorSelector =
|
| + new Selector.binaryOperator(operator.selectorName);
|
| + if (semantics == null) {
|
| + semantics = computeSuperAccessSemanticsForSelectors(
|
| + node, getterSelector, setterSelector);
|
| +
|
| + registry.registerStaticInvocation(semantics.getter);
|
| + registry.registerStaticInvocation(semantics.setter);
|
| +
|
| + // TODO(johnniwinther): Remove these when elements are only accessed
|
| + // through the send structure.
|
| + registry.useElement(node, semantics.setter);
|
| + registry.useElement(node.selector, semantics.getter);
|
| + }
|
| +
|
| + // TODO(johnniwinther): Remove these when selectors are only accessed
|
| + // through the send structure.
|
| + registry.setGetterSelectorInComplexSendSet(node, getterSelector);
|
| + registry.setSelector(node, setterSelector);
|
| + registry.setOperatorSelectorInComplexSendSet(node, operatorSelector);
|
| +
|
| + registry.registerDynamicInvocation(
|
| + new UniverseSelector(operatorSelector, null));
|
| +
|
| + SendStructure sendStructure = new CompoundIndexSetStructure(
|
| + semantics, operator, getterSelector, setterSelector);
|
| + registry.registerSendStructure(node, sendStructure);
|
| + return const NoneResult();
|
| + }
|
| + }
|
| + }
|
| +
|
| ResolutionResult visitSendSet(SendSet node) {
|
| if (node.isIndex) {
|
| if (node.isSuperCall) {
|
| - // TODO(johnniwinther): Refactor index operations on super.
|
| + return handleSuperIndexSendSet(node);
|
| } else {
|
| return handleIndexSendSet(node);
|
| }
|
|
|