use rustc_data_structures::profiling::VerboseTimingGuard;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::Emitter;
-use rustc_errors::{DiagnosticId, FatalError, Handler, Level};
+use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
use rustc_fs_util::link_or_copy;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_incremental::{
}
}
+impl Translate for SharedEmitter {
+ fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+ None
+ }
+
+ fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
+ panic!("shared emitter attempted to translate a diagnostic");
+ }
+}
+
impl Emitter for SharedEmitter {
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
let fluent_args = self.to_fluent_args(diag.args());
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None
}
-
- fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
- None
- }
-
- fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
- panic!("shared emitter attempted to translate a diagnostic");
- }
}
impl SharedEmitterMain {
use crate::emitter::FileWithAnnotatedLines;
use crate::snippet::Line;
+use crate::translation::Translate;
use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
macro_backtrace: bool,
}
+impl Translate for AnnotateSnippetEmitterWriter {
+ fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
+ self.fluent_bundle.as_ref()
+ }
+
+ fn fallback_fluent_bundle(&self) -> &FluentBundle {
+ &**self.fallback_bundle
+ }
+}
+
impl Emitter for AnnotateSnippetEmitterWriter {
/// The entry point for the diagnostics generation
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
self.source_map.as_ref()
}
- fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
- self.fluent_bundle.as_ref()
- }
-
- fn fallback_fluent_bundle(&self) -> &FluentBundle {
- &**self.fallback_bundle
- }
-
fn should_show_explain(&self) -> bool {
!self.short_message
}
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
+use crate::translation::Translate;
use crate::{
- CodeSuggestion, Diagnostic, DiagnosticArg, DiagnosticId, DiagnosticMessage, FluentBundle,
- Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight,
- SuggestionStyle,
+ CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
+ LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
};
use rustc_lint_defs::pluralize;
const ANONYMIZED_LINE_NUM: &str = "LL";
/// Emitter trait for emitting errors.
-pub trait Emitter {
+pub trait Emitter: Translate {
/// Emit a structured diagnostic.
fn emit_diagnostic(&mut self, diag: &Diagnostic);
fn source_map(&self) -> Option<&Lrc<SourceMap>>;
- /// 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<&Lrc<FluentBundle>>;
-
- /// 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;
-
- /// Convert diagnostic arguments (a rustc internal type that exists to implement
- /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
- ///
- /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
- /// passed around as a reference thereafter.
- fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> {
- FromIterator::from_iter(args.to_vec().drain(..))
- }
-
- /// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
- fn translate_messages(
- &self,
- messages: &[(DiagnosticMessage, Style)],
- args: &FluentArgs<'_>,
- ) -> Cow<'_, str> {
- Cow::Owned(
- messages.iter().map(|(m, _)| self.translate_message(m, args)).collect::<String>(),
- )
- }
-
- /// Convert a `DiagnosticMessage` to a string, performing translation if necessary.
- fn translate_message<'a>(
- &'a self,
- message: &'a DiagnosticMessage,
- args: &'a FluentArgs<'_>,
- ) -> Cow<'_, str> {
- trace!(?message, ?args);
- let (identifier, attr) = match message {
- DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
- DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
- };
-
- let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> {
- let message = bundle.get_message(&identifier)?;
- let value = match attr {
- Some(attr) => message.get_attribute(attr)?.value(),
- None => message.value()?,
- };
- debug!(?message, ?value);
-
- let mut errs = vec![];
- let translated = bundle.format_pattern(value, Some(&args), &mut errs);
- debug!(?translated, ?errs);
- Some((translated, errs))
- };
-
- self.fluent_bundle()
- .and_then(|bundle| translate_with_bundle(bundle))
- // If `translate_with_bundle` returns `None` with the primary bundle, this is likely
- // just that the primary bundle doesn't contain the message being translated, so
- // proceed to the fallback bundle.
- //
- // However, when errors are produced from translation, then that means the translation
- // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided).
- //
- // In debug builds, assert so that compiler devs can spot the broken translation and
- // fix it..
- .inspect(|(_, errs)| {
- debug_assert!(
- errs.is_empty(),
- "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
- identifier,
- attr,
- args,
- errs
- );
- })
- // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so
- // just hide it and try with the fallback bundle.
- .filter(|(_, errs)| errs.is_empty())
- .or_else(|| translate_with_bundle(self.fallback_fluent_bundle()))
- .map(|(translated, errs)| {
- // Always bail out for errors with the fallback bundle.
- assert!(
- errs.is_empty(),
- "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
- identifier,
- attr,
- args,
- errs
- );
- translated
- })
- .expect("failed to find message in primary or fallback fluent bundles")
- }
-
/// Formats the substitutions of the primary_span
///
/// There are a lot of conditions to this method, but in short:
}
}
-impl Emitter for EmitterWriter {
- fn source_map(&self) -> Option<&Lrc<SourceMap>> {
- self.sm.as_ref()
- }
-
+impl Translate for EmitterWriter {
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
self.fluent_bundle.as_ref()
}
fn fallback_fluent_bundle(&self) -> &FluentBundle {
&**self.fallback_bundle
}
+}
+
+impl Emitter for EmitterWriter {
+ fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+ self.sm.as_ref()
+ }
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
let fluent_args = self.to_fluent_args(diag.args());
pub fatal_note: Option<String>,
}
-impl Emitter for SilentEmitter {
- fn source_map(&self) -> Option<&Lrc<SourceMap>> {
- None
- }
-
+impl Translate for SilentEmitter {
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
None
}
fn fallback_fluent_bundle(&self) -> &FluentBundle {
panic!("silent emitter attempted to translate message")
}
+}
+
+impl Emitter for SilentEmitter {
+ fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+ None
+ }
fn emit_diagnostic(&mut self, d: &Diagnostic) {
if d.level == Level::Fatal {
use crate::emitter::{Emitter, HumanReadableErrorType};
use crate::registry::Registry;
+use crate::translation::Translate;
use crate::DiagnosticId;
use crate::{
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
}
}
+impl Translate for JsonEmitter {
+ fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
+ self.fluent_bundle.as_ref()
+ }
+
+ fn fallback_fluent_bundle(&self) -> &FluentBundle {
+ &**self.fallback_bundle
+ }
+}
+
impl Emitter for JsonEmitter {
fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) {
let data = Diagnostic::from_errors_diagnostic(diag, self);
Some(&self.sm)
}
- fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
- self.fluent_bundle.as_ref()
- }
-
- fn fallback_fluent_bundle(&self) -> &FluentBundle {
- &**self.fallback_bundle
- }
-
fn should_show_explain(&self) -> bool {
!matches!(self.json_rendered, HumanReadableErrorType::Short(_))
}
pub mod registry;
mod snippet;
mod styled_buffer;
+pub mod translation;
pub use snippet::Style;
--- /dev/null
+use crate::snippet::Style;
+use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle};
+use rustc_data_structures::sync::Lrc;
+use rustc_error_messages::FluentArgs;
+use std::borrow::Cow;
+
+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<&Lrc<FluentBundle>>;
+
+ /// 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;
+
+ /// Convert diagnostic arguments (a rustc internal type that exists to implement
+ /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
+ ///
+ /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
+ /// passed around as a reference thereafter.
+ fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> {
+ FromIterator::from_iter(args.to_vec().drain(..))
+ }
+
+ /// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
+ fn translate_messages(
+ &self,
+ messages: &[(DiagnosticMessage, Style)],
+ args: &FluentArgs<'_>,
+ ) -> Cow<'_, str> {
+ Cow::Owned(
+ messages.iter().map(|(m, _)| self.translate_message(m, args)).collect::<String>(),
+ )
+ }
+
+ /// Convert a `DiagnosticMessage` to a string, performing translation if necessary.
+ fn translate_message<'a>(
+ &'a self,
+ message: &'a DiagnosticMessage,
+ args: &'a FluentArgs<'_>,
+ ) -> Cow<'_, str> {
+ trace!(?message, ?args);
+ let (identifier, attr) = match message {
+ DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
+ DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
+ };
+
+ let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> {
+ let message = bundle.get_message(&identifier)?;
+ let value = match attr {
+ Some(attr) => message.get_attribute(attr)?.value(),
+ None => message.value()?,
+ };
+ debug!(?message, ?value);
+
+ let mut errs = vec![];
+ let translated = bundle.format_pattern(value, Some(&args), &mut errs);
+ debug!(?translated, ?errs);
+ Some((translated, errs))
+ };
+
+ self.fluent_bundle()
+ .and_then(|bundle| translate_with_bundle(bundle))
+ // If `translate_with_bundle` returns `None` with the primary bundle, this is likely
+ // just that the primary bundle doesn't contain the message being translated, so
+ // proceed to the fallback bundle.
+ //
+ // However, when errors are produced from translation, then that means the translation
+ // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided).
+ //
+ // In debug builds, assert so that compiler devs can spot the broken translation and
+ // fix it..
+ .inspect(|(_, errs)| {
+ debug_assert!(
+ errs.is_empty(),
+ "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
+ identifier,
+ attr,
+ args,
+ errs
+ );
+ })
+ // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so
+ // just hide it and try with the fallback bundle.
+ .filter(|(_, errs)| errs.is_empty())
+ .or_else(|| translate_with_bundle(self.fallback_fluent_bundle()))
+ .map(|(translated, errs)| {
+ // Always bail out for errors with the fallback bundle.
+ assert!(
+ errs.is_empty(),
+ "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
+ identifier,
+ attr,
+ args,
+ errs
+ );
+ translated
+ })
+ .expect("failed to find message in primary or fallback fluent bundles")
+ }
+}
//! Validates syntax inside Rust code blocks (\`\`\`rust).
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{
- emitter::Emitter, Applicability, Diagnostic, Handler, LazyFallbackBundle, LintDiagnosticBuilder,
+ emitter::Emitter, translation::Translate, Applicability, Diagnostic, Handler,
+ LazyFallbackBundle, LintDiagnosticBuilder,
};
use rustc_parse::parse_stream_from_source_str;
use rustc_session::parse::ParseSess;
fallback_bundle: LazyFallbackBundle,
}
+impl Translate for BufferEmitter {
+ fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+ None
+ }
+
+ fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
+ &**self.fallback_bundle
+ }
+}
+
impl Emitter for BufferEmitter {
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
let mut buffer = self.buffer.borrow_mut();
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None
}
-
- fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
- None
- }
-
- fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
- &**self.fallback_bundle
- }
}
use rustc_data_structures::sync::{Lrc, Send};
use rustc_errors::emitter::{Emitter, EmitterWriter};
+use rustc_errors::translation::Translate;
use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel};
use rustc_session::parse::ParseSess as RawParseSess;
use rustc_span::{
/// Emitter which discards every error.
struct SilentEmitter;
-impl Emitter for SilentEmitter {
- fn source_map(&self) -> Option<&Lrc<SourceMap>> {
- None
- }
- fn emit_diagnostic(&mut self, _db: &Diagnostic) {}
+impl Translate for SilentEmitter {
fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
None
}
+
fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
panic!("silent emitter attempted to translate a diagnostic");
}
}
+impl Emitter for SilentEmitter {
+ fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+ None
+ }
+
+ fn emit_diagnostic(&mut self, _db: &Diagnostic) {}
+}
+
fn silent_emitter() -> Box<dyn Emitter + Send> {
Box::new(SilentEmitter {})
}
}
}
+impl Translate for SilentOnIgnoredFilesEmitter {
+ fn fluent_bundle(&self) -> Option<&Lrc<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<&Lrc<SourceMap>> {
None
}
+
fn emit_diagnostic(&mut self, db: &Diagnostic) {
if db.level() == DiagnosticLevel::Fatal {
return self.handle_non_ignoreable_error(db);
}
self.handle_non_ignoreable_error(db);
}
-
- fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
- self.emitter.fluent_bundle()
- }
-
- fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
- self.emitter.fallback_fluent_bundle()
- }
}
fn default_handler(
num_emitted_errors: Lrc<AtomicU32>,
}
+ impl Translate for TestEmitter {
+ fn fluent_bundle(&self) -> Option<&Lrc<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<&Lrc<SourceMap>> {
None
}
+
fn emit_diagnostic(&mut self, _db: &Diagnostic) {
self.num_emitted_errors.fetch_add(1, Ordering::Release);
}
- fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
- None
- }
- fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
- panic!("test emitter attempted to translate a diagnostic");
- }
}
fn build_diagnostic(level: DiagnosticLevel, span: Option<MultiSpan>) -> Diagnostic {
"src/tools/bump-stage0",
]
+[autolabel."A-translation"]
+trigger_files = [
+ "compiler/rustc_error_messages",
+ "compiler/rustc_errors/src/translation.rs",
+ "compiler/rustc_macros/src/diagnostics"
+]
+
[notify-zulip."I-prioritize"]
zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "#{number} {title}"
[mentions."compiler/rustc_middle/src/mir/syntax.rs"]
message = "This PR changes MIR"
cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@celinval", "@vakaras"]
+
+[mentions."compiler/rustc_error_messages"]
+message = "`rustc_error_messages` was changed"
+cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank"]
+
+[mentions."compiler/rustc_errors/src/translation.rs"]
+message = "`rustc_errors::translation` was changed"
+cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank"]
+
+[mentions."compiler/rustc_macros/src/diagnostics"]
+message = "`rustc_macros::diagnostics` was changed"
+cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank"]