diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index bbf9cceef2a00..c3bfe4c13cdf7 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -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}; @@ -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, @@ -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 { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index d53126d041431..daeca43169d4a 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -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`. @@ -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, @@ -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(); diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 1d3b5b20751a7..194fc2450ba47 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -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; @@ -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 FluentBundle>>; +pub type LazyFallbackBundle = + Arc 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); @@ -228,7 +228,7 @@ pub fn fallback_fluent_bundle( } fallback_bundle - })) + }))) } /// Identifier for the Fluent message/attribute corresponding to a diagnostic message. diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index f3aeb8d224b9d..2eb3c23259ffa 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -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>, - fluent_bundle: Option>, - fallback_bundle: LazyFallbackBundle, + translator: Translator, /// If true, hides the longer explanation text short_message: bool, @@ -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) { @@ -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` @@ -104,19 +96,11 @@ fn annotation_level_for_level(level: Level) -> annotate_snippets::Level { impl AnnotateSnippetEmitter { pub fn new( source_map: Option>, - fluent_bundle: Option>, - 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. @@ -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() { diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 6ab6f96079ebd..e333de4b660ba 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -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. @@ -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); @@ -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: @@ -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, 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 @@ -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() @@ -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, pub fatal_note: Option, - 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 } } @@ -615,9 +624,8 @@ pub struct HumanEmitter { #[setters(skip)] dst: IntoDynSyncSend, sm: Option>, - fluent_bundle: Option>, #[setters(skip)] - fallback_bundle: LazyFallbackBundle, + translator: Translator, short_message: bool, ui_testing: bool, ignored_directories_in_source_blocks: Vec, @@ -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(), @@ -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::>(); if lines.len() > 1 { @@ -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( @@ -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, @@ -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(), ) }); diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index d67e2ba2d60ec..6d600f896a0f0 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -32,11 +32,8 @@ use crate::emitter::{ }; use crate::registry::Registry; use crate::timings::{TimingRecord, TimingSection}; -use crate::translation::{Translate, to_fluent_args}; -use crate::{ - CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, Suggestions, - TerminalUrl, -}; +use crate::translation::{Translator, to_fluent_args}; +use crate::{CodeSuggestion, MultiSpan, SpanLabel, Subdiag, Suggestions, TerminalUrl}; #[cfg(test)] mod tests; @@ -47,9 +44,8 @@ pub struct JsonEmitter { dst: IntoDynSyncSend>, #[setters(skip)] sm: Option>, - fluent_bundle: Option>, #[setters(skip)] - fallback_bundle: LazyFallbackBundle, + translator: Translator, #[setters(skip)] pretty: bool, ui_testing: bool, @@ -67,7 +63,7 @@ impl JsonEmitter { pub fn new( dst: Box, sm: Option>, - fallback_bundle: LazyFallbackBundle, + translator: Translator, pretty: bool, json_rendered: HumanReadableErrorType, color_config: ColorConfig, @@ -75,8 +71,7 @@ impl JsonEmitter { JsonEmitter { dst: IntoDynSyncSend(dst), sm, - fluent_bundle: None, - fallback_bundle, + translator, pretty, ui_testing: false, ignored_directories_in_source_blocks: Vec::new(), @@ -110,16 +105,6 @@ enum EmitTyped<'a> { UnusedExtern(UnusedExterns<'a>), } -impl Translate for JsonEmitter { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - self.fluent_bundle.as_deref() - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &self.fallback_bundle - } -} - impl Emitter for JsonEmitter { fn emit_diagnostic(&mut self, diag: crate::DiagInner, registry: &Registry) { let data = Diagnostic::from_errors_diagnostic(diag, self, registry); @@ -194,6 +179,10 @@ impl Emitter for JsonEmitter { fn should_show_explain(&self) -> bool { !self.json_rendered.short() } + + fn translator(&self) -> &Translator { + &self.translator + } } // The following data types are provided just for serialisation. @@ -324,7 +313,7 @@ impl Diagnostic { let args = to_fluent_args(diag.args.iter()); let sugg_to_diag = |sugg: &CodeSuggestion| { let translated_message = - je.translate_message(&sugg.msg, &args).map_err(Report::new).unwrap(); + je.translator.translate_message(&sugg.msg, &args).map_err(Report::new).unwrap(); Diagnostic { message: translated_message.to_string(), code: None, @@ -368,7 +357,7 @@ impl Diagnostic { } } - let translated_message = je.translate_messages(&diag.messages, &args); + let translated_message = je.translator.translate_messages(&diag.messages, &args); let code = if let Some(code) = diag.code { Some(DiagnosticCode { @@ -396,10 +385,9 @@ impl Diagnostic { ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)), ColorConfig::Never => {} } - HumanEmitter::new(dst, Arc::clone(&je.fallback_bundle)) + HumanEmitter::new(dst, je.translator.clone()) .short_message(short) .sm(je.sm.clone()) - .fluent_bundle(je.fluent_bundle.clone()) .diagnostic_width(je.diagnostic_width) .macro_backtrace(je.macro_backtrace) .track_diagnostics(je.track_diagnostics) @@ -430,7 +418,7 @@ impl Diagnostic { args: &FluentArgs<'_>, je: &JsonEmitter, ) -> Diagnostic { - let translated_message = je.translate_messages(&subdiag.messages, args); + let translated_message = je.translator.translate_messages(&subdiag.messages, args); Diagnostic { message: translated_message.to_string(), code: None, @@ -454,7 +442,7 @@ impl DiagnosticSpan { span.is_primary, span.label .as_ref() - .map(|m| je.translate_message(m, args).unwrap()) + .map(|m| je.translator.translate_message(m, args).unwrap()) .map(|m| m.to_string()), suggestion, je, diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index 40973e8e5d8a4..8cf81f467d84c 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -41,14 +41,14 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { rustc_span::create_default_session_globals_then(|| { let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned()); - let fallback_bundle = - crate::fallback_fluent_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); + let translator = + Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); let output = Arc::new(Mutex::new(Vec::new())); let je = JsonEmitter::new( Box::new(Shared { data: output.clone() }), Some(sm), - fallback_bundle, + translator, true, // pretty HumanReadableErrorType::Short, ColorConfig::Never, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 0bd259366def7..207aed8c75545 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -748,40 +748,10 @@ impl DiagCtxt { Self { inner: Lock::new(DiagCtxtInner::new(emitter)) } } - pub fn make_silent(&self, fatal_note: Option, emit_fatal_diagnostic: bool) { - // An empty type that implements `Emitter` to temporarily swap in place of the real one, - // which will be used in constructing its replacement. - struct FalseEmitter; - - impl Emitter for FalseEmitter { - fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) { - unimplemented!("false emitter must only used during `make_silent`") - } - - fn source_map(&self) -> Option<&SourceMap> { - unimplemented!("false emitter must only used during `make_silent`") - } - } - - impl translation::Translate for FalseEmitter { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - unimplemented!("false emitter must only used during `make_silent`") - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - unimplemented!("false emitter must only used during `make_silent`") - } - } - + pub fn make_silent(&self) { let mut inner = self.inner.borrow_mut(); - let mut prev_emitter = Box::new(FalseEmitter) as Box; - std::mem::swap(&mut inner.emitter, &mut prev_emitter); - let new_emitter = Box::new(emitter::SilentEmitter { - fatal_emitter: prev_emitter, - fatal_note, - emit_fatal_diagnostic, - }); - inner.emitter = new_emitter; + let translator = inner.emitter.translator().clone(); + inner.emitter = Box::new(emitter::SilentEmitter { translator }); } pub fn set_emitter(&self, emitter: Box) { @@ -1771,7 +1741,12 @@ impl DiagCtxtInner { args: impl Iterator>, ) -> String { let args = crate::translation::to_fluent_args(args); - self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string() + self.emitter + .translator() + .translate_message(&message, &args) + .map_err(Report::new) + .unwrap() + .to_string() } fn eagerly_translate_for_subdiag( diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index 376fd24d57bab..34ebac0fde11b 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, LazyLock}; + use rustc_data_structures::sync::IntoDynSyncSend; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; use rustc_error_messages::{DiagMessage, langid}; @@ -5,23 +7,9 @@ use rustc_error_messages::{DiagMessage, langid}; use crate::FluentBundle; use crate::error::{TranslateError, TranslateErrorKind}; use crate::fluent_bundle::*; -use crate::translation::Translate; - -struct Dummy { - bundle: FluentBundle, -} - -impl Translate for Dummy { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - None - } +use crate::translation::Translator; - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &self.bundle - } -} - -fn make_dummy(ftl: &'static str) -> Dummy { +fn make_translator(ftl: &'static str) -> Translator { let resource = FluentResource::try_new(ftl.into()).expect("Failed to parse an FTL string."); let langid_en = langid!("en-US"); @@ -33,12 +21,15 @@ fn make_dummy(ftl: &'static str) -> Dummy { bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle."); - Dummy { bundle } + Translator { + fluent_bundle: None, + fallback_fluent_bundle: Arc::new(LazyLock::new(Box::new(|| bundle))), + } } #[test] fn wellformed_fluent() { - let dummy = make_dummy("mir_build_borrow_of_moved_value = borrow of moved value + let translator = make_translator("mir_build_borrow_of_moved_value = borrow of moved value .label = value moved into `{$name}` here .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait .value_borrowed_label = value borrowed here after move @@ -54,7 +45,7 @@ fn wellformed_fluent() { ); assert_eq!( - dummy.translate_message(&message, &args).unwrap(), + translator.translate_message(&message, &args).unwrap(), "borrow this binding in the pattern to avoid moving the value" ); } @@ -66,7 +57,7 @@ fn wellformed_fluent() { ); assert_eq!( - dummy.translate_message(&message, &args).unwrap(), + translator.translate_message(&message, &args).unwrap(), "value borrowed here after move" ); } @@ -78,7 +69,7 @@ fn wellformed_fluent() { ); assert_eq!( - dummy.translate_message(&message, &args).unwrap(), + translator.translate_message(&message, &args).unwrap(), "move occurs because `\u{2068}Foo\u{2069}` has type `\u{2068}std::string::String\u{2069}` which does not implement the `Copy` trait" ); @@ -89,7 +80,7 @@ fn wellformed_fluent() { ); assert_eq!( - dummy.translate_message(&message, &args).unwrap(), + translator.translate_message(&message, &args).unwrap(), "value moved into `\u{2068}Foo\u{2069}` here" ); } @@ -98,7 +89,7 @@ fn wellformed_fluent() { #[test] fn misformed_fluent() { - let dummy = make_dummy("mir_build_borrow_of_moved_value = borrow of moved value + let translator = make_translator("mir_build_borrow_of_moved_value = borrow of moved value .label = value moved into `{name}` here .occurs_because_label = move occurs because `{$oops}` has type `{$ty}` which does not implement the `Copy` trait .suggestion = borrow this binding in the pattern to avoid moving the value"); @@ -112,7 +103,7 @@ fn misformed_fluent() { Some("value_borrowed_label".into()), ); - let err = dummy.translate_message(&message, &args).unwrap_err(); + let err = translator.translate_message(&message, &args).unwrap_err(); assert!( matches!( &err, @@ -141,7 +132,7 @@ fn misformed_fluent() { Some("label".into()), ); - let err = dummy.translate_message(&message, &args).unwrap_err(); + let err = translator.translate_message(&message, &args).unwrap_err(); if let TranslateError::Two { primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, @@ -168,7 +159,7 @@ fn misformed_fluent() { Some("occurs_because_label".into()), ); - let err = dummy.translate_message(&message, &args).unwrap_err(); + let err = translator.translate_message(&message, &args).unwrap_err(); if let TranslateError::Two { primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index 156f5e5d26e64..c0bcec093c7ee 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -1,8 +1,9 @@ use std::borrow::Cow; use std::env; use std::error::Report; +use std::sync::Arc; -pub use rustc_error_messages::FluentArgs; +pub use rustc_error_messages::{FluentArgs, LazyFallbackBundle}; use tracing::{debug, trace}; use crate::error::{TranslateError, TranslateErrorKind}; @@ -28,19 +29,33 @@ pub fn to_fluent_args<'iter>(iter: impl Iterator>) -> Flue args } -pub trait Translate { - /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no - /// language was requested by the user then this will be `None` and `fallback_fluent_bundle` - /// should be used. - fn fluent_bundle(&self) -> Option<&FluentBundle>; - +#[derive(Clone)] +pub struct Translator { + /// Localized diagnostics for the locale requested by the user. If no language was requested by + /// the user then this will be `None` and `fallback_fluent_bundle` should be used. + pub fluent_bundle: Option>, /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler. /// Used when the user has not requested a specific language or when a localized diagnostic is /// unavailable for the requested locale. - fn fallback_fluent_bundle(&self) -> &FluentBundle; + pub fallback_fluent_bundle: LazyFallbackBundle, +} + +impl Translator { + pub fn with_fallback_bundle( + resources: Vec<&'static str>, + with_directionality_markers: bool, + ) -> Translator { + Translator { + fluent_bundle: None, + fallback_fluent_bundle: crate::fallback_fluent_bundle( + resources, + with_directionality_markers, + ), + } + } /// Convert `DiagMessage`s to a string, performing translation if necessary. - fn translate_messages( + pub fn translate_messages( &self, messages: &[(DiagMessage, Style)], args: &FluentArgs<'_>, @@ -54,7 +69,7 @@ pub trait Translate { } /// Convert a `DiagMessage` to a string, performing translation if necessary. - fn translate_message<'a>( + pub fn translate_message<'a>( &'a self, message: &'a DiagMessage, args: &'a FluentArgs<'_>, @@ -91,7 +106,7 @@ pub trait Translate { }; try { - match self.fluent_bundle().map(|b| translate_with_bundle(b)) { + match self.fluent_bundle.as_ref().map(|b| translate_with_bundle(b)) { // The primary bundle was present and translation succeeded Some(Ok(t)) => t, @@ -102,7 +117,7 @@ pub trait Translate { primary @ TranslateError::One { kind: TranslateErrorKind::MessageMissing, .. }, - )) => translate_with_bundle(self.fallback_fluent_bundle()) + )) => translate_with_bundle(&self.fallback_fluent_bundle) .map_err(|fallback| primary.and(fallback))?, // Always yeet out for errors on debug (unless @@ -118,11 +133,11 @@ pub trait Translate { // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so // just hide it and try with the fallback bundle. - Some(Err(primary)) => translate_with_bundle(self.fallback_fluent_bundle()) + Some(Err(primary)) => translate_with_bundle(&self.fallback_fluent_bundle) .map_err(|fallback| primary.and(fallback))?, // The primary bundle is missing, proceed to the fallback bundle - None => translate_with_bundle(self.fallback_fluent_bundle()) + None => translate_with_bundle(&self.fallback_fluent_bundle) .map_err(|fallback| TranslateError::primary(identifier, args).and(fallback))?, } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index e824e9d4aa91c..d62bf7f85e0e6 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -52,10 +52,9 @@ pub struct Compiler { pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec) -> Cfg { cfgs.into_iter() .map(|s| { - let psess = ParseSess::with_silent_emitter( + let psess = ParseSess::with_fatal_emitter( vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], format!("this error occurred on the command line: `--cfg={s}`"), - true, ); let filename = FileName::cfg_spec_source_code(&s); @@ -116,10 +115,9 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() }; for s in specs { - let psess = ParseSess::with_silent_emitter( + let psess = ParseSess::with_fatal_emitter( vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], format!("this error occurred on the command line: `--check-cfg={s}`"), - true, ); let filename = FileName::cfg_spec_source_code(&s); diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 2a44c90abc177..15679d23bc565 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -14,6 +14,7 @@ use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, Toke use rustc_ast::{self as ast, PatKind, visit}; use rustc_ast_pretty::pprust::item_to_string; use rustc_errors::emitter::{HumanEmitter, OutputTheme}; +use rustc_errors::translation::Translator; use rustc_errors::{DiagCtxt, MultiSpan, PResult}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; @@ -41,9 +42,8 @@ fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { fn create_test_handler(theme: OutputTheme) -> (DiagCtxt, Arc, Arc>>) { let output = Arc::new(Mutex::new(Vec::new())); let source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); - let mut emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), fallback_bundle) + let translator = Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); + let mut emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), translator) .sm(Some(source_map.clone())) .diagnostic_width(Some(140)); emitter = emitter.theme(theme); diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 87c848cf857f8..0118cdb1fc274 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -8,10 +8,11 @@ use rustc_ast::attr::AttrIdGenerator; use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock}; -use rustc_errors::emitter::{HumanEmitter, SilentEmitter, stderr_destination}; +use rustc_errors::emitter::{FatalOnlyEmitter, HumanEmitter, stderr_destination}; +use rustc_errors::translation::Translator; use rustc_errors::{ ColorConfig, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, EmissionGuarantee, MultiSpan, - StashKey, fallback_fluent_bundle, + StashKey, }; use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue}; use rustc_span::edition::Edition; @@ -242,10 +243,10 @@ pub struct ParseSess { impl ParseSess { /// Used for testing. pub fn new(locale_resources: Vec<&'static str>) -> Self { - let fallback_bundle = fallback_fluent_bundle(locale_resources, false); + let translator = Translator::with_fallback_bundle(locale_resources, false); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new( - HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle) + HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator) .sm(Some(Arc::clone(&sm))), ); let dcx = DiagCtxt::new(emitter); @@ -274,19 +275,14 @@ impl ParseSess { } } - pub fn with_silent_emitter( - locale_resources: Vec<&'static str>, - fatal_note: String, - emit_fatal_diagnostic: bool, - ) -> Self { - let fallback_bundle = fallback_fluent_bundle(locale_resources, false); + pub fn with_fatal_emitter(locale_resources: Vec<&'static str>, fatal_note: String) -> Self { + let translator = Translator::with_fallback_bundle(locale_resources, false); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let fatal_emitter = - Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle)); - let dcx = DiagCtxt::new(Box::new(SilentEmitter { + Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator)); + let dcx = DiagCtxt::new(Box::new(FatalOnlyEmitter { fatal_emitter, fatal_note: Some(fatal_note), - emit_fatal_diagnostic, })) .disable_warnings(); ParseSess::with_dcx(dcx, sm) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ca42c5a425660..ad58c3c8f7d8b 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -19,9 +19,10 @@ use rustc_errors::emitter::{ }; use rustc_errors::json::JsonEmitter; use rustc_errors::timings::TimingSectionHandler; +use rustc_errors::translation::Translator; use rustc_errors::{ Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort, - FluentBundle, LazyFallbackBundle, TerminalUrl, fallback_fluent_bundle, + TerminalUrl, fallback_fluent_bundle, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -948,8 +949,7 @@ impl Session { fn default_emitter( sopts: &config::Options, source_map: Arc, - bundle: Option>, - fallback_bundle: LazyFallbackBundle, + translator: Translator, ) -> Box { let macro_backtrace = sopts.unstable_opts.macro_backtrace; let track_diagnostics = sopts.unstable_opts.track_diagnostics; @@ -974,17 +974,11 @@ fn default_emitter( let short = kind.short(); if let HumanReadableErrorType::AnnotateSnippet = kind { - let emitter = AnnotateSnippetEmitter::new( - source_map, - bundle, - fallback_bundle, - short, - macro_backtrace, - ); + let emitter = + AnnotateSnippetEmitter::new(source_map, translator, short, macro_backtrace); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } else { - let emitter = HumanEmitter::new(stderr_destination(color_config), fallback_bundle) - .fluent_bundle(bundle) + let emitter = HumanEmitter::new(stderr_destination(color_config), translator) .sm(source_map) .short_message(short) .diagnostic_width(sopts.diagnostic_width) @@ -1006,12 +1000,11 @@ fn default_emitter( JsonEmitter::new( Box::new(io::BufWriter::new(io::stderr())), source_map, - fallback_bundle, + translator, pretty, json_rendered, color_config, ) - .fluent_bundle(bundle) .ui_testing(sopts.unstable_opts.ui_testing) .ignored_directories_in_source_blocks( sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(), @@ -1030,7 +1023,7 @@ fn default_emitter( pub fn build_session( sopts: config::Options, io: CompilerIO, - bundle: Option>, + fluent_bundle: Option>, registry: rustc_errors::registry::Registry, fluent_resources: Vec<&'static str>, driver_lint_caps: FxHashMap, @@ -1052,12 +1045,15 @@ pub fn build_session( let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow); let can_emit_warnings = !(warnings_allow || cap_lints_allow); - let fallback_bundle = fallback_fluent_bundle( - fluent_resources, - sopts.unstable_opts.translate_directionality_markers, - ); + let translator = Translator { + fluent_bundle, + fallback_fluent_bundle: fallback_fluent_bundle( + fluent_resources, + sopts.unstable_opts.translate_directionality_markers, + ), + }; let source_map = rustc_span::source_map::get_source_map().unwrap(); - let emitter = default_emitter(&sopts, Arc::clone(&source_map), bundle, fallback_bundle); + let emitter = default_emitter(&sopts, Arc::clone(&source_map), translator); let mut dcx = DiagCtxt::new(emitter) .with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings)) @@ -1500,13 +1496,13 @@ impl EarlyDiagCtxt { fn mk_emitter(output: ErrorOutputType) -> Box { // FIXME(#100717): early errors aren't translated at the moment, so this is fine, but it will // need to reference every crate that might emit an early error for translation to work. - let fallback_bundle = - fallback_fluent_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false); + let translator = + Translator::with_fallback_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false); let emitter: Box = match output { config::ErrorOutputType::HumanReadable { kind, color_config } => { let short = kind.short(); Box::new( - HumanEmitter::new(stderr_destination(color_config), fallback_bundle) + HumanEmitter::new(stderr_destination(color_config), translator) .theme(if let HumanReadableErrorType::Unicode = kind { OutputTheme::Unicode } else { @@ -1519,7 +1515,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box { Box::new(JsonEmitter::new( Box::new(io::BufWriter::new(io::stderr())), Some(Arc::new(SourceMap::new(FilePathMapping::empty()))), - fallback_bundle, + translator, pretty, json_rendered, color_config, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 204f8decffcc0..3b1d89bbecd9d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -149,15 +149,12 @@ pub(crate) fn new_dcx( diagnostic_width: Option, unstable_opts: &UnstableOptions, ) -> rustc_errors::DiagCtxt { - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); + let translator = rustc_driver::default_translator(); let emitter: Box = match error_format { ErrorOutputType::HumanReadable { kind, color_config } => { let short = kind.short(); Box::new( - HumanEmitter::new(stderr_destination(color_config), fallback_bundle) + HumanEmitter::new(stderr_destination(color_config), translator) .sm(source_map.map(|sm| sm as _)) .short_message(short) .diagnostic_width(diagnostic_width) @@ -178,7 +175,7 @@ pub(crate) fn new_dcx( JsonEmitter::new( Box::new(io::BufWriter::new(io::stderr())), Some(source_map), - fallback_bundle, + translator, pretty, json_rendered, color_config, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 3ff6828e52f96..f229f77c97846 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -456,16 +456,13 @@ fn parse_source( let filename = FileName::anon_source_code(&wrapped_source); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); + let translator = rustc_driver::default_translator(); info.supports_color = - HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle.clone()) + HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator.clone()) .supports_color(); // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that the parser emits directly into a `Sink` instead of stderr. - let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle); + let emitter = HumanEmitter::new(Box::new(io::sink()), translator); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 9662dd85d678b..91cddbe5a5bc7 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -6,8 +6,8 @@ use std::sync::Arc; use rustc_data_structures::sync::Lock; use rustc_errors::emitter::Emitter; use rustc_errors::registry::Registry; -use rustc_errors::translation::{Translate, to_fluent_args}; -use rustc_errors::{Applicability, DiagCtxt, DiagInner, LazyFallbackBundle}; +use rustc_errors::translation::{Translator, to_fluent_args}; +use rustc_errors::{Applicability, DiagCtxt, DiagInner}; use rustc_parse::{source_str_to_stream, unwrap_or_emit_fatal}; use rustc_resolve::rustdoc::source_span_for_markdown_range; use rustc_session::parse::ParseSess; @@ -36,11 +36,8 @@ fn check_rust_syntax( code_block: RustCodeBlock, ) { let buffer = Arc::new(Lock::new(Buffer::default())); - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); - let emitter = BufferEmitter { buffer: Arc::clone(&buffer), fallback_bundle }; + let translator = rustc_driver::default_translator(); + let emitter = BufferEmitter { buffer: Arc::clone(&buffer), translator }; let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); @@ -149,17 +146,7 @@ struct Buffer { struct BufferEmitter { buffer: Arc>, - fallback_bundle: LazyFallbackBundle, -} - -impl Translate for BufferEmitter { - fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { - None - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - &self.fallback_bundle - } + translator: Translator, } impl Emitter for BufferEmitter { @@ -168,6 +155,7 @@ impl Emitter for BufferEmitter { let fluent_args = to_fluent_args(diag.args.iter()); let translated_main_message = self + .translator .translate_message(&diag.messages[0].0, &fluent_args) .unwrap_or_else(|e| panic!("{e}")); @@ -180,4 +168,8 @@ impl Emitter for BufferEmitter { fn source_map(&self) -> Option<&SourceMap> { None } + + fn translator(&self) -> &Translator { + &self.translator + } } diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index ec4538039a918..7ba11c20f456b 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -42,9 +42,8 @@ pub fn check( let mut test_attr_spans = vec![]; let filename = FileName::anon_source_code(&code); - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); - let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle); + let translator = rustc_driver::default_translator(); + let emitter = HumanEmitter::new(Box::new(io::sink()), translator); let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); #[expect(clippy::arc_with_non_send_sync)] // `Arc` is expected by with_dcx let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index afd847f951576..10e2809e58bf4 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination}; use rustc_errors::registry::Registry; -use rustc_errors::translation::Translate; +use rustc_errors::translation::Translator; use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel}; use rustc_session::parse::ParseSess as RawParseSess; use rustc_span::{ @@ -47,16 +47,6 @@ impl SilentOnIgnoredFilesEmitter { } } -impl Translate for SilentOnIgnoredFilesEmitter { - fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { - self.emitter.fluent_bundle() - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - self.emitter.fallback_fluent_bundle() - } -} - impl Emitter for SilentOnIgnoredFilesEmitter { fn source_map(&self) -> Option<&SourceMap> { None @@ -84,6 +74,10 @@ impl Emitter for SilentOnIgnoredFilesEmitter { } self.handle_non_ignoreable_error(diag, registry); } + + fn translator(&self) -> &Translator { + self.emitter.translator() + } } impl From for ColorConfig { @@ -110,23 +104,15 @@ fn default_dcx( ColorConfig::Never }; - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); - let emitter = Box::new( - HumanEmitter::new(stderr_destination(emit_color), fallback_bundle) - .sm(Some(source_map.clone())), - ); - - let emitter: Box = if !show_parse_errors { - Box::new(SilentEmitter { - fatal_emitter: emitter, - fatal_note: None, - emit_fatal_diagnostic: false, - }) + let translator = rustc_driver::default_translator(); + + let emitter: Box = if show_parse_errors { + Box::new( + HumanEmitter::new(stderr_destination(emit_color), translator) + .sm(Some(source_map.clone())), + ) } else { - emitter + Box::new(SilentEmitter { translator }) }; DiagCtxt::new(Box::new(SilentOnIgnoredFilesEmitter { has_non_ignorable_parser_errors: false, @@ -205,7 +191,7 @@ impl ParseSess { } pub(crate) fn set_silent_emitter(&mut self) { - self.raw_psess.dcx().make_silent(None, false); + self.raw_psess.dcx().make_silent(); } pub(crate) fn span_to_filename(&self, span: Span) -> FileName { @@ -335,16 +321,6 @@ mod tests { num_emitted_errors: Arc, } - impl Translate for TestEmitter { - fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { - None - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - panic!("test emitter attempted to translate a diagnostic"); - } - } - impl Emitter for TestEmitter { fn source_map(&self) -> Option<&SourceMap> { None @@ -353,6 +329,10 @@ mod tests { fn emit_diagnostic(&mut self, _diag: DiagInner, _registry: &Registry) { self.num_emitted_errors.fetch_add(1, Ordering::Release); } + + fn translator(&self) -> &Translator { + panic!("test emitter attempted to translate a diagnostic"); + } } fn build_diagnostic(level: DiagnosticLevel, span: Option) -> DiagInner {