Chromium Code Reviews| 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 57004c3d40b5c159744798daaf3cdb2ef44d82e2..12468031a68e31a34a407504cfe0c39da812d6c7 100644 |
| --- a/pkg/compiler/lib/src/resolution/members.dart |
| +++ b/pkg/compiler/lib/src/resolution/members.dart |
| @@ -2648,13 +2648,13 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| } |
| // TODO(johnniwinther): Ensure correct behavior if currentClass is a |
| // patch. |
| - target = currentClass.lookupSuperSelector(selector); |
| + target = currentClass.lookupSuperByName(selector.memberName); |
| // [target] may be null which means invoking noSuchMethod on |
| // super. |
| if (target == null) { |
| target = reportAndCreateErroneousElement( |
| node, name, MessageKind.NO_SUCH_SUPER_MEMBER, |
| - {'className': currentClass, 'memberName': name}); |
| + {'className': currentClass.name, 'memberName': name}); |
| // We still need to register the invocation, because we might |
| // call [:super.noSuchMethod:] which calls |
| // [JSInvocationMirror._invokeOn]. |
| @@ -2859,15 +2859,342 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| } |
| } |
| - ResolutionResult visitSend(Send node) { |
| + /// Check that access to `super` is currently allowed. |
| + bool checkSuperAccess(Node node) { |
| + registry.registerSuperUse(node); |
|
karlklose
2015/05/26 08:23:32
Move this to after the checks?
Johnni Winther
2015/05/26 08:53:11
Done.
|
| + if (!inInstanceContext) { |
| + compiler.reportError(node, MessageKind.NO_SUPER_AVAILABLE); |
| + return false; |
| + } |
| + 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 true; |
| + } |
| + |
| + /// Compute the [AccessSemantics] corresponding to a super access of [target]. |
| + AccessSemantics computeSuperAccess(Spannable node, Element target) { |
| + if (target.isErroneous) { |
| + return new StaticAccess.unresolvedSuper(target); |
| + } else if (target.isGetter) { |
| + return new StaticAccess.superGetter(target); |
| + } else if (target.isSetter) { |
| + return new StaticAccess.superSetter(target); |
| + } else if (target.isField) { |
| + return new StaticAccess.superField(target); |
| + } else { |
| + assert(invariant(node, target.isFunction, |
| + message: "Unexpected super target '$target'.")); |
| + return new StaticAccess.superMethod(target); |
| + } |
| + } |
| + |
| + AccessSemantics computeSuperSemantics(Spannable node, |
| + Selector selector, |
| + {Name alternateName}) { |
| + Name name = selector.memberName; |
| + // TODO(johnniwinther): Ensure correct behavior if currentClass is a |
| + // patch. |
| + Element target = currentClass.lookupSuperByName(name); |
| + // [target] may be null which means invoking noSuchMethod on super. |
| + if (target == null) { |
| + Element error = reportAndCreateErroneousElement( |
| + node, name.text, MessageKind.NO_SUCH_SUPER_MEMBER, |
| + {'className': currentClass.name, 'memberName': name}); |
| + if (alternateName != null) { |
| + target = currentClass.lookupSuperByName(alternateName); |
| + } |
| + if (target == null) { |
| + // If a setter wasn't resolved, use the [ErroneousElement]. |
| + target = error; |
| + } |
| + // We still need to register the invocation, because we might |
| + // call [:super.noSuchMethod:] which calls [JSInvocationMirror._invokeOn]. |
| + registry.registerDynamicInvocation(selector); |
| + registry.registerSuperNoSuchMethod(); |
| + } |
| + return computeSuperAccess(node, target); |
| + } |
| + |
| + ResolutionResult visitExpression(Node node) { |
| bool oldSendIsMemberAccess = sendIsMemberAccess; |
| - sendIsMemberAccess = node.isPropertyAccess || node.isCall; |
| - ResolutionResult result; |
| - if (node.isLogicalAnd) { |
| - result = doInPromotionScope(node.receiver, () => resolveSend(node)); |
| + sendIsMemberAccess = false; |
| + ResolutionResult result = visit(node); |
| + sendIsMemberAccess = oldSendIsMemberAccess; |
| + return result; |
| + } |
| + |
| + ResolutionResult handleIs(Send node) { |
| + Node expression = node.receiver; |
| + visitExpression(expression); |
| + |
| + // TODO(johnniwinther): Use seen type tests to avoid registration of |
| + // mutation/access to unpromoted variables. |
| + |
| + Send notTypeNode = node.arguments.head.asSend(); |
| + DartType type; |
| + SendStructure sendStructure; |
| + if (notTypeNode != null) { |
| + // `e is! T`. |
| + Node typeNode = notTypeNode.receiver; |
| + type = resolveTypeAnnotation(typeNode); |
| + sendStructure = new IsNotStructure(type); |
| } else { |
| - result = resolveSend(node); |
| + // `e is T`. |
| + Node typeNode = node.arguments.head; |
| + type = resolveTypeAnnotation(typeNode); |
| + sendStructure = new IsStructure(type); |
| } |
| + registry.registerIsCheck(type); |
| + registry.registerSendStructure(node, sendStructure); |
| + return null; |
|
karlklose
2015/05/26 08:23:32
Not this change, but: I really do not like to retu
Johnni Winther
2015/05/26 08:53:11
Acknowledged.
|
| + } |
| + |
| + ResolutionResult handleAs(Send node) { |
| + Node expression = node.receiver; |
| + visitExpression(expression); |
| + |
| + Node typeNode = node.arguments.head; |
| + DartType type = resolveTypeAnnotation(typeNode); |
| + registry.registerAsCheck(type); |
| + registry.registerSendStructure(node, new AsStructure(type)); |
| + return null; |
| + } |
| + |
| + ResolutionResult handleUnresolvedUnary(Send node, String text) { |
| + Node expression = node.receiver; |
| + if (node.isSuperCall) { |
| + checkSuperAccess(node); |
| + } else { |
| + visitExpression(expression); |
| + } |
| + |
| + registry.registerSendStructure(node, const InvalidUnaryStructure()); |
| + return null; |
| + } |
| + |
| + ResolutionResult handleUserDefinableUnary(Send node, UnaryOperator operator) { |
| + Node expression = node.receiver; |
| + Selector selector = operator.selector; |
| + // TODO(johnniwinther): Remove this when all information goes through the |
| + // [SendStructure]. |
| + registry.setSelector(node, selector); |
| + |
| + AccessSemantics semantics; |
| + if (node.isSuperCall) { |
| + if (checkSuperAccess(node)) { |
| + semantics = computeSuperSemantics(node, selector); |
| + // TODO(johnniwinther): Add information to [AccessSemantics] about |
| + // whether it is erroneous. |
| + switch (semantics.kind) { |
|
karlklose
2015/05/26 08:23:32
How about
if (semantics.kind == AccessKind.SUPER_
Johnni Winther
2015/05/26 08:53:11
Done.
|
| + case AccessKind.SUPER_METHOD: |
| + registry.registerStaticUse(semantics.element.declaration); |
| + break; |
| + default: |
| + } |
| + // TODO(johnniwinther): Remove this when all information goes through |
| + // the [SendStructure]. |
| + registry.useElement(node, semantics.element); |
| + } |
| + } else { |
| + visitExpression(expression); |
| + semantics = new DynamicAccess.dynamicProperty(expression); |
| + registry.registerDynamicInvocation(selector); |
| + } |
| + if (semantics != null) { |
| + // TODO(johnniwinther): Support invalid super access as an |
| + // [AccessSemantics]. |
| + registry.registerSendStructure(node, |
| + new UnaryStructure(semantics, operator)); |
| + } |
| + return null; |
| + } |
| + |
| + ResolutionResult handleNot(Send node, UnaryOperator operator) { |
| + assert(invariant(node, operator.kind == UnaryOperatorKind.NOT)); |
| + |
| + Node expression = node.receiver; |
| + visitExpression(expression); |
| + registry.registerSendStructure(node, |
| + new NotStructure(new DynamicAccess.dynamicProperty(expression))); |
| + return null; |
| + } |
| + |
| + ResolutionResult handleLogicalAnd(Send node) { |
| + Node left = node.receiver; |
| + Node right = node.arguments.head; |
| + doInPromotionScope(left, () => visitExpression(left)); |
| + doInPromotionScope(right, () => visitExpression(right)); |
| + registry.registerSendStructure(node, const LogicalAndStructure()); |
| + return null; |
| + } |
| + |
| + ResolutionResult handleLogicalOr(Send node) { |
| + Node left = node.receiver; |
| + Node right = node.arguments.head; |
| + visitExpression(left); |
| + visitExpression(right); |
| + registry.registerSendStructure(node, const LogicalOrStructure()); |
| + return null; |
| + } |
| + |
| + ResolutionResult handleUnresolvedBinary(Send node, String text) { |
| + Node left = node.receiver; |
| + Node right = node.arguments.head; |
| + if (node.isSuperCall) { |
| + checkSuperAccess(node); |
| + } else { |
| + visitExpression(left); |
| + } |
| + visitExpression(right); |
| + registry.registerSendStructure(node, const InvalidBinaryStructure()); |
| + return null; |
| + } |
| + |
| + ResolutionResult handleUserDefinableBinary(Send node, |
| + BinaryOperator operator) { |
| + Node left = node.receiver; |
| + Node right = node.arguments.head; |
| + AccessSemantics semantics; |
| + Selector selector; |
| + if (operator.kind == BinaryOperatorKind.INDEX) { |
| + selector = new Selector.index(); |
| + } else { |
| + selector = new Selector.binaryOperator(operator.selectorName); |
| + } |
| + // TODO(johnniwinther): Remove this when all information goes through the |
| + // [SendStructure]. |
| + registry.setSelector(node, selector); |
| + |
| + if (node.isSuperCall) { |
| + if (checkSuperAccess(node)) { |
| + semantics = computeSuperSemantics(node, selector); |
| + // TODO(johnniwinther): Add information to [AccessSemantics] about |
| + // whether it is erroneous. |
| + switch (semantics.kind) { |
|
karlklose
2015/05/26 08:23:33
See comment for l. 2993.
Johnni Winther
2015/05/26 08:53:11
Done.
|
| + case AccessKind.SUPER_METHOD: |
| + registry.registerStaticUse(semantics.element.declaration); |
| + break; |
| + default: |
| + } |
| + // TODO(johnniwinther): Remove this when all information goes through |
| + // the [SendStructure]. |
| + registry.useElement(node, semantics.element); |
| + |
| + } |
| + } else { |
| + visitExpression(left); |
| + registry.registerDynamicInvocation(selector); |
| + semantics = new DynamicAccess.dynamicProperty(left); |
| + } |
| + visitExpression(right); |
| + |
| + if (semantics != null) { |
| + // TODO(johnniwinther): Support invalid super access as an |
| + // [AccessSemantics]. |
| + SendStructure sendStructure; |
| + switch (operator.kind) { |
| + case BinaryOperatorKind.EQ: |
| + sendStructure = new EqualsStructure(semantics); |
| + break; |
| + case BinaryOperatorKind.NOT_EQ: |
| + sendStructure = new NotEqualsStructure(semantics); |
| + break; |
| + case BinaryOperatorKind.INDEX: |
| + sendStructure = new IndexStructure(semantics); |
| + break; |
| + case BinaryOperatorKind.ADD: |
| + case BinaryOperatorKind.SUB: |
| + case BinaryOperatorKind.MUL: |
| + case BinaryOperatorKind.DIV: |
| + case BinaryOperatorKind.IDIV: |
| + case BinaryOperatorKind.MOD: |
| + case BinaryOperatorKind.SHL: |
| + case BinaryOperatorKind.SHR: |
| + case BinaryOperatorKind.GTEQ: |
| + case BinaryOperatorKind.GT: |
| + case BinaryOperatorKind.LTEQ: |
| + case BinaryOperatorKind.LT: |
| + case BinaryOperatorKind.AND: |
| + case BinaryOperatorKind.OR: |
| + case BinaryOperatorKind.XOR: |
| + sendStructure = new BinaryStructure(semantics, operator); |
| + break; |
| + case BinaryOperatorKind.LOGICAL_AND: |
| + case BinaryOperatorKind.LOGICAL_OR: |
| + internalError(node, "Unexpected binary operator '${operator}'."); |
| + break; |
| + } |
| + registry.registerSendStructure(node, sendStructure); |
| + } |
| + return null; |
| + } |
| + |
| + ResolutionResult visitSend(Send node) { |
| + if (node.isOperator) { |
| + String operatorText = node.selector.asOperator().source; |
| + if (operatorText == 'is') { |
| + return handleIs(node); |
| + } else if (operatorText == 'as') { |
| + return handleAs(node); |
| + } else if (node.arguments.isEmpty) { |
| + UnaryOperator operator = UnaryOperator.parse(operatorText); |
| + if (operator == null) { |
| + return handleUnresolvedUnary(node, operatorText); |
| + } else { |
| + switch (operator.kind) { |
| + case UnaryOperatorKind.NOT: |
| + return handleNot(node, operator); |
| + case UnaryOperatorKind.COMPLEMENT: |
| + case UnaryOperatorKind.NEGATE: |
| + assert(invariant(node, operator.isUserDefinable, |
| + message: "Unexpected unary operator '${operator}'.")); |
| + return handleUserDefinableUnary(node, operator); |
| + } |
| + return handleUserDefinableUnary(node, operator); |
| + } |
| + } else { |
| + BinaryOperator operator = BinaryOperator.parse(operatorText); |
| + if (operator == null) { |
| + return handleUnresolvedBinary(node, operatorText); |
| + } else { |
| + switch (operator.kind) { |
| + case BinaryOperatorKind.LOGICAL_AND: |
| + return handleLogicalAnd(node); |
| + case BinaryOperatorKind.LOGICAL_OR: |
| + return handleLogicalOr(node); |
| + case BinaryOperatorKind.EQ: |
| + case BinaryOperatorKind.NOT_EQ: |
| + case BinaryOperatorKind.INDEX: |
| + case BinaryOperatorKind.ADD: |
| + case BinaryOperatorKind.SUB: |
| + case BinaryOperatorKind.MUL: |
| + case BinaryOperatorKind.DIV: |
| + case BinaryOperatorKind.IDIV: |
| + case BinaryOperatorKind.MOD: |
| + case BinaryOperatorKind.SHL: |
| + case BinaryOperatorKind.SHR: |
| + case BinaryOperatorKind.GTEQ: |
| + case BinaryOperatorKind.GT: |
| + case BinaryOperatorKind.LTEQ: |
| + case BinaryOperatorKind.LT: |
| + case BinaryOperatorKind.AND: |
| + case BinaryOperatorKind.OR: |
| + case BinaryOperatorKind.XOR: |
| + return handleUserDefinableBinary(node, operator); |
| + } |
| + } |
| + } |
| + } |
| + |
| + bool oldSendIsMemberAccess = sendIsMemberAccess; |
| + sendIsMemberAccess = node.isPropertyAccess || node.isCall; |
| + |
| + ResolutionResult result = resolveSend(node); |
| sendIsMemberAccess = oldSendIsMemberAccess; |
| Element target = result != null ? result.element : null; |
| @@ -2918,43 +3245,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| } |
| bool resolvedArguments = false; |
| - if (node.isOperator) { |
| - String operatorString = node.selector.asOperator().source; |
| - SendStructure sendStructure; |
| - if (operatorString == 'is') { |
| - // TODO(johnniwinther): Use seen type tests to avoid registration of |
| - // mutation/access to unpromoted variables. |
| - DartType type = |
| - resolveTypeAnnotation(node.typeAnnotationFromIsCheckOrCast); |
| - if (type != null) { |
| - sendStructure = node.isIsNotCheck |
| - ? new IsNotStructure(type) : new IsStructure(type); |
| - registry.registerIsCheck(type); |
| - } |
| - resolvedArguments = true; |
| - } else if (identical(operatorString, 'as')) { |
| - DartType type = resolveTypeAnnotation(node.arguments.head); |
| - if (type != null) { |
| - sendStructure = new AsStructure(type); |
| - registry.registerAsCheck(type); |
| - } |
| - resolvedArguments = true; |
| - } else if (identical(operatorString, '&&')) { |
| - doInPromotionScope(node.arguments.head, |
| - () => resolveArguments(node.argumentsNode)); |
| - sendStructure = const LogicalAndStructure(); |
| - resolvedArguments = true; |
| - } else if (operatorString == '||') { |
| - sendStructure = const LogicalOrStructure(); |
| - } |
| - if (sendStructure != null) { |
| - registry.registerSendStructure(node, sendStructure); |
| - } |
| - } |
| - |
| - if (!resolvedArguments) { |
| - resolveArguments(node.argumentsNode); |
| - } |
| + resolveArguments(node.argumentsNode); |
| // If the selector is null, it means that we will not be generating |
| // code for this as a send. |
| @@ -3124,11 +3415,11 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| registerSend(getterSelector, getter); |
| registry.setGetterSelectorInComplexSendSet(node, getterSelector); |
| if (node.isSuperCall) { |
| - getter = currentClass.lookupSuperSelector(getterSelector); |
| + getter = currentClass.lookupSuperByName(getterSelector.memberName); |
| if (getter == null) { |
| target = reportAndCreateErroneousElement( |
| node, selector.name, MessageKind.NO_SUCH_SUPER_MEMBER, |
| - {'className': currentClass, 'memberName': selector.name}); |
| + {'className': currentClass.name, 'memberName': selector.name}); |
| registry.registerSuperNoSuchMethod(); |
| } |
| } |