Make Emitter::emit_diagnostic consuming.

All the other `emit`/`emit_diagnostic` methods were recently made
consuming (e.g. #119606), but this one wasn't. But it makes sense to.

Much of this is straightforward, and lots of `clone` calls are avoided.
There are a couple of tricky bits.
- `Emitter::primary_span_formatted` no longer takes a `Diagnostic` and
  returns a pair. Instead it takes the two fields from `Diagnostic` that
  it used (`span` and `suggestions`) as `&mut`, and modifies them. This
  is necessary to avoid the cloning of `diag.children` in two emitters.
- `from_errors_diagnostic` is rearranged so various uses of `diag` occur
  before the consuming `emit_diagnostic` call.
This commit is contained in:
Nicholas Nethercote 2024-02-02 15:44:22 +11:00
parent 4e3eed4892
commit d9508a1fd2
7 changed files with 84 additions and 75 deletions

View file

@ -193,7 +193,7 @@ pub type DynEmitter = dyn Emitter + DynSend;
/// Emitter trait for emitting errors.
pub trait Emitter: Translate {
/// 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.
/// Currently only supported for the JSON format.
@ -230,17 +230,17 @@ pub trait Emitter: Translate {
///
/// * If the current `Diagnostic` has only one visible `CodeSuggestion`,
/// 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,
/// we return the original `primary_span` and the original suggestions.
fn primary_span_formatted<'a>(
/// we leave `primary_span` and the suggestions untouched.
fn primary_span_formatted(
&mut self,
diag: &'a Diagnostic,
primary_span: &mut MultiSpan,
suggestions: &mut Vec<CodeSuggestion>,
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() {
let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap();
if rest.is_empty() &&
@ -287,16 +287,15 @@ pub trait Emitter: Translate {
primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
// We return only the modified primary_span
(primary_span, &[])
suggestions.clear();
} else {
// if there are multiple suggestions, print them all in full
// to be consistent. We could try to figure out if we can
// make one (or the first one) inline, but that would give
// undue importance to a semi-random suggestion
(primary_span, suggestions)
}
} else {
(primary_span, suggestions)
// do nothing
}
}
@ -518,16 +517,15 @@ impl Emitter for HumanEmitter {
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 mut children = diag.children.clone();
let (mut primary_span, suggestions) = self.primary_span_formatted(diag, &fluent_args);
debug!("emit_diagnostic: suggestions={:?}", suggestions);
let mut suggestions = diag.suggestions.unwrap_or(vec![]);
self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args);
self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
&mut primary_span,
&mut children,
&mut diag.span,
&mut diag.children,
&diag.level,
self.macro_backtrace,
);
@ -537,9 +535,9 @@ impl Emitter for HumanEmitter {
&diag.messages,
&fluent_args,
&diag.code,
&primary_span,
&children,
suggestions,
&diag.span,
&diag.children,
&suggestions,
self.track_diagnostics.then_some(&diag.emitted_at),
);
}
@ -576,9 +574,8 @@ impl Emitter for SilentEmitter {
None
}
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
fn emit_diagnostic(&mut self, mut diag: Diagnostic) {
if diag.level == Level::Fatal {
let mut diag = diag.clone();
diag.note(self.fatal_note.clone());
self.fatal_dcx.emit_diagnostic(diag);
}