errors: only eagerly translate subdiagnostics
Subdiagnostics don't need to be lazily translated, they can always be eagerly translated. Eager translation is slightly more complex as we need to have a `DiagCtxt` available to perform the translation, which involves slightly more threading of that context. This slight increase in complexity should enable later simplifications - like passing `DiagCtxt` into `AddToDiagnostic` and moving Fluent messages into the diagnostic structs rather than having them in separate files (working on that was what led to this change). Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
parent
bb89df6903
commit
b80fc5d4e8
43 changed files with 532 additions and 388 deletions
|
@ -851,18 +851,11 @@ impl Diagnostic {
|
|||
self
|
||||
}
|
||||
|
||||
/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
|
||||
/// [rustc_macros::Subdiagnostic]).
|
||||
pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
|
||||
subdiagnostic.add_to_diagnostic(self);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
|
||||
/// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
|
||||
/// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
|
||||
/// interpolated variables).
|
||||
pub fn eager_subdiagnostic(
|
||||
pub fn subdiagnostic(
|
||||
&mut self,
|
||||
dcx: &crate::DiagCtxt,
|
||||
subdiagnostic: impl AddToDiagnostic,
|
||||
|
@ -921,7 +914,7 @@ impl Diagnostic {
|
|||
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
|
||||
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
|
||||
/// passes the user's string along).
|
||||
fn subdiagnostic_message_to_diagnostic_message(
|
||||
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
|
||||
&self,
|
||||
attr: impl Into<SubdiagnosticMessage>,
|
||||
) -> DiagnosticMessage {
|
||||
|
|
|
@ -404,9 +404,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
|||
name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg,
|
||||
));
|
||||
forward!((subdiagnostic, with_subdiagnostic)(
|
||||
subdiagnostic: impl crate::AddToDiagnostic,
|
||||
));
|
||||
forward!((eager_subdiagnostic, with_eager_subdiagnostic)(
|
||||
dcx: &DiagCtxt,
|
||||
subdiagnostic: impl crate::AddToDiagnostic,
|
||||
));
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{FileLines, FileName, SourceFile, Span};
|
||||
|
||||
use crate::error::TranslateError;
|
||||
use crate::snippet::{
|
||||
Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
|
||||
};
|
||||
|
@ -559,6 +560,18 @@ pub struct SilentEmitter {
|
|||
pub fatal_note: String,
|
||||
}
|
||||
|
||||
pub fn silent_translate<'a>(
|
||||
message: &'a DiagnosticMessage,
|
||||
) -> Result<Cow<'_, str>, TranslateError<'_>> {
|
||||
match message {
|
||||
DiagnosticMessage::Str(msg) | DiagnosticMessage::Translated(msg) => Ok(Cow::Borrowed(msg)),
|
||||
DiagnosticMessage::FluentIdentifier(identifier, _) => {
|
||||
// Any value works here.
|
||||
Ok(identifier.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Translate for SilentEmitter {
|
||||
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
|
||||
None
|
||||
|
@ -567,6 +580,16 @@ impl Translate for SilentEmitter {
|
|||
fn fallback_fluent_bundle(&self) -> &FluentBundle {
|
||||
panic!("silent emitter attempted to translate message")
|
||||
}
|
||||
|
||||
// Override `translate_message` for the silent emitter because eager translation of
|
||||
// subdiagnostics result in a call to this.
|
||||
fn translate_message<'a>(
|
||||
&'a self,
|
||||
message: &'a DiagnosticMessage,
|
||||
_: &'a FluentArgs<'_>,
|
||||
) -> Result<Cow<'_, str>, TranslateError<'_>> {
|
||||
silent_translate(message)
|
||||
}
|
||||
}
|
||||
|
||||
impl Emitter for SilentEmitter {
|
||||
|
|
|
@ -640,7 +640,8 @@ impl DiagCtxt {
|
|||
message: DiagnosticMessage,
|
||||
args: impl Iterator<Item = DiagnosticArg<'a>>,
|
||||
) -> SubdiagnosticMessage {
|
||||
SubdiagnosticMessage::Eager(Cow::from(self.eagerly_translate_to_string(message, args)))
|
||||
let inner = self.inner.borrow();
|
||||
inner.eagerly_translate(message, args)
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `String`.
|
||||
|
@ -650,8 +651,7 @@ impl DiagCtxt {
|
|||
args: impl Iterator<Item = DiagnosticArg<'a>>,
|
||||
) -> String {
|
||||
let inner = self.inner.borrow();
|
||||
let args = crate::translation::to_fluent_args(args);
|
||||
inner.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
|
||||
inner.eagerly_translate_to_string(message, args)
|
||||
}
|
||||
|
||||
// This is here to not allow mutation of flags;
|
||||
|
@ -1446,6 +1446,25 @@ impl DiagCtxtInner {
|
|||
.or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `SubdiagnosticMessage::Eager`.
|
||||
pub fn eagerly_translate<'a>(
|
||||
&self,
|
||||
message: DiagnosticMessage,
|
||||
args: impl Iterator<Item = DiagnosticArg<'a>>,
|
||||
) -> SubdiagnosticMessage {
|
||||
SubdiagnosticMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `String`.
|
||||
pub fn eagerly_translate_to_string<'a>(
|
||||
&self,
|
||||
message: DiagnosticMessage,
|
||||
args: impl Iterator<Item = DiagnosticArg<'a>>,
|
||||
) -> String {
|
||||
let args = crate::translation::to_fluent_args(args);
|
||||
self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
|
||||
}
|
||||
|
||||
fn flush_delayed(&mut self) {
|
||||
if self.delayed_bugs.is_empty() {
|
||||
return;
|
||||
|
@ -1484,15 +1503,22 @@ impl DiagCtxtInner {
|
|||
}
|
||||
|
||||
let mut bug =
|
||||
if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner };
|
||||
if backtrace || self.ice_file.is_none() { bug.decorate(self) } else { bug.inner };
|
||||
|
||||
// "Undelay" the delayed bugs (into plain `Bug`s).
|
||||
if bug.level != DelayedBug {
|
||||
// NOTE(eddyb) not panicking here because we're already producing
|
||||
// an ICE, and the more information the merrier.
|
||||
bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel {
|
||||
let subdiag = InvalidFlushedDelayedDiagnosticLevel {
|
||||
span: bug.span.primary_span().unwrap(),
|
||||
level: bug.level,
|
||||
};
|
||||
// FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it
|
||||
// just uses `DiagCtxtInner` functions.
|
||||
subdiag.add_to_diagnostic_with(&mut bug, |diag, msg| {
|
||||
let args = diag.args();
|
||||
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
||||
self.eagerly_translate(msg, args)
|
||||
});
|
||||
}
|
||||
bug.level = Bug;
|
||||
|
@ -1527,25 +1553,35 @@ impl DelayedDiagnostic {
|
|||
DelayedDiagnostic { inner: diagnostic, note: backtrace }
|
||||
}
|
||||
|
||||
fn decorate(mut self) -> Diagnostic {
|
||||
fn decorate(mut self, dcx: &DiagCtxtInner) -> Diagnostic {
|
||||
// FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it
|
||||
// just uses `DiagCtxtInner` functions.
|
||||
let subdiag_with = |diag: &mut Diagnostic, msg| {
|
||||
let args = diag.args();
|
||||
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
||||
dcx.eagerly_translate(msg, args)
|
||||
};
|
||||
|
||||
match self.note.status() {
|
||||
BacktraceStatus::Captured => {
|
||||
let inner = &self.inner;
|
||||
self.inner.subdiagnostic(DelayedAtWithNewline {
|
||||
let subdiag = DelayedAtWithNewline {
|
||||
span: inner.span.primary_span().unwrap_or(DUMMY_SP),
|
||||
emitted_at: inner.emitted_at.clone(),
|
||||
note: self.note,
|
||||
});
|
||||
};
|
||||
subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with);
|
||||
}
|
||||
// Avoid the needless newline when no backtrace has been captured,
|
||||
// the display impl should just be a single line.
|
||||
_ => {
|
||||
let inner = &self.inner;
|
||||
self.inner.subdiagnostic(DelayedAtWithoutNewline {
|
||||
let subdiag = DelayedAtWithoutNewline {
|
||||
span: inner.span.primary_span().unwrap_or(DUMMY_SP),
|
||||
emitted_at: inner.emitted_at.clone(),
|
||||
note: self.note,
|
||||
});
|
||||
};
|
||||
subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1691,15 +1727,15 @@ impl Level {
|
|||
}
|
||||
|
||||
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
|
||||
pub fn add_elided_lifetime_in_path_suggestion(
|
||||
pub fn add_elided_lifetime_in_path_suggestion<E: EmissionGuarantee>(
|
||||
source_map: &SourceMap,
|
||||
diag: &mut Diagnostic,
|
||||
diag: &mut DiagnosticBuilder<'_, E>,
|
||||
n: usize,
|
||||
path_span: Span,
|
||||
incl_angl_brckt: bool,
|
||||
insertion_span: Span,
|
||||
) {
|
||||
diag.subdiagnostic(ExpectedLifetimeParameter { span: path_span, count: n });
|
||||
diag.subdiagnostic(diag.dcx, ExpectedLifetimeParameter { span: path_span, count: n });
|
||||
if !source_map.is_span_accessible(insertion_span) {
|
||||
// Do not try to suggest anything if generated by a proc-macro.
|
||||
return;
|
||||
|
@ -1708,11 +1744,10 @@ pub fn add_elided_lifetime_in_path_suggestion(
|
|||
let suggestion =
|
||||
if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
|
||||
|
||||
diag.subdiagnostic(IndicateAnonymousLifetime {
|
||||
span: insertion_span.shrink_to_hi(),
|
||||
count: n,
|
||||
suggestion,
|
||||
});
|
||||
diag.subdiagnostic(
|
||||
diag.dcx,
|
||||
IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion },
|
||||
);
|
||||
}
|
||||
|
||||
pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::error::{TranslateError, TranslateErrorKind};
|
|||
use crate::snippet::Style;
|
||||
use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_error_messages::FluentArgs;
|
||||
pub use rustc_error_messages::FluentArgs;
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::error::Report;
|
||||
|
@ -61,7 +61,7 @@ pub trait Translate {
|
|||
) -> Result<Cow<'_, str>, TranslateError<'_>> {
|
||||
trace!(?message, ?args);
|
||||
let (identifier, attr) = match message {
|
||||
DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => {
|
||||
DiagnosticMessage::Str(msg) | DiagnosticMessage::Translated(msg) => {
|
||||
return Ok(Cow::Borrowed(msg));
|
||||
}
|
||||
DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue