Skip to content

Refactor Translator #142650

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 7 additions & 13 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ use rustc_data_structures::jobserver::{self, Acquired};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
use rustc_errors::emitter::Emitter;
use rustc_errors::translation::Translate;
use rustc_errors::translation::Translator;
use rustc_errors::{
Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalError, FluentBundle, Level, MultiSpan,
Style, Suggestions,
Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalError, Level, MultiSpan, Style,
Suggestions,
};
use rustc_fs_util::link_or_copy;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
Expand Down Expand Up @@ -1889,16 +1889,6 @@ impl SharedEmitter {
}
}

impl Translate for SharedEmitter {
fn fluent_bundle(&self) -> Option<&FluentBundle> {
None
}

fn fallback_fluent_bundle(&self) -> &FluentBundle {
panic!("shared emitter attempted to translate a diagnostic");
}
}

impl Emitter for SharedEmitter {
fn emit_diagnostic(
&mut self,
Expand Down Expand Up @@ -1932,6 +1922,10 @@ impl Emitter for SharedEmitter {
fn source_map(&self) -> Option<&SourceMap> {
None
}

fn translator(&self) -> &Translator {
panic!("shared emitter attempted to translate a diagnostic");
}
}

impl SharedEmitterMain {
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use rustc_data_structures::profiling::{
};
use rustc_errors::emitter::stderr_destination;
use rustc_errors::registry::Registry;
use rustc_errors::translation::Translator;
use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown};
use rustc_feature::find_gated_cfg;
// This avoids a false positive with `-Wunused_crate_dependencies`.
Expand Down Expand Up @@ -109,6 +110,10 @@ use crate::session_diagnostics::{

rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

pub fn default_translator() -> Translator {
Translator::with_fallback_bundle(DEFAULT_LOCALE_RESOURCES.to_vec(), false)
}

pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
// tidy-alphabetical-start
crate::DEFAULT_LOCALE_RESOURCE,
Expand Down Expand Up @@ -1413,11 +1418,10 @@ fn report_ice(
extra_info: fn(&DiagCtxt),
using_internal_features: &AtomicBool,
) {
let fallback_bundle =
rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
let translator = default_translator();
let emitter = Box::new(rustc_errors::emitter::HumanEmitter::new(
stderr_destination(rustc_errors::ColorConfig::Auto),
fallback_bundle,
translator,
));
let dcx = rustc_errors::DiagCtxt::new(emitter);
let dcx = dcx.handle();
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_error_messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue};
use fluent_syntax::parser::ParserError;
use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker};
use intl_memoizer::concurrent::IntlLangMemoizer;
use rustc_data_structures::sync::IntoDynSyncSend;
use rustc_data_structures::sync::{DynSend, IntoDynSyncSend};
use rustc_macros::{Decodable, Encodable};
use rustc_span::Span;
use smallvec::SmallVec;
Expand Down Expand Up @@ -204,16 +204,16 @@ fn register_functions(bundle: &mut FluentBundle) {

/// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily
/// evaluated fluent bundle.
pub type LazyFallbackBundle = Arc<LazyLock<FluentBundle, impl FnOnce() -> FluentBundle>>;
pub type LazyFallbackBundle =
Arc<LazyLock<FluentBundle, Box<dyn FnOnce() -> FluentBundle + DynSend>>>;

/// Return the default `FluentBundle` with standard "en-US" diagnostic messages.
#[instrument(level = "trace", skip(resources))]
#[define_opaque(LazyFallbackBundle)]
pub fn fallback_fluent_bundle(
resources: Vec<&'static str>,
with_directionality_markers: bool,
) -> LazyFallbackBundle {
Arc::new(LazyLock::new(move || {
Arc::new(LazyLock::new(Box::new(move || {
let mut fallback_bundle = new_bundle(vec![langid!("en-US")]);

register_functions(&mut fallback_bundle);
Expand All @@ -228,7 +228,7 @@ pub fn fallback_fluent_bundle(
}

fallback_bundle
}))
})))
}

/// Identifier for the Fluent message/attribute corresponding to a diagnostic message.
Expand Down
36 changes: 10 additions & 26 deletions compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ use rustc_span::source_map::SourceMap;
use crate::emitter::FileWithAnnotatedLines;
use crate::registry::Registry;
use crate::snippet::Line;
use crate::translation::{Translate, to_fluent_args};
use crate::translation::{Translator, to_fluent_args};
use crate::{
CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, FluentBundle, LazyFallbackBundle,
Level, MultiSpan, Style, Subdiag,
CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, Level, MultiSpan, Style, Subdiag,
};

/// Generates diagnostics using annotate-snippet
pub struct AnnotateSnippetEmitter {
source_map: Option<Arc<SourceMap>>,
fluent_bundle: Option<Arc<FluentBundle>>,
fallback_bundle: LazyFallbackBundle,
translator: Translator,

/// If true, hides the longer explanation text
short_message: bool,
Expand All @@ -35,16 +33,6 @@ pub struct AnnotateSnippetEmitter {
macro_backtrace: bool,
}

impl Translate for AnnotateSnippetEmitter {
fn fluent_bundle(&self) -> Option<&FluentBundle> {
self.fluent_bundle.as_deref()
}

fn fallback_fluent_bundle(&self) -> &FluentBundle {
&self.fallback_bundle
}
}

impl Emitter for AnnotateSnippetEmitter {
/// The entry point for the diagnostics generation
fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) {
Expand Down Expand Up @@ -78,6 +66,10 @@ impl Emitter for AnnotateSnippetEmitter {
fn should_show_explain(&self) -> bool {
!self.short_message
}

fn translator(&self) -> &Translator {
&self.translator
}
}

/// Provides the source string for the given `line` of `file`
Expand All @@ -104,19 +96,11 @@ fn annotation_level_for_level(level: Level) -> annotate_snippets::Level {
impl AnnotateSnippetEmitter {
pub fn new(
source_map: Option<Arc<SourceMap>>,
fluent_bundle: Option<Arc<FluentBundle>>,
fallback_bundle: LazyFallbackBundle,
translator: Translator,
short_message: bool,
macro_backtrace: bool,
) -> Self {
Self {
source_map,
fluent_bundle,
fallback_bundle,
short_message,
ui_testing: false,
macro_backtrace,
}
Self { source_map, translator, short_message, ui_testing: false, macro_backtrace }
}

/// Allows to modify `Self` to enable or disable the `ui_testing` flag.
Expand All @@ -137,7 +121,7 @@ impl AnnotateSnippetEmitter {
_children: &[Subdiag],
_suggestions: &[CodeSuggestion],
) {
let message = self.translate_messages(messages, args);
let message = self.translator.translate_messages(messages, args);
if let Some(source_map) = &self.source_map {
// Make sure our primary file comes first
let primary_lo = if let Some(primary_span) = msp.primary_span().as_ref() {
Expand Down
88 changes: 50 additions & 38 deletions compiler/rustc_errors/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ use crate::snippet::{
};
use crate::styled_buffer::StyledBuffer;
use crate::timings::TimingRecord;
use crate::translation::{Translate, to_fluent_args};
use crate::translation::{Translator, to_fluent_args};
use crate::{
CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level,
MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl,
CodeSuggestion, DiagInner, DiagMessage, ErrCode, Level, MultiSpan, Subdiag,
SubstitutionHighlight, SuggestionStyle, TerminalUrl,
};

/// Default column width, used in tests and when terminal dimensions cannot be determined.
Expand Down Expand Up @@ -175,7 +175,7 @@ const ANONYMIZED_LINE_NUM: &str = "LL";
pub type DynEmitter = dyn Emitter + DynSend;

/// Emitter trait for emitting errors and other structured information.
pub trait Emitter: Translate {
pub trait Emitter {
/// Emit a structured diagnostic.
fn emit_diagnostic(&mut self, diag: DiagInner, registry: &Registry);

Expand Down Expand Up @@ -212,6 +212,8 @@ pub trait Emitter: Translate {

fn source_map(&self) -> Option<&SourceMap>;

fn translator(&self) -> &Translator;

/// Formats the substitutions of the primary_span
///
/// There are a lot of conditions to this method, but in short:
Expand All @@ -224,13 +226,17 @@ pub trait Emitter: Translate {
/// * If the current `DiagInner` has multiple suggestions,
/// we leave `primary_span` and the suggestions untouched.
fn primary_span_formatted(
&mut self,
&self,
primary_span: &mut MultiSpan,
suggestions: &mut Vec<CodeSuggestion>,
fluent_args: &FluentArgs<'_>,
) {
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
.translator()
.translate_message(&sugg.msg, fluent_args)
.map_err(Report::new)
.unwrap();
if rest.is_empty()
// ^ if there is only one suggestion
// don't display multi-suggestions as labels
Expand Down Expand Up @@ -491,16 +497,6 @@ pub trait Emitter: Translate {
}
}

impl Translate for HumanEmitter {
fn fluent_bundle(&self) -> Option<&FluentBundle> {
self.fluent_bundle.as_deref()
}

fn fallback_fluent_bundle(&self) -> &FluentBundle {
&self.fallback_bundle
}
}

impl Emitter for HumanEmitter {
fn source_map(&self) -> Option<&SourceMap> {
self.sm.as_deref()
Expand Down Expand Up @@ -538,39 +534,52 @@ impl Emitter for HumanEmitter {
fn supports_color(&self) -> bool {
self.dst.supports_color()
}

fn translator(&self) -> &Translator {
&self.translator
}
}

/// An emitter that does nothing when emitting a non-fatal diagnostic.
/// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent
/// failures of rustc, as witnessed e.g. in issue #89358.
pub struct SilentEmitter {
pub struct FatalOnlyEmitter {
pub fatal_emitter: Box<dyn Emitter + DynSend>,
pub fatal_note: Option<String>,
pub emit_fatal_diagnostic: bool,
}

impl Translate for SilentEmitter {
fn fluent_bundle(&self) -> Option<&FluentBundle> {
impl Emitter for FatalOnlyEmitter {
fn source_map(&self) -> Option<&SourceMap> {
None
}

fn fallback_fluent_bundle(&self) -> &FluentBundle {
self.fatal_emitter.fallback_fluent_bundle()
fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) {
if diag.level == Level::Fatal {
if let Some(fatal_note) = &self.fatal_note {
diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
}
self.fatal_emitter.emit_diagnostic(diag, registry);
}
}

fn translator(&self) -> &Translator {
self.fatal_emitter.translator()
}
}

pub struct SilentEmitter {
pub translator: Translator,
}

impl Emitter for SilentEmitter {
fn source_map(&self) -> Option<&SourceMap> {
None
}

fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) {
if self.emit_fatal_diagnostic && diag.level == Level::Fatal {
if let Some(fatal_note) = &self.fatal_note {
diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
}
self.fatal_emitter.emit_diagnostic(diag, registry);
}
fn emit_diagnostic(&mut self, _diag: DiagInner, _registry: &Registry) {}

fn translator(&self) -> &Translator {
&self.translator
}
}

Expand Down Expand Up @@ -615,9 +624,8 @@ pub struct HumanEmitter {
#[setters(skip)]
dst: IntoDynSyncSend<Destination>,
sm: Option<Arc<SourceMap>>,
fluent_bundle: Option<Arc<FluentBundle>>,
#[setters(skip)]
fallback_bundle: LazyFallbackBundle,
translator: Translator,
short_message: bool,
ui_testing: bool,
ignored_directories_in_source_blocks: Vec<String>,
Expand All @@ -637,12 +645,11 @@ pub(crate) struct FileWithAnnotatedLines {
}

impl HumanEmitter {
pub fn new(dst: Destination, fallback_bundle: LazyFallbackBundle) -> HumanEmitter {
pub fn new(dst: Destination, translator: Translator) -> HumanEmitter {
HumanEmitter {
dst: IntoDynSyncSend(dst),
sm: None,
fluent_bundle: None,
fallback_bundle,
translator,
short_message: false,
ui_testing: false,
ignored_directories_in_source_blocks: Vec::new(),
Expand Down Expand Up @@ -1433,7 +1440,7 @@ impl HumanEmitter {
// very *weird* formats
// see?
for (text, style) in msgs.iter() {
let text = self.translate_message(text, args).map_err(Report::new).unwrap();
let text = self.translator.translate_message(text, args).map_err(Report::new).unwrap();
let text = &normalize_whitespace(&text);
let lines = text.split('\n').collect::<Vec<_>>();
if lines.len() > 1 {
Expand Down Expand Up @@ -1528,7 +1535,8 @@ impl HumanEmitter {
}
let mut line = 0;
for (text, style) in msgs.iter() {
let text = self.translate_message(text, args).map_err(Report::new).unwrap();
let text =
self.translator.translate_message(text, args).map_err(Report::new).unwrap();
// Account for newlines to align output to its label.
for text in normalize_whitespace(&text).lines() {
buffer.append(
Expand Down Expand Up @@ -1560,7 +1568,7 @@ impl HumanEmitter {
.into_iter()
.filter_map(|label| match label.label {
Some(msg) if label.is_primary => {
let text = self.translate_message(&msg, args).ok()?;
let text = self.translator.translate_message(&msg, args).ok()?;
if !text.trim().is_empty() { Some(text.to_string()) } else { None }
}
_ => None,
Expand Down Expand Up @@ -3104,7 +3112,11 @@ impl FileWithAnnotatedLines {

let label = label.as_ref().map(|m| {
normalize_whitespace(
&emitter.translate_message(m, args).map_err(Report::new).unwrap(),
&emitter
.translator()
.translate_message(m, args)
.map_err(Report::new)
.unwrap(),
)
});

Expand Down
Loading
Loading