 Chromium Code Reviews
 Chromium Code Reviews Issue 1334673002:
  Add warnings and hints to for-in.  (Closed) 
  Base URL: https://github.com/dart-lang/sdk.git@master
    
  
    Issue 1334673002:
  Add warnings and hints to for-in.  (Closed) 
  Base URL: https://github.com/dart-lang/sdk.git@master| 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 |