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.typechecker; | 5 library dart2js.typechecker; |
6 | 6 |
7 import 'common/names.dart' show | |
8 Identifiers; | |
7 import 'common/tasks.dart' show | 9 import 'common/tasks.dart' show |
8 CompilerTask; | 10 CompilerTask; |
9 import 'compiler.dart' show | 11 import 'compiler.dart' show |
10 Compiler; | 12 Compiler; |
11 import 'constants/expressions.dart'; | 13 import 'constants/expressions.dart'; |
12 import 'constants/values.dart'; | 14 import 'constants/values.dart'; |
13 import 'core_types.dart'; | 15 import 'core_types.dart'; |
14 import 'dart_types.dart'; | 16 import 'dart_types.dart'; |
15 import 'diagnostics/invariant.dart' show | 17 import 'diagnostics/invariant.dart' show |
16 invariant; | 18 invariant; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
55 import '../compiler_new.dart' as api; | 57 import '../compiler_new.dart' as api; |
56 | 58 |
57 class TypeCheckerTask extends CompilerTask { | 59 class TypeCheckerTask extends CompilerTask { |
58 TypeCheckerTask(Compiler compiler) : super(compiler); | 60 TypeCheckerTask(Compiler compiler) : super(compiler); |
59 String get name => "Type checker"; | 61 String get name => "Type checker"; |
60 | 62 |
61 void check(AstElement element) { | 63 void check(AstElement element) { |
62 if (element.isClass) return; | 64 if (element.isClass) return; |
63 if (element.isTypedef) return; | 65 if (element.isTypedef) return; |
64 ResolvedAst resolvedAst = element.resolvedAst; | 66 ResolvedAst resolvedAst = element.resolvedAst; |
65 compiler.withCurrentElement(element, () { | 67 compiler.withCurrentElement(element.implementation, () { |
66 measure(() { | 68 measure(() { |
67 TypeCheckerVisitor visitor = new TypeCheckerVisitor( | 69 TypeCheckerVisitor visitor = new TypeCheckerVisitor( |
68 compiler, resolvedAst.elements, compiler.types); | 70 compiler, resolvedAst.elements, compiler.types); |
69 if (element.isField) { | 71 if (element.isField) { |
70 visitor.analyzingInitializer = true; | 72 visitor.analyzingInitializer = true; |
71 } | 73 } |
72 resolvedAst.node.accept(visitor); | 74 resolvedAst.node.accept(visitor); |
73 }); | 75 }); |
74 }); | 76 }); |
75 } | 77 } |
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
413 } | 415 } |
414 } | 416 } |
415 | 417 |
416 LibraryElement get currentLibrary => elements.analyzedElement.library; | 418 LibraryElement get currentLibrary => elements.analyzedElement.library; |
417 | 419 |
418 reportTypeWarning(Spannable spannable, MessageKind kind, | 420 reportTypeWarning(Spannable spannable, MessageKind kind, |
419 [Map arguments = const {}]) { | 421 [Map arguments = const {}]) { |
420 compiler.reportWarning(spannable, kind, arguments); | 422 compiler.reportWarning(spannable, kind, arguments); |
421 } | 423 } |
422 | 424 |
425 reportMessage(Spannable spannable, MessageKind kind, | |
426 Map arguments, | |
427 {bool isHint: false}) { | |
428 if (isHint) { | |
429 compiler.reportHint(spannable, kind, arguments); | |
430 } else { | |
431 compiler.reportWarning(spannable, kind, arguments); | |
432 } | |
433 } | |
434 | |
423 reportTypeInfo(Spannable spannable, MessageKind kind, | 435 reportTypeInfo(Spannable spannable, MessageKind kind, |
424 [Map arguments = const {}]) { | 436 [Map arguments = const {}]) { |
425 compiler.reportInfo(spannable, kind, arguments); | 437 compiler.reportInfo(spannable, kind, arguments); |
426 } | 438 } |
427 | 439 |
428 reportTypePromotionHint(TypePromotion typePromotion) { | 440 reportTypePromotionHint(TypePromotion typePromotion) { |
429 if (!reportedTypePromotions.contains(typePromotion)) { | 441 if (!reportedTypePromotions.contains(typePromotion)) { |
430 reportedTypePromotions.add(typePromotion); | 442 reportedTypePromotions.add(typePromotion); |
431 for (TypePromotionMessage message in typePromotion.messages) { | 443 for (TypePromotionMessage message in typePromotion.messages) { |
432 switch (message.diagnostic) { | 444 switch (message.diagnostic) { |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
726 node, | 738 node, |
727 MessageKind.PRIVATE_ACCESS, | 739 MessageKind.PRIVATE_ACCESS, |
728 {'name': name, | 740 {'name': name, |
729 'libraryName': element.library.getLibraryOrScriptName()}); | 741 'libraryName': element.library.getLibraryOrScriptName()}); |
730 } | 742 } |
731 | 743 |
732 } | 744 } |
733 | 745 |
734 ElementAccess lookupMember(Node node, DartType receiverType, String name, | 746 ElementAccess lookupMember(Node node, DartType receiverType, String name, |
735 MemberKind memberKind, Element receiverElement, | 747 MemberKind memberKind, Element receiverElement, |
736 {bool lookupClassMember: false}) { | 748 {bool lookupClassMember: false, |
749 bool isHint: false}) { | |
737 if (receiverType.treatAsDynamic) { | 750 if (receiverType.treatAsDynamic) { |
738 return const DynamicAccess(); | 751 return const DynamicAccess(); |
739 } | 752 } |
740 | 753 |
741 Name memberName = new Name(name, currentLibrary, | 754 Name memberName = new Name(name, currentLibrary, |
742 isSetter: memberKind == MemberKind.SETTER); | 755 isSetter: memberKind == MemberKind.SETTER); |
743 | 756 |
744 // Compute the unaliased type of the first non type variable bound of | 757 // Compute the unaliased type of the first non type variable bound of |
745 // [type]. | 758 // [type]. |
746 DartType computeUnaliasedBound(DartType type) { | 759 DartType computeUnaliasedBound(DartType type) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
833 // We didn't find a member with the correct name. If this lookup is for a | 846 // We didn't find a member with the correct name. If this lookup is for a |
834 // super or redirecting initializer, the resolver has already emitted an | 847 // super or redirecting initializer, the resolver has already emitted an |
835 // error message. If the target is a proxy, no warning needs to be emitted. | 848 // error message. If the target is a proxy, no warning needs to be emitted. |
836 // Otherwise, try to emit the most precise warning. | 849 // Otherwise, try to emit the most precise warning. |
837 if (!interface.element.isProxy && !analyzingInitializer) { | 850 if (!interface.element.isProxy && !analyzingInitializer) { |
838 bool foundPrivateMember = false; | 851 bool foundPrivateMember = false; |
839 if (memberName.isPrivate) { | 852 if (memberName.isPrivate) { |
840 void findPrivateMember(MemberSignature member) { | 853 void findPrivateMember(MemberSignature member) { |
841 if (memberName.isSimilarTo(member.name)) { | 854 if (memberName.isSimilarTo(member.name)) { |
842 PrivateName privateName = member.name; | 855 PrivateName privateName = member.name; |
843 reportTypeWarning( | 856 reportMessage( |
844 node, | 857 node, |
845 MessageKind.PRIVATE_ACCESS, | 858 MessageKind.PRIVATE_ACCESS, |
846 {'name': name, | 859 {'name': name, |
847 'libraryName': privateName.library.getLibraryOrScriptName()}); | 860 'libraryName': privateName.library.getLibraryOrScriptName()}, |
861 isHint: isHint); | |
848 foundPrivateMember = true; | 862 foundPrivateMember = true; |
849 } | 863 } |
850 } | 864 } |
851 // TODO(johnniwinther): Avoid computation of all class members. | 865 // TODO(johnniwinther): Avoid computation of all class members. |
852 MembersCreator.computeAllClassMembers(compiler, interface.element); | 866 MembersCreator.computeAllClassMembers(compiler, interface.element); |
853 if (lookupClassMember) { | 867 if (lookupClassMember) { |
854 interface.element.forEachClassMember(findPrivateMember); | 868 interface.element.forEachClassMember(findPrivateMember); |
855 } else { | 869 } else { |
856 interface.element.forEachInterfaceMember(findPrivateMember); | 870 interface.element.forEachInterfaceMember(findPrivateMember); |
857 } | 871 } |
858 | 872 |
859 } | 873 } |
860 if (!foundPrivateMember) { | 874 if (!foundPrivateMember) { |
861 switch (memberKind) { | 875 switch (memberKind) { |
862 case MemberKind.METHOD: | 876 case MemberKind.METHOD: |
863 reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, | 877 reportMessage(node, MessageKind.METHOD_NOT_FOUND, |
864 {'className': receiverType.name, 'memberName': name}); | 878 {'className': receiverType.name, 'memberName': name}, |
879 isHint: isHint); | |
865 break; | 880 break; |
866 case MemberKind.OPERATOR: | 881 case MemberKind.OPERATOR: |
867 reportTypeWarning(node, MessageKind.OPERATOR_NOT_FOUND, | 882 reportMessage(node, MessageKind.OPERATOR_NOT_FOUND, |
868 {'className': receiverType.name, 'memberName': name}); | 883 {'className': receiverType.name, 'memberName': name}, |
884 isHint: isHint); | |
869 break; | 885 break; |
870 case MemberKind.GETTER: | 886 case MemberKind.GETTER: |
871 if (lookupMemberSignature(memberName.setter, interface) != null) { | 887 if (lookupMemberSignature(memberName.setter, interface) != null) { |
872 // A setter is present so warn explicitly about the missing | 888 // A setter is present so warn explicitly about the missing |
873 // getter. | 889 // getter. |
874 reportTypeWarning(node, MessageKind.GETTER_NOT_FOUND, | 890 reportMessage(node, MessageKind.GETTER_NOT_FOUND, |
875 {'className': receiverType.name, 'memberName': name}); | 891 {'className': receiverType.name, 'memberName': name}, |
892 isHint: isHint); | |
876 } else if (name == 'await') { | 893 } else if (name == 'await') { |
877 Map arguments = {'className': receiverType.name}; | 894 Map arguments = {'className': receiverType.name}; |
878 String functionName = executableContext.name; | 895 String functionName = executableContext.name; |
879 MessageKind kind; | 896 MessageKind kind; |
880 if (functionName == '') { | 897 if (functionName == '') { |
881 kind = MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE; | 898 kind = MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE; |
882 } else { | 899 } else { |
883 kind = MessageKind.AWAIT_MEMBER_NOT_FOUND; | 900 kind = MessageKind.AWAIT_MEMBER_NOT_FOUND; |
884 arguments['functionName'] = functionName; | 901 arguments['functionName'] = functionName; |
885 } | 902 } |
886 reportTypeWarning(node, kind, arguments); | 903 reportMessage(node, kind, arguments, isHint: isHint); |
887 } else { | 904 } else { |
888 reportTypeWarning(node, MessageKind.MEMBER_NOT_FOUND, | 905 reportMessage(node, MessageKind.MEMBER_NOT_FOUND, |
889 {'className': receiverType.name, 'memberName': name}); | 906 {'className': receiverType.name, 'memberName': name}, |
907 isHint: isHint); | |
890 } | 908 } |
891 break; | 909 break; |
892 case MemberKind.SETTER: | 910 case MemberKind.SETTER: |
893 reportTypeWarning(node, MessageKind.SETTER_NOT_FOUND, | 911 reportMessage(node, MessageKind.SETTER_NOT_FOUND, |
894 {'className': receiverType.name, 'memberName': name}); | 912 {'className': receiverType.name, 'memberName': name}, |
913 isHint: isHint); | |
895 break; | 914 break; |
896 } | 915 } |
897 } | 916 } |
898 } | 917 } |
899 return const DynamicAccess(); | 918 return const DynamicAccess(); |
900 } | 919 } |
901 | 920 |
902 DartType lookupMemberType(Node node, DartType type, String name, | 921 DartType lookupMemberType(Node node, DartType type, String name, |
903 MemberKind memberKind) { | 922 MemberKind memberKind, |
904 return lookupMember(node, type, name, memberKind, null) | 923 {bool isHint: false}) { |
924 return lookupMember(node, type, name, memberKind, null, isHint: isHint) | |
905 .computeType(compiler); | 925 .computeType(compiler); |
906 } | 926 } |
907 | 927 |
908 void analyzeArguments(Send send, Element element, DartType type, | 928 void analyzeArguments(Send send, Element element, DartType type, |
909 [LinkBuilder<DartType> argumentTypes]) { | 929 [LinkBuilder<DartType> argumentTypes]) { |
910 Link<Node> arguments = send.arguments; | 930 Link<Node> arguments = send.arguments; |
911 DartType unaliasedType = type.unalias(compiler); | 931 DartType unaliasedType = type.unalias(compiler); |
912 if (identical(unaliasedType.kind, TypeKind.FUNCTION)) { | 932 if (identical(unaliasedType.kind, TypeKind.FUNCTION)) { |
913 bool error = false; | 933 bool error = false; |
914 FunctionType funType = unaliasedType; | 934 FunctionType funType = unaliasedType; |
(...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1790 } | 1810 } |
1791 | 1811 |
1792 visitBreakStatement(BreakStatement node) { | 1812 visitBreakStatement(BreakStatement node) { |
1793 return const StatementType(); | 1813 return const StatementType(); |
1794 } | 1814 } |
1795 | 1815 |
1796 visitContinueStatement(ContinueStatement node) { | 1816 visitContinueStatement(ContinueStatement node) { |
1797 return const StatementType(); | 1817 return const StatementType(); |
1798 } | 1818 } |
1799 | 1819 |
1800 visitAsyncForIn(AsyncForIn node) { | 1820 visitAsyncForIn(AsyncForIn node) { |
sigurdm
2015/09/10 13:07:21
Could you do the same for async for-in?
Johnni Winther
2015/09/11 10:36:41
Will do in a follow-up (need helpers added in anot
| |
1801 analyze(node.expression); | 1821 analyze(node.expression); |
1802 analyze(node.body); | 1822 analyze(node.body); |
1803 return const StatementType(); | 1823 return const StatementType(); |
1804 } | 1824 } |
1805 | 1825 |
1806 visitSyncForIn(SyncForIn node) { | 1826 visitSyncForIn(SyncForIn node) { |
1807 analyze(node.expression); | 1827 DartType elementType; |
1828 VariableDefinitions declaredIdentifier = | |
1829 node.declaredIdentifier.asVariableDefinitions(); | |
1830 if (declaredIdentifier != null) { | |
1831 elementType = | |
1832 analyzeWithDefault(declaredIdentifier.type, const DynamicType()); | |
1833 } else { | |
1834 elementType = analyze(node.declaredIdentifier); | |
1835 } | |
1836 DartType expressionType = analyze(node.expression); | |
1837 DartType iteratorType = lookupMemberType(node.expression, | |
1838 expressionType, Identifiers.iterator, MemberKind.GETTER); | |
1839 DartType currentType = lookupMemberType(node.expression, | |
1840 iteratorType, Identifiers.current, MemberKind.GETTER, | |
1841 isHint: true); | |
1842 if (!types.isAssignable(currentType, elementType)) { | |
1843 reportMessage(node.expression, | |
1844 MessageKind.FORIN_NOT_ASSIGNABLE, | |
1845 {'currentType': currentType, | |
1846 'expressionType': expressionType, | |
1847 'elementType': elementType}, | |
1848 isHint: true); | |
1849 } | |
1808 analyze(node.body); | 1850 analyze(node.body); |
1809 return const StatementType(); | 1851 return const StatementType(); |
1810 } | 1852 } |
1811 | 1853 |
1812 visitLabeledStatement(LabeledStatement node) { | 1854 visitLabeledStatement(LabeledStatement node) { |
1813 return analyze(node.statement); | 1855 return analyze(node.statement); |
1814 } | 1856 } |
1815 | 1857 |
1816 visitLiteralMap(LiteralMap node) { | 1858 visitLiteralMap(LiteralMap node) { |
1817 InterfaceType mapType = elements.getType(node); | 1859 InterfaceType mapType = elements.getType(node); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1926 | 1968 |
1927 visitTypedef(Typedef node) { | 1969 visitTypedef(Typedef node) { |
1928 // Do not typecheck [Typedef] nodes. | 1970 // Do not typecheck [Typedef] nodes. |
1929 } | 1971 } |
1930 | 1972 |
1931 visitNode(Node node) { | 1973 visitNode(Node node) { |
1932 compiler.internalError(node, | 1974 compiler.internalError(node, |
1933 'Unexpected node ${node.getObjectDescription()} in the type checker.'); | 1975 'Unexpected node ${node.getObjectDescription()} in the type checker.'); |
1934 } | 1976 } |
1935 } | 1977 } |
OLD | NEW |