Chromium Code Reviews| Index: dart/frog/leg/resolver.dart |
| diff --git a/dart/frog/leg/resolver.dart b/dart/frog/leg/resolver.dart |
| index a8b08665d3ca52510867b1a58e04dd979d6af605..61ac6fdda653b4eff5301312210f8e8ae4e89514 100644 |
| --- a/dart/frog/leg/resolver.dart |
| +++ b/dart/frog/leg/resolver.dart |
| @@ -533,6 +533,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| ClassElement currentClass; |
| bool typeRequired = false; |
| StatementScope statementScope; |
| + int allowedCategory = ElementCategory.SLOT | ElementCategory.FUNCTION; |
| ResolverVisitor(Compiler compiler, Element element) |
| : this.mapping = new TreeElementMapping(), |
| @@ -574,7 +575,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| inStaticContext(() => visit(node)); |
| } |
| - visitIdentifier(Identifier node) { |
| + Element visitIdentifier(Identifier node) { |
| if (node.isThis()) { |
| if (!inInstanceContext) { |
| error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]); |
| @@ -582,11 +583,19 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| return null; |
| } else if (node.isSuper()) { |
| if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC); |
| + if ((ElementCategory.SUPER & allowedCategory) == 0) { |
| + error(node, MessageKind.INVALID_USE_OF_SUPER); |
| + } |
| return null; |
| } else { |
| Element element = lookup(node, node.source); |
| - if (element == null) { |
| - error(node, MessageKind.CANNOT_RESOLVE, [node]); |
| + if (element === null) { |
| + if (!inInstanceContext) error(node, MessageKind.CANNOT_RESOLVE, [node]); |
| + } else { |
| + if ((element.kind.category & allowedCategory) == 0) { |
| + // TODO(ahe): Improve error message. Need UX input. |
| + error(node, MessageKind.GENERIC, ["is not an expression $element"]); |
| + } |
| } |
| return useElement(node, element); |
| } |
| @@ -611,7 +620,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| } else { |
| warning(node, MessageKind.CANNOT_RESOLVE_TYPE, [className]); |
| } |
| - } else if (!element.isClassOrInterfaceOrTypedef()) { |
| + } else if (!element.impliesType()) { |
| if (typeRequired) { |
| error(node, MessageKind.NOT_A_TYPE, [className]); |
| } else { |
| @@ -742,7 +751,6 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| statementScope = oldScope; |
| context = context.parent; |
| - return enclosingElement; |
| } |
| visitIf(If node) { |
| @@ -757,53 +765,46 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| } |
| Element resolveSend(Send node) { |
| + if (node.receiver === null || node.selector.isThis()) { |
| + return node.selector.accept(this); |
| + } |
| + var oldCategory = allowedCategory; |
| + allowedCategory |= |
| + ElementCategory.CLASS | ElementCategory.PREFIX | ElementCategory.SUPER; |
| Element resolvedReceiver = visit(node.receiver); |
| + allowedCategory = oldCategory; |
| - Element target = null; |
| - if (node.selector.asIdentifier() === null) { |
| - // We are calling a closure returned from an expression. |
| - assert(node.selector.asExpression() !== null); |
| - assert(resolvedReceiver === null); |
| - visit(node.selector); |
| - } else { |
| - SourceString name = node.selector.asIdentifier().source; |
| - if (node.receiver === null) { |
| - target = lookup(node, name); |
| - if (target === null && !inInstanceContext) { |
| - error(node, MessageKind.CANNOT_RESOLVE, [name]); |
| - } |
| - } else if (node.isSuperCall) { |
| - if (currentClass !== null) { |
| - ClassElement superElement = currentClass.superclass; |
| - if (superElement !== null) { |
| - // TODO(ngeoffray): The lookup should continue on super |
| - // classes. |
| - target = superElement.lookupLocalMember(name); |
| - } |
| - if (target === null) { |
| - error(node, |
| - MessageKind.METHOD_NOT_FOUND, |
| - [superElement.name, name]); |
| - } |
| - } |
| - } else if (resolvedReceiver === null) { |
| - return null; |
| - } else if (resolvedReceiver.kind === ElementKind.CLASS) { |
| - ClassElement receiverClass = resolvedReceiver; |
| - target = receiverClass.resolve(compiler).lookupLocalMember(name); |
| - if (target === null) { |
| - error(node, MessageKind.METHOD_NOT_FOUND, [receiverClass.name, name]); |
| - } else if (target.isInstanceMember()) { |
| - error(node, MessageKind.MEMBER_NOT_STATIC, |
| - [receiverClass.name, name]); |
| - } |
| - } else if (resolvedReceiver.kind === ElementKind.PREFIX) { |
| - PrefixElement prefix = resolvedReceiver; |
| - target = prefix.library.lookupLocalMember(name); |
| - if (target == null) { |
| - error(node, MessageKind.NO_SUCH_LIBRARY_MEMBER, |
| - [resolvedReceiver.name, name]); |
| - } |
| + Element target; |
| + SourceString name = node.selector.asIdentifier().source; |
| + if (node.isSuperCall) { |
| + if (isUserDefinableOperator(name.stringValue)) { |
| + name = Elements.constructOperatorName(const SourceString('operator'), |
| + name); |
| + } |
| + if (currentClass === null || !inInstanceContext) { |
|
ngeoffray
2012/03/08 14:00:45
Shouldn't that just be '!inInstanceContext' ?
ahe
2012/03/08 18:13:40
Done.
|
| + error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, [name]); |
| + } |
| + target = currentClass.lookupSuperMember(name); |
| + if (target === null) { |
| + error(node.selector, MessageKind.METHOD_NOT_FOUND, |
| + [currentClass.superclass.name, name]); |
| + } |
| + } else if (resolvedReceiver === null) { |
| + return null; |
| + } else if (resolvedReceiver.kind === ElementKind.CLASS) { |
|
ngeoffray
2012/03/08 14:00:45
You can now change it to resolvedReceiver.isClass(
ahe
2012/03/08 18:13:40
I'm not sure that I like that.
|
| + ClassElement receiverClass = resolvedReceiver; |
| + target = receiverClass.resolve(compiler).lookupLocalMember(name); |
| + if (target === null) { |
| + error(node, MessageKind.METHOD_NOT_FOUND, [receiverClass.name, name]); |
| + } else if (target.isInstanceMember()) { |
| + error(node, MessageKind.MEMBER_NOT_STATIC, |
| + [receiverClass.name, name]); |
|
karlklose
2012/03/08 14:01:45
Would this fit into one line?
ahe
2012/03/08 18:13:40
Done.
|
| + } |
| + } else if (resolvedReceiver.kind === ElementKind.PREFIX) { |
| + PrefixElement prefix = resolvedReceiver; |
| + target = prefix.lookupLocalMember(name); |
| + if (target == null) { |
| + error(node, MessageKind.NO_SUCH_LIBRARY_MEMBER, [prefix.name, name]); |
| } |
| } |
| return target; |
| @@ -864,7 +865,8 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
| } |
| // TODO(ngeoffray): Warn if target is null and the send is |
| // unqualified. |
| - return useElement(node, target); |
| + useElement(node, target); |
| + if (node.isPropertyAccess) return target; |
| } |
| visitSendSet(SendSet node) { |
| @@ -1199,18 +1201,14 @@ class ClassResolverVisitor extends CommonResolverVisitor<Type> { |
| } |
| Type visitTypeAnnotation(TypeAnnotation node) { |
| - Identifier name = node.typeName.asIdentifier(); |
| - if (name === null) { |
| - unimplemented(node.typeName, "prefixes"); |
| - } |
| - return visit(name); |
| + return visit(node.typeName); |
| } |
| Type visitIdentifier(Identifier node) { |
| Element element = context.lookup(node.source); |
| if (element === null) { |
| error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]); |
| - } else if (!element.isClassOrInterfaceOrTypedef()) { |
| + } else if (!element.impliesType()) { |
| error(node, MessageKind.NOT_A_TYPE, [node]); |
| } else { |
| if (element.isClass()) { |
| @@ -1221,6 +1219,24 @@ class ClassResolverVisitor extends CommonResolverVisitor<Type> { |
| } |
| return null; |
| } |
| + |
| + Type visitSend(Send node) { |
| + Identifier prefix = node.receiver.asIdentifier(); |
| + if (prefix === null) { |
| + error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); |
| + return null; |
| + } |
| + Element element = context.lookup(prefix.source); |
| + if (element.kind === ElementKind.PREFIX) { |
| + var e = element.library.lookupLocalMember(node.selector.source); |
| + if (e === null) { |
| + error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, [node.selector]); |
| + return null; |
| + } |
| + return e.computeType(compiler); |
| + } |
|
ngeoffray
2012/03/08 14:00:45
Why don't you warn here that you resolve to someth
ahe
2012/03/08 18:13:40
Done.
|
| + return null; |
| + } |
| } |
| class VariableDefinitionsVisitor extends CommonResolverVisitor<SourceString> { |