OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 part of dart2js; | 5 part of dart2js; |
6 | 6 |
7 /** | 7 /** |
8 * The messages in this file should meet the following guide lines: | 8 * The messages in this file should meet the following guide lines: |
9 * | 9 * |
10 * 1. The message should start with exactly one of "Error", "Internal error", | 10 * 1. The message should start with exactly one of "Error", "Internal error", |
11 * "Warning", "Info", or "Hint" followed by a colon. It is crucial to users to | 11 * "Warning", "Info", or "Hint" followed by a colon. It is crucial to users to |
12 * be able to locate errors in the midst of warnings, but we are operating | 12 * be able to locate errors in the midst of warnings. |
13 * under the assumption that these messages will eventually be translated to | 13 * TODO(ahe): Remove these prefixes from the error message. |
14 * other languages than English, and that it is therefor not possible to | |
15 * automatically apply these prefixes. | |
16 * | 14 * |
17 * 2. After the colon, one space and a complete sentence starting with an | 15 * 2. After the colon, one space and a complete sentence starting with an |
18 * uppercase letter, and ending with a period. | 16 * uppercase letter, and ending with a period. |
19 * | 17 * |
20 * 3. Reserved words and embedded identifiers should be in quotes (double | 18 * 3. Reserved words and embedded identifiers should be in single quotes, so |
21 * quotes), so prefer single quotes for the complete message. For example, | 19 * prefer double quotes for the complete message. For example, "Error: The |
22 * 'Error: The class "#{className}" cannot use "super".' Notice that the word | 20 * class '#{className}' can't use 'super'." Notice that the word 'class' in the |
23 * "class" in the preceding message is not quoted as it refers to the concept | 21 * preceding message is not quoted as it refers to the concept 'class', not the |
24 * "class", not the reserved word. On the other hand, "super" refers to the | 22 * reserved word. On the other hand, 'super' refers to the reserved word. Do |
25 * reserved word. Do not quote "null" and numeric literals. | 23 * not quote 'null' and numeric literals. |
26 * | 24 * |
27 * 4. Do not try to compose messages, as it can make translating them hard. | 25 * 4. Do not try to compose messages, as it can make translating them hard. |
28 * | 26 * |
29 * 5. Try to keep the error messages short, but informative. | 27 * 5. Try to keep the error messages short, but informative. |
30 * | 28 * |
31 * 6. Use simple words and terminology, assume the reader of the message does | 29 * 6. Use simple words and terminology, assume the reader of the message |
32 * not have an advanced degree in math, and that English is not the reader's | 30 * doesn't have an advanced degree in math, and that English is not the |
33 * native language. Do not assume any formal computer science training. For | 31 * reader's native language. Do not assume any formal computer science |
34 * example, do not use Latin abbreviations (prefer "that is" over "i.e.", and | 32 * training. For example, do not use Latin abbreviations (prefer "that is" over |
35 * "for example" over "e.g."). Also avoid phrases such as "if and only if" and | 33 * "i.e.", and "for example" over "e.g."). Also avoid phrases such as "if and |
36 * "iff", that level of precision is unnecessary. | 34 * only if" and "iff", that level of precision is unnecessary. |
37 * | 35 * |
38 * 7. Do not use contractions, for example, prefer "cannot" over "can't". This | 36 * 7. Prefer contractions when they are in common use, for example, prefer |
39 * is again to benefit readers to whom English is not their first language. | 37 * "can't" over "cannot". Using "cannot", "must not", "shall not", etc. is |
| 38 * off-putting to people new to programming. |
40 * | 39 * |
41 * 8. Use common terminology, preferably from the Dart Language | 40 * 8. Use common terminology, preferably from the Dart Language |
42 * Specification. This increases the user's chance of finding a good | 41 * Specification. This increases the user's chance of finding a good |
43 * explanation on the web. | 42 * explanation on the web. |
44 * | 43 * |
45 * 9. Do not try to be cute or funny. It is extremely frustrating to work on a | 44 * 9. Do not try to be cute or funny. It is extremely frustrating to work on a |
46 * product that crashes with a "tongue-in-cheek" message, especially if you did | 45 * product that crashes with a "tongue-in-cheek" message, especially if you did |
47 * not want to use this product to begin with with. | 46 * not want to use this product to begin with with. |
48 * | 47 * |
49 * 10. Do not lie, that is, do not write error messages containing phrases like | 48 * 10. Do not lie, that is, do not write error messages containing phrases like |
50 * "cannot happen". If the user ever saw this message, it would be a | 49 * "can't happen". If the user ever saw this message, it would be a |
51 * lie. Prefer messages like: 'Internal error: This function should not be | 50 * lie. Prefer messages like: "Internal error: This function should not be |
52 * called when "x" is null.'. | 51 * called when 'x' is null.". |
| 52 * |
| 53 * 11. Prefer to not use imperative tone. That is, the message should not sound |
| 54 * accusing or like it is ordering the user around. The computer should |
| 55 * describe the problem, not criticize for violating the specification. |
| 56 * |
| 57 * Other things to keep in mind: |
| 58 * |
| 59 * An INFO message should always be preceded by a non-INFO message, and the |
| 60 * INFO messages are additional details about the preceding non-INFO |
| 61 * message. For example, consider duplicated elements. First report a WARNING |
| 62 * or ERROR about the duplicated element, and then report an INFO about the |
| 63 * location of the existing element. |
| 64 * |
| 65 * Generally, we want to provide messages that consists of three sentences: |
| 66 * 1. what is wrong, 2. why is it wrong, 3. how do I fix it. However, we |
| 67 * combine the first two in [template] and the last in [howToFix]. |
53 */ | 68 */ |
54 class MessageKind { | 69 class MessageKind { |
| 70 /// Should describe what is wrong and why. |
55 final String template; | 71 final String template; |
56 const MessageKind(this.template); | 72 |
| 73 /// Should describe how to fix the problem. Elided when using --terse option. |
| 74 final String howToFix; |
| 75 |
| 76 /// Examples will be checked by |
| 77 /// tests/compiler/dart2js/message_kind_test.dart. |
| 78 final List<String> examples; |
| 79 |
| 80 const MessageKind(this.template, {this.howToFix, this.examples}); |
57 | 81 |
58 /// Do not use this. It is here for legacy and debugging. It violates item 4 | 82 /// Do not use this. It is here for legacy and debugging. It violates item 4 |
59 /// above. | 83 /// above. |
60 static const MessageKind GENERIC = const MessageKind('#{text}'); | 84 static const MessageKind GENERIC = const MessageKind('#{text}'); |
61 | 85 |
62 static const DualKind NOT_ASSIGNABLE = const DualKind( | 86 static const DualKind NOT_ASSIGNABLE = const DualKind( |
63 error: const MessageKind( | 87 error: const MessageKind( |
64 'Error: "#{fromType}" is not assignable to "#{toType}".'), | 88 'Error: "#{fromType}" is not assignable to "#{toType}".'), |
65 warning: const MessageKind( | 89 warning: const MessageKind( |
66 'Warning: "#{fromType}" is not assignable to "#{toType}".')); | 90 'Warning: "#{fromType}" is not assignable to "#{toType}".')); |
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 'Did you mean "#{lhs} == #{rhs}" or "identical(#{lhs}, #{rhs})"?'); | 636 'Did you mean "#{lhs} == #{rhs}" or "identical(#{lhs}, #{rhs})"?'); |
613 | 637 |
614 static const MessageKind UNSUPPORTED_BANG_EQ_EQ = const MessageKind( | 638 static const MessageKind UNSUPPORTED_BANG_EQ_EQ = const MessageKind( |
615 'Error: "!==" is not an operator. ' | 639 'Error: "!==" is not an operator. ' |
616 'Did you mean "#{lhs} != #{rhs}" or "!identical(#{lhs}, #{rhs})"?'); | 640 'Did you mean "#{lhs} != #{rhs}" or "!identical(#{lhs}, #{rhs})"?'); |
617 | 641 |
618 static const MessageKind UNSUPPORTED_THROW_WITHOUT_EXP = const MessageKind( | 642 static const MessageKind UNSUPPORTED_THROW_WITHOUT_EXP = const MessageKind( |
619 'Error: No expression after "throw". ' | 643 'Error: No expression after "throw". ' |
620 'Did you mean "rethrow"?'); | 644 'Did you mean "rethrow"?'); |
621 | 645 |
| 646 static const MessageKind MIRRORS_EXPECTED_STRING = const MessageKind( |
| 647 "Hint: Can't use '#{name}' here because it's an instance of '#{type}' " |
| 648 "and a 'String' value is expected.", |
| 649 howToFix: "Did you forget to add quotes?", |
| 650 examples: const [ |
| 651 """ |
| 652 // 'main' is a method, not a class. |
| 653 @MirrorsUsed(symbols: const [Foo]) |
| 654 import 'dart:mirrors'; |
| 655 |
| 656 class Foo {} |
| 657 |
| 658 main() {} |
| 659 """]); |
| 660 |
| 661 static const MessageKind MIRRORS_EXPECTED_STRING_OR_TYPE = const MessageKind( |
| 662 "Hint: Can't use '#{name}' here because it's an instance of '#{type}' " |
| 663 "and a 'String' or 'Type' value is expected.", |
| 664 howToFix: "Did you forget to add quotes?", |
| 665 examples: const [ |
| 666 """ |
| 667 // 'main' is a method, not a class. |
| 668 @MirrorsUsed(targets: const [main]) |
| 669 import 'dart:mirrors'; |
| 670 |
| 671 main() {} |
| 672 """]); |
| 673 |
| 674 static const MessageKind MIRRORS_EXPECTED_STRING_OR_LIST = const MessageKind( |
| 675 "Hint: Can't use '#{name}' here because it's an instance of '#{type}' " |
| 676 "and a 'String' or 'List' value is expected.", |
| 677 howToFix: "Did you forget to add quotes?", |
| 678 examples: const [ |
| 679 """ |
| 680 // 'Foo' is not a string. |
| 681 @MirrorsUsed(symbols: Foo) |
| 682 import 'dart:mirrors'; |
| 683 |
| 684 class Foo {} |
| 685 |
| 686 main() {} |
| 687 """]); |
| 688 |
| 689 static const MessageKind MIRRORS_EXPECTED_STRING_TYPE_OR_LIST = |
| 690 const MessageKind( |
| 691 "Hint: Can't use '#{name}' here because it's an instance of '#{type}' " |
| 692 "but a 'String', 'Type', or 'List' value is expected.", |
| 693 howToFix: "Did you forget to add quotes?", |
| 694 examples: const [ |
| 695 """ |
| 696 // '1' is not a string. |
| 697 @MirrorsUsed(targets: 1) |
| 698 import 'dart:mirrors'; |
| 699 |
| 700 main() {} |
| 701 """]); |
| 702 |
| 703 static const MessageKind MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY = |
| 704 const MessageKind( |
| 705 "Hint: Can't find '#{name}' in the current library.", |
| 706 // TODO(ahe): The closest identifiers in edit distance would be nice. |
| 707 howToFix: "Did you forget to add an import?", |
| 708 examples: const [ |
| 709 """ |
| 710 // 'window' is not in scope because dart:html isn't imported. |
| 711 @MirrorsUsed(targets: 'window') |
| 712 import 'dart:mirrors'; |
| 713 |
| 714 main() {} |
| 715 """]); |
| 716 |
| 717 static const MessageKind MIRRORS_CANNOT_RESOLVE_IN_LIBRARY = |
| 718 const MessageKind( |
| 719 "Hint: Can't find '#{name}' in the library '#{library}'.", |
| 720 // TODO(ahe): The closest identifiers in edit distance would be nice. |
| 721 howToFix: "Is '#{name}' spelled right?", |
| 722 examples: const [ |
| 723 """ |
| 724 // 'List' is misspelled. |
| 725 @MirrorsUsed(targets: 'dart.core.Lsit') |
| 726 import 'dart:mirrors'; |
| 727 |
| 728 main() {} |
| 729 """]); |
| 730 |
| 731 static const MessageKind MIRRORS_CANNOT_FIND_IN_ELEMENT = |
| 732 const MessageKind( |
| 733 "Hint: Can't find '#{name}' in '#{element}'.", |
| 734 // TODO(ahe): The closest identifiers in edit distance would be nice. |
| 735 howToFix: "Is '#{name}' spelled right?", |
| 736 examples: const [ |
| 737 """ |
| 738 // 'addAll' is misspelled. |
| 739 @MirrorsUsed(targets: 'dart.core.List.addAl') |
| 740 import 'dart:mirrors'; |
| 741 |
| 742 main() {} |
| 743 """]); |
| 744 |
622 static const MessageKind COMPILER_CRASHED = const MessageKind( | 745 static const MessageKind COMPILER_CRASHED = const MessageKind( |
623 'Error: The compiler crashed when compiling this element.'); | 746 'Error: The compiler crashed when compiling this element.'); |
624 | 747 |
625 static const MessageKind PLEASE_REPORT_THE_CRASH = const MessageKind(''' | 748 static const MessageKind PLEASE_REPORT_THE_CRASH = const MessageKind(''' |
626 The compiler is broken. | 749 The compiler is broken. |
627 | 750 |
628 When compiling the above element, the compiler crashed. It is not | 751 When compiling the above element, the compiler crashed. It is not |
629 possible to tell if this is caused by a problem in your program or | 752 possible to tell if this is caused by a problem in your program or |
630 not. Regardless, the compiler should not crash. | 753 not. Regardless, the compiler should not crash. |
631 | 754 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
729 static const MessageKind PATCH_NON_FUNCTION = const MessageKind( | 852 static const MessageKind PATCH_NON_FUNCTION = const MessageKind( |
730 'Error: Cannot patch non-function with function patch ' | 853 'Error: Cannot patch non-function with function patch ' |
731 '"#{functionName}".'); | 854 '"#{functionName}".'); |
732 | 855 |
733 ////////////////////////////////////////////////////////////////////////////// | 856 ////////////////////////////////////////////////////////////////////////////// |
734 // Patch errors end. | 857 // Patch errors end. |
735 ////////////////////////////////////////////////////////////////////////////// | 858 ////////////////////////////////////////////////////////////////////////////// |
736 | 859 |
737 toString() => template; | 860 toString() => template; |
738 | 861 |
739 Message message([Map arguments = const {}]) { | 862 Message message([Map arguments = const {}, bool terse = false]) { |
740 return new Message(this, arguments); | 863 return new Message(this, arguments, terse); |
741 } | 864 } |
742 | 865 |
743 CompilationError error([Map arguments = const {}]) { | 866 CompilationError error([Map arguments = const {}, bool terse = false]) { |
744 return new CompilationError(this, arguments); | 867 return new CompilationError(this, arguments, terse); |
745 } | 868 } |
746 } | 869 } |
747 | 870 |
748 class DualKind { | 871 class DualKind { |
749 final MessageKind error; | 872 final MessageKind error; |
750 final MessageKind warning; | 873 final MessageKind warning; |
751 | 874 |
752 const DualKind({this.error, this.warning}); | 875 const DualKind({this.error, this.warning}); |
753 } | 876 } |
754 | 877 |
755 class Message { | 878 class Message { |
756 final kind; | 879 final MessageKind kind; |
757 final Map arguments; | 880 final Map arguments; |
| 881 final bool terse; |
758 String message; | 882 String message; |
759 | 883 |
760 Message(this.kind, this.arguments) { | 884 Message(this.kind, this.arguments, this.terse) { |
761 assert(() { computeMessage(); return true; }); | 885 assert(() { computeMessage(); return true; }); |
762 } | 886 } |
763 | 887 |
764 String computeMessage() { | 888 String computeMessage() { |
765 if (message == null) { | 889 if (message == null) { |
766 message = kind.template; | 890 message = kind.template; |
767 arguments.forEach((key, value) { | 891 arguments.forEach((key, value) { |
768 String string = slowToString(value); | 892 String string = slowToString(value); |
769 message = message.replaceAll('#{${key}}', string); | 893 message = message.replaceAll('#{${key}}', string); |
770 }); | 894 }); |
771 assert(invariant( | 895 assert(invariant( |
772 CURRENT_ELEMENT_SPANNABLE, | 896 CURRENT_ELEMENT_SPANNABLE, |
773 !message.contains(new RegExp(r'#\{.+\}')), | 897 !message.contains(new RegExp(r'#\{.+\}')), |
774 message: 'Missing arguments in error message: "$message"')); | 898 message: 'Missing arguments in error message: "$message"')); |
| 899 if (!terse && kind.howToFix != null) { |
| 900 String howToFix = kind.howToFix; |
| 901 arguments.forEach((key, value) { |
| 902 String string = slowToString(value); |
| 903 howToFix = howToFix.replaceAll('#{${key}}', string); |
| 904 }); |
| 905 message = '$message\n$howToFix'; |
| 906 } |
775 } | 907 } |
776 return message; | 908 return message; |
777 } | 909 } |
778 | 910 |
779 String toString() { | 911 String toString() { |
780 return computeMessage(); | 912 return computeMessage(); |
781 } | 913 } |
782 | 914 |
783 bool operator==(other) { | 915 bool operator==(other) { |
784 if (other is !Message) return false; | 916 if (other is !Message) return false; |
785 return (kind == other.kind) && (toString() == other.toString()); | 917 return (kind == other.kind) && (toString() == other.toString()); |
786 } | 918 } |
787 | 919 |
788 int get hashCode => throw new UnsupportedError('Message.hashCode'); | 920 int get hashCode => throw new UnsupportedError('Message.hashCode'); |
789 | 921 |
790 String slowToString(object) { | 922 String slowToString(object) { |
791 if (object is SourceString) { | 923 if (object is SourceString) { |
792 return object.slowToString(); | 924 return object.slowToString(); |
793 } else { | 925 } else { |
794 return object.toString(); | 926 return object.toString(); |
795 } | 927 } |
796 } | 928 } |
797 } | 929 } |
798 | 930 |
799 class Diagnostic { | 931 class Diagnostic { |
800 final Message message; | 932 final Message message; |
801 Diagnostic(MessageKind kind, [Map arguments = const {}]) | 933 Diagnostic(MessageKind kind, Map arguments, bool terse) |
802 : message = new Message(kind, arguments); | 934 : message = new Message(kind, arguments, terse); |
803 String toString() => message.toString(); | 935 String toString() => message.toString(); |
804 } | 936 } |
805 | 937 |
806 class TypeWarning extends Diagnostic { | 938 class TypeWarning extends Diagnostic { |
807 TypeWarning(MessageKind kind, [Map arguments = const {}]) | 939 TypeWarning(MessageKind kind, Map arguments, bool terse) |
808 : super(kind, arguments); | 940 : super(kind, arguments, terse); |
809 } | 941 } |
810 | 942 |
811 class ResolutionWarning extends Diagnostic { | 943 class ResolutionWarning extends Diagnostic { |
812 ResolutionWarning(MessageKind kind, [Map arguments = const {}]) | 944 ResolutionWarning(MessageKind kind, Map arguments, bool terse) |
813 : super(kind, arguments); | 945 : super(kind, arguments, terse); |
814 } | 946 } |
815 | 947 |
816 class CompileTimeConstantError extends Diagnostic { | 948 class CompileTimeConstantError extends Diagnostic { |
817 CompileTimeConstantError(MessageKind kind, [Map arguments = const {}]) | 949 CompileTimeConstantError(MessageKind kind, Map arguments, bool terse) |
818 : super(kind, arguments); | 950 : super(kind, arguments, terse); |
819 } | 951 } |
820 | 952 |
821 class CompilationError extends Diagnostic { | 953 class CompilationError extends Diagnostic { |
822 CompilationError(MessageKind kind, [Map arguments = const {}]) | 954 CompilationError(MessageKind kind, Map arguments, bool terse) |
823 : super(kind, arguments); | 955 : super(kind, arguments, terse); |
824 } | 956 } |
OLD | NEW |