@@ -3,7 +3,6 @@ use std::fs::File;
33use std:: io:: BufReader ;
44use std:: io:: prelude:: * ;
55use std:: path:: Path ;
6- use std:: str:: FromStr ;
76use std:: sync:: OnceLock ;
87
98use regex:: Regex ;
@@ -18,30 +17,42 @@ pub enum ErrorKind {
1817 Warning ,
1918}
2019
21- impl FromStr for ErrorKind {
22- type Err = ( ) ;
23- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
24- let s = s. to_uppercase ( ) ;
25- let part0: & str = s. split ( ':' ) . next ( ) . unwrap ( ) ;
26- match part0 {
27- "HELP" => Ok ( ErrorKind :: Help ) ,
28- "ERROR" => Ok ( ErrorKind :: Error ) ,
29- "NOTE" => Ok ( ErrorKind :: Note ) ,
30- "SUGGESTION" => Ok ( ErrorKind :: Suggestion ) ,
31- "WARN" | "WARNING" => Ok ( ErrorKind :: Warning ) ,
32- _ => Err ( ( ) ) ,
20+ impl ErrorKind {
21+ pub fn from_compiler_str ( s : & str ) -> ErrorKind {
22+ match s {
23+ "help" => ErrorKind :: Help ,
24+ "error" | "error: internal compiler error" => ErrorKind :: Error ,
25+ "note" | "failure-note" => ErrorKind :: Note ,
26+ "warning" => ErrorKind :: Warning ,
27+ _ => panic ! ( "unexpected compiler diagnostic kind `{s}`" ) ,
28+ }
29+ }
30+
31+ fn from_user_str ( s : & str ) -> ErrorKind {
32+ match s {
33+ "HELP" => ErrorKind :: Help ,
34+ "HELP_NONVIRAL" => ErrorKind :: Help ,
35+ "ERROR" => ErrorKind :: Error ,
36+ "NOTE" => ErrorKind :: Note ,
37+ "NOTE_NONVIRAL" => ErrorKind :: Note ,
38+ "SUGGESTION" => ErrorKind :: Suggestion ,
39+ "WARN" | "WARNING" => ErrorKind :: Warning ,
40+ _ => panic ! (
41+ "unexpected diagnostic kind `{s}`, expected \
42+ `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
43+ ) ,
3344 }
3445 }
3546}
3647
3748impl fmt:: Display for ErrorKind {
3849 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
3950 match * self {
40- ErrorKind :: Help => write ! ( f, "help message " ) ,
41- ErrorKind :: Error => write ! ( f, "error " ) ,
42- ErrorKind :: Note => write ! ( f, "note " ) ,
43- ErrorKind :: Suggestion => write ! ( f, "suggestion " ) ,
44- ErrorKind :: Warning => write ! ( f, "warning " ) ,
51+ ErrorKind :: Help => write ! ( f, "HELP " ) ,
52+ ErrorKind :: Error => write ! ( f, "ERROR " ) ,
53+ ErrorKind :: Note => write ! ( f, "NOTE " ) ,
54+ ErrorKind :: Suggestion => write ! ( f, "SUGGESTION " ) ,
55+ ErrorKind :: Warning => write ! ( f, "WARN " ) ,
4556 }
4657 }
4758}
@@ -50,20 +61,21 @@ impl fmt::Display for ErrorKind {
5061pub struct Error {
5162 pub line_num : Option < usize > ,
5263 /// What kind of message we expect (e.g., warning, error, suggestion).
53- /// `None` if not specified or unknown message kind.
54- pub kind : Option < ErrorKind > ,
64+ pub kind : ErrorKind ,
5565 pub msg : String ,
66+ /// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations
67+ /// are not mandatory, even if they would otherwise be mandatory for primary errors.
68+ /// Only makes sense for "found" errors, not for "expected" errors.
69+ pub should_annotate : bool ,
70+ /// A temporary measure to avoid adding too many `NOTE` and `HELP` annotations in #NNNNNN.
71+ /// Only makes sense for "expected" errors, not for "found" errors.
72+ pub viral : bool ,
5673}
5774
5875impl Error {
5976 pub fn render_for_expected ( & self ) -> String {
6077 use colored:: Colorize ;
61- format ! (
62- "{: <10}line {: >3}: {}" ,
63- self . kind. map( |kind| kind. to_string( ) ) . unwrap_or_default( ) . to_uppercase( ) ,
64- self . line_num_str( ) ,
65- self . msg. cyan( ) ,
66- )
78+ format ! ( "{: <10}line {: >3}: {}" , self . kind, self . line_num_str( ) , self . msg. cyan( ) )
6779 }
6880
6981 pub fn line_num_str ( & self ) -> String {
@@ -150,18 +162,13 @@ fn parse_expected(
150162 }
151163
152164 // Get the part of the comment after the sigil (e.g. `~^^` or ~|).
153- let whole_match = captures. get ( 0 ) . unwrap ( ) ;
154- let ( _, mut msg) = line. split_at ( whole_match. end ( ) ) ;
155-
156- let first_word = msg. split_whitespace ( ) . next ( ) . expect ( "Encountered unexpected empty comment" ) ;
157-
158- // If we find `//~ ERROR foo` or something like that, skip the first word.
159- let kind = first_word. parse :: < ErrorKind > ( ) . ok ( ) ;
160- if kind. is_some ( ) {
161- msg = & msg. trim_start ( ) . split_at ( first_word. len ( ) ) . 1 ;
162- }
163-
164- let msg = msg. trim ( ) . to_owned ( ) ;
165+ let tag = captures. get ( 0 ) . unwrap ( ) ;
166+ let rest = line[ tag. end ( ) ..] . trim_start ( ) ;
167+ let ( kind, _) =
168+ rest. split_once ( |c| !unicode_xid:: UnicodeXID :: is_xid_continue ( c) ) . unwrap_or ( ( rest, "" ) ) ;
169+ let msg = rest[ kind. len ( ) ..] . trim ( ) . to_owned ( ) ;
170+ let viral = kind != "NOTE_NONVIRAL" && kind != "HELP_NONVIRAL" ;
171+ let kind = ErrorKind :: from_user_str ( kind) ;
165172
166173 let line_num_adjust = & captures[ "adjust" ] ;
167174 let ( follow_prev, line_num) = if line_num_adjust == "|" {
@@ -177,12 +184,12 @@ fn parse_expected(
177184 debug ! (
178185 "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}" ,
179186 line_num,
180- whole_match . as_str( ) ,
187+ tag . as_str( ) ,
181188 follow_prev,
182189 kind,
183190 msg
184191 ) ;
185- Some ( ( follow_prev, Error { line_num, kind, msg } ) )
192+ Some ( ( follow_prev, Error { line_num, kind, msg, should_annotate : true , viral } ) )
186193}
187194
188195#[ cfg( test) ]
0 commit comments