Chromium Code Reviews| Index: lib/compiler/implementation/resolver.dart |
| diff --git a/lib/compiler/implementation/resolver.dart b/lib/compiler/implementation/resolver.dart |
| index 8e7b7a3edb9f7fbcacd6d8e59598e88020f66081..ea8913a7c06491519fdbde5553ed98f71a71ac4f 100644 |
| --- a/lib/compiler/implementation/resolver.dart |
| +++ b/lib/compiler/implementation/resolver.dart |
| @@ -449,6 +449,7 @@ class InitializerResolver { |
| error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); |
| } |
| visitor.useElement(init, target); |
| + visitor.world.registerStaticUse(target); |
| // Check for duplicate initializers. |
| if (initialized.containsKey(name)) { |
| error(init, MessageKind.DUPLICATE_INITIALIZER, [name]); |
| @@ -466,7 +467,7 @@ class InitializerResolver { |
| ResolverTask resolver = visitor.compiler.resolver; |
| visitor.inStaticContext(() { |
| visitor.resolveSelector(call); |
| - visitor.visitArguments(call.argumentsNode); |
| + visitor.resolveArguments(call.argumentsNode); |
| }); |
| Selector selector = visitor.mapping.getSelector(call); |
| bool isSuperCall = Initializers.isSuperConstructorCall(call); |
| @@ -474,6 +475,7 @@ class InitializerResolver { |
| Element result = resolveSuperOrThis( |
| constructor, isSuperCall, false, constructorName, selector, call); |
| visitor.useElement(call, result); |
| + visitor.world.registerStaticUse(result); |
| return result; |
| } |
| @@ -963,24 +965,6 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| Element useElement(Node node, Element element) { |
| if (element === null) return null; |
| mapping[node] = element; |
| - if (element.isTopLevel() || element.isMember()) { |
| - if (element.isInstanceMember()) { |
| - var send = node.asSend(); |
| - if (send !== null) { |
| - Selector selector = mapping.getSelector(send); |
| - if (selector !== null) { |
| - world.registerDynamicInvocation(element.name, selector); |
| - } |
| - } |
| - } else { |
| - if (!element.isPrefix() && |
| - !element.isClass() && |
| - !element.isTypedef() && |
| - !element.isTypeVariable()) { |
| - world.registerStaticUse(element); |
| - } |
| - } |
| - } |
| return element; |
|
ahe
2012/08/15 14:32:21
These two lines can be merged.
And yay!
kasperl
2012/08/16 10:35:47
Done.
|
| } |
| @@ -1185,7 +1169,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| static Selector computeSendSelector(Send node, LibraryElement library) { |
| // First determine if this is part of an assignment. |
| - bool isSet = node is SendSet; |
| + bool isSet = node.asSendSet() !== null; |
| if (node.isIndex) { |
| return isSet ? new Selector.indexSet() : new Selector.index(); |
| @@ -1193,12 +1177,12 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| if (node.isOperator) { |
| SourceString source = node.selector.asOperator().source; |
| - switch (source.stringValue) { |
| - case '!' : case '&&' : case '||': |
| - case 'is' : case 'as' : |
| - case '===': case '!==': |
| - case '>>>': |
| - return null; |
| + String string = source.stringValue; |
| + if (string === '!' || string === '&&' || string == '||' || |
| + string === 'is' || string === 'as' || |
| + string === '===' || string === '!==' || |
| + string === '>>>') { |
| + return null; |
| } |
| return node.arguments.isEmpty() |
| ? new Selector.unaryOperator(source) |
| @@ -1220,17 +1204,16 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| !link.isEmpty(); |
| link = link.tail) { |
| Expression argument = link.head; |
| - if (argument.asNamedArgument() != null) { |
| - named.add((argument as NamedArgument).name.source); |
| + NamedArgument namedArgument = argument.asNamedArgument(); |
| + if (namedArgument !== null) { |
| + named.add(namedArgument.name.source); |
| } |
| arity++; |
| } |
| - // If we're invoking a closure, we do not have an identifier. In |
| - // that case, we create a wildcard selector that can call any |
| - // method that may have been closurized. |
| - return (identifier == null) |
| - ? new Selector.callAny(arity, named) |
| + // If we're invoking a closure, we do not have an identifier. |
| + return (identifier === null) |
| + ? new Selector.callClosure(arity, named) |
| : new Selector.call(identifier.source, library, arity, named); |
| } |
| @@ -1241,7 +1224,8 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| return selector; |
| } |
| - void visitArguments(NodeList list) { |
| + void resolveArguments(NodeList list) { |
| + if (list === null) return; |
| bool seenNamedArgument = false; |
| for (Link<Node> link = list.nodes; !link.isEmpty(); link = link.tail) { |
| Expression argument = link.head; |
| @@ -1256,42 +1240,41 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| visitSend(Send node) { |
| Element target = resolveSend(node); |
| + if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) { |
| + AbstractFieldElement field = target; |
| + target = field.getter; |
| + } |
| + |
| + bool resolvedArguments = false; |
| if (node.isOperator) { |
| - Operator op = node.selector.asOperator(); |
| - if (op.source.stringValue === 'is' || op.source.stringValue === 'as') { |
| - resolveTypeTest(node.arguments.head); |
| + String operatorString = node.selector.asOperator().source.stringValue; |
| + if (operatorString === 'is' || operatorString === 'as') { |
| assert(node.arguments.tail.isEmpty()); |
| - } else if (node.arguments.isEmpty()) { |
| - assert(op.token.kind !== PLUS_TOKEN); |
| - } else { |
| - visit(node.argumentsNode); |
| + resolveTypeTest(node.arguments.head); |
| + resolvedArguments = true; |
| } |
| - } else if (node.isIndex) { |
| - visit(node.argumentsNode); |
| - assert(node.arguments.tail.isEmpty()); |
| - } else if (node.isPropertyAccess) { |
| - // Nothing to do here. |
| - } else { |
| - visitArguments(node.argumentsNode); |
| } |
| - if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) { |
| - AbstractFieldElement field = target; |
| - target = field.getter; |
| + if (!resolvedArguments) { |
| + resolveArguments(node.argumentsNode); |
| } |
| + |
| + // If the selector is null, it means that we will not be generating |
| + // code for this as a send. |
| + Selector selector = mapping.getSelector(node); |
| + if (selector === null) return; |
| + |
| + // If we don't know what we're calling or if we are calling a getter, |
| + // we need to register that fact that we may be calling a closure |
| + // with the same arguments. |
| if (node.isCall && |
| (target === null || |
| target.isGetter() || |
| Elements.isClosureSend(node, target))) { |
| - Selector selector = mapping.getSelector(node); |
| - Selector call = new Selector.call( |
| - compiler.namer.CLOSURE_INVOCATION_NAME, |
| - selector.library, |
| - selector.argumentCount, |
| - selector.namedArguments); |
| - world.registerDynamicInvocation(compiler.namer.CLOSURE_INVOCATION_NAME, |
| - call); |
| + Selector call = new Selector.callClosureFrom(selector); |
| + world.registerDynamicInvocation(call.name, call); |
| } |
| + |
| // TODO(ngeoffray): We should do the check in |
| // visitExpressionStatement instead. |
| if (target === compiler.assertMethod && !node.isCall) { |
| @@ -1301,83 +1284,59 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| } |
| target = null; |
| } |
| + |
| // TODO(ngeoffray): Warn if target is null and the send is |
| // unqualified. |
| useElement(node, target); |
| - if (target === null) registerDynamicSend(node); |
| - if (node.isPropertyAccess) return target; |
| + registerSend(node, selector, target); |
| + return node.isPropertyAccess ? target : null; |
| } |
| visitSendSet(SendSet node) { |
| Element target = resolveSend(node); |
| - Element setter = null; |
| - Element getter = null; |
| + Element setter = target; |
| + Element getter = target; |
| if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) { |
| AbstractFieldElement field = target; |
| setter = field.setter; |
| getter = field.getter; |
| - } else { |
| - setter = target; |
| - getter = target; |
| } |
| + |
| + visit(node.argumentsNode); |
| + |
| // TODO(ngeoffray): Check if the target can be assigned. |
| + // TODO(ngeoffray): Warn if target is null and the send is |
| + // unqualified. |
| + |
| + Selector selector = mapping.getSelector(node); |
| Identifier identifier = node.assignmentOperator; |
| - bool compoundAssignment = identifier.source.stringValue !== '='; |
| - if (compoundAssignment) { |
| + bool isCompound = identifier.source.stringValue !== '='; |
|
floitsch
2012/08/15 14:14:04
this should be a predicate on the SendSet node.
No
|
| + if (isCompound) { |
| useElement(node.selector, getter); |
| + registerSend(node, new Selector.getterFrom(selector), getter); |
| } |
| - visit(node.argumentsNode); |
| - // TODO(ngeoffray): Warn if target is null and the send is |
| - // unqualified. |
| - registerDynamicSend(node); |
| + |
| + registerSend(node, selector, setter); |
| return useElement(node, setter); |
| } |
| - registerDynamicSend(Send node) { |
| - Identifier id = node.selector.asIdentifier(); |
| - if (id === null) return; |
| - SourceString name = node.selector.asIdentifier().source; |
| - if (node.isIndex && node is SendSet) { |
| - name = Elements.constructOperatorName( |
| - const SourceString('operator'), |
| - const SourceString('[]=')); |
| - } else if (node.selector.asOperator() != null) { |
| - switch (name.stringValue) { |
| - case '===': |
| - case '!==': |
| - case '!': |
| - case '&&': |
| - case '||': |
| - case 'is': |
| - case 'as': |
| - case '>>>': |
| - return null; |
| - } |
| - name = Elements.constructOperatorName( |
| - const SourceString('operator'), |
| - name, |
| - node.argumentsNode is Prefix); |
| - } |
| - Selector selector = mapping.getSelector(node); |
| - if (selector.isGetter()) { |
| - world.registerDynamicGetter(name, selector); |
| - } else if (selector.isSetter()) { |
| - world.registerDynamicSetter(name, selector); |
| - // Also register the getter for compound assignments. |
| - LibraryElement library = enclosingElement.getLibrary(); |
| - Selector getter = new Selector.getter(name, library); |
| - world.registerDynamicGetter(name, getter); |
| - } else { |
| - if (selector.isIndexSet()) { |
| - // Also register the index selector for compound assignments. |
| - Selector index = new Selector.index(); |
| - world.registerDynamicInvocation(index.name, index); |
| + void registerSend(Node node, Selector selector, Element target) { |
| + if (target === null || target.isInstanceMember()) { |
| + if (selector.isGetter()) { |
| + world.registerDynamicGetter(selector.name, selector); |
| + } else if (selector.isSetter()) { |
| + world.registerDynamicSetter(selector.name, selector); |
| + } else { |
| + world.registerDynamicInvocation(selector.name, selector); |
| } |
| - world.registerDynamicInvocation(name, selector); |
| + } else if (Elements.isStaticOrTopLevel(target)) { |
| + world.registerStaticUse(target); |
| } |
| + |
| + // TODO(kasperl): Pass the selector directly. |
| var interceptor = new Interceptors(compiler).getStaticInterceptor( |
| - name, |
| - node.argumentCount()); |
| + selector.name, |
| + selector.argumentCount); |
| if (interceptor !== null) { |
| world.registerStaticUse(interceptor); |
| } |
| @@ -1442,7 +1401,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| FunctionElement constructor = resolveConstructor(node); |
| resolveSelector(node.send); |
| - visitArguments(node.send.argumentsNode); |
| + resolveArguments(node.send.argumentsNode); |
| if (constructor === null) return null; |
| // TODO(karlklose): handle optional arguments. |
| if (node.send.argumentCount() != constructor.parameterCount(compiler)) { |
| @@ -1451,6 +1410,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| // List constructor. |
| } |
| useElement(node.send, constructor); |
| + world.registerStaticUse(constructor); |
| compiler.withCurrentElement(constructor, () { |
| FunctionExpression tree = constructor.parseNode(compiler); |
| compiler.resolver.resolveConstructorImplementation(constructor, tree); |