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 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
609 static const MessageKind IMPORTED_HERE = const MessageKind( | 633 static const MessageKind IMPORTED_HERE = const MessageKind( |
610 'Info: "#{element}" is imported here.'); | 634 'Info: "#{element}" is imported here.'); |
611 | 635 |
612 static const MessageKind OVERRIDE_EQUALS_NOT_HASH_CODE = const MessageKind( | 636 static const MessageKind OVERRIDE_EQUALS_NOT_HASH_CODE = const MessageKind( |
613 'Hint: The class "#{class}" overrides "operator==", ' | 637 'Hint: The class "#{class}" overrides "operator==", ' |
614 'but not "get hashCode".'); | 638 'but not "get hashCode".'); |
615 | 639 |
616 static const MessageKind PACKAGE_ROOT_NOT_SET = const MessageKind( | 640 static const MessageKind PACKAGE_ROOT_NOT_SET = const MessageKind( |
617 'Error: Cannot resolve "#{uri}". Package root has not been set.'); | 641 'Error: Cannot resolve "#{uri}". Package root has not been set.'); |
618 | 642 |
643 static const MessageKind MIRRORS_EXPECTED_STRING = const MessageKind( | |
644 "Hint: Can't use '#{name}' here because it's an instance of '#{type}' " | |
645 "and a 'String' value is expected.", | |
646 howToFix: "Did you forget to add quotes?", | |
647 examples: const [ | |
648 """ | |
649 // 'main' is a method, not a class. | |
650 @MirrorsUsed(symbols: const [Foo]) | |
651 import 'dart:mirrors'; | |
652 | |
653 class Foo {} | |
654 | |
655 main() {} | |
656 """]); | |
657 | |
658 static const MessageKind MIRRORS_EXPECTED_STRING_OR_TYPE = const MessageKind( | |
659 "Hint: Can't use '#{name}' here because it's an instance of '#{type}' " | |
660 "and a 'String' or 'Type' value is expected.", | |
661 howToFix: "Did you forget to add quotes?", | |
662 examples: const [ | |
663 """ | |
664 // 'main' is a method, not a class. | |
665 @MirrorsUsed(targets: const [main]) | |
666 import 'dart:mirrors'; | |
667 | |
668 main() {} | |
669 """]); | |
670 | |
671 static const MessageKind MIRRORS_EXPECTED_STRING_OR_LIST = const MessageKind( | |
672 "Hint: Can't use '#{name}' here because it's an instance of '#{type}' " | |
673 "and a 'String' or 'List' value is expected.", | |
674 howToFix: "Did you forget to add quotes?", | |
675 examples: const [ | |
676 """ | |
677 // 'Foo' is not a string. | |
678 @MirrorsUsed(symbols: Foo) | |
679 import 'dart:mirrors'; | |
680 | |
681 class Foo {} | |
682 | |
683 main() {} | |
684 """]); | |
685 | |
686 static const MessageKind MIRRORS_EXPECTED_STRING_TYPE_OR_LIST = | |
687 const MessageKind( | |
688 "Hint: Can't use '#{name}' here because it's an instance of '#{type}' " | |
689 "but a 'String', 'Type', or 'List' value is expected.", | |
690 howToFix: "Did you forget to add quotes?", | |
691 examples: const [ | |
692 """ | |
693 // '1' is not a string. | |
694 @MirrorsUsed(targets: 1) | |
695 import 'dart:mirrors'; | |
696 | |
697 main() {} | |
698 """]); | |
699 | |
700 static const MessageKind MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY = | |
701 const MessageKind( | |
702 "Hint: Can't find '#{name}' in the current library.", | |
703 howToFix: "Did you forget to add an import?", | |
704 examples: const [ | |
705 """ | |
706 // 'window' is not in scope because dart:html isn't imported. | |
707 @MirrorsUsed(targets: 'window') | |
708 import 'dart:mirrors'; | |
709 | |
710 main() {} | |
711 """]); | |
712 | |
713 static const MessageKind MIRRORS_CANNOT_RESOLVE_IN_LIBRARY = | |
714 const MessageKind( | |
715 "Hint: Can't find '#{name}' in the library '#{library}'.", | |
716 howToFix: "Did you check the spelling of '#{name}'?", | |
Johnni Winther
2013/08/07 10:39:17
Strange question to ask (they probably _forgot_ to
karlklose
2013/08/07 10:48:11
It would be much more useful if we could find the
ahe
2013/08/07 13:40:20
I agree with Karl, but I don't have the next close
| |
717 examples: const [ | |
718 """ | |
719 // 'List' is misspelled. | |
720 @MirrorsUsed(targets: 'dart.core.Lsit') | |
721 import 'dart:mirrors'; | |
722 | |
723 main() {} | |
724 """]); | |
725 | |
726 static const MessageKind MIRRORS_CANNOT_FIND_IN_ELEMENT = | |
727 const MessageKind( | |
728 "Hint: Can't find '#{name}' in '#{element}'.", | |
729 howToFix: "Did you check the spelling of '#{name}'?", | |
Johnni Winther
2013/08/07 10:39:17
Ditto.
| |
730 examples: const [ | |
731 """ | |
732 // 'addAll' is misspelled. | |
733 @MirrorsUsed(targets: 'dart.core.List.addAl') | |
734 import 'dart:mirrors'; | |
735 | |
736 main() {} | |
737 """]); | |
738 | |
619 static const MessageKind COMPILER_CRASHED = const MessageKind( | 739 static const MessageKind COMPILER_CRASHED = const MessageKind( |
620 'Error: The compiler crashed when compiling this element.'); | 740 'Error: The compiler crashed when compiling this element.'); |
621 | 741 |
622 static const MessageKind PLEASE_REPORT_THE_CRASH = const MessageKind(''' | 742 static const MessageKind PLEASE_REPORT_THE_CRASH = const MessageKind(''' |
623 The compiler is broken. | 743 The compiler is broken. |
624 | 744 |
625 When compiling the above element, the compiler crashed. It is not | 745 When compiling the above element, the compiler crashed. It is not |
626 possible to tell if this is caused by a problem in your program or | 746 possible to tell if this is caused by a problem in your program or |
627 not. Regardless, the compiler should not crash. | 747 not. Regardless, the compiler should not crash. |
628 | 748 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
726 static const MessageKind PATCH_NON_FUNCTION = const MessageKind( | 846 static const MessageKind PATCH_NON_FUNCTION = const MessageKind( |
727 'Error: Cannot patch non-function with function patch ' | 847 'Error: Cannot patch non-function with function patch ' |
728 '"#{functionName}".'); | 848 '"#{functionName}".'); |
729 | 849 |
730 ////////////////////////////////////////////////////////////////////////////// | 850 ////////////////////////////////////////////////////////////////////////////// |
731 // Patch errors end. | 851 // Patch errors end. |
732 ////////////////////////////////////////////////////////////////////////////// | 852 ////////////////////////////////////////////////////////////////////////////// |
733 | 853 |
734 toString() => template; | 854 toString() => template; |
735 | 855 |
736 Message message([Map arguments = const {}]) { | 856 Message message([Map arguments = const {}, bool terse = false]) { |
737 return new Message(this, arguments); | 857 return new Message(this, arguments, terse); |
738 } | 858 } |
739 | 859 |
740 CompilationError error([Map arguments = const {}]) { | 860 CompilationError error([Map arguments = const {}, bool terse = false]) { |
741 return new CompilationError(this, arguments); | 861 return new CompilationError(this, arguments, terse); |
742 } | 862 } |
743 } | 863 } |
744 | 864 |
745 class DualKind { | 865 class DualKind { |
746 final MessageKind error; | 866 final MessageKind error; |
747 final MessageKind warning; | 867 final MessageKind warning; |
748 | 868 |
749 const DualKind({this.error, this.warning}); | 869 const DualKind({this.error, this.warning}); |
750 } | 870 } |
751 | 871 |
752 class Message { | 872 class Message { |
753 final kind; | 873 final MessageKind kind; |
754 final Map arguments; | 874 final Map arguments; |
875 final bool terse; | |
755 String message; | 876 String message; |
756 | 877 |
757 Message(this.kind, this.arguments) { | 878 Message(this.kind, this.arguments, this.terse) { |
758 assert(() { computeMessage(); return true; }); | 879 assert(() { computeMessage(); return true; }); |
759 } | 880 } |
760 | 881 |
761 String computeMessage() { | 882 String computeMessage() { |
762 if (message == null) { | 883 if (message == null) { |
763 message = kind.template; | 884 message = kind.template; |
764 arguments.forEach((key, value) { | 885 arguments.forEach((key, value) { |
765 String string = slowToString(value); | 886 String string = slowToString(value); |
766 message = message.replaceAll('#{${key}}', string); | 887 message = message.replaceAll('#{${key}}', string); |
767 }); | 888 }); |
768 assert(invariant( | 889 assert(invariant( |
769 CURRENT_ELEMENT_SPANNABLE, | 890 CURRENT_ELEMENT_SPANNABLE, |
770 !message.contains(new RegExp(r'#\{.+\}')), | 891 !message.contains(new RegExp(r'#\{.+\}')), |
771 message: 'Missing arguments in error message: "$message"')); | 892 message: 'Missing arguments in error message: "$message"')); |
893 if (!terse && kind.howToFix != null) { | |
894 String howToFix = kind.howToFix; | |
895 arguments.forEach((key, value) { | |
896 String string = slowToString(value); | |
897 howToFix = howToFix.replaceAll('#{${key}}', string); | |
898 }); | |
899 message = '$message\n$howToFix'; | |
900 } | |
772 } | 901 } |
773 return message; | 902 return message; |
774 } | 903 } |
775 | 904 |
776 String toString() { | 905 String toString() { |
777 return computeMessage(); | 906 return computeMessage(); |
778 } | 907 } |
779 | 908 |
780 bool operator==(other) { | 909 bool operator==(other) { |
781 if (other is !Message) return false; | 910 if (other is !Message) return false; |
782 return (kind == other.kind) && (toString() == other.toString()); | 911 return (kind == other.kind) && (toString() == other.toString()); |
783 } | 912 } |
784 | 913 |
785 int get hashCode => throw new UnsupportedError('Message.hashCode'); | 914 int get hashCode => throw new UnsupportedError('Message.hashCode'); |
786 | 915 |
787 String slowToString(object) { | 916 String slowToString(object) { |
788 if (object is SourceString) { | 917 if (object is SourceString) { |
789 return object.slowToString(); | 918 return object.slowToString(); |
790 } else { | 919 } else { |
791 return object.toString(); | 920 return object.toString(); |
792 } | 921 } |
793 } | 922 } |
794 } | 923 } |
795 | 924 |
796 class Diagnostic { | 925 class Diagnostic { |
797 final Message message; | 926 final Message message; |
798 Diagnostic(MessageKind kind, [Map arguments = const {}]) | 927 Diagnostic(MessageKind kind, Map arguments, bool terse) |
799 : message = new Message(kind, arguments); | 928 : message = new Message(kind, arguments, terse); |
800 String toString() => message.toString(); | 929 String toString() => message.toString(); |
801 } | 930 } |
802 | 931 |
803 class TypeWarning extends Diagnostic { | 932 class TypeWarning extends Diagnostic { |
804 TypeWarning(MessageKind kind, [Map arguments = const {}]) | 933 TypeWarning(MessageKind kind, Map arguments, bool terse) |
805 : super(kind, arguments); | 934 : super(kind, arguments, terse); |
806 } | 935 } |
807 | 936 |
808 class ResolutionWarning extends Diagnostic { | 937 class ResolutionWarning extends Diagnostic { |
809 ResolutionWarning(MessageKind kind, [Map arguments = const {}]) | 938 ResolutionWarning(MessageKind kind, Map arguments, bool terse) |
810 : super(kind, arguments); | 939 : super(kind, arguments, terse); |
811 } | 940 } |
812 | 941 |
813 class CompileTimeConstantError extends Diagnostic { | 942 class CompileTimeConstantError extends Diagnostic { |
814 CompileTimeConstantError(MessageKind kind, [Map arguments = const {}]) | 943 CompileTimeConstantError(MessageKind kind, Map arguments, bool terse) |
815 : super(kind, arguments); | 944 : super(kind, arguments, terse); |
816 } | 945 } |
817 | 946 |
818 class CompilationError extends Diagnostic { | 947 class CompilationError extends Diagnostic { |
819 CompilationError(MessageKind kind, [Map arguments = const {}]) | 948 CompilationError(MessageKind kind, Map arguments, bool terse) |
820 : super(kind, arguments); | 949 : super(kind, arguments, terse); |
821 } | 950 } |
OLD | NEW |