Chromium Code Reviews| 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 |