diff --git a/Cargo.lock b/Cargo.lock index 1a930b64f4581..333ed33e231bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3808,7 +3808,6 @@ name = "rustc_error_messages" version = "0.0.0" dependencies = [ "fluent-bundle", - "fluent-syntax", "icu_list", "icu_locale", "intl-memoizer", @@ -3819,7 +3818,6 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", - "tracing", "unic-langid", ] diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 444f7877689fc..7f82cca4554b4 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -12,7 +12,6 @@ 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::Translator; use rustc_errors::{ Diag, DiagArgMap, DiagCtxt, DiagCtxtHandle, DiagMessage, ErrCode, FatalError, FatalErrorMarker, Level, MultiSpan, Style, Suggestions, catch_fatal_errors, @@ -2010,10 +2009,6 @@ 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 a235d3e0aecdd..fc46102f6a30f 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -34,7 +34,6 @@ use rustc_data_structures::profiling::{ }; pub use rustc_errors::catch_fatal_errors; use rustc_errors::emitter::stderr_destination; -use rustc_errors::translation::Translator; use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, PResult, markdown}; use rustc_feature::find_gated_cfg; // This avoids a false positive with `-Wunused_crate_dependencies`. @@ -107,10 +106,6 @@ use crate::session_diagnostics::{ RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead, UnstableFeatureUsage, }; -pub fn default_translator() -> Translator { - Translator::new() -} - /// Exit status code used for successful compilation and help output. pub const EXIT_SUCCESS: i32 = 0; @@ -1525,11 +1520,9 @@ fn report_ice( extra_info: fn(&DiagCtxt), using_internal_features: &AtomicBool, ) { - let translator = Translator::new(); let emitter = Box::new(rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter::new( stderr_destination(rustc_errors::ColorConfig::Auto), - translator, )); let dcx = rustc_errors::DiagCtxt::new(emitter); let dcx = dcx.handle(); diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index db22e065907e3..f280aaff11260 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -6,7 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start fluent-bundle = "0.16" -fluent-syntax = "0.12" icu_list = { version = "2.0", default-features = false, features = ["alloc"] } icu_locale = { version = "2.0", default-features = false } intl-memoizer = "0.5.1" @@ -17,6 +16,5 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } -tracing = "0.1" unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 0b30102eb992b..583ca36f07130 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -4,194 +4,16 @@ // tidy-alphabetical-end use std::borrow::Cow; -use std::error::Error; -use std::path::Path; -use std::sync::{Arc, LazyLock}; -use std::{fmt, fs, io}; -use fluent_bundle::FluentResource; pub use fluent_bundle::types::FluentType; pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue}; -use fluent_syntax::parser::ParserError; -use intl_memoizer::concurrent::IntlLangMemoizer; -use rustc_data_structures::sync::{DynSend, IntoDynSyncSend}; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; -use tracing::{instrument, trace}; pub use unic_langid::{LanguageIdentifier, langid}; mod diagnostic_impls; pub use diagnostic_impls::DiagArgFromDisplay; -pub type FluentBundle = - IntoDynSyncSend>; - -fn new_bundle(locales: Vec) -> FluentBundle { - IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new_concurrent(locales)) -} - -#[derive(Debug)] -pub enum TranslationBundleError { - /// Failed to read from `.ftl` file. - ReadFtl(io::Error), - /// Failed to parse contents of `.ftl` file. - ParseFtl(ParserError), - /// Failed to add `FluentResource` to `FluentBundle`. - AddResource(FluentError), - /// `$sysroot/share/locale/$locale` does not exist. - MissingLocale, - /// Cannot read directory entries of `$sysroot/share/locale/$locale`. - ReadLocalesDir(io::Error), - /// Cannot read directory entry of `$sysroot/share/locale/$locale`. - ReadLocalesDirEntry(io::Error), - /// `$sysroot/share/locale/$locale` is not a directory. - LocaleIsNotDir, -} - -impl fmt::Display for TranslationBundleError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TranslationBundleError::ReadFtl(e) => write!(f, "could not read ftl file: {e}"), - TranslationBundleError::ParseFtl(e) => { - write!(f, "could not parse ftl file: {e}") - } - TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {e}"), - TranslationBundleError::MissingLocale => write!(f, "missing locale directory"), - TranslationBundleError::ReadLocalesDir(e) => { - write!(f, "could not read locales dir: {e}") - } - TranslationBundleError::ReadLocalesDirEntry(e) => { - write!(f, "could not read locales dir entry: {e}") - } - TranslationBundleError::LocaleIsNotDir => { - write!(f, "`$sysroot/share/locales/$locale` is not a directory") - } - } - } -} - -impl Error for TranslationBundleError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - TranslationBundleError::ReadFtl(e) => Some(e), - TranslationBundleError::ParseFtl(e) => Some(e), - TranslationBundleError::AddResource(e) => Some(e), - TranslationBundleError::MissingLocale => None, - TranslationBundleError::ReadLocalesDir(e) => Some(e), - TranslationBundleError::ReadLocalesDirEntry(e) => Some(e), - TranslationBundleError::LocaleIsNotDir => None, - } - } -} - -impl From<(FluentResource, Vec)> for TranslationBundleError { - fn from((_, mut errs): (FluentResource, Vec)) -> Self { - TranslationBundleError::ParseFtl(errs.pop().expect("failed ftl parse with no errors")) - } -} - -impl From> for TranslationBundleError { - fn from(mut errs: Vec) -> Self { - TranslationBundleError::AddResource( - errs.pop().expect("failed adding resource to bundle with no errors"), - ) - } -} - -/// Returns Fluent bundle with the user's locale resources from -/// `$sysroot/share/locale/$requested_locale/*.ftl`. -/// -/// If `-Z additional-ftl-path` was provided, load that resource and add it to the bundle -/// (overriding any conflicting messages). -#[instrument(level = "trace")] -pub fn fluent_bundle( - sysroot_candidates: &[&Path], - requested_locale: Option, - additional_ftl_path: Option<&Path>, - with_directionality_markers: bool, -) -> Result>, TranslationBundleError> { - if requested_locale.is_none() && additional_ftl_path.is_none() { - return Ok(None); - } - - let fallback_locale = langid!("en-US"); - let requested_fallback_locale = requested_locale.as_ref() == Some(&fallback_locale); - trace!(?requested_fallback_locale); - if requested_fallback_locale && additional_ftl_path.is_none() { - return Ok(None); - } - // If there is only `-Z additional-ftl-path`, assume locale is "en-US", otherwise use user - // provided locale. - let locale = requested_locale.clone().unwrap_or(fallback_locale); - trace!(?locale); - let mut bundle = new_bundle(vec![locale]); - - // Add convenience functions available to ftl authors. - register_functions(&mut bundle); - - // Fluent diagnostics can insert directionality isolation markers around interpolated variables - // indicating that there may be a shift from right-to-left to left-to-right text (or - // vice-versa). These are disabled because they are sometimes visible in the error output, but - // may be worth investigating in future (for example: if type names are left-to-right and the - // surrounding diagnostic messages are right-to-left, then these might be helpful). - bundle.set_use_isolating(with_directionality_markers); - - // If the user requests the default locale then don't try to load anything. - if let Some(requested_locale) = requested_locale { - let mut found_resources = false; - for sysroot in sysroot_candidates { - let mut sysroot = sysroot.to_path_buf(); - sysroot.push("share"); - sysroot.push("locale"); - sysroot.push(requested_locale.to_string()); - trace!(?sysroot); - - if !sysroot.exists() { - trace!("skipping"); - continue; - } - - if !sysroot.is_dir() { - return Err(TranslationBundleError::LocaleIsNotDir); - } - - for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? { - let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?; - let path = entry.path(); - trace!(?path); - if path.extension().and_then(|s| s.to_str()) != Some("ftl") { - trace!("skipping"); - continue; - } - - let resource_str = - fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?; - let resource = - FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?; - trace!(?resource); - bundle.add_resource(resource).map_err(TranslationBundleError::from)?; - found_resources = true; - } - } - - if !found_resources { - return Err(TranslationBundleError::MissingLocale); - } - } - - if let Some(additional_ftl_path) = additional_ftl_path { - let resource_str = - fs::read_to_string(additional_ftl_path).map_err(TranslationBundleError::ReadFtl)?; - let resource = - FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?; - trace!(?resource); - bundle.add_resource_overriding(resource); - } - - let bundle = Arc::new(bundle); - Ok(Some(bundle)) -} - pub fn register_functions(bundle: &mut fluent_bundle::bundle::FluentBundle) { bundle .add_function("STREQ", |positional, _named| match positional { @@ -201,35 +23,6 @@ pub fn register_functions(bundle: &mut fluent_bundle::bundle::FluentBundle .expect("Failed to add a function to the bundle."); } -/// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily -/// evaluated fluent bundle. -pub type LazyFallbackBundle = - Arc FluentBundle + DynSend>>>; - -/// Return the default `FluentBundle` with standard "en-US" diagnostic messages. -#[instrument(level = "trace", skip(resources))] -pub fn fallback_fluent_bundle( - resources: Vec<&'static str>, - with_directionality_markers: bool, -) -> LazyFallbackBundle { - Arc::new(LazyLock::new(Box::new(move || { - let mut fallback_bundle = new_bundle(vec![langid!("en-US")]); - - register_functions(&mut fallback_bundle); - - // See comment in `fluent_bundle`. - fallback_bundle.set_use_isolating(with_directionality_markers); - - for resource in resources { - let resource = FluentResource::try_new(resource.to_string()) - .expect("failed to parse fallback fluent resource"); - fallback_bundle.add_resource_overriding(resource); - } - - fallback_bundle - }))) -} - /// Abstraction over a message in a diagnostic to support both translatable and non-translatable /// diagnostic messages. /// diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index bdd3266adb66d..b68b5e87df1db 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -27,7 +27,7 @@ use crate::emitter::{ ConfusionType, Destination, MAX_SUGGESTIONS, OutputTheme, detect_confusion_type, is_different, normalize_whitespace, should_show_source_code, }; -use crate::translation::{Translator, to_fluent_args}; +use crate::translation::{format_diag_message, format_diag_messages, to_fluent_args}; use crate::{ CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, Level, MultiSpan, Style, Subdiag, SuggestionStyle, TerminalUrl, @@ -39,8 +39,6 @@ pub struct AnnotateSnippetEmitter { #[setters(skip)] dst: IntoDynSyncSend, sm: Option>, - #[setters(skip)] - translator: Translator, short_message: bool, ui_testing: bool, ignored_directories_in_source_blocks: Vec, @@ -108,10 +106,6 @@ impl Emitter for AnnotateSnippetEmitter { !self.short_message } - fn translator(&self) -> &Translator { - &self.translator - } - fn supports_color(&self) -> bool { false } @@ -133,11 +127,10 @@ fn annotation_level_for_level(level: Level) -> annotate_snippets::level::Level<' } impl AnnotateSnippetEmitter { - pub fn new(dst: Destination, translator: Translator) -> Self { + pub fn new(dst: Destination) -> Self { Self { dst: IntoDynSyncSend(dst), sm: None, - translator, short_message: false, ui_testing: false, ignored_directories_in_source_blocks: Vec::new(), @@ -169,7 +162,7 @@ impl AnnotateSnippetEmitter { .clone() .secondary_title(Cow::Owned(self.pre_style_msgs(msgs, *level, args))) } else { - annotation_level.clone().primary_title(self.translator.translate_messages(msgs, args)) + annotation_level.clone().primary_title(format_diag_messages(msgs, args)) }; if let Some(c) = code { @@ -185,7 +178,7 @@ impl AnnotateSnippetEmitter { // If we don't have span information, emit and exit let Some(sm) = self.sm.as_ref() else { group = group.elements(children.iter().map(|c| { - let msg = self.translator.translate_messages(&c.messages, args).to_string(); + let msg = format_diag_messages(&c.messages, args).to_string(); let level = annotation_level_for_level(c.level); level.message(msg) })); @@ -202,7 +195,7 @@ impl AnnotateSnippetEmitter { return; }; - let mut file_ann = collect_annotations(args, msp, sm, &self.translator); + let mut file_ann = collect_annotations(args, msp, sm); // Make sure our primary file comes first let primary_span = msp.primary_span().unwrap_or_default(); @@ -256,7 +249,7 @@ impl AnnotateSnippetEmitter { let msg = if c.messages.iter().any(|(_, style)| style != &crate::Style::NoStyle) { Cow::Owned(self.pre_style_msgs(&c.messages, c.level, args)) } else { - self.translator.translate_messages(&c.messages, args) + format_diag_messages(&c.messages, args) }; // This is a secondary message with no span info @@ -270,7 +263,7 @@ impl AnnotateSnippetEmitter { Group::with_title(level.clone().secondary_title(msg)), )); - let mut file_ann = collect_annotations(args, &c.span, sm, &self.translator); + let mut file_ann = collect_annotations(args, &c.span, sm); let primary_span = c.span.primary_span().unwrap_or_default(); if !primary_span.is_dummy() { let primary_lo = sm.lookup_char_pos(primary_span.lo()); @@ -308,9 +301,10 @@ impl AnnotateSnippetEmitter { // do not display this suggestion, it is meant only for tools } SuggestionStyle::HideCodeAlways => { - let msg = self - .translator - .translate_messages(&[(suggestion.msg.to_owned(), Style::HeaderMsg)], args); + let msg = format_diag_messages( + &[(suggestion.msg.to_owned(), Style::HeaderMsg)], + args, + ); group = group.element(annotate_snippets::Level::HELP.message(msg)); } SuggestionStyle::HideCodeInline @@ -367,9 +361,7 @@ impl AnnotateSnippetEmitter { if substitutions.is_empty() { continue; } - let mut msg = self - .translator - .translate_message(&suggestion.msg, args) + let mut msg = format_diag_message(&suggestion.msg, args) .map_err(Report::new) .unwrap() .to_string(); @@ -555,7 +547,7 @@ impl AnnotateSnippetEmitter { ) -> String { msgs.iter() .filter_map(|(m, style)| { - let text = self.translator.translate_message(m, args).map_err(Report::new).unwrap(); + let text = format_diag_message(m, args).map_err(Report::new).unwrap(); let style = style.anstyle(level); if text.is_empty() { None } else { Some(format!("{style}{text}{style:#}")) } }) @@ -688,7 +680,6 @@ fn collect_annotations( args: &FluentArgs<'_>, msp: &MultiSpan, sm: &Arc, - translator: &Translator, ) -> Vec<(Arc, Vec)> { let mut output: Vec<(Arc, Vec)> = vec![]; @@ -704,9 +695,7 @@ fn collect_annotations( let kind = if is_primary { AnnotationKind::Primary } else { AnnotationKind::Context }; let label = label.as_ref().map(|m| { - normalize_whitespace( - &translator.translate_message(m, args).map_err(Report::new).unwrap(), - ) + normalize_whitespace(&format_diag_message(m, args).map_err(Report::new).unwrap()) }); let ann = Annotation { kind, span, label }; diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 4ceb5cf06f938..8571f1584fe8d 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -25,7 +25,7 @@ use rustc_span::{FileName, SourceFile, Span}; use tracing::{debug, warn}; use crate::timings::TimingRecord; -use crate::translation::Translator; +use crate::translation::format_diag_message; use crate::{ CodeSuggestion, DiagInner, DiagMessage, Level, MultiSpan, Style, Subdiag, SuggestionStyle, }; @@ -88,8 +88,6 @@ pub trait Emitter { 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: @@ -108,11 +106,7 @@ pub trait Emitter { fluent_args: &FluentArgs<'_>, ) { if let Some((sugg, rest)) = suggestions.split_first() { - let msg = self - .translator() - .translate_message(&sugg.msg, fluent_args) - .map_err(Report::new) - .unwrap(); + let msg = format_diag_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 @@ -383,15 +377,9 @@ impl Emitter for EmitterWithNote { diag.sub(Level::Note, self.note.clone(), MultiSpan::new()); self.emitter.emit_diagnostic(diag); } - - fn translator(&self) -> &Translator { - self.emitter.translator() - } } -pub struct SilentEmitter { - pub translator: Translator, -} +pub struct SilentEmitter; impl Emitter for SilentEmitter { fn source_map(&self) -> Option<&SourceMap> { @@ -399,10 +387,6 @@ impl Emitter for SilentEmitter { } fn emit_diagnostic(&mut self, _diag: DiagInner) {} - - fn translator(&self) -> &Translator { - &self.translator - } } /// Maximum number of suggestions to be shown diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 310a64745bad6..f956fe9490796 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -32,7 +32,7 @@ use crate::emitter::{ should_show_source_code, }; use crate::timings::{TimingRecord, TimingSection}; -use crate::translation::{Translator, to_fluent_args}; +use crate::translation::{format_diag_message, format_diag_messages, to_fluent_args}; use crate::{CodeSuggestion, MultiSpan, SpanLabel, Subdiag, Suggestions, TerminalUrl}; #[cfg(test)] @@ -45,8 +45,6 @@ pub struct JsonEmitter { #[setters(skip)] sm: Option>, #[setters(skip)] - translator: Translator, - #[setters(skip)] pretty: bool, ui_testing: bool, ignored_directories_in_source_blocks: Vec, @@ -63,7 +61,6 @@ impl JsonEmitter { pub fn new( dst: Box, sm: Option>, - translator: Translator, pretty: bool, json_rendered: HumanReadableErrorType, color_config: ColorConfig, @@ -71,7 +68,6 @@ impl JsonEmitter { JsonEmitter { dst: IntoDynSyncSend(dst), sm, - translator, pretty, ui_testing: false, ignored_directories_in_source_blocks: Vec::new(), @@ -180,10 +176,6 @@ 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. @@ -310,7 +302,7 @@ impl Diagnostic { let args = to_fluent_args(diag.args.iter()); let sugg_to_diag = |sugg: &CodeSuggestion| { let translated_message = - je.translator.translate_message(&sugg.msg, &args).map_err(Report::new).unwrap(); + format_diag_message(&sugg.msg, &args).map_err(Report::new).unwrap(); Diagnostic { message: translated_message.to_string(), code: None, @@ -341,7 +333,7 @@ impl Diagnostic { } } - let translated_message = je.translator.translate_messages(&diag.messages, &args); + let translated_message = format_diag_messages(&diag.messages, &args); let code = if let Some(code) = diag.code { Some(DiagnosticCode { @@ -373,7 +365,7 @@ impl Diagnostic { choice => choice, }, ); - AnnotateSnippetEmitter::new(dst, je.translator.clone()) + AnnotateSnippetEmitter::new(dst) .short_message(je.json_rendered.short) .sm(je.sm.clone()) .diagnostic_width(je.diagnostic_width) @@ -403,7 +395,7 @@ impl Diagnostic { args: &FluentArgs<'_>, je: &JsonEmitter, ) -> Diagnostic { - let translated_message = je.translator.translate_messages(&subdiag.messages, args); + let translated_message = format_diag_messages(&subdiag.messages, args); Diagnostic { message: translated_message.to_string(), code: None, @@ -427,7 +419,7 @@ impl DiagnosticSpan { span.is_primary, span.label .as_ref() - .map(|m| je.translator.translate_message(m, args).unwrap()) + .map(|m| format_diag_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 ffcf9947a7a86..71b66f2e0223b 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -45,13 +45,11 @@ 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(filename(&sm, "test.rs"), code.to_owned()); - let translator = Translator::new(); let output = Arc::new(Mutex::new(Vec::new())); let je = JsonEmitter::new( Box::new(Shared { data: output.clone() }), Some(sm), - translator, true, // pretty HumanReadableErrorType { short: true, unicode: false }, ColorConfig::Never, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index c0398b3e8da0b..0e6b85140adbc 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -56,9 +56,8 @@ use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{DynSend, Lock}; use rustc_data_structures::{AtomicRef, assert_matches}; pub use rustc_error_messages::{ - DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg, - LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, fallback_fluent_bundle, - fluent_bundle, into_diag_arg_using_display, + DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg, + LanguageIdentifier, MultiSpan, SpanLabel, fluent_bundle, into_diag_arg_using_display, }; use rustc_hashes::Hash128; use rustc_lint_defs::LintExpectationId; @@ -72,6 +71,7 @@ use tracing::debug; use crate::emitter::TimingEvent; use crate::timings::TimingRecord; +use crate::translation::format_diag_message; pub mod annotate_snippet_emitter_writer; pub mod codes; @@ -480,8 +480,7 @@ impl DiagCtxt { pub fn make_silent(&self) { let mut inner = self.inner.borrow_mut(); - let translator = inner.emitter.translator().clone(); - inner.emitter = Box::new(emitter::SilentEmitter { translator }); + inner.emitter = Box::new(emitter::SilentEmitter {}); } pub fn set_emitter(&self, emitter: Box) { @@ -1439,12 +1438,7 @@ impl DiagCtxtInner { args: impl Iterator>, ) -> String { let args = crate::translation::to_fluent_args(args); - self.emitter - .translator() - .translate_message(&message, &args) - .map_err(Report::new) - .unwrap() - .to_string() + format_diag_message(&message, &args).map_err(Report::new).unwrap().to_string() } fn eagerly_translate_for_subdiag( diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index b5de3f87e9f35..a719edb499c8c 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -1,14 +1,13 @@ use std::borrow::Cow; use std::error::Report; -use std::sync::Arc; -pub use rustc_error_messages::{FluentArgs, LazyFallbackBundle}; +pub use rustc_error_messages::FluentArgs; use rustc_error_messages::{langid, register_functions}; use tracing::{debug, trace}; use crate::error::TranslateError; use crate::fluent_bundle::FluentResource; -use crate::{DiagArg, DiagMessage, FluentBundle, Style, fluent_bundle}; +use crate::{DiagArg, DiagMessage, Style, fluent_bundle}; /// Convert diagnostic arguments (a rustc internal type that exists to implement /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation. @@ -29,63 +28,48 @@ pub fn to_fluent_args<'iter>(iter: impl Iterator>) -> Flue args } -#[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>, +/// Convert `DiagMessage`s to a string +pub fn format_diag_messages( + messages: &[(DiagMessage, Style)], + args: &FluentArgs<'_>, +) -> Cow<'static, str> { + Cow::Owned( + messages + .iter() + .map(|(m, _)| format_diag_message(m, args).map_err(Report::new).unwrap()) + .collect::(), + ) } -impl Translator { - pub fn new() -> Translator { - Translator { fluent_bundle: None } - } - - /// Convert `DiagMessage`s to a string, performing translation if necessary. - pub fn translate_messages( - &self, - messages: &[(DiagMessage, Style)], - args: &FluentArgs<'_>, - ) -> Cow<'_, str> { - Cow::Owned( - messages - .iter() - .map(|(m, _)| self.translate_message(m, args).map_err(Report::new).unwrap()) - .collect::(), - ) - } - - /// Convert a `DiagMessage` to a string, performing translation if necessary. - pub fn translate_message<'a>( - &'a self, - message: &'a DiagMessage, - args: &'a FluentArgs<'_>, - ) -> Result, TranslateError<'a>> { - trace!(?message, ?args); - match message { - DiagMessage::Str(msg) => Ok(Cow::Borrowed(msg)), - // This translates an inline fluent diagnostic message - // It does this by creating a new `FluentBundle` with only one message, - // and then translating using this bundle. - DiagMessage::Inline(msg) => { - const GENERATED_MSG_ID: &str = "generated_msg"; - let resource = - FluentResource::try_new(format!("{GENERATED_MSG_ID} = {msg}\n")).unwrap(); - let mut bundle = fluent_bundle::FluentBundle::new(vec![langid!("en-US")]); - bundle.set_use_isolating(false); - bundle.add_resource(resource).unwrap(); - register_functions(&mut bundle); - let message = bundle.get_message(GENERATED_MSG_ID).unwrap(); - let value = message.value().unwrap(); +/// Convert a `DiagMessage` to a string +pub fn format_diag_message<'a>( + message: &'a DiagMessage, + args: &'a FluentArgs<'_>, +) -> Result, TranslateError<'a>> { + trace!(?message, ?args); + match message { + DiagMessage::Str(msg) => Ok(Cow::Borrowed(msg)), + // This translates an inline fluent diagnostic message + // It does this by creating a new `FluentBundle` with only one message, + // and then translating using this bundle. + DiagMessage::Inline(msg) => { + const GENERATED_MSG_ID: &str = "generated_msg"; + let resource = + FluentResource::try_new(format!("{GENERATED_MSG_ID} = {msg}\n")).unwrap(); + let mut bundle = fluent_bundle::FluentBundle::new(vec![langid!("en-US")]); + bundle.set_use_isolating(false); + bundle.add_resource(resource).unwrap(); + register_functions(&mut bundle); + let message = bundle.get_message(GENERATED_MSG_ID).unwrap(); + let value = message.value().unwrap(); - let mut errs = vec![]; - let translated = bundle.format_pattern(value, Some(args), &mut errs).to_string(); - debug!(?translated, ?errs); - if errs.is_empty() { - Ok(Cow::Owned(translated)) - } else { - Err(TranslateError::fluent(&Cow::Borrowed(GENERATED_MSG_ID), args, errs)) - } + let mut errs = vec![]; + let translated = bundle.format_pattern(value, Some(args), &mut errs).to_string(); + debug!(?translated, ?errs); + if errs.is_empty() { + Ok(Cow::Owned(translated)) + } else { + Err(TranslateError::fluent(&Cow::Borrowed(GENERATED_MSG_ID), args, errs)) } } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 72080c5f53696..b4fd4c564b269 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -436,16 +436,6 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); - let bundle = match rustc_errors::fluent_bundle( - &config.opts.sysroot.all_paths().collect::>(), - config.opts.unstable_opts.translate_lang.clone(), - config.opts.unstable_opts.translate_additional_ftl.as_deref(), - config.opts.unstable_opts.translate_directionality_markers, - ) { - Ok(bundle) => bundle, - Err(e) => early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")), - }; - let mut sess = rustc_session::build_session( config.opts, CompilerIO { @@ -454,7 +444,6 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se output_file: config.output_file, temps_dir, }, - bundle, config.lint_caps, target, util::rustc_version_str().unwrap_or("unknown"), diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 5ebf898f45a34..b2a6e999b87c4 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -71,7 +71,6 @@ where let sess = build_session( sessopts, io, - None, Default::default(), target, "", diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index ac9c3e63e8534..f9c3384458488 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -13,7 +13,6 @@ use rustc_ast_pretty::pprust::item_to_string; use rustc_data_structures::assert_matches; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::OutputTheme; -use rustc_errors::translation::Translator; use rustc_errors::{AutoStream, DiagCtxt, MultiSpan, PResult}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; @@ -42,11 +41,10 @@ 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 translator = Translator::new(); let shared: Box = Box::new(Shared { data: output.clone() }); let auto_stream = AutoStream::never(shared); let dcx = DiagCtxt::new(Box::new( - AnnotateSnippetEmitter::new(auto_stream, translator) + AnnotateSnippetEmitter::new(auto_stream) .sm(Some(source_map.clone())) .diagnostic_width(Some(140)) .theme(theme), diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9219b5a7e8aca..58a63b54da6df 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -7,7 +7,7 @@ use rustc_abi::Align; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::profiling::TimePassesFormat; use rustc_data_structures::stable_hasher::StableHasher; -use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl}; +use rustc_errors::{ColorConfig, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; use rustc_hir::attrs::CollapseMacroDebuginfo; @@ -790,7 +790,6 @@ mod desc { pub(crate) const parse_string: &str = "a string"; pub(crate) const parse_opt_string: &str = parse_string; pub(crate) const parse_string_push: &str = parse_string; - pub(crate) const parse_opt_langid: &str = "a language identifier"; pub(crate) const parse_opt_pathbuf: &str = "a path"; pub(crate) const parse_list: &str = "a space-separated list of strings"; pub(crate) const parse_list_with_polarity: &str = @@ -998,17 +997,6 @@ pub mod parse { } } - /// Parse an optional language identifier, e.g. `en-US` or `zh-CN`. - pub(crate) fn parse_opt_langid(slot: &mut Option, v: Option<&str>) -> bool { - match v { - Some(s) => { - *slot = rustc_errors::LanguageIdentifier::from_str(s).ok(); - true - } - None => false, - } - } - pub(crate) fn parse_opt_pathbuf(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { @@ -2710,15 +2698,6 @@ written to standard error output)"), "for every macro invocation, print its name and arguments (default: no)"), track_diagnostics: bool = (false, parse_bool, [UNTRACKED], "tracks where in rustc a diagnostic was emitted"), - // Diagnostics are considered side-effects of a query (see `QuerySideEffect`) and are saved - // alongside query results and changes to translation options can affect diagnostics - so - // translation options should be tracked. - translate_additional_ftl: Option = (None, parse_opt_pathbuf, [TRACKED], - "additional fluent translation to preferentially use (for testing translation)"), - translate_directionality_markers: bool = (false, parse_bool, [TRACKED], - "emit directionality isolation markers in translated diagnostics"), - translate_lang: Option = (None, parse_opt_langid, [TRACKED], - "language identifier for diagnostic output"), translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED], "translate remapped paths into local paths when possible (default: yes)"), trap_unreachable: Option = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 62c23424f371f..9c12c480cacdd 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -10,7 +10,6 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock}; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{EmitterWithNote, stderr_destination}; -use rustc_errors::translation::Translator; use rustc_errors::{ BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, EmissionGuarantee, MultiSpan, StashKey, @@ -281,10 +280,9 @@ pub struct ParseSess { impl ParseSess { /// Used for testing. pub fn new() -> Self { - let translator = Translator::new(); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new( - AnnotateSnippetEmitter::new(stderr_destination(ColorConfig::Auto), translator) + AnnotateSnippetEmitter::new(stderr_destination(ColorConfig::Auto)) .sm(Some(Arc::clone(&sm))), ); let dcx = DiagCtxt::new(emitter); @@ -314,12 +312,8 @@ impl ParseSess { } pub fn emitter_with_note(note: String) -> Self { - let translator = Translator::new(); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = Box::new(AnnotateSnippetEmitter::new( - stderr_destination(ColorConfig::Auto), - translator, - )); + let emitter = Box::new(AnnotateSnippetEmitter::new(stderr_destination(ColorConfig::Auto))); let dcx = DiagCtxt::new(Box::new(EmitterWithNote { emitter, note })); ParseSess::with_dcx(dcx, sm) } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ed37e9e960cd8..691e0196d309a 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -16,7 +16,6 @@ use rustc_errors::codes::*; use rustc_errors::emitter::{DynEmitter, HumanReadableErrorType, OutputTheme, stderr_destination}; 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, TerminalUrl, @@ -896,11 +895,7 @@ impl Session { // JUSTIFICATION: part of session construction #[allow(rustc::bad_opt_access)] -fn default_emitter( - sopts: &config::Options, - source_map: Arc, - translator: Translator, -) -> Box { +fn default_emitter(sopts: &config::Options, source_map: Arc) -> Box { let macro_backtrace = sopts.unstable_opts.macro_backtrace; let track_diagnostics = sopts.unstable_opts.track_diagnostics; let terminal_url = match sopts.unstable_opts.terminal_urls { @@ -922,21 +917,17 @@ fn default_emitter( match sopts.error_format { config::ErrorOutputType::HumanReadable { kind, color_config } => match kind { HumanReadableErrorType { short, unicode } => { - let emitter = - AnnotateSnippetEmitter::new(stderr_destination(color_config), translator) - .sm(source_map) - .short_message(short) - .diagnostic_width(sopts.diagnostic_width) - .macro_backtrace(macro_backtrace) - .track_diagnostics(track_diagnostics) - .terminal_url(terminal_url) - .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii }) - .ignored_directories_in_source_blocks( - sopts - .unstable_opts - .ignore_directory_in_diagnostics_source_blocks - .clone(), - ); + let emitter = AnnotateSnippetEmitter::new(stderr_destination(color_config)) + .sm(source_map) + .short_message(short) + .diagnostic_width(sopts.diagnostic_width) + .macro_backtrace(macro_backtrace) + .track_diagnostics(track_diagnostics) + .terminal_url(terminal_url) + .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii }) + .ignored_directories_in_source_blocks( + sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(), + ); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } }, @@ -944,7 +935,6 @@ fn default_emitter( JsonEmitter::new( Box::new(io::BufWriter::new(io::stderr())), source_map, - translator, pretty, json_rendered, color_config, @@ -966,7 +956,6 @@ fn default_emitter( pub fn build_session( sopts: config::Options, io: CompilerIO, - fluent_bundle: Option>, driver_lint_caps: FxHashMap, target: Target, cfg_version: &'static str, @@ -984,9 +973,8 @@ 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 translator = Translator { fluent_bundle }; let source_map = rustc_span::source_map::get_source_map().unwrap(); - let emitter = default_emitter(&sopts, Arc::clone(&source_map), translator); + let emitter = default_emitter(&sopts, Arc::clone(&source_map)); let mut dcx = DiagCtxt::new(emitter).with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings)); @@ -1421,13 +1409,10 @@ 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 translator = Translator::new(); let emitter: Box = match output { config::ErrorOutputType::HumanReadable { kind, color_config } => match kind { HumanReadableErrorType { short, unicode } => Box::new( - AnnotateSnippetEmitter::new(stderr_destination(color_config), translator) + AnnotateSnippetEmitter::new(stderr_destination(color_config)) .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii }) .short_message(short), ), @@ -1436,7 +1421,6 @@ fn mk_emitter(output: ErrorOutputType) -> Box { Box::new(JsonEmitter::new( Box::new(io::BufWriter::new(io::stderr())), Some(Arc::new(SourceMap::new(FilePathMapping::empty()))), - translator, pretty, json_rendered, color_config, diff --git a/src/doc/rustc-dev-guide/src/diagnostics/translation.md b/src/doc/rustc-dev-guide/src/diagnostics/translation.md index e66c9430914a6..aef97a7ab7903 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/translation.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/translation.md @@ -170,48 +170,6 @@ have such implementations. `set_arg` calls are handled transparently by diagnostic derives but need to be added manually when using diagnostic builder APIs. -### Loading - -rustc makes a distinction between the "fallback bundle" for `en-US` that is used -by default and when another locale is missing a message; and the primary fluent -bundle which is requested by the user. - -Diagnostic emitters implement the `Emitter` trait which has two functions for -accessing the fallback and primary fluent bundles (`fallback_fluent_bundle` and -`fluent_bundle` respectively). - -`Emitter` also has member functions with default implementations for performing -translation of a `DiagMessage` using the results of -`fallback_fluent_bundle` and `fluent_bundle`. - -All of the emitters in rustc load the fallback Fluent bundle lazily, only -reading Fluent resources and parsing them when an error message is first being -translated (for performance reasons - it doesn't make sense to do this if no -error is being emitted). `rustc_error_messages::fallback_fluent_bundle` returns -a `std::lazy::Lazy` which is provided to emitters and evaluated -in the first call to `Emitter::fallback_fluent_bundle`. - -The primary Fluent bundle (for the user's desired locale) is expected to be -returned by `Emitter::fluent_bundle`. This bundle is used preferentially when -translating messages, the fallback bundle is only used if the primary bundle is -missing a message or not provided. - -There are no locale bundles distributed with the compiler, -but mechanisms are implemented for loading them. - -- `-Ztranslate-additional-ftl` can be used to load a specific resource as the - primary bundle for testing purposes. -- `-Ztranslate-lang` can be provided a language identifier (something like - `en-US`) and will load any Fluent resources found in - `$sysroot/share/locale/$locale/` directory (both the user provided - sysroot and any sysroot candidates). - -Primary bundles are not currently loaded lazily and if requested will be loaded -at the start of compilation regardless of whether an error occurs. Lazily -loading primary bundles is possible if it can be assumed that loading a bundle -won't fail. Bundle loading can fail if a requested locale is missing, Fluent -files are malformed, or a message is duplicated in multiple resources. - [Fluent]: https://projectfluent.org [`compiler/rustc_borrowck/messages.ftl`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_borrowck/messages.ftl [`compiler/rustc_parse/messages.ftl`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_parse/messages.ftl diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7629425ffb559..375f8338319b6 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -157,11 +157,10 @@ pub(crate) fn new_dcx( diagnostic_width: Option, unstable_opts: &UnstableOptions, ) -> rustc_errors::DiagCtxt { - let translator = rustc_driver::default_translator(); let emitter: Box = match error_format { ErrorOutputType::HumanReadable { kind, color_config } => match kind { HumanReadableErrorType { short, unicode } => Box::new( - AnnotateSnippetEmitter::new(stderr_destination(color_config), translator) + AnnotateSnippetEmitter::new(stderr_destination(color_config)) .sm(source_map.map(|sm| sm as _)) .short_message(short) .diagnostic_width(diagnostic_width) @@ -178,7 +177,6 @@ pub(crate) fn new_dcx( JsonEmitter::new( Box::new(io::BufWriter::new(io::stderr())), Some(source_map), - translator, pretty, json_rendered, color_config, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index d30d869cd4c19..a77efaaed8d58 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -467,7 +467,6 @@ fn parse_source( let filename = FileName::anon_source_code(&wrapped_source); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); - let translator = rustc_driver::default_translator(); let supports_color = match get_stderr_color_choice(ColorConfig::Auto, &std::io::stderr()) { ColorChoice::Auto => unreachable!(), ColorChoice::AlwaysAnsi | ColorChoice::Always => true, @@ -476,7 +475,7 @@ fn parse_source( info.supports_color = 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 = AnnotateSnippetEmitter::new(AutoStream::never(Box::new(io::sink())), translator); + let emitter = AnnotateSnippetEmitter::new(AutoStream::never(Box::new(io::sink()))); // 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 5749b4ac081e1..b3199f11a680a 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use rustc_data_structures::sync::Lock; use rustc_errors::emitter::Emitter; -use rustc_errors::translation::{Translator, to_fluent_args}; +use rustc_errors::translation::{format_diag_message, 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; @@ -35,8 +35,7 @@ fn check_rust_syntax( code_block: RustCodeBlock, ) { let buffer = Arc::new(Lock::new(Buffer::default())); - let translator = rustc_driver::default_translator(); - let emitter = BufferEmitter { buffer: Arc::clone(&buffer), translator }; + let emitter = BufferEmitter { buffer: Arc::clone(&buffer) }; let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); @@ -145,7 +144,6 @@ struct Buffer { struct BufferEmitter { buffer: Arc>, - translator: Translator, } impl Emitter for BufferEmitter { @@ -153,9 +151,7 @@ impl Emitter for BufferEmitter { let mut buffer = self.buffer.borrow_mut(); let fluent_args = to_fluent_args(diag.args.iter()); - let translated_main_message = self - .translator - .translate_message(&diag.messages[0].0, &fluent_args) + let translated_main_message = format_diag_message(&diag.messages[0].0, &fluent_args) .unwrap_or_else(|e| panic!("{e}")); buffer.messages.push(format!("error from rustc: {translated_main_message}")); @@ -167,8 +163,4 @@ impl Emitter for BufferEmitter { fn source_map(&self) -> Option<&SourceMap> { None } - - fn translator(&self) -> &Translator { - &self.translator - } } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 2a5c8f776427d..83a77e73cb7ea 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -5,7 +5,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{DynEmitter, Emitter, SilentEmitter, stderr_destination}; -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::{ @@ -74,10 +73,6 @@ impl Emitter for SilentOnIgnoredFilesEmitter { } self.handle_non_ignoreable_error(diag); } - - fn translator(&self) -> &Translator { - self.emitter.translator() - } } impl From for ColorConfig { @@ -104,15 +99,13 @@ fn default_dcx( ColorConfig::Never }; - let translator = rustc_driver::default_translator(); - let emitter: Box = if show_parse_errors { Box::new( - AnnotateSnippetEmitter::new(stderr_destination(emit_color), translator) + AnnotateSnippetEmitter::new(stderr_destination(emit_color)) .sm(Some(source_map.clone())), ) } else { - Box::new(SilentEmitter { translator }) + Box::new(SilentEmitter) }; DiagCtxt::new(Box::new(SilentOnIgnoredFilesEmitter { has_non_ignorable_parser_errors: false, @@ -342,10 +335,6 @@ mod tests { fn emit_diagnostic(&mut self, _diag: DiagInner) { 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 { diff --git a/tests/run-make/translation/broken.ftl b/tests/run-make/translation/broken.ftl deleted file mode 100644 index f1dd6ff0bbd20..0000000000000 --- a/tests/run-make/translation/broken.ftl +++ /dev/null @@ -1,3 +0,0 @@ -# `foo` isn't provided by this diagnostic so it is expected that the fallback message is used. -parse_struct_literal_body_without_path = this is a {$foo} message - .suggestion = this is a test suggestion diff --git a/tests/run-make/translation/missing.ftl b/tests/run-make/translation/missing.ftl deleted file mode 100644 index 6be24dc7bb988..0000000000000 --- a/tests/run-make/translation/missing.ftl +++ /dev/null @@ -1,3 +0,0 @@ -# `parse_struct_literal_body_without_path` isn't provided by this resource at all, so the -# fallback should be used. -foo = bar diff --git a/tests/run-make/translation/rmake.rs b/tests/run-make/translation/rmake.rs deleted file mode 100644 index 4d7fd71a2f4a9..0000000000000 --- a/tests/run-make/translation/rmake.rs +++ /dev/null @@ -1,197 +0,0 @@ -//! Smoke test for the rustc diagnostics translation infrastructure. -//! -//! # References -//! -//! - Current tracking issue: . -//! - Old tracking issue: -//! - Initial translation infra implementation: . - -// This test uses symbolic links to stub out a fake sysroot to save testing time. -//@ needs-symlink -//@ needs-subprocess - -// FIXME(151366) Currently `-Ztranslate-additional-ftl` is currently broken -//@ ignore-test - -#![deny(warnings)] - -use std::path::{Path, PathBuf}; - -use run_make_support::rustc::sysroot; -use run_make_support::{cwd, rfs, run_in_tmpdir, rustc}; - -fn main() { - builtin_fallback_bundle(); - additional_primary_bundle(); - missing_slug_prefers_fallback_bundle(); - broken_primary_bundle_prefers_fallback_bundle(); - locale_sysroot(); - missing_sysroot(); - file_sysroot(); -} - -/// Check that the test works normally, using the built-in fallback bundle. -fn builtin_fallback_bundle() { - rustc().input("test.rs").run_fail().assert_stderr_contains("struct literal body without path"); -} - -/// Check that a primary bundle can be loaded and will be preferentially used where possible. -fn additional_primary_bundle() { - rustc() - .input("test.rs") - .arg("-Ztranslate-additional-ftl=working.ftl") - .run_fail() - .assert_stderr_contains("this is a test message"); -} - -/// Check that a primary bundle without the desired message will use the fallback bundle. -fn missing_slug_prefers_fallback_bundle() { - rustc() - .input("test.rs") - .arg("-Ztranslate-additional-ftl=missing.ftl") - .run_fail() - .assert_stderr_contains("struct literal body without path"); -} - -/// Check that a primary bundle with a broken message (e.g. an interpolated variable is not -/// provided) will use the fallback bundle. -fn broken_primary_bundle_prefers_fallback_bundle() { - // FIXME(#135817): as of the rmake.rs port, the compiler actually ICEs on the additional - // `broken.ftl`, even though the original intention seems to be that it should gracefully - // failover to the fallback bundle. On `aarch64-apple-darwin`, somehow it *doesn't* ICE. - - rustc() - .env("RUSTC_ICE", "0") // disable ICE dump file, not needed - .input("test.rs") - .arg("-Ztranslate-additional-ftl=broken.ftl") - .run_fail(); -} - -#[track_caller] -fn shallow_symlink_dir_entries(src_dir: &Path, dst_dir: &Path) { - for entry in rfs::read_dir(src_dir) { - let entry = entry.unwrap(); - let src_entry_path = entry.path(); - let src_filename = src_entry_path.file_name().unwrap(); - let meta = rfs::symlink_metadata(&src_entry_path); - if meta.is_symlink() || meta.is_file() { - rfs::symlink_file(&src_entry_path, dst_dir.join(src_filename)); - } else if meta.is_dir() { - rfs::symlink_dir(&src_entry_path, dst_dir.join(src_filename)); - } else { - unreachable!() - } - } -} - -#[track_caller] -fn shallow_symlink_dir_entries_materialize_single_dir( - src_dir: &Path, - dst_dir: &Path, - dir_filename: &str, -) { - shallow_symlink_dir_entries(src_dir, dst_dir); - - let dst_symlink_meta = rfs::symlink_metadata(dst_dir.join(dir_filename)); - - if dst_symlink_meta.is_file() || dst_symlink_meta.is_dir() { - unreachable!(); - } - - #[cfg(windows)] - { - use std::os::windows::fs::FileTypeExt as _; - if dst_symlink_meta.file_type().is_symlink_file() { - rfs::remove_file(dst_dir.join(dir_filename)); - } else if dst_symlink_meta.file_type().is_symlink_dir() { - rfs::remove_dir(dst_dir.join(dir_filename)); - } else { - unreachable!(); - } - } - #[cfg(not(windows))] - { - rfs::remove_file(dst_dir.join(dir_filename)); - } - - rfs::create_dir_all(dst_dir.join(dir_filename)); -} - -#[track_caller] -fn setup_fakeroot_parents() -> PathBuf { - let sysroot = sysroot(); - let fakeroot = cwd().join("fakeroot"); - rfs::create_dir_all(&fakeroot); - shallow_symlink_dir_entries_materialize_single_dir(&sysroot, &fakeroot, "lib"); - shallow_symlink_dir_entries_materialize_single_dir( - &sysroot.join("lib"), - &fakeroot.join("lib"), - "rustlib", - ); - shallow_symlink_dir_entries_materialize_single_dir( - &sysroot.join("lib").join("rustlib"), - &fakeroot.join("lib").join("rustlib"), - "src", - ); - shallow_symlink_dir_entries( - &sysroot.join("lib").join("rustlib").join("src"), - &fakeroot.join("lib").join("rustlib").join("src"), - ); - fakeroot -} - -/// Check that a locale can be loaded from the sysroot given a language identifier by making a local -/// copy of the sysroot and adding the custom locale to it. -fn locale_sysroot() { - run_in_tmpdir(|| { - let fakeroot = setup_fakeroot_parents(); - - // When download-rustc is enabled, real sysroot will have a share directory. Delete the link - // to it. - let _ = std::fs::remove_file(fakeroot.join("share")); - - let fake_locale_path = fakeroot.join("share").join("locale").join("zh-CN"); - rfs::create_dir_all(&fake_locale_path); - rfs::symlink_file( - cwd().join("working.ftl"), - fake_locale_path.join("basic-translation.ftl"), - ); - - rustc() - .env("RUSTC_ICE", "0") - .input("test.rs") - .sysroot(&fakeroot) - .arg("-Ztranslate-lang=zh-CN") - .run_fail() - .assert_stderr_contains("this is a test message"); - }); -} - -/// Check that the compiler errors out when the sysroot requested cannot be found. This test might -/// start failing if there actually exists a Klingon translation of rustc's error messages. -fn missing_sysroot() { - run_in_tmpdir(|| { - rustc() - .input("test.rs") - .arg("-Ztranslate-lang=tlh") - .run_fail() - .assert_stderr_contains("missing locale directory"); - }); -} - -/// Check that the compiler errors out when the directory for the locale in the sysroot is actually -/// a file. -fn file_sysroot() { - run_in_tmpdir(|| { - let fakeroot = setup_fakeroot_parents(); - rfs::create_dir_all(fakeroot.join("share").join("locale")); - rfs::write(fakeroot.join("share").join("locale").join("zh-CN"), b"not a dir"); - - rustc() - .input("test.rs") - .sysroot(&fakeroot) - .arg("-Ztranslate-lang=zh-CN") - .run_fail() - .assert_stderr_contains("is not a directory"); - }); -} diff --git a/tests/run-make/translation/test.rs b/tests/run-make/translation/test.rs deleted file mode 100644 index b8f5bff315337..0000000000000 --- a/tests/run-make/translation/test.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Exact error being tested isn't relevant, it just needs to be known that it uses Fluent-backed -// diagnostics. - -struct Foo { - val: (), -} - -fn foo() -> Foo { - val: (), -} - -fn main() { - let x = foo(); - x.val == 42; - let x = { - val: (), - }; -} diff --git a/tests/run-make/translation/working.ftl b/tests/run-make/translation/working.ftl deleted file mode 100644 index 50d126e3fbfec..0000000000000 --- a/tests/run-make/translation/working.ftl +++ /dev/null @@ -1,2 +0,0 @@ -parse_struct_literal_body_without_path = this is a test message - .suggestion = this is a test suggestion diff --git a/tests/ui/README.md b/tests/ui/README.md index 237cfb9c4f071..7fe32fdf93e37 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -446,10 +446,6 @@ Everything to do with `--diagnostic-width`. Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic attribute namespace](https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md). -## `tests/ui/diagnostics-infra` - -This directory contains tests and infrastructure related to the diagnostics system, including support for translatable diagnostics - ## `tests/ui/did_you_mean/` Tests for miscellaneous suggestions. diff --git a/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs deleted file mode 100644 index f2965778431c9..0000000000000 --- a/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Regression test for https://github.com/rust-lang/rust/issues/106755 - -//@ compile-flags:-Ztranslate-lang=en_US - -#![feature(negative_impls)] -#![feature(marker_trait_attr)] - -#[marker] -trait MyTrait {} - -struct TestType(::std::marker::PhantomData); - -unsafe impl Send for TestType {} - -impl !Send for TestType {} -//~^ ERROR found both positive and negative implementation -//~| ERROR `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not - -unsafe impl Send for TestType {} //~ ERROR conflicting implementations - -impl !Send for TestType {} -//~^ ERROR `!Send` impls cannot be specialized - -fn main() {} diff --git a/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.stderr b/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.stderr deleted file mode 100644 index 1dc31e161a76a..0000000000000 --- a/tests/ui/diagnostics-infra/primary-fluent-bundle-missing.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0751]: found both positive and negative implementation of trait `Send` for type `TestType<_>`: - --> $DIR/primary-fluent-bundle-missing.rs:15:1 - | -LL | unsafe impl Send for TestType {} - | ------------------------------------------------------ positive implementation here -LL | -LL | impl !Send for TestType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here - -error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>` - --> $DIR/primary-fluent-bundle-missing.rs:19:1 - | -LL | unsafe impl Send for TestType {} - | ------------------------------------------------------ first implementation here -... -LL | unsafe impl Send for TestType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` - -error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not - --> $DIR/primary-fluent-bundle-missing.rs:15:9 - | -LL | impl !Send for TestType {} - | ^^^^^^^ - | -note: the implementor must specify the same requirement - --> $DIR/primary-fluent-bundle-missing.rs:11:1 - | -LL | struct TestType(::std::marker::PhantomData); - | ^^^^^^^^^^^^^^^^^^ - -error[E0366]: `!Send` impls cannot be specialized - --> $DIR/primary-fluent-bundle-missing.rs:21:1 - | -LL | impl !Send for TestType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `i32` is not a generic parameter -note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/primary-fluent-bundle-missing.rs:11:1 - | -LL | struct TestType(::std::marker::PhantomData); - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0119, E0366, E0367, E0751. -For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.rs b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.rs index 891b8c1f74d6e..d9e8f1f4a5b74 100644 --- a/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.rs +++ b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.rs @@ -1,5 +1,3 @@ -//@ compile-flags:-Ztranslate-lang=en_US - #![feature(negative_impls)] #![feature(marker_trait_attr)] diff --git a/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr index 100b3bf1ae311..729b1616b6d95 100644 --- a/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr +++ b/tests/ui/marker_trait_attr/conflicting-send-impls-for-marker-trait-106755.stderr @@ -1,5 +1,5 @@ error[E0751]: found both positive and negative implementation of trait `Send` for type `TestType<_>`: - --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:13:1 + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:11:1 | LL | unsafe impl Send for TestType {} | ------------------------------------------------------ positive implementation here @@ -8,7 +8,7 @@ LL | impl !Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>` - --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:17:1 + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:15:1 | LL | unsafe impl Send for TestType {} | ------------------------------------------------------ first implementation here @@ -17,26 +17,26 @@ LL | unsafe impl Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not - --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:13:9 + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:11:9 | LL | impl !Send for TestType {} | ^^^^^^^ | note: the implementor must specify the same requirement - --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:9:1 + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:7:1 | LL | struct TestType(::std::marker::PhantomData); | ^^^^^^^^^^^^^^^^^^ error[E0366]: `!Send` impls cannot be specialized - --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:19:1 + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:17:1 | LL | impl !Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `i32` is not a generic parameter note: use the same sequence of generic lifetime, type and const parameters as the struct definition - --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:9:1 + --> $DIR/conflicting-send-impls-for-marker-trait-106755.rs:7:1 | LL | struct TestType(::std::marker::PhantomData); | ^^^^^^^^^^^^^^^^^^