Skip to content

Commit f22f55d

Browse files
committed
[PoC] Make NOTE less viral
1 parent 23a4bcc commit f22f55d

File tree

3 files changed

+73
-30
lines changed

3 files changed

+73
-30
lines changed

src/tools/compiletest/src/errors.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub struct Error {
7070
/// A temporary measure to avoid adding too many `NOTE` and `HELP` annotations in #NNNNNN.
7171
/// Only makes sense for "expected" errors, not for "found" errors.
7272
pub viral: bool,
73+
pub parent: Option<usize>,
7374
}
7475

7576
impl Error {
@@ -189,7 +190,7 @@ fn parse_expected(
189190
kind,
190191
msg
191192
);
192-
Some((follow_prev, Error { line_num, kind, msg, should_annotate: true, viral }))
193+
Some((follow_prev, Error { line_num, kind, msg, should_annotate: true, viral, parent: None }))
193194
}
194195

195196
#[cfg(test)]

src/tools/compiletest/src/json.rs

+33-13
Original file line numberDiff line numberDiff line change
@@ -141,25 +141,31 @@ pub fn extract_rendered(output: &str) -> String {
141141
}
142142

143143
pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
144-
output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
144+
let mut expected_errors = vec![];
145+
for line in output.lines() {
146+
parse_line(&mut expected_errors, file_name, line, output, proc_res);
147+
}
148+
expected_errors
145149
}
146150

147-
fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
151+
fn parse_line(
152+
expected_errors: &mut Vec<Error>,
153+
file_name: &str,
154+
line: &str,
155+
output: &str,
156+
proc_res: &ProcRes,
157+
) {
148158
// The compiler sometimes intermingles non-JSON stuff into the
149159
// output. This hack just skips over such lines. Yuck.
150160
if line.starts_with('{') {
151161
match serde_json::from_str::<Diagnostic>(line) {
152162
Ok(diagnostic) => {
153-
let mut expected_errors = vec![];
154-
push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
155-
expected_errors
163+
push_expected_errors(expected_errors, &diagnostic, &[], file_name, None)
156164
}
157165
Err(error) => {
158166
// Ignore the future compat report message - this is handled
159167
// by `extract_rendered`
160-
if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
161-
vec![]
162-
} else {
168+
if !serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
163169
proc_res.fatal(
164170
Some(&format!(
165171
"failed to decode compiler output as json: \
@@ -171,8 +177,6 @@ fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) ->
171177
}
172178
}
173179
}
174-
} else {
175-
vec![]
176180
}
177181
}
178182

@@ -181,6 +185,7 @@ fn push_expected_errors(
181185
diagnostic: &Diagnostic,
182186
default_spans: &[&DiagnosticSpan],
183187
file_name: &str,
188+
prev_parent: Option<usize>,
184189
) {
185190
// In case of macro expansions, we need to get the span of the callsite
186191
let spans_info_in_this_file: Vec<_> = diagnostic
@@ -240,6 +245,7 @@ fn push_expected_errors(
240245
// more structured shortly anyhow.
241246
let kind = ErrorKind::from_compiler_str(&diagnostic.level);
242247
let mut message_lines = diagnostic.message.lines();
248+
let mut parent = None;
243249
if let Some(first_line) = message_lines.next() {
244250
let ignore = |s| {
245251
static RE: OnceLock<Regex> = OnceLock::new();
@@ -250,21 +256,29 @@ fn push_expected_errors(
250256
};
251257

252258
if primary_spans.is_empty() && !ignore(first_line) {
259+
if parent.is_none() {
260+
parent = Some(expected_errors.len());
261+
}
253262
expected_errors.push(Error {
254263
line_num: None,
255264
kind,
256265
msg: with_code(None, first_line),
257266
should_annotate: diagnostic.level != "failure-note",
258267
viral: true,
268+
parent: prev_parent,
259269
});
260270
} else {
261271
for span in primary_spans {
272+
if parent.is_none() {
273+
parent = Some(expected_errors.len());
274+
}
262275
expected_errors.push(Error {
263276
line_num: Some(span.line_start),
264277
kind,
265278
msg: with_code(Some(span), first_line),
266279
should_annotate: diagnostic.level != "failure-note",
267280
viral: true,
281+
parent: prev_parent,
268282
});
269283
}
270284
}
@@ -277,6 +291,7 @@ fn push_expected_errors(
277291
msg: with_code(None, next_line),
278292
should_annotate: false,
279293
viral: true,
294+
parent: prev_parent,
280295
});
281296
} else {
282297
for span in primary_spans {
@@ -286,6 +301,7 @@ fn push_expected_errors(
286301
msg: with_code(Some(span), next_line),
287302
should_annotate: false,
288303
viral: true,
304+
parent: prev_parent,
289305
});
290306
}
291307
}
@@ -301,6 +317,7 @@ fn push_expected_errors(
301317
msg: line.to_string(),
302318
should_annotate: true,
303319
viral: true,
320+
parent,
304321
});
305322
}
306323
}
@@ -309,7 +326,7 @@ fn push_expected_errors(
309326
// Add notes for the backtrace
310327
for span in primary_spans {
311328
if let Some(frame) = &span.expansion {
312-
push_backtrace(expected_errors, frame, file_name);
329+
push_backtrace(expected_errors, frame, file_name, parent);
313330
}
314331
}
315332

@@ -321,19 +338,21 @@ fn push_expected_errors(
321338
msg: span.label.clone().unwrap(),
322339
should_annotate: true,
323340
viral: true,
341+
parent,
324342
});
325343
}
326344

327345
// Flatten out the children.
328346
for child in &diagnostic.children {
329-
push_expected_errors(expected_errors, child, primary_spans, file_name);
347+
push_expected_errors(expected_errors, child, primary_spans, file_name, parent);
330348
}
331349
}
332350

333351
fn push_backtrace(
334352
expected_errors: &mut Vec<Error>,
335353
expansion: &DiagnosticSpanMacroExpansion,
336354
file_name: &str,
355+
parent: Option<usize>,
337356
) {
338357
if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
339358
expected_errors.push(Error {
@@ -342,10 +361,11 @@ fn push_backtrace(
342361
msg: format!("in this expansion of {}", expansion.macro_decl_name),
343362
should_annotate: true,
344363
viral: true,
364+
parent,
345365
});
346366
}
347367

348368
if let Some(previous_expansion) = &expansion.span.expansion {
349-
push_backtrace(expected_errors, previous_expansion, file_name);
369+
push_backtrace(expected_errors, previous_expansion, file_name, parent);
350370
}
351371
}

src/tools/compiletest/src/runtest.rs

+38-16
Original file line numberDiff line numberDiff line change
@@ -713,13 +713,16 @@ impl<'test> TestCx<'test> {
713713
// Otherwise, all "help" messages reported by the compiler will be ignored.
714714
// This logic also applies to "note" messages.
715715
let expect_help = expected_errors.iter().any(|ee| ee.kind == ErrorKind::Help && ee.viral);
716-
let expect_note = expected_errors.iter().any(|ee| ee.kind == ErrorKind::Note && ee.viral);
716+
// let expect_note = expected_errors.iter().any(|ee| ee.kind == ErrorKind::Note && ee.viral);
717717

718718
// Parse the JSON output from the compiler and extract out the messages.
719-
let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
719+
let mut actual_errors =
720+
json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
720721
let mut unexpected = Vec::new();
721722
let mut found = vec![false; expected_errors.len()];
722-
for mut actual_error in actual_errors {
723+
let mut unexpected_actual_indices = Vec::new();
724+
let mut poisoned_parents = HashSet::new();
725+
for (actual_index, actual_error) in actual_errors.iter_mut().enumerate() {
723726
actual_error.msg = self.normalize_output(&actual_error.msg, &[]);
724727

725728
let opt_index =
@@ -735,22 +738,41 @@ impl<'test> TestCx<'test> {
735738
// found a match, everybody is happy
736739
assert!(!found[index]);
737740
found[index] = true;
738-
}
739741

740-
None => {
741-
// If the test is a known bug, don't require that the error is annotated
742-
if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note)
743-
{
744-
self.error(&format!(
745-
"{}:{}: unexpected {}: '{}'",
746-
file_name,
747-
actual_error.line_num_str(),
748-
actual_error.kind,
749-
actual_error.msg
750-
));
751-
unexpected.push(actual_error);
742+
if actual_error.kind == ErrorKind::Note {
743+
poisoned_parents.insert(actual_error.parent);
752744
}
753745
}
746+
747+
None => unexpected_actual_indices.push(actual_index),
748+
}
749+
}
750+
751+
for unexpected_actual_index in unexpected_actual_indices {
752+
// If the test is a known bug, don't require that the error is annotated
753+
let actual_error = &actual_errors[unexpected_actual_index];
754+
let mut expect_note = false;
755+
let mut next_parent = actual_error.parent;
756+
loop {
757+
if poisoned_parents.contains(&next_parent) {
758+
expect_note = true;
759+
break;
760+
}
761+
match next_parent {
762+
Some(next) => next_parent = actual_errors[next].parent,
763+
None => break,
764+
}
765+
}
766+
767+
if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note) {
768+
self.error(&format!(
769+
"{}:{}: unexpected {}: '{}'",
770+
file_name,
771+
actual_error.line_num_str(),
772+
actual_error.kind,
773+
actual_error.msg
774+
));
775+
unexpected.push(actual_error);
754776
}
755777
}
756778

0 commit comments

Comments
 (0)