| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 interface TreeElements { | 5 interface TreeElements { |
| 6 Element operator[](Node node); | 6 Element operator[](Node node); |
| 7 Selector getSelector(Send send); | 7 Selector getSelector(Send send); |
| 8 } | 8 } |
| 9 | 9 |
| 10 class TreeElementMapping implements TreeElements { | 10 class TreeElementMapping implements TreeElements { |
| (...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 | 526 |
| 527 | 527 |
| 528 class ResolverVisitor extends CommonResolverVisitor<Element> { | 528 class ResolverVisitor extends CommonResolverVisitor<Element> { |
| 529 final TreeElementMapping mapping; | 529 final TreeElementMapping mapping; |
| 530 final Element enclosingElement; | 530 final Element enclosingElement; |
| 531 bool inInstanceContext; | 531 bool inInstanceContext; |
| 532 Scope context; | 532 Scope context; |
| 533 ClassElement currentClass; | 533 ClassElement currentClass; |
| 534 bool typeRequired = false; | 534 bool typeRequired = false; |
| 535 StatementScope statementScope; | 535 StatementScope statementScope; |
| 536 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION; |
| 536 | 537 |
| 537 ResolverVisitor(Compiler compiler, Element element) | 538 ResolverVisitor(Compiler compiler, Element element) |
| 538 : this.mapping = new TreeElementMapping(), | 539 : this.mapping = new TreeElementMapping(), |
| 539 this.enclosingElement = element, | 540 this.enclosingElement = element, |
| 540 inInstanceContext = element.isInstanceMember() | 541 inInstanceContext = element.isInstanceMember() |
| 541 || element.isGenerativeConstructor(), | 542 || element.isGenerativeConstructor(), |
| 542 this.context = element.isMember() | 543 this.context = element.isMember() |
| 543 ? new ClassScope(element.enclosingElement, element.getLibrary()) | 544 ? new ClassScope(element.enclosingElement, element.getLibrary()) |
| 544 : new TopScope(element.getLibrary()), | 545 : new TopScope(element.getLibrary()), |
| 545 this.currentClass = element.isMember() ? element.enclosingElement : null, | 546 this.currentClass = element.isMember() ? element.enclosingElement : null, |
| (...skipping 21 matching lines...) Expand all Loading... |
| 567 bool wasInstanceContext = inInstanceContext; | 568 bool wasInstanceContext = inInstanceContext; |
| 568 inInstanceContext = false; | 569 inInstanceContext = false; |
| 569 action(); | 570 action(); |
| 570 inInstanceContext = wasInstanceContext; | 571 inInstanceContext = wasInstanceContext; |
| 571 } | 572 } |
| 572 | 573 |
| 573 visitInStaticContext(Node node) { | 574 visitInStaticContext(Node node) { |
| 574 inStaticContext(() => visit(node)); | 575 inStaticContext(() => visit(node)); |
| 575 } | 576 } |
| 576 | 577 |
| 577 visitIdentifier(Identifier node) { | 578 Element visitIdentifier(Identifier node) { |
| 578 if (node.isThis()) { | 579 if (node.isThis()) { |
| 579 if (!inInstanceContext) { | 580 if (!inInstanceContext) { |
| 580 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]); | 581 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]); |
| 581 } | 582 } |
| 582 return null; | 583 return null; |
| 583 } else if (node.isSuper()) { | 584 } else if (node.isSuper()) { |
| 584 if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC); | 585 if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC); |
| 586 if ((ElementCategory.SUPER & allowedCategory) == 0) { |
| 587 error(node, MessageKind.INVALID_USE_OF_SUPER); |
| 588 } |
| 585 return null; | 589 return null; |
| 586 } else { | 590 } else { |
| 587 Element element = lookup(node, node.source); | 591 Element element = lookup(node, node.source); |
| 588 if (element == null) { | 592 if (element === null) { |
| 589 error(node, MessageKind.CANNOT_RESOLVE, [node]); | 593 if (!inInstanceContext) error(node, MessageKind.CANNOT_RESOLVE, [node]); |
| 594 } else { |
| 595 if ((element.kind.category & allowedCategory) == 0) { |
| 596 // TODO(ahe): Improve error message. Need UX input. |
| 597 error(node, MessageKind.GENERIC, ["is not an expression $element"]); |
| 598 } |
| 590 } | 599 } |
| 591 return useElement(node, element); | 600 return useElement(node, element); |
| 592 } | 601 } |
| 593 } | 602 } |
| 594 | 603 |
| 595 visitTypeAnnotation(TypeAnnotation node) { | 604 visitTypeAnnotation(TypeAnnotation node) { |
| 596 SourceString className; | 605 SourceString className; |
| 597 if (node.typeName.asSend() !== null) { | 606 if (node.typeName.asSend() !== null) { |
| 598 // In new and const expressions, the type name can be a Send to | 607 // In new and const expressions, the type name can be a Send to |
| 599 // denote named constructors or library prefixes. | 608 // denote named constructors or library prefixes. |
| 600 Send send = node.typeName.asSend(); | 609 Send send = node.typeName.asSend(); |
| 601 className = send.receiver.asIdentifier().source; | 610 className = send.receiver.asIdentifier().source; |
| 602 } else { | 611 } else { |
| 603 className = node.typeName.asIdentifier().source; | 612 className = node.typeName.asIdentifier().source; |
| 604 } | 613 } |
| 605 if (className == const SourceString('var')) return null; | 614 if (className == const SourceString('var')) return null; |
| 606 if (className == const SourceString('void')) return null; | 615 if (className == const SourceString('void')) return null; |
| 607 Element element = context.lookup(className); | 616 Element element = context.lookup(className); |
| 608 if (element === null) { | 617 if (element === null) { |
| 609 if (typeRequired) { | 618 if (typeRequired) { |
| 610 error(node, MessageKind.CANNOT_RESOLVE_TYPE, [className]); | 619 error(node, MessageKind.CANNOT_RESOLVE_TYPE, [className]); |
| 611 } else { | 620 } else { |
| 612 warning(node, MessageKind.CANNOT_RESOLVE_TYPE, [className]); | 621 warning(node, MessageKind.CANNOT_RESOLVE_TYPE, [className]); |
| 613 } | 622 } |
| 614 } else if (!element.isClassOrInterfaceOrTypedef()) { | 623 } else if (!element.impliesType()) { |
| 615 if (typeRequired) { | 624 if (typeRequired) { |
| 616 error(node, MessageKind.NOT_A_TYPE, [className]); | 625 error(node, MessageKind.NOT_A_TYPE, [className]); |
| 617 } else { | 626 } else { |
| 618 warning(node, MessageKind.NOT_A_TYPE, [className]); | 627 warning(node, MessageKind.NOT_A_TYPE, [className]); |
| 619 } | 628 } |
| 620 } else { | 629 } else { |
| 621 if (element.isClass()) { | 630 if (element.isClass()) { |
| 622 // TODO(ngeoffray): Should we also resolve typedef? | 631 // TODO(ngeoffray): Should we also resolve typedef? |
| 623 ClassElement cls = element; | 632 ClassElement cls = element; |
| 624 compiler.resolver.toResolve.add(element); | 633 compiler.resolver.toResolve.add(element); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 setupFunction(node, enclosingElement); | 744 setupFunction(node, enclosingElement); |
| 736 defineElement(node, enclosingElement, doAddToScope: node.name !== null); | 745 defineElement(node, enclosingElement, doAddToScope: node.name !== null); |
| 737 | 746 |
| 738 // Run the body in a fresh statement scope. | 747 // Run the body in a fresh statement scope. |
| 739 StatementScope oldScope = statementScope; | 748 StatementScope oldScope = statementScope; |
| 740 statementScope = new StatementScope(); | 749 statementScope = new StatementScope(); |
| 741 visit(node.body); | 750 visit(node.body); |
| 742 statementScope = oldScope; | 751 statementScope = oldScope; |
| 743 | 752 |
| 744 context = context.parent; | 753 context = context.parent; |
| 745 return enclosingElement; | |
| 746 } | 754 } |
| 747 | 755 |
| 748 visitIf(If node) { | 756 visitIf(If node) { |
| 749 visit(node.condition); | 757 visit(node.condition); |
| 750 visit(node.thenPart); | 758 visit(node.thenPart); |
| 751 visit(node.elsePart); | 759 visit(node.elsePart); |
| 752 } | 760 } |
| 753 | 761 |
| 754 static bool isLogicalOperator(Identifier op) { | 762 static bool isLogicalOperator(Identifier op) { |
| 755 String str = op.source.stringValue; | 763 String str = op.source.stringValue; |
| 756 return (str === '&&' || str == '||' || str == '!'); | 764 return (str === '&&' || str == '||' || str == '!'); |
| 757 } | 765 } |
| 758 | 766 |
| 759 Element resolveSend(Send node) { | 767 Element resolveSend(Send node) { |
| 768 if (node.receiver === null || node.selector.isThis()) { |
| 769 return node.selector.accept(this); |
| 770 } |
| 771 var oldCategory = allowedCategory; |
| 772 allowedCategory |= |
| 773 ElementCategory.CLASS | ElementCategory.PREFIX | ElementCategory.SUPER; |
| 760 Element resolvedReceiver = visit(node.receiver); | 774 Element resolvedReceiver = visit(node.receiver); |
| 775 allowedCategory = oldCategory; |
| 761 | 776 |
| 762 Element target = null; | 777 Element target; |
| 763 if (node.selector.asIdentifier() === null) { | 778 SourceString name = node.selector.asIdentifier().source; |
| 764 // We are calling a closure returned from an expression. | 779 if (node.isSuperCall) { |
| 765 assert(node.selector.asExpression() !== null); | 780 if (isUserDefinableOperator(name.stringValue)) { |
| 766 assert(resolvedReceiver === null); | 781 name = Elements.constructOperatorName(const SourceString('operator'), |
| 767 visit(node.selector); | 782 name); |
| 768 } else { | 783 } |
| 769 SourceString name = node.selector.asIdentifier().source; | 784 if (!inInstanceContext) { |
| 770 if (node.receiver === null) { | 785 error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, [name]); |
| 771 target = lookup(node, name); | |
| 772 if (target === null && !inInstanceContext) { | |
| 773 error(node, MessageKind.CANNOT_RESOLVE, [name]); | |
| 774 } | |
| 775 } else if (node.isSuperCall) { | |
| 776 if (currentClass !== null) { | |
| 777 ClassElement superElement = currentClass.superclass; | |
| 778 if (superElement !== null) { | |
| 779 // TODO(ngeoffray): The lookup should continue on super | |
| 780 // classes. | |
| 781 target = superElement.lookupLocalMember(name); | |
| 782 } | |
| 783 if (target === null) { | |
| 784 error(node, | |
| 785 MessageKind.METHOD_NOT_FOUND, | |
| 786 [superElement.name, name]); | |
| 787 } | |
| 788 } | |
| 789 } else if (resolvedReceiver === null) { | |
| 790 return null; | 786 return null; |
| 791 } else if (resolvedReceiver.kind === ElementKind.CLASS) { | 787 } |
| 792 ClassElement receiverClass = resolvedReceiver; | 788 target = currentClass.lookupSuperMember(name); |
| 793 target = receiverClass.resolve(compiler).lookupLocalMember(name); | 789 if (target === null) { |
| 794 if (target === null) { | 790 error(node.selector, MessageKind.METHOD_NOT_FOUND, |
| 795 error(node, MessageKind.METHOD_NOT_FOUND, [receiverClass.name, name]); | 791 [currentClass.superclass.name, name]); |
| 796 } else if (target.isInstanceMember()) { | 792 } |
| 797 error(node, MessageKind.MEMBER_NOT_STATIC, | 793 } else if (resolvedReceiver === null) { |
| 798 [receiverClass.name, name]); | 794 return null; |
| 799 } | 795 } else if (resolvedReceiver.kind === ElementKind.CLASS) { |
| 800 } else if (resolvedReceiver.kind === ElementKind.PREFIX) { | 796 ClassElement receiverClass = resolvedReceiver; |
| 801 PrefixElement prefix = resolvedReceiver; | 797 target = receiverClass.resolve(compiler).lookupLocalMember(name); |
| 802 target = prefix.library.lookupLocalMember(name); | 798 if (target === null) { |
| 803 if (target == null) { | 799 error(node, MessageKind.METHOD_NOT_FOUND, [receiverClass.name, name]); |
| 804 error(node, MessageKind.NO_SUCH_LIBRARY_MEMBER, | 800 } else if (target.isInstanceMember()) { |
| 805 [resolvedReceiver.name, name]); | 801 error(node, MessageKind.MEMBER_NOT_STATIC, [receiverClass.name, name]); |
| 806 } | 802 } |
| 803 } else if (resolvedReceiver.kind === ElementKind.PREFIX) { |
| 804 PrefixElement prefix = resolvedReceiver; |
| 805 target = prefix.lookupLocalMember(name); |
| 806 if (target == null) { |
| 807 error(node, MessageKind.NO_SUCH_LIBRARY_MEMBER, [prefix.name, name]); |
| 807 } | 808 } |
| 808 } | 809 } |
| 809 return target; | 810 return target; |
| 810 } | 811 } |
| 811 | 812 |
| 812 resolveTypeTest(Node argument) { | 813 resolveTypeTest(Node argument) { |
| 813 TypeAnnotation node = argument.asTypeAnnotation(); | 814 TypeAnnotation node = argument.asTypeAnnotation(); |
| 814 if (node == null) { | 815 if (node == null) { |
| 815 node = argument.asSend().receiver; | 816 node = argument.asSend().receiver; |
| 816 } | 817 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 857 mapping.setSelector(node, Selector.GETTER); | 858 mapping.setSelector(node, Selector.GETTER); |
| 858 } else { | 859 } else { |
| 859 handleArguments(node); | 860 handleArguments(node); |
| 860 } | 861 } |
| 861 if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) { | 862 if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) { |
| 862 AbstractFieldElement field = target; | 863 AbstractFieldElement field = target; |
| 863 target = field.getter; | 864 target = field.getter; |
| 864 } | 865 } |
| 865 // TODO(ngeoffray): Warn if target is null and the send is | 866 // TODO(ngeoffray): Warn if target is null and the send is |
| 866 // unqualified. | 867 // unqualified. |
| 867 return useElement(node, target); | 868 useElement(node, target); |
| 869 if (node.isPropertyAccess) return target; |
| 868 } | 870 } |
| 869 | 871 |
| 870 visitSendSet(SendSet node) { | 872 visitSendSet(SendSet node) { |
| 871 Element target = resolveSend(node); | 873 Element target = resolveSend(node); |
| 872 Element setter = null; | 874 Element setter = null; |
| 873 Element getter = null; | 875 Element getter = null; |
| 874 if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) { | 876 if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) { |
| 875 AbstractFieldElement field = target; | 877 AbstractFieldElement field = target; |
| 876 setter = field.setter; | 878 setter = field.setter; |
| 877 getter = field.getter; | 879 getter = field.getter; |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1192 } | 1194 } |
| 1193 for (Link<Node> link = node.interfaces.nodes; | 1195 for (Link<Node> link = node.interfaces.nodes; |
| 1194 !link.isEmpty(); | 1196 !link.isEmpty(); |
| 1195 link = link.tail) { | 1197 link = link.tail) { |
| 1196 element.interfaces = element.interfaces.prepend(visit(link.head)); | 1198 element.interfaces = element.interfaces.prepend(visit(link.head)); |
| 1197 } | 1199 } |
| 1198 return element.computeType(compiler); | 1200 return element.computeType(compiler); |
| 1199 } | 1201 } |
| 1200 | 1202 |
| 1201 Type visitTypeAnnotation(TypeAnnotation node) { | 1203 Type visitTypeAnnotation(TypeAnnotation node) { |
| 1202 Identifier name = node.typeName.asIdentifier(); | 1204 return visit(node.typeName); |
| 1203 if (name === null) { | |
| 1204 unimplemented(node.typeName, "prefixes"); | |
| 1205 } | |
| 1206 return visit(name); | |
| 1207 } | 1205 } |
| 1208 | 1206 |
| 1209 Type visitIdentifier(Identifier node) { | 1207 Type visitIdentifier(Identifier node) { |
| 1210 Element element = context.lookup(node.source); | 1208 Element element = context.lookup(node.source); |
| 1211 if (element === null) { | 1209 if (element === null) { |
| 1212 error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]); | 1210 error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]); |
| 1213 } else if (!element.isClassOrInterfaceOrTypedef()) { | 1211 } else if (!element.impliesType()) { |
| 1214 error(node, MessageKind.NOT_A_TYPE, [node]); | 1212 error(node, MessageKind.NOT_A_TYPE, [node]); |
| 1215 } else { | 1213 } else { |
| 1216 if (element.isClass()) { | 1214 if (element.isClass()) { |
| 1217 compiler.resolver.toResolve.add(element); | 1215 compiler.resolver.toResolve.add(element); |
| 1218 } | 1216 } |
| 1219 // TODO(ngeoffray): Use type variables. | 1217 // TODO(ngeoffray): Use type variables. |
| 1220 return element.computeType(compiler); | 1218 return element.computeType(compiler); |
| 1221 } | 1219 } |
| 1222 return null; | 1220 return null; |
| 1223 } | 1221 } |
| 1222 |
| 1223 Type visitSend(Send node) { |
| 1224 Identifier prefix = node.receiver.asIdentifier(); |
| 1225 if (prefix === null) { |
| 1226 error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); |
| 1227 return null; |
| 1228 } |
| 1229 Element element = context.lookup(prefix.source); |
| 1230 if (element === null || element.kind !== ElementKind.PREFIX) { |
| 1231 error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); |
| 1232 return null; |
| 1233 } |
| 1234 var e = element.library.lookupLocalMember(node.selector.source); |
| 1235 if (e === null || !e.impliesType()) { |
| 1236 error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, [node.selector]); |
| 1237 return null; |
| 1238 } |
| 1239 return e.computeType(compiler); |
| 1240 } |
| 1224 } | 1241 } |
| 1225 | 1242 |
| 1226 class VariableDefinitionsVisitor extends CommonResolverVisitor<SourceString> { | 1243 class VariableDefinitionsVisitor extends CommonResolverVisitor<SourceString> { |
| 1227 VariableDefinitions definitions; | 1244 VariableDefinitions definitions; |
| 1228 ResolverVisitor resolver; | 1245 ResolverVisitor resolver; |
| 1229 ElementKind kind; | 1246 ElementKind kind; |
| 1230 VariableListElement variables; | 1247 VariableListElement variables; |
| 1231 | 1248 |
| 1232 VariableDefinitionsVisitor(Compiler compiler, | 1249 VariableDefinitionsVisitor(Compiler compiler, |
| 1233 this.definitions, this.resolver, this.kind) | 1250 this.definitions, this.resolver, this.kind) |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1544 class TopScope extends Scope { | 1561 class TopScope extends Scope { |
| 1545 LibraryElement get library() => element; | 1562 LibraryElement get library() => element; |
| 1546 | 1563 |
| 1547 TopScope(LibraryElement library) : super(null, library); | 1564 TopScope(LibraryElement library) : super(null, library); |
| 1548 Element lookup(SourceString name) => library.find(name); | 1565 Element lookup(SourceString name) => library.find(name); |
| 1549 | 1566 |
| 1550 Element add(Element element) { | 1567 Element add(Element element) { |
| 1551 throw "Cannot add an element in the top scope"; | 1568 throw "Cannot add an element in the top scope"; |
| 1552 } | 1569 } |
| 1553 } | 1570 } |
| OLD | NEW |