Rollup merge of #120575 - nnethercote:simplify-codegen-diag-handling, r=estebank

Simplify codegen diagnostic handling

Some nice improvements. Details in the individual commit logs.

r? ````@estebank````
This commit is contained in:
Matthias Krüger 2024-02-06 19:40:06 +01:00 committed by GitHub
commit a3d3ccf098
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 84 additions and 75 deletions

View File

@ -1810,7 +1810,7 @@ fn fallback_fluent_bundle(&self) -> &FluentBundle {
} }
impl Emitter for SharedEmitter { impl Emitter for SharedEmitter {
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) { fn emit_diagnostic(&mut self, diag: rustc_errors::Diagnostic) {
let args: FxHashMap<DiagnosticArgName, DiagnosticArgValue> = let args: FxHashMap<DiagnosticArgName, DiagnosticArgValue> =
diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect(); diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect();
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {

View File

@ -44,15 +44,15 @@ fn fallback_fluent_bundle(&self) -> &FluentBundle {
impl Emitter for AnnotateSnippetEmitter { impl Emitter for AnnotateSnippetEmitter {
/// The entry point for the diagnostics generation /// The entry point for the diagnostics generation
fn emit_diagnostic(&mut self, diag: &Diagnostic) { fn emit_diagnostic(&mut self, mut diag: Diagnostic) {
let fluent_args = to_fluent_args(diag.args()); let fluent_args = to_fluent_args(diag.args());
let mut children = diag.children.clone(); let mut suggestions = diag.suggestions.unwrap_or(vec![]);
let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args); self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args);
self.fix_multispans_in_extern_macros_and_render_macro_backtrace( self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
&mut primary_span, &mut diag.span,
&mut children, &mut diag.children,
&diag.level, &diag.level,
self.macro_backtrace, self.macro_backtrace,
); );
@ -62,9 +62,9 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
&diag.messages, &diag.messages,
&fluent_args, &fluent_args,
&diag.code, &diag.code,
&primary_span, &diag.span,
&children, &diag.children,
suggestions, &suggestions,
); );
} }

View File

@ -193,7 +193,7 @@ fn right(&self, line_len: usize) -> usize {
/// Emitter trait for emitting errors. /// Emitter trait for emitting errors.
pub trait Emitter: Translate { pub trait Emitter: Translate {
/// Emit a structured diagnostic. /// Emit a structured diagnostic.
fn emit_diagnostic(&mut self, diag: &Diagnostic); fn emit_diagnostic(&mut self, diag: Diagnostic);
/// Emit a notification that an artifact has been output. /// Emit a notification that an artifact has been output.
/// Currently only supported for the JSON format. /// Currently only supported for the JSON format.
@ -230,17 +230,17 @@ fn supports_color(&self) -> bool {
/// ///
/// * If the current `Diagnostic` has only one visible `CodeSuggestion`, /// * If the current `Diagnostic` has only one visible `CodeSuggestion`,
/// we format the `help` suggestion depending on the content of the /// we format the `help` suggestion depending on the content of the
/// substitutions. In that case, we return the modified span only. /// substitutions. In that case, we modify the span and clear the
/// suggestions.
/// ///
/// * If the current `Diagnostic` has multiple suggestions, /// * If the current `Diagnostic` has multiple suggestions,
/// we return the original `primary_span` and the original suggestions. /// we leave `primary_span` and the suggestions untouched.
fn primary_span_formatted<'a>( fn primary_span_formatted(
&mut self, &mut self,
diag: &'a Diagnostic, primary_span: &mut MultiSpan,
suggestions: &mut Vec<CodeSuggestion>,
fluent_args: &FluentArgs<'_>, fluent_args: &FluentArgs<'_>,
) -> (MultiSpan, &'a [CodeSuggestion]) { ) {
let mut primary_span = diag.span.clone();
let suggestions = diag.suggestions.as_deref().unwrap_or(&[]);
if let Some((sugg, rest)) = suggestions.split_first() { if let Some((sugg, rest)) = suggestions.split_first() {
let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap(); let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap();
if rest.is_empty() && if rest.is_empty() &&
@ -287,16 +287,15 @@ fn primary_span_formatted<'a>(
primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg); primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
// We return only the modified primary_span // We return only the modified primary_span
(primary_span, &[]) suggestions.clear();
} else { } else {
// if there are multiple suggestions, print them all in full // if there are multiple suggestions, print them all in full
// to be consistent. We could try to figure out if we can // to be consistent. We could try to figure out if we can
// make one (or the first one) inline, but that would give // make one (or the first one) inline, but that would give
// undue importance to a semi-random suggestion // undue importance to a semi-random suggestion
(primary_span, suggestions)
} }
} else { } else {
(primary_span, suggestions) // do nothing
} }
} }
@ -518,16 +517,15 @@ fn source_map(&self) -> Option<&Lrc<SourceMap>> {
self.sm.as_ref() self.sm.as_ref()
} }
fn emit_diagnostic(&mut self, diag: &Diagnostic) { fn emit_diagnostic(&mut self, mut diag: Diagnostic) {
let fluent_args = to_fluent_args(diag.args()); let fluent_args = to_fluent_args(diag.args());
let mut children = diag.children.clone(); let mut suggestions = diag.suggestions.unwrap_or(vec![]);
let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args); self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args);
debug!("emit_diagnostic: suggestions={:?}", suggestions);
self.fix_multispans_in_extern_macros_and_render_macro_backtrace( self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
&mut primary_span, &mut diag.span,
&mut children, &mut diag.children,
&diag.level, &diag.level,
self.macro_backtrace, self.macro_backtrace,
); );
@ -537,9 +535,9 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
&diag.messages, &diag.messages,
&fluent_args, &fluent_args,
&diag.code, &diag.code,
&primary_span, &diag.span,
&children, &diag.children,
suggestions, &suggestions,
self.track_diagnostics.then_some(&diag.emitted_at), self.track_diagnostics.then_some(&diag.emitted_at),
); );
} }
@ -576,9 +574,8 @@ fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None None
} }
fn emit_diagnostic(&mut self, diag: &Diagnostic) { fn emit_diagnostic(&mut self, mut diag: Diagnostic) {
if diag.level == Level::Fatal { if diag.level == Level::Fatal {
let mut diag = diag.clone();
diag.note(self.fatal_note.clone()); diag.note(self.fatal_note.clone());
self.fatal_dcx.emit_diagnostic(diag); self.fatal_dcx.emit_diagnostic(diag);
} }

View File

@ -176,7 +176,7 @@ fn fallback_fluent_bundle(&self) -> &FluentBundle {
} }
impl Emitter for JsonEmitter { impl Emitter for JsonEmitter {
fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) { fn emit_diagnostic(&mut self, diag: crate::Diagnostic) {
let data = Diagnostic::from_errors_diagnostic(diag, self); let data = Diagnostic::from_errors_diagnostic(diag, self);
let result = self.emit(EmitTyped::Diagnostic(data)); let result = self.emit(EmitTyped::Diagnostic(data));
if let Err(e) = result { if let Err(e) = result {
@ -201,7 +201,7 @@ fn emit_future_breakage_report(&mut self, diags: Vec<crate::Diagnostic>) {
} }
FutureBreakageItem { FutureBreakageItem {
diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic( diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(
&diag, self, diag, self,
)), )),
} }
}) })
@ -340,7 +340,7 @@ struct UnusedExterns<'a, 'b, 'c> {
} }
impl Diagnostic { impl Diagnostic {
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { fn from_errors_diagnostic(diag: crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
let args = to_fluent_args(diag.args()); let args = to_fluent_args(diag.args());
let sugg = diag.suggestions.iter().flatten().map(|sugg| { let sugg = diag.suggestions.iter().flatten().map(|sugg| {
let translated_message = let translated_message =
@ -382,6 +382,28 @@ fn reset(&mut self) -> io::Result<()> {
Ok(()) Ok(())
} }
} }
let translated_message = je.translate_messages(&diag.messages, &args);
let code = if let Some(code) = diag.code {
Some(DiagnosticCode {
code: code.to_string(),
explanation: je.registry.as_ref().unwrap().try_find_description(code).ok(),
})
} else if let Some(IsLint { name, .. }) = &diag.is_lint {
Some(DiagnosticCode { code: name.to_string(), explanation: None })
} else {
None
};
let level = diag.level.to_str();
let spans = DiagnosticSpan::from_multispan(&diag.span, &args, je);
let children = diag
.children
.iter()
.map(|c| Diagnostic::from_sub_diagnostic(c, &args, je))
.chain(sugg)
.collect();
let buf = BufWriter::default(); let buf = BufWriter::default();
let output = buf.clone(); let output = buf.clone();
je.json_rendered je.json_rendered
@ -398,30 +420,12 @@ fn reset(&mut self) -> io::Result<()> {
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
let output = String::from_utf8(output).unwrap(); let output = String::from_utf8(output).unwrap();
let translated_message = je.translate_messages(&diag.messages, &args);
let code = if let Some(code) = diag.code {
Some(DiagnosticCode {
code: code.to_string(),
explanation: je.registry.as_ref().unwrap().try_find_description(code).ok(),
})
} else if let Some(IsLint { name, .. }) = &diag.is_lint {
Some(DiagnosticCode { code: name.to_string(), explanation: None })
} else {
None
};
Diagnostic { Diagnostic {
message: translated_message.to_string(), message: translated_message.to_string(),
code, code,
level: diag.level.to_str(), level,
spans: DiagnosticSpan::from_multispan(&diag.span, &args, je), spans,
children: diag children,
.children
.iter()
.map(|c| Diagnostic::from_sub_diagnostic(c, &args, je))
.chain(sugg)
.collect(),
rendered: Some(output), rendered: Some(output),
} }
} }

View File

@ -981,9 +981,13 @@ pub fn print_error_count(&self, registry: &Registry) {
match (errors.len(), warnings.len()) { match (errors.len(), warnings.len()) {
(0, 0) => return, (0, 0) => return,
(0, _) => inner (0, _) => {
.emitter // Use `inner.emitter` directly, otherwise the warning might not be emitted, e.g.
.emit_diagnostic(&Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))), // with a configuration like `--cap-lints allow --force-warn bare_trait_objects`.
inner
.emitter
.emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings)));
}
(_, 0) => { (_, 0) => {
inner.emit_diagnostic(Diagnostic::new(Fatal, errors)); inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
} }
@ -1047,7 +1051,7 @@ pub fn must_teach(&self, code: ErrCode) -> bool {
} }
pub fn force_print_diagnostic(&self, db: Diagnostic) { pub fn force_print_diagnostic(&self, db: Diagnostic) {
self.inner.borrow_mut().emitter.emit_diagnostic(&db); self.inner.borrow_mut().emitter.emit_diagnostic(db);
} }
pub fn emit_diagnostic(&self, diagnostic: Diagnostic) -> Option<ErrorGuaranteed> { pub fn emit_diagnostic(&self, diagnostic: Diagnostic) -> Option<ErrorGuaranteed> {
@ -1315,11 +1319,15 @@ fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option<ErrorGuarant
!self.emitted_diagnostics.insert(diagnostic_hash) !self.emitted_diagnostics.insert(diagnostic_hash)
}; };
let is_error = diagnostic.is_error();
let is_lint = diagnostic.is_lint.is_some();
// Only emit the diagnostic if we've been asked to deduplicate or // Only emit the diagnostic if we've been asked to deduplicate or
// haven't already emitted an equivalent diagnostic. // haven't already emitted an equivalent diagnostic.
if !(self.flags.deduplicate_diagnostics && already_emitted) { if !(self.flags.deduplicate_diagnostics && already_emitted) {
debug!(?diagnostic); debug!(?diagnostic);
debug!(?self.emitted_diagnostics); debug!(?self.emitted_diagnostics);
let already_emitted_sub = |sub: &mut SubDiagnostic| { let already_emitted_sub = |sub: &mut SubDiagnostic| {
debug!(?sub); debug!(?sub);
if sub.level != OnceNote && sub.level != OnceHelp { if sub.level != OnceNote && sub.level != OnceHelp {
@ -1331,7 +1339,6 @@ fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option<ErrorGuarant
debug!(?diagnostic_hash); debug!(?diagnostic_hash);
!self.emitted_diagnostics.insert(diagnostic_hash) !self.emitted_diagnostics.insert(diagnostic_hash)
}; };
diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {}); diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {});
if already_emitted { if already_emitted {
diagnostic.note( diagnostic.note(
@ -1339,16 +1346,17 @@ fn emit_diagnostic(&mut self, mut diagnostic: Diagnostic) -> Option<ErrorGuarant
); );
} }
self.emitter.emit_diagnostic(&diagnostic); if is_error {
if diagnostic.is_error() {
self.deduplicated_err_count += 1; self.deduplicated_err_count += 1;
} else if matches!(diagnostic.level, ForceWarning(_) | Warning) { } else if matches!(diagnostic.level, ForceWarning(_) | Warning) {
self.deduplicated_warn_count += 1; self.deduplicated_warn_count += 1;
} }
self.has_printed = true; self.has_printed = true;
self.emitter.emit_diagnostic(diagnostic);
} }
if diagnostic.is_error() { if is_error {
if diagnostic.is_lint.is_some() { if is_lint {
self.lint_err_count += 1; self.lint_err_count += 1;
} else { } else {
self.err_count += 1; self.err_count += 1;

View File

@ -156,7 +156,7 @@ fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
} }
impl Emitter for BufferEmitter { impl Emitter for BufferEmitter {
fn emit_diagnostic(&mut self, diag: &Diagnostic) { fn emit_diagnostic(&mut self, diag: Diagnostic) {
let mut buffer = self.buffer.borrow_mut(); let mut buffer = self.buffer.borrow_mut();
let fluent_args = to_fluent_args(diag.args()); let fluent_args = to_fluent_args(diag.args());

View File

@ -47,7 +47,7 @@ fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None None
} }
fn emit_diagnostic(&mut self, _db: &Diagnostic) {} fn emit_diagnostic(&mut self, _db: Diagnostic) {}
} }
fn silent_emitter() -> Box<DynEmitter> { fn silent_emitter() -> Box<DynEmitter> {
@ -64,7 +64,7 @@ struct SilentOnIgnoredFilesEmitter {
} }
impl SilentOnIgnoredFilesEmitter { impl SilentOnIgnoredFilesEmitter {
fn handle_non_ignoreable_error(&mut self, db: &Diagnostic) { fn handle_non_ignoreable_error(&mut self, db: Diagnostic) {
self.has_non_ignorable_parser_errors = true; self.has_non_ignorable_parser_errors = true;
self.can_reset.store(false, Ordering::Release); self.can_reset.store(false, Ordering::Release);
self.emitter.emit_diagnostic(db); self.emitter.emit_diagnostic(db);
@ -86,7 +86,7 @@ fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None None
} }
fn emit_diagnostic(&mut self, db: &Diagnostic) { fn emit_diagnostic(&mut self, db: Diagnostic) {
if db.level() == DiagnosticLevel::Fatal { if db.level() == DiagnosticLevel::Fatal {
return self.handle_non_ignoreable_error(db); return self.handle_non_ignoreable_error(db);
} }
@ -365,7 +365,7 @@ fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None None
} }
fn emit_diagnostic(&mut self, _db: &Diagnostic) { fn emit_diagnostic(&mut self, _db: Diagnostic) {
self.num_emitted_errors.fetch_add(1, Ordering::Release); self.num_emitted_errors.fetch_add(1, Ordering::Release);
} }
} }
@ -424,7 +424,7 @@ fn handles_fatal_parse_error_in_ignored_file() {
); );
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, Some(span)); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, Some(span));
emitter.emit_diagnostic(&fatal_diagnostic); emitter.emit_diagnostic(fatal_diagnostic);
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
assert_eq!(can_reset_errors.load(Ordering::Acquire), false); assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
} }
@ -449,7 +449,7 @@ fn handles_recoverable_parse_error_in_ignored_file() {
); );
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
emitter.emit_diagnostic(&non_fatal_diagnostic); emitter.emit_diagnostic(non_fatal_diagnostic);
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0);
assert_eq!(can_reset_errors.load(Ordering::Acquire), true); assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
} }
@ -473,7 +473,7 @@ fn handles_recoverable_parse_error_in_non_ignored_file() {
); );
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
emitter.emit_diagnostic(&non_fatal_diagnostic); emitter.emit_diagnostic(non_fatal_diagnostic);
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
assert_eq!(can_reset_errors.load(Ordering::Acquire), false); assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
} }
@ -512,9 +512,9 @@ fn handles_mix_of_recoverable_parse_error() {
let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span)); let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span));
let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span)); let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span));
let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None);
emitter.emit_diagnostic(&bar_diagnostic); emitter.emit_diagnostic(bar_diagnostic);
emitter.emit_diagnostic(&foo_diagnostic); emitter.emit_diagnostic(foo_diagnostic);
emitter.emit_diagnostic(&fatal_diagnostic); emitter.emit_diagnostic(fatal_diagnostic);
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 2); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 2);
assert_eq!(can_reset_errors.load(Ordering::Acquire), false); assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
} }