diff --git a/src/errors.rs b/src/errors.rs index c3da891..474f0e0 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -61,6 +61,10 @@ pub struct Error { /// `None` if not specified or unknown message kind. pub kind: Option, pub msg: String, + /// We can expect a specific number of sub-spans. + /// This count is used only for expected errors. + /// `None` when multiple actual messages on the same line should be treated as one. + pub count: Option, } #[derive(PartialEq, Debug)] @@ -124,24 +128,38 @@ fn parse_expected(last_nonfollow_error: Option, (false, line[start + tag.len()..].chars().take_while(|c| *c == '^').count()) }; let kind_start = start + tag.len() + adjusts + (follow as usize); - let (kind, msg); - match - line[kind_start..].split_whitespace() - .next() - .expect("Encountered unexpected empty comment") - .parse::() - { + let (kind, msg, count); + let kind_str = line[kind_start..].trim_left() + .chars() + .take_while(|c| !c.is_whitespace() && *c != '*') + .collect::(); + match kind_str.parse::() { Ok(k) => { - // If we find `//~ ERROR foo` or something like that: + // If we find `//~ ERROR foo` or `//~ ERROR*9 foo` something like that: kind = Some(k); - let letters = line[kind_start..].chars(); - msg = letters.skip_while(|c| c.is_whitespace()) - .skip_while(|c| !c.is_whitespace()) - .collect::(); + let rest = line[kind_start..].trim_left() + .chars() + .skip_while(|c| !c.is_whitespace() && *c != '*') + .collect::(); + if rest.starts_with('*') { + // We found `//~ ERROR*9 foo` + let count_str = rest.chars().skip(1) + .take_while(|c| c.is_digit(10)) + .collect::(); + count = Some(count_str.parse::().expect("Incorrect message count")); + msg = rest.chars().skip(1) + .skip_while(|c| c.is_digit(10)) + .collect::(); + } else { + // We found `//~ ERROR foo` + count = None; + msg = rest; + } } Err(_) => { // Otherwise we found `//~ foo`: kind = None; + count = None; let letters = line[kind_start..].chars(); msg = letters.skip_while(|c| c.is_whitespace()) .collect::(); @@ -163,7 +181,12 @@ fn parse_expected(last_nonfollow_error: Option, debug!("line={} tag={:?} which={:?} kind={:?} msg={:?}", line_num, tag, which, kind, msg); - Some((which, Error { line_num: line_num, - kind: kind, - msg: msg, })) + Some((which, + Error { + line_num: line_num, + kind: kind, + msg: msg, + count: count, + } + )) } diff --git a/src/json.rs b/src/json.rs index 84b7854..fda6c1d 100644 --- a/src/json.rs +++ b/src/json.rs @@ -149,6 +149,7 @@ fn push_expected_errors(expected_errors: &mut Vec, line_num: span.line_start, kind: kind, msg: msg, + count: None, } ); } @@ -160,6 +161,7 @@ fn push_expected_errors(expected_errors: &mut Vec, line_num: span.line_start, kind: None, msg: with_code(span, next_line), + count: None, } ); } @@ -174,7 +176,8 @@ fn push_expected_errors(expected_errors: &mut Vec, Error { line_num: start_line + index, kind: Some(ErrorKind::Suggestion), - msg: line.to_string() + msg: line.to_string(), + count: None, } ); } @@ -196,7 +199,8 @@ fn push_expected_errors(expected_errors: &mut Vec, expected_errors.push(Error { line_num: span.line_start, kind: Some(ErrorKind::Note), - msg: span.label.clone().unwrap() + msg: span.label.clone().unwrap(), + count: None, }); } @@ -215,6 +219,7 @@ fn push_backtrace(expected_errors: &mut Vec, line_num: expansion.span.line_start, kind: Some(ErrorKind::Note), msg: format!("in this expansion of {}", expansion.macro_decl_name), + count: None, } ); } diff --git a/src/runtest.rs b/src/runtest.rs index 42edbd4..9827b7f 100644 --- a/src/runtest.rs +++ b/src/runtest.rs @@ -1015,13 +1015,14 @@ actual:\n\ let mut unexpected = 0; let mut not_found = 0; let mut found = vec![false; expected_errors.len()]; + let mut counts_expected = expected_errors.iter().map(|ee| ee.count).collect::>(); for actual_error in &actual_errors { let opt_index = expected_errors .iter() .enumerate() .position(|(index, expected_error)| { - !found[index] && + counts_expected[index] != Some(0) && actual_error.line_num == expected_error.line_num && (expected_error.kind.is_none() || actual_error.kind == expected_error.kind) && @@ -1031,8 +1032,11 @@ actual:\n\ match opt_index { Some(index) => { // found a match, everybody is happy - assert!(!found[index]); found[index] = true; + if let &mut Some(ref mut count) = &mut counts_expected[index] { + assert!(*count != 0); + *count -= 1; + } } None => { @@ -1053,7 +1057,8 @@ actual:\n\ // anything not yet found is a problem for (index, expected_error) in expected_errors.iter().enumerate() { - if !found[index] { + let count_is_good = counts_expected[index] == None || counts_expected[index] == Some(0); + if !found[index] || !count_is_good { self.error( &format!("{}:{}: expected {} not found: {}", file_name, diff --git a/test-project/tests/compile-fail/multiple-errors.rs b/test-project/tests/compile-fail/multiple-errors.rs index ce11277..8748741 100644 --- a/test-project/tests/compile-fail/multiple-errors.rs +++ b/test-project/tests/compile-fail/multiple-errors.rs @@ -1,5 +1,9 @@ -fn main() { - let x: (u64, bool) = (true, 42u64); +fn foo() { + let x: (u64, bool, bool) = (true, 42u64, 666u64); //~^ ERROR mismatched types - //~^^ ERROR mismatched types +} + +fn bar() { + let x: (u64, bool) = (true, 42u64); + //~^ ERROR*2 mismatched types }