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 142f5e6b46423a804d4d7d73e51d2aac965dce26..24ea86acaaee2387d9165f6bf96055235f8f4d12 100644 |
| --- a/pkg/compiler/lib/src/resolution/members.dart |
| +++ b/pkg/compiler/lib/src/resolution/members.dart |
| @@ -639,148 +639,6 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| return const NoneResult(); |
| } |
| - ResolutionResult resolveSend(Send node) { |
| - Selector selector = resolveSelector(node, null); |
| - if (node.isSuperCall) registry.registerSuperUse(node); |
| - |
| - if (node.receiver == null) { |
| - // If this send is of the form "assert(expr);", then |
| - // this is an assertion. |
| - if (selector.isAssert) { |
| - internalError(node, "Unexpected assert: $node"); |
| - } |
| - |
| - return node.selector.accept(this); |
| - } |
| - |
| - var oldCategory = allowedCategory; |
| - allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER; |
| - |
| - bool oldSendIsMemberAccess = sendIsMemberAccess; |
| - int oldAllowedCategory = allowedCategory; |
| - |
| - // 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. |
| - if (node.isConditional) { |
| - sendIsMemberAccess = false; |
| - allowedCategory = |
| - ElementCategory.VARIABLE | |
| - ElementCategory.FUNCTION | |
| - ElementCategory.IMPLIES_TYPE; |
| - } |
| - ResolutionResult resolvedReceiver = visit(node.receiver); |
| - if (node.isConditional) { |
| - sendIsMemberAccess = oldSendIsMemberAccess; |
| - allowedCategory = oldAllowedCategory; |
| - } |
| - |
| - allowedCategory = oldCategory; |
| - |
| - Element target; |
| - String name = node.selector.asIdentifier().source; |
| - if (identical(name, 'this')) { |
| - error(node.selector, MessageKind.THIS_PROPERTY); |
| - return const NoneResult(); |
| - } else if (node.isSuperCall) { |
| - if (node.isOperator) { |
| - if (isUserDefinableOperator(name)) { |
| - name = selector.name; |
| - } else { |
| - error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name}); |
| - return const NoneResult(); |
| - } |
| - } |
| - if (!inInstanceContext) { |
| - error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name}); |
| - return const NoneResult(); |
| - } |
| - if (currentClass.supertype == null) { |
| - // This is just to guard against internal errors, so no need |
| - // for a real error message. |
| - error(node.receiver, MessageKind.GENERIC, |
| - {'text': "Object has no superclass"}); |
| - return const NoneResult(); |
| - } |
| - // TODO(johnniwinther): Ensure correct behavior if currentClass is a |
| - // patch. |
| - 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.name, 'memberName': name}); |
| - // We still need to register the invocation, because we might |
| - // call [:super.noSuchMethod:] which calls |
| - // [JSInvocationMirror._invokeOn]. |
| - registry.registerDynamicInvocation( |
| - new UniverseSelector(selector, null)); |
| - registry.registerSuperNoSuchMethod(); |
| - } |
| - } else if (Elements.isUnresolved(resolvedReceiver.element)) { |
| - return const NoneResult(); |
| - } else if (resolvedReceiver.element.isClass) { |
| - ClassElement receiverClass = resolvedReceiver.element; |
| - 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); |
| - target = receiverClass.lookupLocalMember(name); |
| - if (target == null || target.isInstanceMember) { |
| - 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. |
| - MessageKind kind = (target == null) |
| - ? MessageKind.MEMBER_NOT_FOUND |
| - : MessageKind.MEMBER_NOT_STATIC; |
| - return new ElementResult(reportAndCreateErroneousElement( |
| - node, name, kind, |
| - {'className': receiverClass.name, 'memberName': name})); |
| - } else if (isPrivateName(name) && |
| - target.library != enclosingElement.library) { |
| - registry.registerThrowNoSuchMethod(); |
| - return new ElementResult(reportAndCreateErroneousElement( |
| - node, name, MessageKind.PRIVATE_ACCESS, |
| - {'libraryName': target.library.getLibraryOrScriptName(), |
| - 'name': name})); |
| - } |
| - } else if (resolvedReceiver.element.isPrefix) { |
| - PrefixElement prefix = resolvedReceiver.element; |
| - target = prefix.lookupLocalMember(name); |
| - if (Elements.isUnresolved(target)) { |
| - registry.registerThrowNoSuchMethod(); |
| - return new ElementResult(reportAndCreateErroneousElement( |
| - node, name, MessageKind.NO_SUCH_LIBRARY_MEMBER, |
| - {'libraryName': prefix.name, 'memberName': name})); |
| - } else if (target.isAmbiguous) { |
| - registry.registerThrowNoSuchMethod(); |
| - AmbiguousElement ambiguous = target; |
| - target = reportAndCreateErroneousElement( |
| - node, name, ambiguous.messageKind, ambiguous.messageArguments); |
| - ambiguous.diagnose(enclosingElement, compiler); |
| - return new ElementResult(target); |
| - } else if (target.kind == ElementKind.CLASS) { |
| - ClassElement classElement = target; |
| - classElement.ensureResolved(compiler); |
| - } |
| - } |
| - return new ResolutionResult.forElement(target); |
| - } |
| - |
| static Selector computeSendSelector(Send node, |
| LibraryElement library, |
| Element element) { |
| @@ -900,47 +758,6 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| isValidAsConstant: isValidAsConstant); |
| } |
| - void registerTypeLiteralAccess(Send node, Element target) { |
| - // Set the type of the node to [Type] to mark this send as a |
| - // type literal. |
| - DartType type; |
| - |
| - // TODO(johnniwinther): Remove this hack when we can pass more complex |
| - // information between methods than resolved elements. |
| - if (target == compiler.typeClass && node.receiver == null) { |
| - // Potentially a 'dynamic' type literal. |
| - type = registry.getType(node.selector); |
| - } |
| - if (type == null) { |
| - if (target.isTypedef || target.isClass) { |
| - TypeDeclarationElement typeDeclaration = target; |
| - typeDeclaration.computeType(compiler); |
| - type = typeDeclaration.rawType; |
| - } else { |
| - TypeVariableElement typeVariable = target; |
| - type = typeVariable.type; |
| - } |
| - } |
| - registry.registerTypeLiteral(node, type); |
| - |
| - if (!target.isTypeVariable) { |
| - // Don't try to make constants of calls and assignments to type literals. |
| - if (!node.isCall && node.asSendSet() == null) { |
| - analyzeConstantDeferred(node, enforceConst: false); |
| - } else { |
| - // The node itself is not a constant but we register the selector (the |
| - // identifier that refers to the class/typedef) as a constant. |
| - if (node.receiver != null) { |
| - // This is a hack for the case of prefix.Type, we need to store |
| - // the element on the selector, so [analyzeConstant] can build |
| - // the type literal from the selector. |
| - registry.useElement(node.selector, target); |
| - } |
| - analyzeConstantDeferred(node.selector, enforceConst: false); |
| - } |
| - } |
| - } |
| - |
| /// Check that access to `super` is currently allowed. Returns an |
| /// [AccessSemantics] in case of an error, `null` otherwise. |
| AccessSemantics checkSuperAccess(Send node) { |
| @@ -1947,6 +1764,29 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| node, name, new StaticAccess.unresolved(error)); |
| } |
| + /// Handle qualified update to an unresolved static class member, like |
| + /// `a.b = c` or `a.b++` where `a` is a class and `b` is unresolved. |
| + ResolutionResult handleUnresolvedStaticMemberUpdate( |
| + SendSet node, Name name, ClassElement receiverClass) { |
| + // TODO(johnniwinther): Share code with [handleStaticInstanceMemberUpdate] |
| + // and [handlePrivateStaticMemberUpdate]. |
| + 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(johnniwinther): Produce a different error for complex update. |
| + 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 handleUpdate(node, name, 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( |
| @@ -1970,8 +1810,28 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| node, name, new StaticAccess.unresolved(error)); |
| } |
| + /// Handle qualified update of an instance member, like `a.b = c` or `a.b++` |
| + /// where `a` is a class and `b` is a non-static member. |
| + ResolutionResult handleStaticInstanceMemberUpdate( |
| + SendSet 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(johnniwinther): Produce a different error for complex update. |
| + 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 handleUpdate(node, name, 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` |
| + /// 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) { |
| @@ -1986,6 +1846,21 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| node, name, new StaticAccess.unresolved(error)); |
| } |
| + /// Handle qualified update of an inaccessible private static class member, |
| + /// like `a._b = c` or `a._b++` where `a` is class, `_b` is static member of |
| + /// `a` but `a` is not defined in the current library. |
| + ResolutionResult handlePrivateStaticMemberUpdate( |
| + SendSet 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 handleUpdate(node, name, 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( |
| @@ -2020,6 +1895,31 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| } |
| } |
| + /// Handle qualified update to a static member, like `a.b = c` or `a.b++` |
| + /// where `a` is a class and `b` is a static member of `a`. |
| + ResolutionResult handleStaticMemberUpdate( |
| + Send node, Name memberName, ClassElement receiverClass) { |
| + String name = memberName.text; |
| + receiverClass.ensureResolved(compiler); |
| + MembersCreator.computeClassMembersByName( |
| + compiler, receiverClass.declaration, name); |
| + Element member = receiverClass.lookupLocalMember(name); |
| + if (member == null) { |
| + return handleUnresolvedStaticMemberUpdate( |
| + node, memberName, receiverClass); |
| + } else if (member.isAmbiguous) { |
| + return handleAmbiguousUpdate(node, memberName, member); |
| + } else if (member.isInstanceMember) { |
| + return handleStaticInstanceMemberUpdate( |
| + node, memberName, receiverClass, member); |
| + } else if (memberName.isPrivate && memberName.library != member.library) { |
| + return handlePrivateStaticMemberUpdate( |
| + node, memberName, receiverClass, member); |
| + } else { |
| + return handleStaticOrTopLevelUpdate(node, memberName, member); |
| + } |
| + } |
| + |
| /// Handle access to a type literal of type variable [element]. Like `T` or |
| /// `T()` where 'T' is type variable. |
| // TODO(johnniwinther): Remove [name] when [Selector] is not required for the |
| @@ -2331,6 +2231,34 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| return result; |
| } |
| + /// Handle qualified [SendSet] where the receiver resolves to a [prefix], |
| + /// like `prefix.toplevelField = b` or `prefix.Class.staticField++` where |
| + /// `prefix` is a library prefix. |
| + ResolutionResult handleLibraryPrefixSendSet( |
| + SendSet node, Name name, PrefixElement prefix) { |
| + 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}); |
| + return handleUpdate(node, name, new StaticAccess.unresolved(error)); |
| + } else { |
| + result = handleResolvedSendSet(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 |
| /// `prefix.Class` or `prefix` in `prefix()`, the latter being a compile time |
| /// error. |
| @@ -2378,6 +2306,27 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| } |
| } |
| + /// Handle qualified [SendSet] where the receiver resolves to an [Element], |
| + /// like `a.b = c` where `a` is a prefix or a class. |
| + ResolutionResult handlePrefixSendSet( |
| + SendSet node, Name name, PrefixResult prefixResult) { |
| + Element element = prefixResult.element; |
| + if (element.isPrefix) { |
| + if (node.isConditional) { |
| + return handleLibraryPrefix(node, name, element); |
| + } else { |
| + return handleLibraryPrefixSendSet(node, name, element); |
| + } |
| + } else { |
| + assert(element.isClass); |
| + ResolutionResult result = handleStaticMemberUpdate(node, name, element); |
| + if (prefixResult.isDeferred) { |
| + result = handleDeferredAccess(node, prefixResult.prefix, result); |
| + } |
| + return result; |
| + } |
| + } |
| + |
| /// Handle dynamic access of [semantics]. |
| ResolutionResult handleDynamicAccessSemantics( |
| Send node, Name name, AccessSemantics semantics) { |
| @@ -2482,6 +2431,37 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| } |
| } |
| + /// Handle a qualified [SendSet], that is where the receiver is non-null, like |
| + /// `a.b = c`, `a.b++`, and `a.b += c`. |
| + ResolutionResult handleQualifiedSendSet(SendSet node) { |
| + Identifier selector = node.selector.asIdentifier(); |
| + String text = selector.source; |
| + Name name = new Name(text, enclosingElement.library); |
| + if (text == 'this') { |
|
floitsch
2015/08/20 16:28:34
That feels like a weird check.
Is it for captured
Johnni Winther
2015/08/21 07:17:36
This is for cases like 'C.this' for which there is
floitsch
2015/08/21 09:27:50
Ah...
Didn't realize this was the selector and not
|
| + return handleQualifiedThisAccess(node, name); |
| + } else if (node.receiver.isThis()) { |
| + if (checkThisAccess(node)) { |
| + return handleThisPropertyUpdate(node, name, null); |
| + } |
| + // TODO(johnniwinther): Handle invalid this access as an |
| + // [AccessSemantics]. |
| + return const NoneResult(); |
| + } |
| + ResolutionResult result = visitExpressionPrefix(node.receiver); |
| + if (result.kind == ResultKind.PREFIX) { |
| + return handlePrefixSendSet(node, name, result); |
| + } else if (node.isConditional) { |
| + return handleDynamicUpdateSemantics( |
| + node, name, null, const DynamicAccess.ifNotNullProperty()); |
| + } else { |
| + // Handle dynamic property access, like `a.b = c`, `a.b++` or `a.b += c` |
| + // where `a` is not a prefix or class. |
| + // TODO(johnniwinther): Use the `element` of [result]. |
| + return handleDynamicUpdateSemantics( |
| + node, name, null, const DynamicAccess.dynamicProperty()); |
| + } |
| + } |
| + |
| /// Handle access unresolved access to [name] in a non-instance context. |
| ResolutionResult handleUnresolvedAccess( |
| Send node, Name name, Element element) { |
| @@ -3030,7 +3010,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| } else if (element.isStatic || element.isTopLevel) { |
| return handleStaticOrTopLevelUpdate(node, name, element); |
| } |
| - return oldVisitSendSet(node); |
| + return internalError(node, "Unexpected resolved send: $element"); |
| } |
| /// Handle an unqualified [Send], that is where the `node.receiver` is null, |
| @@ -3499,150 +3479,23 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| ResolutionResult visitSendSet(SendSet node) { |
| if (node.isIndex) { |
| + // `a[b] = c` |
| if (node.isSuperCall) { |
| + // `super[b] = c` |
| return handleSuperIndexSendSet(node); |
| } else { |
| return handleIndexSendSet(node); |
| } |
| } else if (node.isSuperCall) { |
| + // `super.a = c` |
| return handleSuperSendSet(node); |
| } else if (node.receiver == null) { |
| + // `a = c` |
| return handleUnqualifiedSendSet(node); |
| + } else { |
| + // `a.b = c` |
| + return handleQualifiedSendSet(node); |
| } |
| - return oldVisitSendSet(node); |
| - } |
| - |
| - ResolutionResult oldVisitSendSet(SendSet node) { |
| - bool oldSendIsMemberAccess = sendIsMemberAccess; |
| - sendIsMemberAccess = node.isPropertyAccess || node.isCall; |
| - ResolutionResult result = resolveSend(node); |
| - sendIsMemberAccess = oldSendIsMemberAccess; |
| - Element target = result.element; |
| - Element setter = target; |
| - Element getter = target; |
| - String operatorName = node.assignmentOperator.source; |
| - String source = operatorName; |
| - bool isComplex = !identical(source, '='); |
| - if (!(result is AssertResult || Elements.isUnresolved(target))) { |
| - if (target.isAbstractField) { |
| - AbstractFieldElement field = target; |
| - setter = field.setter; |
| - getter = field.getter; |
| - if (setter == null) { |
| - if (!inInstanceContext || getter.isTopLevel || getter.isStatic) { |
| - setter = reportAndCreateErroneousElement(node.selector, field.name, |
| - MessageKind.CANNOT_RESOLVE_SETTER, const {}); |
| - registry.registerThrowNoSuchMethod(); |
| - } |
| - } |
| - if (isComplex && getter == null && !inInstanceContext) { |
| - getter = reportAndCreateErroneousElement(node.selector, field.name, |
| - MessageKind.CANNOT_RESOLVE_GETTER, const {}); |
| - registry.registerThrowNoSuchMethod(); |
| - } |
| - } else if (target.impliesType) { |
| - if (node.isIfNullAssignment) { |
| - setter = reportAndCreateErroneousElement(node.selector, target.name, |
| - MessageKind.IF_NULL_ASSIGNING_TYPE, const {}); |
| - // In this case, no assignment happens, the rest of the compiler can |
| - // treat the expression `C ??= e` as if it's just reading `C`. |
| - } else { |
| - setter = reportAndCreateErroneousElement(node.selector, target.name, |
| - MessageKind.ASSIGNING_TYPE, const {}); |
| - registry.registerThrowNoSuchMethod(); |
| - } |
| - registerTypeLiteralAccess(node, target); |
| - } else if (target.isFinal || target.isConst) { |
| - if (Elements.isStaticOrTopLevelField(target) || target.isLocal) { |
| - setter = reportAndCreateErroneousElement( |
| - node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER, |
| - const {}); |
| - } else if (node.isSuperCall) { |
| - setter = reportAndCreateErroneousElement( |
| - node.selector, target.name, MessageKind.SETTER_NOT_FOUND_IN_SUPER, |
| - {'name': target.name, 'className': currentClass.name}); |
| - registry.registerSuperNoSuchMethod(); |
| - } else { |
| - // For instance fields we don't report a warning here because the type |
| - // checker will detect this as well and report a better error message |
| - // with the context of the containing class. |
| - } |
| - registry.registerThrowNoSuchMethod(); |
| - } else if (target.isFunction && target.name != '[]=') { |
| - assert(!target.isSetter); |
| - if (Elements.isStaticOrTopLevelFunction(target) || target.isLocal) { |
| - setter = reportAndCreateErroneousElement( |
| - node.selector, target.name, MessageKind.ASSIGNING_METHOD, |
| - const {}); |
| - } else if (node.isSuperCall) { |
| - setter = reportAndCreateErroneousElement( |
| - node.selector, target.name, MessageKind.ASSIGNING_METHOD_IN_SUPER, |
| - {'name': target.name, |
| - 'superclassName': target.enclosingClass.name}); |
| - registry.registerSuperNoSuchMethod(); |
| - } else { |
| - // For instance methods we don't report a warning here because the |
| - // type checker will detect this as well and report a better error |
| - // message with the context of the containing class. |
| - } |
| - registry.registerThrowNoSuchMethod(); |
| - } |
| - if (isPotentiallyMutableTarget(target)) { |
| - registry.registerPotentialMutation(target, node); |
| - if (enclosingElement != target.enclosingElement) { |
| - registry.registerPotentialMutationInClosure(target, node); |
| - } |
| - for (Node scope in promotionScope) { |
| - registry.registerPotentialMutationIn(scope, target, node); |
| - } |
| - } |
| - } |
| - |
| - resolveArguments(node.argumentsNode); |
| - |
| - Selector selector = registry.getSelector(node); |
| - if (isComplex) { |
| - Selector getterSelector; |
| - if (selector.isSetter) { |
| - getterSelector = new Selector.getterFrom(selector); |
| - } else { |
| - assert(selector.isIndexSet); |
| - getterSelector = new Selector.index(); |
| - } |
| - registerSend(getterSelector, getter); |
| - registry.setGetterSelectorInComplexSendSet(node, getterSelector); |
| - if (node.isSuperCall) { |
| - getter = currentClass.lookupSuperByName(getterSelector.memberName); |
| - if (getter == null) { |
| - target = reportAndCreateErroneousElement( |
| - node, selector.name, MessageKind.NO_SUCH_SUPER_MEMBER, |
| - {'className': currentClass.name, 'memberName': selector.name}); |
| - registry.registerSuperNoSuchMethod(); |
| - } |
| - } |
| - registry.useElement(node.selector, getter); |
| - |
| - // Make sure we include the + and - operators if we are using |
| - // the ++ and -- ones. Also, if op= form is used, include op itself. |
| - void registerBinaryOperator(String name) { |
| - Selector binop = new Selector.binaryOperator(name); |
| - registry.registerDynamicInvocation( |
| - new UniverseSelector(binop, null)); |
| - registry.setOperatorSelectorInComplexSendSet(node, binop); |
| - } |
| - if (identical(source, '++')) { |
| - registerBinaryOperator('+'); |
| - registry.registerInstantiatedClass(compiler.intClass); |
| - } else if (identical(source, '--')) { |
| - registerBinaryOperator('-'); |
| - registry.registerInstantiatedClass(compiler.intClass); |
| - } else if (source.endsWith('=')) { |
| - registerBinaryOperator(Elements.mapToUserOperator(operatorName)); |
| - } |
| - } |
| - |
| - registerSend(selector, setter); |
| - return new ResolutionResult.forElement(registry.useElement(node, setter)); |
| } |
| void registerSend(Selector selector, Element target) { |