Skip to content

Commit 24f60a7

Browse files
committed
errors: DiagnosticMessage::Eager
Add variant of `DiagnosticMessage` for eagerly translated messages (messages in the target language which don't need translated by the emitter during emission). Also adds `eager_subdiagnostic` function which is intended to be invoked by the diagnostic derive for subdiagnostic fields which are marked as needing eager translation. Signed-off-by: David Wood <[email protected]>
1 parent 1a74a82 commit 24f60a7

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

compiler/rustc_error_messages/src/lib.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,18 @@ pub enum SubdiagnosticMessage {
276276
/// Non-translatable diagnostic message.
277277
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
278278
Str(String),
279+
/// Translatable message which has already been translated eagerly.
280+
///
281+
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
282+
/// be instantiated multiple times with different values. As translation normally happens
283+
/// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
284+
/// the setting of diagnostic arguments in the derived code will overwrite previous variable
285+
/// values and only the final value will be set when translation occurs - resulting in
286+
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
287+
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
288+
/// stores messages which have been translated eagerly.
289+
// FIXME(#100717): can a `Cow<'static, str>` be used here?
290+
Eager(String),
279291
/// Identifier of a Fluent message. Instances of this variant are generated by the
280292
/// `Subdiagnostic` derive.
281293
FluentIdentifier(FluentId),
@@ -303,8 +315,20 @@ impl<S: Into<String>> From<S> for SubdiagnosticMessage {
303315
#[rustc_diagnostic_item = "DiagnosticMessage"]
304316
pub enum DiagnosticMessage {
305317
/// Non-translatable diagnostic message.
306-
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
318+
// FIXME(#100717): can a `Cow<'static, str>` be used here?
307319
Str(String),
320+
/// Translatable message which has already been translated eagerly.
321+
///
322+
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
323+
/// be instantiated multiple times with different values. As translation normally happens
324+
/// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
325+
/// the setting of diagnostic arguments in the derived code will overwrite previous variable
326+
/// values and only the final value will be set when translation occurs - resulting in
327+
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
328+
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
329+
/// stores messages which have been translated eagerly.
330+
// FIXME(#100717): can a `Cow<'static, str>` be used here?
331+
Eager(String),
308332
/// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
309333
/// message.
310334
///
@@ -323,6 +347,7 @@ impl DiagnosticMessage {
323347
pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
324348
let attr = match sub {
325349
SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
350+
SubdiagnosticMessage::Eager(s) => return DiagnosticMessage::Eager(s),
326351
SubdiagnosticMessage::FluentIdentifier(id) => {
327352
return DiagnosticMessage::FluentIdentifier(id, None);
328353
}
@@ -331,6 +356,7 @@ impl DiagnosticMessage {
331356

332357
match self {
333358
DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
359+
DiagnosticMessage::Eager(s) => DiagnosticMessage::Eager(s.clone()),
334360
DiagnosticMessage::FluentIdentifier(id, _) => {
335361
DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
336362
}
@@ -379,6 +405,7 @@ impl Into<SubdiagnosticMessage> for DiagnosticMessage {
379405
fn into(self) -> SubdiagnosticMessage {
380406
match self {
381407
DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
408+
DiagnosticMessage::Eager(s) => SubdiagnosticMessage::Eager(s),
382409
DiagnosticMessage::FluentIdentifier(id, None) => {
383410
SubdiagnosticMessage::FluentIdentifier(id)
384411
}

compiler/rustc_errors/src/diagnostic.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,23 @@ impl Diagnostic {
939939
self
940940
}
941941

942+
/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
943+
/// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
944+
/// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
945+
/// interpolated variables).
946+
pub fn eager_subdiagnostic(
947+
&mut self,
948+
handler: &crate::Handler,
949+
subdiagnostic: impl AddToDiagnostic,
950+
) -> &mut Self {
951+
subdiagnostic.add_to_diagnostic_with(self, |diag, msg| {
952+
let args = diag.args();
953+
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
954+
handler.eagerly_translate(msg, args)
955+
});
956+
self
957+
}
958+
942959
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
943960
self.span = sp.into();
944961
if let Some(span) = self.span.primary_span() {
@@ -994,7 +1011,7 @@ impl Diagnostic {
9941011
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
9951012
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
9961013
/// passes the user's string along).
997-
fn subdiagnostic_message_to_diagnostic_message(
1014+
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
9981015
&self,
9991016
attr: impl Into<SubdiagnosticMessage>,
10001017
) -> DiagnosticMessage {

compiler/rustc_errors/src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,17 @@ impl Handler {
597597
}
598598
}
599599

600+
/// Translate `message` eagerly with `args`.
601+
pub fn eagerly_translate<'a>(
602+
&self,
603+
message: DiagnosticMessage,
604+
args: impl Iterator<Item = DiagnosticArg<'a, 'static>>,
605+
) -> SubdiagnosticMessage {
606+
let inner = self.inner.borrow();
607+
let args = crate::translation::to_fluent_args(args);
608+
SubdiagnosticMessage::Eager(inner.emitter.translate_message(&message, &args).to_string())
609+
}
610+
600611
// This is here to not allow mutation of flags;
601612
// as of this writing it's only used in tests in librustc_middle.
602613
pub fn can_emit_warnings(&self) -> bool {

compiler/rustc_errors/src/translation.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ pub trait Translate {
5555
) -> Cow<'_, str> {
5656
trace!(?message, ?args);
5757
let (identifier, attr) = match message {
58-
DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
58+
DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => {
59+
return Cow::Borrowed(&msg);
60+
}
5961
DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
6062
};
6163

0 commit comments

Comments
 (0)