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 library dart2js.resolution.members; | 5 library dart2js.resolution.members; |
6 | 6 |
7 import '../common/names.dart' show | 7 import '../common/names.dart' show |
8 Selectors; | 8 Selectors; |
9 import '../compiler.dart' show | 9 import '../compiler.dart' show |
10 Compiler, | 10 Compiler, |
(...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
632 } | 632 } |
633 | 633 |
634 ResolutionResult visitIf(If node) { | 634 ResolutionResult visitIf(If node) { |
635 doInPromotionScope(node.condition.expression, () => visit(node.condition)); | 635 doInPromotionScope(node.condition.expression, () => visit(node.condition)); |
636 doInPromotionScope(node.thenPart, | 636 doInPromotionScope(node.thenPart, |
637 () => visitIn(node.thenPart, new BlockScope(scope))); | 637 () => visitIn(node.thenPart, new BlockScope(scope))); |
638 visitIn(node.elsePart, new BlockScope(scope)); | 638 visitIn(node.elsePart, new BlockScope(scope)); |
639 return const NoneResult(); | 639 return const NoneResult(); |
640 } | 640 } |
641 | 641 |
642 ResolutionResult resolveSend(Send node) { | |
643 Selector selector = resolveSelector(node, null); | |
644 if (node.isSuperCall) registry.registerSuperUse(node); | |
645 | |
646 if (node.receiver == null) { | |
647 // If this send is of the form "assert(expr);", then | |
648 // this is an assertion. | |
649 if (selector.isAssert) { | |
650 internalError(node, "Unexpected assert: $node"); | |
651 } | |
652 | |
653 return node.selector.accept(this); | |
654 } | |
655 | |
656 var oldCategory = allowedCategory; | |
657 allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER; | |
658 | |
659 bool oldSendIsMemberAccess = sendIsMemberAccess; | |
660 int oldAllowedCategory = allowedCategory; | |
661 | |
662 // Conditional sends like `e?.foo` treat the receiver as an expression. So | |
663 // `C?.foo` needs to be treated like `(C).foo`, not like C.foo. Prefixes and | |
664 // super are not allowed on their own in that context. | |
665 if (node.isConditional) { | |
666 sendIsMemberAccess = false; | |
667 allowedCategory = | |
668 ElementCategory.VARIABLE | | |
669 ElementCategory.FUNCTION | | |
670 ElementCategory.IMPLIES_TYPE; | |
671 } | |
672 ResolutionResult resolvedReceiver = visit(node.receiver); | |
673 if (node.isConditional) { | |
674 sendIsMemberAccess = oldSendIsMemberAccess; | |
675 allowedCategory = oldAllowedCategory; | |
676 } | |
677 | |
678 allowedCategory = oldCategory; | |
679 | |
680 Element target; | |
681 String name = node.selector.asIdentifier().source; | |
682 if (identical(name, 'this')) { | |
683 error(node.selector, MessageKind.THIS_PROPERTY); | |
684 return const NoneResult(); | |
685 } else if (node.isSuperCall) { | |
686 if (node.isOperator) { | |
687 if (isUserDefinableOperator(name)) { | |
688 name = selector.name; | |
689 } else { | |
690 error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name}); | |
691 return const NoneResult(); | |
692 } | |
693 } | |
694 if (!inInstanceContext) { | |
695 error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name}); | |
696 return const NoneResult(); | |
697 } | |
698 if (currentClass.supertype == null) { | |
699 // This is just to guard against internal errors, so no need | |
700 // for a real error message. | |
701 error(node.receiver, MessageKind.GENERIC, | |
702 {'text': "Object has no superclass"}); | |
703 return const NoneResult(); | |
704 } | |
705 // TODO(johnniwinther): Ensure correct behavior if currentClass is a | |
706 // patch. | |
707 target = currentClass.lookupSuperByName(selector.memberName); | |
708 // [target] may be null which means invoking noSuchMethod on | |
709 // super. | |
710 if (target == null) { | |
711 target = reportAndCreateErroneousElement( | |
712 node, name, MessageKind.NO_SUCH_SUPER_MEMBER, | |
713 {'className': currentClass.name, 'memberName': name}); | |
714 // We still need to register the invocation, because we might | |
715 // call [:super.noSuchMethod:] which calls | |
716 // [JSInvocationMirror._invokeOn]. | |
717 registry.registerDynamicInvocation( | |
718 new UniverseSelector(selector, null)); | |
719 registry.registerSuperNoSuchMethod(); | |
720 } | |
721 } else if (Elements.isUnresolved(resolvedReceiver.element)) { | |
722 return const NoneResult(); | |
723 } else if (resolvedReceiver.element.isClass) { | |
724 ClassElement receiverClass = resolvedReceiver.element; | |
725 receiverClass.ensureResolved(compiler); | |
726 if (node.isOperator) { | |
727 // When the resolved receiver is a class, we can have two cases: | |
728 // 1) a static send: C.foo, or | |
729 // 2) an operator send, where the receiver is a class literal: 'C + 1'. | |
730 // The following code that looks up the selector on the resolved | |
731 // receiver will treat the second as the invocation of a static operator | |
732 // if the resolved receiver is not null. | |
733 return const NoneResult(); | |
734 } | |
735 MembersCreator.computeClassMembersByName( | |
736 compiler, receiverClass.declaration, name); | |
737 target = receiverClass.lookupLocalMember(name); | |
738 if (target == null || target.isInstanceMember) { | |
739 registry.registerThrowNoSuchMethod(); | |
740 // TODO(johnniwinther): With the simplified [TreeElements] invariant, | |
741 // try to resolve injected elements if [currentClass] is in the patch | |
742 // library of [receiverClass]. | |
743 | |
744 // TODO(karlklose): this should be reported by the caller of | |
745 // [resolveSend] to select better warning messages for getters and | |
746 // setters. | |
747 MessageKind kind = (target == null) | |
748 ? MessageKind.MEMBER_NOT_FOUND | |
749 : MessageKind.MEMBER_NOT_STATIC; | |
750 return new ElementResult(reportAndCreateErroneousElement( | |
751 node, name, kind, | |
752 {'className': receiverClass.name, 'memberName': name})); | |
753 } else if (isPrivateName(name) && | |
754 target.library != enclosingElement.library) { | |
755 registry.registerThrowNoSuchMethod(); | |
756 return new ElementResult(reportAndCreateErroneousElement( | |
757 node, name, MessageKind.PRIVATE_ACCESS, | |
758 {'libraryName': target.library.getLibraryOrScriptName(), | |
759 'name': name})); | |
760 } | |
761 } else if (resolvedReceiver.element.isPrefix) { | |
762 PrefixElement prefix = resolvedReceiver.element; | |
763 target = prefix.lookupLocalMember(name); | |
764 if (Elements.isUnresolved(target)) { | |
765 registry.registerThrowNoSuchMethod(); | |
766 return new ElementResult(reportAndCreateErroneousElement( | |
767 node, name, MessageKind.NO_SUCH_LIBRARY_MEMBER, | |
768 {'libraryName': prefix.name, 'memberName': name})); | |
769 } else if (target.isAmbiguous) { | |
770 registry.registerThrowNoSuchMethod(); | |
771 AmbiguousElement ambiguous = target; | |
772 target = reportAndCreateErroneousElement( | |
773 node, name, ambiguous.messageKind, ambiguous.messageArguments); | |
774 ambiguous.diagnose(enclosingElement, compiler); | |
775 return new ElementResult(target); | |
776 } else if (target.kind == ElementKind.CLASS) { | |
777 ClassElement classElement = target; | |
778 classElement.ensureResolved(compiler); | |
779 } | |
780 } | |
781 return new ResolutionResult.forElement(target); | |
782 } | |
783 | |
784 static Selector computeSendSelector(Send node, | 642 static Selector computeSendSelector(Send node, |
785 LibraryElement library, | 643 LibraryElement library, |
786 Element element) { | 644 Element element) { |
787 // First determine if this is part of an assignment. | 645 // First determine if this is part of an assignment. |
788 bool isSet = node.asSendSet() != null; | 646 bool isSet = node.asSendSet() != null; |
789 | 647 |
790 if (node.isIndex) { | 648 if (node.isIndex) { |
791 return isSet ? new Selector.indexSet() : new Selector.index(); | 649 return isSet ? new Selector.indexSet() : new Selector.index(); |
792 } | 650 } |
793 | 651 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
893 } | 751 } |
894 argumentCount++; | 752 argumentCount++; |
895 } | 753 } |
896 sendIsMemberAccess = oldSendIsMemberAccess; | 754 sendIsMemberAccess = oldSendIsMemberAccess; |
897 return new ArgumentsResult( | 755 return new ArgumentsResult( |
898 new CallStructure(argumentCount, namedArguments), | 756 new CallStructure(argumentCount, namedArguments), |
899 argumentResults, | 757 argumentResults, |
900 isValidAsConstant: isValidAsConstant); | 758 isValidAsConstant: isValidAsConstant); |
901 } | 759 } |
902 | 760 |
903 void registerTypeLiteralAccess(Send node, Element target) { | |
904 // Set the type of the node to [Type] to mark this send as a | |
905 // type literal. | |
906 DartType type; | |
907 | |
908 // TODO(johnniwinther): Remove this hack when we can pass more complex | |
909 // information between methods than resolved elements. | |
910 if (target == compiler.typeClass && node.receiver == null) { | |
911 // Potentially a 'dynamic' type literal. | |
912 type = registry.getType(node.selector); | |
913 } | |
914 if (type == null) { | |
915 if (target.isTypedef || target.isClass) { | |
916 TypeDeclarationElement typeDeclaration = target; | |
917 typeDeclaration.computeType(compiler); | |
918 type = typeDeclaration.rawType; | |
919 } else { | |
920 TypeVariableElement typeVariable = target; | |
921 type = typeVariable.type; | |
922 } | |
923 } | |
924 registry.registerTypeLiteral(node, type); | |
925 | |
926 if (!target.isTypeVariable) { | |
927 // Don't try to make constants of calls and assignments to type literals. | |
928 if (!node.isCall && node.asSendSet() == null) { | |
929 analyzeConstantDeferred(node, enforceConst: false); | |
930 } else { | |
931 // The node itself is not a constant but we register the selector (the | |
932 // identifier that refers to the class/typedef) as a constant. | |
933 if (node.receiver != null) { | |
934 // This is a hack for the case of prefix.Type, we need to store | |
935 // the element on the selector, so [analyzeConstant] can build | |
936 // the type literal from the selector. | |
937 registry.useElement(node.selector, target); | |
938 } | |
939 analyzeConstantDeferred(node.selector, enforceConst: false); | |
940 } | |
941 } | |
942 } | |
943 | |
944 /// Check that access to `super` is currently allowed. Returns an | 761 /// Check that access to `super` is currently allowed. Returns an |
945 /// [AccessSemantics] in case of an error, `null` otherwise. | 762 /// [AccessSemantics] in case of an error, `null` otherwise. |
946 AccessSemantics checkSuperAccess(Send node) { | 763 AccessSemantics checkSuperAccess(Send node) { |
947 if (!inInstanceContext) { | 764 if (!inInstanceContext) { |
948 return new StaticAccess.invalid( | 765 return new StaticAccess.invalid( |
949 reportAndCreateErroneousElement( | 766 reportAndCreateErroneousElement( |
950 node, 'super', | 767 node, 'super', |
951 MessageKind.NO_SUPER_IN_STATIC, {}, | 768 MessageKind.NO_SUPER_IN_STATIC, {}, |
952 isError: true)); | 769 isError: true)); |
953 } | 770 } |
(...skipping 986 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1940 // setters. | 1757 // setters. |
1941 ErroneousElement error = reportAndCreateErroneousElement( | 1758 ErroneousElement error = reportAndCreateErroneousElement( |
1942 node, name.text, MessageKind.MEMBER_NOT_FOUND, | 1759 node, name.text, MessageKind.MEMBER_NOT_FOUND, |
1943 {'className': receiverClass.name, 'memberName': name.text}); | 1760 {'className': receiverClass.name, 'memberName': name.text}); |
1944 // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static | 1761 // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static |
1945 // member access. | 1762 // member access. |
1946 return handleErroneousAccess( | 1763 return handleErroneousAccess( |
1947 node, name, new StaticAccess.unresolved(error)); | 1764 node, name, new StaticAccess.unresolved(error)); |
1948 } | 1765 } |
1949 | 1766 |
1767 /// Handle qualified update to an unresolved static class member, like | |
1768 /// `a.b = c` or `a.b++` where `a` is a class and `b` is unresolved. | |
1769 ResolutionResult handleUnresolvedStaticMemberUpdate( | |
1770 SendSet node, Name name, ClassElement receiverClass) { | |
1771 // TODO(johnniwinther): Share code with [handleStaticInstanceMemberUpdate] | |
1772 // and [handlePrivateStaticMemberUpdate]. | |
1773 registry.registerThrowNoSuchMethod(); | |
1774 // TODO(johnniwinther): Produce a different error if [name] is resolves to | |
1775 // a constructor. | |
1776 | |
1777 // TODO(johnniwinther): With the simplified [TreeElements] invariant, | |
1778 // try to resolve injected elements if [currentClass] is in the patch | |
1779 // library of [receiverClass]. | |
1780 | |
1781 // TODO(johnniwinther): Produce a different error for complex update. | |
1782 ErroneousElement error = reportAndCreateErroneousElement( | |
1783 node, name.text, MessageKind.MEMBER_NOT_FOUND, | |
1784 {'className': receiverClass.name, 'memberName': name.text}); | |
1785 // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static | |
1786 // member access. | |
1787 return handleUpdate(node, name, new StaticAccess.unresolved(error)); | |
1788 } | |
1789 | |
1950 /// Handle qualified access of an instance member, like `a.b` or `a.b()` where | 1790 /// Handle qualified access of an instance member, like `a.b` or `a.b()` where |
1951 /// `a` is a class and `b` is a non-static member. | 1791 /// `a` is a class and `b` is a non-static member. |
1952 ResolutionResult handleStaticInstanceMemberAccess( | 1792 ResolutionResult handleStaticInstanceMemberAccess( |
1953 Send node, Name name, ClassElement receiverClass, Element member) { | 1793 Send node, Name name, ClassElement receiverClass, Element member) { |
1954 | 1794 |
1955 registry.registerThrowNoSuchMethod(); | 1795 registry.registerThrowNoSuchMethod(); |
1956 // TODO(johnniwinther): With the simplified [TreeElements] invariant, | 1796 // TODO(johnniwinther): With the simplified [TreeElements] invariant, |
1957 // try to resolve injected elements if [currentClass] is in the patch | 1797 // try to resolve injected elements if [currentClass] is in the patch |
1958 // library of [receiverClass]. | 1798 // library of [receiverClass]. |
1959 | 1799 |
1960 // TODO(karlklose): this should be reported by the caller of | 1800 // TODO(karlklose): this should be reported by the caller of |
1961 // [resolveSend] to select better warning messages for getters and | 1801 // [resolveSend] to select better warning messages for getters and |
1962 // setters. | 1802 // setters. |
1963 ErroneousElement error = reportAndCreateErroneousElement( | 1803 ErroneousElement error = reportAndCreateErroneousElement( |
1964 node, name.text, MessageKind.MEMBER_NOT_STATIC, | 1804 node, name.text, MessageKind.MEMBER_NOT_STATIC, |
1965 {'className': receiverClass.name, 'memberName': name}); | 1805 {'className': receiverClass.name, 'memberName': name}); |
1966 | 1806 |
1967 // TODO(johnniwinther): Add an [AccessSemantics] for statically accessed | 1807 // TODO(johnniwinther): Add an [AccessSemantics] for statically accessed |
1968 // instance members. | 1808 // instance members. |
1969 return handleErroneousAccess( | 1809 return handleErroneousAccess( |
1970 node, name, new StaticAccess.unresolved(error)); | 1810 node, name, new StaticAccess.unresolved(error)); |
1971 } | 1811 } |
1972 | 1812 |
1813 /// Handle qualified update of an instance member, like `a.b = c` or `a.b++` | |
1814 /// where `a` is a class and `b` is a non-static member. | |
1815 ResolutionResult handleStaticInstanceMemberUpdate( | |
1816 SendSet node, Name name, ClassElement receiverClass, Element member) { | |
1817 | |
1818 registry.registerThrowNoSuchMethod(); | |
1819 // TODO(johnniwinther): With the simplified [TreeElements] invariant, | |
1820 // try to resolve injected elements if [currentClass] is in the patch | |
1821 // library of [receiverClass]. | |
1822 | |
1823 // TODO(johnniwinther): Produce a different error for complex update. | |
1824 ErroneousElement error = reportAndCreateErroneousElement( | |
1825 node, name.text, MessageKind.MEMBER_NOT_STATIC, | |
1826 {'className': receiverClass.name, 'memberName': name}); | |
1827 | |
1828 // TODO(johnniwinther): Add an [AccessSemantics] for statically accessed | |
1829 // instance members. | |
1830 return handleUpdate(node, name, new StaticAccess.unresolved(error)); | |
1831 } | |
1832 | |
1973 /// Handle qualified access of an inaccessible private static class member, | 1833 /// Handle qualified access of an inaccessible private static class member, |
1974 /// like `a._b` or `a.b()` where `a` is class, `_b` is static member of `a` | 1834 /// like `a._b` or `a._b()` where `a` is class, `_b` is static member of `a` |
1975 /// but `a` is not defined in the current library. | 1835 /// but `a` is not defined in the current library. |
1976 ResolutionResult handlePrivateStaticMemberAccess( | 1836 ResolutionResult handlePrivateStaticMemberAccess( |
1977 Send node, Name name, ClassElement receiverClass, Element member) { | 1837 Send node, Name name, ClassElement receiverClass, Element member) { |
1978 registry.registerThrowNoSuchMethod(); | 1838 registry.registerThrowNoSuchMethod(); |
1979 ErroneousElement error = reportAndCreateErroneousElement( | 1839 ErroneousElement error = reportAndCreateErroneousElement( |
1980 node, name.text, MessageKind.PRIVATE_ACCESS, | 1840 node, name.text, MessageKind.PRIVATE_ACCESS, |
1981 {'libraryName': member.library.getLibraryOrScriptName(), | 1841 {'libraryName': member.library.getLibraryOrScriptName(), |
1982 'name': name}); | 1842 'name': name}); |
1983 // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static | 1843 // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static |
1984 // member access. | 1844 // member access. |
1985 return handleErroneousAccess( | 1845 return handleErroneousAccess( |
1986 node, name, new StaticAccess.unresolved(error)); | 1846 node, name, new StaticAccess.unresolved(error)); |
1987 } | 1847 } |
1988 | 1848 |
1849 /// Handle qualified update of an inaccessible private static class member, | |
1850 /// like `a._b = c` or `a._b++` where `a` is class, `_b` is static member of | |
1851 /// `a` but `a` is not defined in the current library. | |
1852 ResolutionResult handlePrivateStaticMemberUpdate( | |
1853 SendSet node, Name name, ClassElement receiverClass, Element member) { | |
1854 registry.registerThrowNoSuchMethod(); | |
1855 ErroneousElement error = reportAndCreateErroneousElement( | |
1856 node, name.text, MessageKind.PRIVATE_ACCESS, | |
1857 {'libraryName': member.library.getLibraryOrScriptName(), | |
1858 'name': name}); | |
1859 // TODO(johnniwinther): Add an [AccessSemantics] for unresolved static | |
1860 // member access. | |
1861 return handleUpdate(node, name, new StaticAccess.unresolved(error)); | |
1862 } | |
1863 | |
1989 /// Handle qualified access to a static member, like `a.b` or `a.b()` where | 1864 /// Handle qualified access to a static member, like `a.b` or `a.b()` where |
1990 /// `a` is a class and `b` is a static member of `a`. | 1865 /// `a` is a class and `b` is a static member of `a`. |
1991 ResolutionResult handleStaticMemberAccess( | 1866 ResolutionResult handleStaticMemberAccess( |
1992 Send node, Name memberName, ClassElement receiverClass) { | 1867 Send node, Name memberName, ClassElement receiverClass) { |
1993 String name = memberName.text; | 1868 String name = memberName.text; |
1994 receiverClass.ensureResolved(compiler); | 1869 receiverClass.ensureResolved(compiler); |
1995 if (node.isOperator) { | 1870 if (node.isOperator) { |
1996 // When the resolved receiver is a class, we can have two cases: | 1871 // When the resolved receiver is a class, we can have two cases: |
1997 // 1) a static send: C.foo, or | 1872 // 1) a static send: C.foo, or |
1998 // 2) an operator send, where the receiver is a class literal: 'C + 1'. | 1873 // 2) an operator send, where the receiver is a class literal: 'C + 1'. |
(...skipping 14 matching lines...) Expand all Loading... | |
2013 return handleStaticInstanceMemberAccess( | 1888 return handleStaticInstanceMemberAccess( |
2014 node, memberName, receiverClass, member); | 1889 node, memberName, receiverClass, member); |
2015 } else if (memberName.isPrivate && memberName.library != member.library) { | 1890 } else if (memberName.isPrivate && memberName.library != member.library) { |
2016 return handlePrivateStaticMemberAccess( | 1891 return handlePrivateStaticMemberAccess( |
2017 node, memberName, receiverClass, member); | 1892 node, memberName, receiverClass, member); |
2018 } else { | 1893 } else { |
2019 return handleStaticOrTopLevelAccess(node, memberName, member); | 1894 return handleStaticOrTopLevelAccess(node, memberName, member); |
2020 } | 1895 } |
2021 } | 1896 } |
2022 | 1897 |
1898 /// Handle qualified update to a static member, like `a.b = c` or `a.b++` | |
1899 /// where `a` is a class and `b` is a static member of `a`. | |
1900 ResolutionResult handleStaticMemberUpdate( | |
1901 Send node, Name memberName, ClassElement receiverClass) { | |
1902 String name = memberName.text; | |
1903 receiverClass.ensureResolved(compiler); | |
1904 MembersCreator.computeClassMembersByName( | |
1905 compiler, receiverClass.declaration, name); | |
1906 Element member = receiverClass.lookupLocalMember(name); | |
1907 if (member == null) { | |
1908 return handleUnresolvedStaticMemberUpdate( | |
1909 node, memberName, receiverClass); | |
1910 } else if (member.isAmbiguous) { | |
1911 return handleAmbiguousUpdate(node, memberName, member); | |
1912 } else if (member.isInstanceMember) { | |
1913 return handleStaticInstanceMemberUpdate( | |
1914 node, memberName, receiverClass, member); | |
1915 } else if (memberName.isPrivate && memberName.library != member.library) { | |
1916 return handlePrivateStaticMemberUpdate( | |
1917 node, memberName, receiverClass, member); | |
1918 } else { | |
1919 return handleStaticOrTopLevelUpdate(node, memberName, member); | |
1920 } | |
1921 } | |
1922 | |
2023 /// Handle access to a type literal of type variable [element]. Like `T` or | 1923 /// Handle access to a type literal of type variable [element]. Like `T` or |
2024 /// `T()` where 'T' is type variable. | 1924 /// `T()` where 'T' is type variable. |
2025 // TODO(johnniwinther): Remove [name] when [Selector] is not required for the | 1925 // TODO(johnniwinther): Remove [name] when [Selector] is not required for the |
2026 // the [GetStructure]. | 1926 // the [GetStructure]. |
2027 // TODO(johnniwinther): Remove [element] when it is no longer needed for | 1927 // TODO(johnniwinther): Remove [element] when it is no longer needed for |
2028 // evaluating constants. | 1928 // evaluating constants. |
2029 ResolutionResult handleTypeVariableTypeLiteralAccess( | 1929 ResolutionResult handleTypeVariableTypeLiteralAccess( |
2030 Send node, | 1930 Send node, |
2031 Name name, | 1931 Name name, |
2032 TypeVariableElement element) { | 1932 TypeVariableElement element) { |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2324 // `prefix.Class.foo`. No need to call [handleDeferredAccess]; it will | 2224 // `prefix.Class.foo`. No need to call [handleDeferredAccess]; it will |
2325 // called on the parent `prefix.Class.foo` node. | 2225 // called on the parent `prefix.Class.foo` node. |
2326 result = new PrefixResult(prefix, result.element); | 2226 result = new PrefixResult(prefix, result.element); |
2327 } else if (prefix.isDeferred && | 2227 } else if (prefix.isDeferred && |
2328 (member == null || !member.isDeferredLoaderGetter)) { | 2228 (member == null || !member.isDeferredLoaderGetter)) { |
2329 result = handleDeferredAccess(node, prefix, result); | 2229 result = handleDeferredAccess(node, prefix, result); |
2330 } | 2230 } |
2331 return result; | 2231 return result; |
2332 } | 2232 } |
2333 | 2233 |
2234 /// Handle qualified [SendSet] where the receiver resolves to a [prefix], | |
2235 /// like `prefix.toplevelField = b` or `prefix.Class.staticField++` where | |
2236 /// `prefix` is a library prefix. | |
2237 ResolutionResult handleLibraryPrefixSendSet( | |
2238 SendSet node, Name name, PrefixElement prefix) { | |
2239 ResolutionResult result; | |
2240 Element member = prefix.lookupLocalMember(name.text); | |
2241 if (member == null) { | |
2242 registry.registerThrowNoSuchMethod(); | |
2243 Element error = reportAndCreateErroneousElement( | |
2244 node, name.text, MessageKind.NO_SUCH_LIBRARY_MEMBER, | |
2245 {'libraryName': prefix.name, 'memberName': name}); | |
2246 return handleUpdate(node, name, new StaticAccess.unresolved(error)); | |
2247 } else { | |
2248 result = handleResolvedSendSet(node, name, member); | |
2249 } | |
2250 if (result.kind == ResultKind.PREFIX) { | |
2251 // [member] is a class prefix of a static access like `prefix.Class` of | |
2252 // `prefix.Class.foo`. No need to call [handleDeferredAccess]; it will | |
2253 // called on the parent `prefix.Class.foo` node. | |
2254 result = new PrefixResult(prefix, result.element); | |
2255 } else if (prefix.isDeferred && | |
2256 (member == null || !member.isDeferredLoaderGetter)) { | |
2257 result = handleDeferredAccess(node, prefix, result); | |
2258 } | |
2259 return result; | |
2260 } | |
2261 | |
2334 /// Handle a [Send] that resolves to a [prefix]. Like `prefix` in | 2262 /// Handle a [Send] that resolves to a [prefix]. Like `prefix` in |
2335 /// `prefix.Class` or `prefix` in `prefix()`, the latter being a compile time | 2263 /// `prefix.Class` or `prefix` in `prefix()`, the latter being a compile time |
2336 /// error. | 2264 /// error. |
2337 ResolutionResult handleLibraryPrefix( | 2265 ResolutionResult handleLibraryPrefix( |
2338 Send node, | 2266 Send node, |
2339 Name name, | 2267 Name name, |
2340 PrefixElement prefix) { | 2268 PrefixElement prefix) { |
2341 if ((ElementCategory.PREFIX & allowedCategory) == 0) { | 2269 if ((ElementCategory.PREFIX & allowedCategory) == 0) { |
2342 ErroneousElement error = reportAndCreateErroneousElement( | 2270 ErroneousElement error = reportAndCreateErroneousElement( |
2343 node, | 2271 node, |
(...skipping 27 matching lines...) Expand all Loading... | |
2371 } else { | 2299 } else { |
2372 assert(element.isClass); | 2300 assert(element.isClass); |
2373 ResolutionResult result = handleStaticMemberAccess(node, name, element); | 2301 ResolutionResult result = handleStaticMemberAccess(node, name, element); |
2374 if (prefixResult.isDeferred) { | 2302 if (prefixResult.isDeferred) { |
2375 result = handleDeferredAccess(node, prefixResult.prefix, result); | 2303 result = handleDeferredAccess(node, prefixResult.prefix, result); |
2376 } | 2304 } |
2377 return result; | 2305 return result; |
2378 } | 2306 } |
2379 } | 2307 } |
2380 | 2308 |
2309 /// Handle qualified [SendSet] where the receiver resolves to an [Element], | |
2310 /// like `a.b = c` where `a` is a prefix or a class. | |
2311 ResolutionResult handlePrefixSendSet( | |
2312 SendSet node, Name name, PrefixResult prefixResult) { | |
2313 Element element = prefixResult.element; | |
2314 if (element.isPrefix) { | |
2315 if (node.isConditional) { | |
2316 return handleLibraryPrefix(node, name, element); | |
2317 } else { | |
2318 return handleLibraryPrefixSendSet(node, name, element); | |
2319 } | |
2320 } else { | |
2321 assert(element.isClass); | |
2322 ResolutionResult result = handleStaticMemberUpdate(node, name, element); | |
2323 if (prefixResult.isDeferred) { | |
2324 result = handleDeferredAccess(node, prefixResult.prefix, result); | |
2325 } | |
2326 return result; | |
2327 } | |
2328 } | |
2329 | |
2381 /// Handle dynamic access of [semantics]. | 2330 /// Handle dynamic access of [semantics]. |
2382 ResolutionResult handleDynamicAccessSemantics( | 2331 ResolutionResult handleDynamicAccessSemantics( |
2383 Send node, Name name, AccessSemantics semantics) { | 2332 Send node, Name name, AccessSemantics semantics) { |
2384 SendStructure sendStructure; | 2333 SendStructure sendStructure; |
2385 Selector selector; | 2334 Selector selector; |
2386 if (node.isCall) { | 2335 if (node.isCall) { |
2387 CallStructure callStructure = | 2336 CallStructure callStructure = |
2388 resolveArguments(node.argumentsNode).callStructure; | 2337 resolveArguments(node.argumentsNode).callStructure; |
2389 selector = new Selector(SelectorKind.CALL, name, callStructure); | 2338 selector = new Selector(SelectorKind.CALL, name, callStructure); |
2390 registry.registerDynamicInvocation( | 2339 registry.registerDynamicInvocation( |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2475 node, name, const DynamicAccess.ifNotNullProperty()); | 2424 node, name, const DynamicAccess.ifNotNullProperty()); |
2476 } else { | 2425 } else { |
2477 // Handle dynamic property access, like `a.b` or `a.b()` where `a` is not | 2426 // Handle dynamic property access, like `a.b` or `a.b()` where `a` is not |
2478 // a prefix or class. | 2427 // a prefix or class. |
2479 // TODO(johnniwinther): Use the `element` of [result]. | 2428 // TODO(johnniwinther): Use the `element` of [result]. |
2480 return handleDynamicAccessSemantics( | 2429 return handleDynamicAccessSemantics( |
2481 node, name, const DynamicAccess.dynamicProperty()); | 2430 node, name, const DynamicAccess.dynamicProperty()); |
2482 } | 2431 } |
2483 } | 2432 } |
2484 | 2433 |
2434 /// Handle a qualified [SendSet], that is where the receiver is non-null, like | |
2435 /// `a.b = c`, `a.b++`, and `a.b += c`. | |
2436 ResolutionResult handleQualifiedSendSet(SendSet node) { | |
2437 Identifier selector = node.selector.asIdentifier(); | |
2438 String text = selector.source; | |
2439 Name name = new Name(text, enclosingElement.library); | |
2440 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
| |
2441 return handleQualifiedThisAccess(node, name); | |
2442 } else if (node.receiver.isThis()) { | |
2443 if (checkThisAccess(node)) { | |
2444 return handleThisPropertyUpdate(node, name, null); | |
2445 } | |
2446 // TODO(johnniwinther): Handle invalid this access as an | |
2447 // [AccessSemantics]. | |
2448 return const NoneResult(); | |
2449 } | |
2450 ResolutionResult result = visitExpressionPrefix(node.receiver); | |
2451 if (result.kind == ResultKind.PREFIX) { | |
2452 return handlePrefixSendSet(node, name, result); | |
2453 } else if (node.isConditional) { | |
2454 return handleDynamicUpdateSemantics( | |
2455 node, name, null, const DynamicAccess.ifNotNullProperty()); | |
2456 } else { | |
2457 // Handle dynamic property access, like `a.b = c`, `a.b++` or `a.b += c` | |
2458 // where `a` is not a prefix or class. | |
2459 // TODO(johnniwinther): Use the `element` of [result]. | |
2460 return handleDynamicUpdateSemantics( | |
2461 node, name, null, const DynamicAccess.dynamicProperty()); | |
2462 } | |
2463 } | |
2464 | |
2485 /// Handle access unresolved access to [name] in a non-instance context. | 2465 /// Handle access unresolved access to [name] in a non-instance context. |
2486 ResolutionResult handleUnresolvedAccess( | 2466 ResolutionResult handleUnresolvedAccess( |
2487 Send node, Name name, Element element) { | 2467 Send node, Name name, Element element) { |
2488 // TODO(johnniwinther): Support unresolved top level access as an | 2468 // TODO(johnniwinther): Support unresolved top level access as an |
2489 // [AccessSemantics]. | 2469 // [AccessSemantics]. |
2490 AccessSemantics semantics = new StaticAccess.unresolved(element); | 2470 AccessSemantics semantics = new StaticAccess.unresolved(element); |
2491 return handleErroneousAccess(node, name, semantics); | 2471 return handleErroneousAccess(node, name, semantics); |
2492 } | 2472 } |
2493 | 2473 |
2494 /// Handle erroneous access of [element] of the given [semantics]. | 2474 /// Handle erroneous access of [element] of the given [semantics]. |
(...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3023 // `C = b`, `C++`, or 'C += b` where 'F' is a typedef. | 3003 // `C = b`, `C++`, or 'C += b` where 'F' is a typedef. |
3024 return handleTypedefTypeLiteralUpdate(node, name, element); | 3004 return handleTypedefTypeLiteralUpdate(node, name, element); |
3025 } else if (element.isTypeVariable) { | 3005 } else if (element.isTypeVariable) { |
3026 // `T = b`, `T++`, or 'T += b` where 'T' is a type variable. | 3006 // `T = b`, `T++`, or 'T += b` where 'T' is a type variable. |
3027 return handleTypeVariableTypeLiteralUpdate(node, name, element); | 3007 return handleTypeVariableTypeLiteralUpdate(node, name, element); |
3028 } else if (element.isLocal) { | 3008 } else if (element.isLocal) { |
3029 return handleLocalUpdate(node, name, element); | 3009 return handleLocalUpdate(node, name, element); |
3030 } else if (element.isStatic || element.isTopLevel) { | 3010 } else if (element.isStatic || element.isTopLevel) { |
3031 return handleStaticOrTopLevelUpdate(node, name, element); | 3011 return handleStaticOrTopLevelUpdate(node, name, element); |
3032 } | 3012 } |
3033 return oldVisitSendSet(node); | 3013 return internalError(node, "Unexpected resolved send: $element"); |
3034 } | 3014 } |
3035 | 3015 |
3036 /// Handle an unqualified [Send], that is where the `node.receiver` is null, | 3016 /// Handle an unqualified [Send], that is where the `node.receiver` is null, |
3037 /// like `a`, `a()`, `this()`, `assert()`, and `(){}()`. | 3017 /// like `a`, `a()`, `this()`, `assert()`, and `(){}()`. |
3038 ResolutionResult handleUnqualifiedSend(Send node) { | 3018 ResolutionResult handleUnqualifiedSend(Send node) { |
3039 Identifier selector = node.selector.asIdentifier(); | 3019 Identifier selector = node.selector.asIdentifier(); |
3040 if (selector == null) { | 3020 if (selector == null) { |
3041 // `(){}()` and `(foo)()`. | 3021 // `(){}()` and `(foo)()`. |
3042 return handleExpressionInvoke(node); | 3022 return handleExpressionInvoke(node); |
3043 } | 3023 } |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3492 SendStructure sendStructure = new CompoundStructure( | 3472 SendStructure sendStructure = new CompoundStructure( |
3493 semantics, operator, getterSelector, setterSelector); | 3473 semantics, operator, getterSelector, setterSelector); |
3494 registry.registerSendStructure(node, sendStructure); | 3474 registry.registerSendStructure(node, sendStructure); |
3495 } | 3475 } |
3496 } | 3476 } |
3497 return new ResolutionResult.forElement(semantics.setter); | 3477 return new ResolutionResult.forElement(semantics.setter); |
3498 } | 3478 } |
3499 | 3479 |
3500 ResolutionResult visitSendSet(SendSet node) { | 3480 ResolutionResult visitSendSet(SendSet node) { |
3501 if (node.isIndex) { | 3481 if (node.isIndex) { |
3482 // `a[b] = c` | |
3502 if (node.isSuperCall) { | 3483 if (node.isSuperCall) { |
3484 // `super[b] = c` | |
3503 return handleSuperIndexSendSet(node); | 3485 return handleSuperIndexSendSet(node); |
3504 } else { | 3486 } else { |
3505 return handleIndexSendSet(node); | 3487 return handleIndexSendSet(node); |
3506 } | 3488 } |
3507 } else if (node.isSuperCall) { | 3489 } else if (node.isSuperCall) { |
3490 // `super.a = c` | |
3508 return handleSuperSendSet(node); | 3491 return handleSuperSendSet(node); |
3509 } else if (node.receiver == null) { | 3492 } else if (node.receiver == null) { |
3493 // `a = c` | |
3510 return handleUnqualifiedSendSet(node); | 3494 return handleUnqualifiedSendSet(node); |
3495 } else { | |
3496 // `a.b = c` | |
3497 return handleQualifiedSendSet(node); | |
3511 } | 3498 } |
3512 return oldVisitSendSet(node); | |
3513 } | |
3514 | |
3515 ResolutionResult oldVisitSendSet(SendSet node) { | |
3516 bool oldSendIsMemberAccess = sendIsMemberAccess; | |
3517 sendIsMemberAccess = node.isPropertyAccess || node.isCall; | |
3518 ResolutionResult result = resolveSend(node); | |
3519 sendIsMemberAccess = oldSendIsMemberAccess; | |
3520 Element target = result.element; | |
3521 Element setter = target; | |
3522 Element getter = target; | |
3523 String operatorName = node.assignmentOperator.source; | |
3524 String source = operatorName; | |
3525 bool isComplex = !identical(source, '='); | |
3526 if (!(result is AssertResult || Elements.isUnresolved(target))) { | |
3527 if (target.isAbstractField) { | |
3528 AbstractFieldElement field = target; | |
3529 setter = field.setter; | |
3530 getter = field.getter; | |
3531 if (setter == null) { | |
3532 if (!inInstanceContext || getter.isTopLevel || getter.isStatic) { | |
3533 setter = reportAndCreateErroneousElement(node.selector, field.name, | |
3534 MessageKind.CANNOT_RESOLVE_SETTER, const {}); | |
3535 registry.registerThrowNoSuchMethod(); | |
3536 } | |
3537 } | |
3538 if (isComplex && getter == null && !inInstanceContext) { | |
3539 getter = reportAndCreateErroneousElement(node.selector, field.name, | |
3540 MessageKind.CANNOT_RESOLVE_GETTER, const {}); | |
3541 registry.registerThrowNoSuchMethod(); | |
3542 } | |
3543 } else if (target.impliesType) { | |
3544 if (node.isIfNullAssignment) { | |
3545 setter = reportAndCreateErroneousElement(node.selector, target.name, | |
3546 MessageKind.IF_NULL_ASSIGNING_TYPE, const {}); | |
3547 // In this case, no assignment happens, the rest of the compiler can | |
3548 // treat the expression `C ??= e` as if it's just reading `C`. | |
3549 } else { | |
3550 setter = reportAndCreateErroneousElement(node.selector, target.name, | |
3551 MessageKind.ASSIGNING_TYPE, const {}); | |
3552 registry.registerThrowNoSuchMethod(); | |
3553 } | |
3554 registerTypeLiteralAccess(node, target); | |
3555 } else if (target.isFinal || target.isConst) { | |
3556 if (Elements.isStaticOrTopLevelField(target) || target.isLocal) { | |
3557 setter = reportAndCreateErroneousElement( | |
3558 node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER, | |
3559 const {}); | |
3560 } else if (node.isSuperCall) { | |
3561 setter = reportAndCreateErroneousElement( | |
3562 node.selector, target.name, MessageKind.SETTER_NOT_FOUND_IN_SUPER, | |
3563 {'name': target.name, 'className': currentClass.name}); | |
3564 registry.registerSuperNoSuchMethod(); | |
3565 } else { | |
3566 // For instance fields we don't report a warning here because the type | |
3567 // checker will detect this as well and report a better error message | |
3568 // with the context of the containing class. | |
3569 } | |
3570 registry.registerThrowNoSuchMethod(); | |
3571 } else if (target.isFunction && target.name != '[]=') { | |
3572 assert(!target.isSetter); | |
3573 if (Elements.isStaticOrTopLevelFunction(target) || target.isLocal) { | |
3574 setter = reportAndCreateErroneousElement( | |
3575 node.selector, target.name, MessageKind.ASSIGNING_METHOD, | |
3576 const {}); | |
3577 } else if (node.isSuperCall) { | |
3578 setter = reportAndCreateErroneousElement( | |
3579 node.selector, target.name, MessageKind.ASSIGNING_METHOD_IN_SUPER, | |
3580 {'name': target.name, | |
3581 'superclassName': target.enclosingClass.name}); | |
3582 registry.registerSuperNoSuchMethod(); | |
3583 } else { | |
3584 // For instance methods we don't report a warning here because the | |
3585 // type checker will detect this as well and report a better error | |
3586 // message with the context of the containing class. | |
3587 } | |
3588 registry.registerThrowNoSuchMethod(); | |
3589 } | |
3590 if (isPotentiallyMutableTarget(target)) { | |
3591 registry.registerPotentialMutation(target, node); | |
3592 if (enclosingElement != target.enclosingElement) { | |
3593 registry.registerPotentialMutationInClosure(target, node); | |
3594 } | |
3595 for (Node scope in promotionScope) { | |
3596 registry.registerPotentialMutationIn(scope, target, node); | |
3597 } | |
3598 } | |
3599 } | |
3600 | |
3601 resolveArguments(node.argumentsNode); | |
3602 | |
3603 Selector selector = registry.getSelector(node); | |
3604 if (isComplex) { | |
3605 Selector getterSelector; | |
3606 if (selector.isSetter) { | |
3607 getterSelector = new Selector.getterFrom(selector); | |
3608 } else { | |
3609 assert(selector.isIndexSet); | |
3610 getterSelector = new Selector.index(); | |
3611 } | |
3612 registerSend(getterSelector, getter); | |
3613 registry.setGetterSelectorInComplexSendSet(node, getterSelector); | |
3614 if (node.isSuperCall) { | |
3615 getter = currentClass.lookupSuperByName(getterSelector.memberName); | |
3616 if (getter == null) { | |
3617 target = reportAndCreateErroneousElement( | |
3618 node, selector.name, MessageKind.NO_SUCH_SUPER_MEMBER, | |
3619 {'className': currentClass.name, 'memberName': selector.name}); | |
3620 registry.registerSuperNoSuchMethod(); | |
3621 } | |
3622 } | |
3623 registry.useElement(node.selector, getter); | |
3624 | |
3625 // Make sure we include the + and - operators if we are using | |
3626 // the ++ and -- ones. Also, if op= form is used, include op itself. | |
3627 void registerBinaryOperator(String name) { | |
3628 Selector binop = new Selector.binaryOperator(name); | |
3629 registry.registerDynamicInvocation( | |
3630 new UniverseSelector(binop, null)); | |
3631 registry.setOperatorSelectorInComplexSendSet(node, binop); | |
3632 } | |
3633 if (identical(source, '++')) { | |
3634 registerBinaryOperator('+'); | |
3635 registry.registerInstantiatedClass(compiler.intClass); | |
3636 } else if (identical(source, '--')) { | |
3637 registerBinaryOperator('-'); | |
3638 registry.registerInstantiatedClass(compiler.intClass); | |
3639 } else if (source.endsWith('=')) { | |
3640 registerBinaryOperator(Elements.mapToUserOperator(operatorName)); | |
3641 } | |
3642 } | |
3643 | |
3644 registerSend(selector, setter); | |
3645 return new ResolutionResult.forElement(registry.useElement(node, setter)); | |
3646 } | 3499 } |
3647 | 3500 |
3648 void registerSend(Selector selector, Element target) { | 3501 void registerSend(Selector selector, Element target) { |
3649 if (target == null || target.isInstanceMember) { | 3502 if (target == null || target.isInstanceMember) { |
3650 if (selector.isGetter) { | 3503 if (selector.isGetter) { |
3651 registry.registerDynamicGetter( | 3504 registry.registerDynamicGetter( |
3652 new UniverseSelector(selector, null)); | 3505 new UniverseSelector(selector, null)); |
3653 } else if (selector.isSetter) { | 3506 } else if (selector.isSetter) { |
3654 registry.registerDynamicSetter( | 3507 registry.registerDynamicSetter( |
3655 new UniverseSelector(selector, null)); | 3508 new UniverseSelector(selector, null)); |
(...skipping 1142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4798 } | 4651 } |
4799 return const NoneResult(); | 4652 return const NoneResult(); |
4800 } | 4653 } |
4801 } | 4654 } |
4802 | 4655 |
4803 /// Looks up [name] in [scope] and unwraps the result. | 4656 /// Looks up [name] in [scope] and unwraps the result. |
4804 Element lookupInScope(Compiler compiler, Node node, | 4657 Element lookupInScope(Compiler compiler, Node node, |
4805 Scope scope, String name) { | 4658 Scope scope, String name) { |
4806 return Elements.unwrap(scope.lookup(name), compiler, node); | 4659 return Elements.unwrap(scope.lookup(name), compiler, node); |
4807 } | 4660 } |
OLD | NEW |