Skip to content

Commit 872124e

Browse files
authored
Unrolled build for #140622
Rollup merge of #140622 - petrochenkov:annusexp, r=jieyouxu compiletest: Improve diagnostics for line annotation mismatches When some line annotations are missing or misplaced, compiletest reports an error, but the error is not very convenient. This PR attempts to improve the user experience. - The "expected ... not found" messages are no longer duplicated. - The `proc_res.status` and `proc_res.cmdline` message is no longer put in the middle of other messages describing the annotation mismatches, it's now put into the end. - Compiletest now makes suggestions if there are fuzzy matches between expected and actually reported errors (e.g. the annotation is put on a wrong line). - Missing diagnostic kinds are no longer produce an error eagerly, but instead treated as always mismatching kinds, so they can produce suggestions telling the right kind. I'll post screenshots in the thread below, but the behavior shown on the screenshots can be reproduced locally using the new test `tests/ui/compiletest-self-test/line-annotation-mismatches.rs`. This also fixes #140940. r? ``@jieyouxu``
2 parents e4b9d01 + 7a4f09c commit 872124e

25 files changed

+297
-111
lines changed

src/tools/compiletest/src/errors.rs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pub enum ErrorKind {
1616
Suggestion,
1717
Warning,
1818
Raw,
19+
/// Used for better recovery and diagnostics in compiletest.
20+
Unknown,
1921
}
2022

2123
impl ErrorKind {
@@ -31,21 +33,25 @@ impl ErrorKind {
3133

3234
/// Either the canonical uppercase string, or some additional versions for compatibility.
3335
/// FIXME: consider keeping only the canonical versions here.
34-
pub fn from_user_str(s: &str) -> ErrorKind {
35-
match s {
36+
fn from_user_str(s: &str) -> Option<ErrorKind> {
37+
Some(match s {
3638
"HELP" | "help" => ErrorKind::Help,
3739
"ERROR" | "error" => ErrorKind::Error,
38-
// `MONO_ITEM` makes annotations in `codegen-units` tests syntactically correct,
39-
// but those tests never use the error kind later on.
40-
"NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note,
40+
"NOTE" | "note" => ErrorKind::Note,
4141
"SUGGESTION" => ErrorKind::Suggestion,
4242
"WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
4343
"RAW" => ErrorKind::Raw,
44-
_ => panic!(
44+
_ => return None,
45+
})
46+
}
47+
48+
pub fn expect_from_user_str(s: &str) -> ErrorKind {
49+
ErrorKind::from_user_str(s).unwrap_or_else(|| {
50+
panic!(
4551
"unexpected diagnostic kind `{s}`, expected \
46-
`ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
47-
),
48-
}
52+
`ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` or `RAW`"
53+
)
54+
})
4955
}
5056
}
5157

@@ -58,13 +64,15 @@ impl fmt::Display for ErrorKind {
5864
ErrorKind::Suggestion => write!(f, "SUGGESTION"),
5965
ErrorKind::Warning => write!(f, "WARN"),
6066
ErrorKind::Raw => write!(f, "RAW"),
67+
ErrorKind::Unknown => write!(f, "UNKNOWN"),
6168
}
6269
}
6370
}
6471

6572
#[derive(Debug)]
6673
pub struct Error {
6774
pub line_num: Option<usize>,
75+
pub column_num: Option<usize>,
6876
/// What kind of message we expect (e.g., warning, error, suggestion).
6977
pub kind: ErrorKind,
7078
pub msg: String,
@@ -74,17 +82,6 @@ pub struct Error {
7482
pub require_annotation: bool,
7583
}
7684

77-
impl Error {
78-
pub fn render_for_expected(&self) -> String {
79-
use colored::Colorize;
80-
format!("{: <10}line {: >3}: {}", self.kind, self.line_num_str(), self.msg.cyan())
81-
}
82-
83-
pub fn line_num_str(&self) -> String {
84-
self.line_num.map_or("?".to_string(), |line_num| line_num.to_string())
85-
}
86-
}
87-
8885
/// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
8986
/// The former is a "follow" that inherits its target from the preceding line;
9087
/// the latter is an "adjusts" that goes that many lines up.
@@ -168,8 +165,10 @@ fn parse_expected(
168165
let rest = line[tag.end()..].trim_start();
169166
let (kind_str, _) =
170167
rest.split_once(|c: char| c != '_' && !c.is_ascii_alphabetic()).unwrap_or((rest, ""));
171-
let kind = ErrorKind::from_user_str(kind_str);
172-
let untrimmed_msg = &rest[kind_str.len()..];
168+
let (kind, untrimmed_msg) = match ErrorKind::from_user_str(kind_str) {
169+
Some(kind) => (kind, &rest[kind_str.len()..]),
170+
None => (ErrorKind::Unknown, rest),
171+
};
173172
let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned();
174173

175174
let line_num_adjust = &captures["adjust"];
@@ -182,6 +181,7 @@ fn parse_expected(
182181
} else {
183182
(false, Some(line_num - line_num_adjust.len()))
184183
};
184+
let column_num = Some(tag.start() + 1);
185185

186186
debug!(
187187
"line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
@@ -191,7 +191,7 @@ fn parse_expected(
191191
kind,
192192
msg
193193
);
194-
Some((follow_prev, Error { line_num, kind, msg, require_annotation: true }))
194+
Some((follow_prev, Error { line_num, column_num, kind, msg, require_annotation: true }))
195195
}
196196

197197
#[cfg(test)]

src/tools/compiletest/src/header.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ impl TestProps {
593593
config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
594594
{
595595
self.dont_require_annotations
596-
.insert(ErrorKind::from_user_str(err_kind.trim()));
596+
.insert(ErrorKind::expect_from_user_str(err_kind.trim()));
597597
}
598598
},
599599
);

src/tools/compiletest/src/json.rs

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ struct UnusedExternNotification {
3636
struct DiagnosticSpan {
3737
file_name: String,
3838
line_start: usize,
39-
line_end: usize,
4039
column_start: usize,
41-
column_end: usize,
4240
is_primary: bool,
4341
label: Option<String>,
4442
suggested_replacement: Option<String>,
@@ -148,6 +146,7 @@ pub fn parse_output(file_name: &str, output: &str) -> Vec<Error> {
148146
Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
149147
Err(_) => errors.push(Error {
150148
line_num: None,
149+
column_num: None,
151150
kind: ErrorKind::Raw,
152151
msg: line.to_string(),
153152
require_annotation: false,
@@ -193,25 +192,9 @@ fn push_actual_errors(
193192
// also ensure that `//~ ERROR E123` *always* works. The
194193
// assumption is that these multi-line error messages are on their
195194
// way out anyhow.
196-
let with_code = |span: Option<&DiagnosticSpan>, text: &str| {
197-
// FIXME(#33000) -- it'd be better to use a dedicated
198-
// UI harness than to include the line/col number like
199-
// this, but some current tests rely on it.
200-
//
201-
// Note: Do NOT include the filename. These can easily
202-
// cause false matches where the expected message
203-
// appears in the filename, and hence the message
204-
// changes but the test still passes.
205-
let span_str = match span {
206-
Some(DiagnosticSpan { line_start, column_start, line_end, column_end, .. }) => {
207-
format!("{line_start}:{column_start}: {line_end}:{column_end}")
208-
}
209-
None => format!("?:?: ?:?"),
210-
};
211-
match &diagnostic.code {
212-
Some(code) => format!("{span_str}: {text} [{}]", code.code),
213-
None => format!("{span_str}: {text}"),
214-
}
195+
let with_code = |text| match &diagnostic.code {
196+
Some(code) => format!("{text} [{}]", code.code),
197+
None => format!("{text}"),
215198
};
216199

217200
// Convert multi-line messages into multiple errors.
@@ -225,17 +208,19 @@ fn push_actual_errors(
225208
|| Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap();
226209
errors.push(Error {
227210
line_num: None,
211+
column_num: None,
228212
kind,
229-
msg: with_code(None, first_line),
213+
msg: with_code(first_line),
230214
require_annotation: diagnostic.level != "failure-note"
231215
&& !RE.get_or_init(re_init).is_match(first_line),
232216
});
233217
} else {
234218
for span in primary_spans {
235219
errors.push(Error {
236220
line_num: Some(span.line_start),
221+
column_num: Some(span.column_start),
237222
kind,
238-
msg: with_code(Some(span), first_line),
223+
msg: with_code(first_line),
239224
require_annotation: true,
240225
});
241226
}
@@ -244,16 +229,18 @@ fn push_actual_errors(
244229
if primary_spans.is_empty() {
245230
errors.push(Error {
246231
line_num: None,
232+
column_num: None,
247233
kind,
248-
msg: with_code(None, next_line),
234+
msg: with_code(next_line),
249235
require_annotation: false,
250236
});
251237
} else {
252238
for span in primary_spans {
253239
errors.push(Error {
254240
line_num: Some(span.line_start),
241+
column_num: Some(span.column_start),
255242
kind,
256-
msg: with_code(Some(span), next_line),
243+
msg: with_code(next_line),
257244
require_annotation: false,
258245
});
259246
}
@@ -266,6 +253,7 @@ fn push_actual_errors(
266253
for (index, line) in suggested_replacement.lines().enumerate() {
267254
errors.push(Error {
268255
line_num: Some(span.line_start + index),
256+
column_num: Some(span.column_start),
269257
kind: ErrorKind::Suggestion,
270258
msg: line.to_string(),
271259
// Empty suggestions (suggestions to remove something) are common
@@ -288,6 +276,7 @@ fn push_actual_errors(
288276
if let Some(label) = &span.label {
289277
errors.push(Error {
290278
line_num: Some(span.line_start),
279+
column_num: Some(span.column_start),
291280
kind: ErrorKind::Note,
292281
msg: label.clone(),
293282
// Empty labels (only underlining spans) are common and do not need annotations.
@@ -310,6 +299,7 @@ fn push_backtrace(
310299
if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
311300
errors.push(Error {
312301
line_num: Some(expansion.span.line_start),
302+
column_num: Some(expansion.span.column_start),
313303
kind: ErrorKind::Note,
314304
msg: format!("in this expansion of {}", expansion.macro_decl_name),
315305
require_annotation: true,

0 commit comments

Comments
 (0)