Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

triagebot: add translation-related mention groups #100379

Merged
merged 3 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc_data_structures::profiling::TimingGuard;
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::{
Expand Down Expand Up @@ -1740,6 +1740,16 @@ impl SharedEmitter {
}
}

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());
Expand All @@ -1761,14 +1771,6 @@ impl Emitter for SharedEmitter {
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 {
Expand Down
19 changes: 11 additions & 8 deletions compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

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,
Expand All @@ -32,6 +33,16 @@ pub struct AnnotateSnippetEmitterWriter {
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) {
Expand Down Expand Up @@ -63,14 +74,6 @@ impl Emitter for AnnotateSnippetEmitterWriter {
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
}
Expand Down
128 changes: 18 additions & 110 deletions compiler/rustc_errors/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ use rustc_span::{FileLines, SourceFile, Span};

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;
Expand Down Expand Up @@ -200,7 +200,7 @@ impl Margin {
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);

Expand Down Expand Up @@ -231,102 +231,6 @@ pub trait Emitter {

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:
Expand Down Expand Up @@ -616,18 +520,20 @@ pub trait Emitter {
}
}

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());
Expand Down Expand Up @@ -672,18 +578,20 @@ pub struct SilentEmitter {
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 {
Expand Down
19 changes: 11 additions & 8 deletions compiler/rustc_errors/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};

use crate::emitter::{Emitter, HumanReadableErrorType};
use crate::registry::Registry;
use crate::translation::Translate;
use crate::DiagnosticId;
use crate::{
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
Expand Down Expand Up @@ -122,6 +123,16 @@ impl JsonEmitter {
}
}

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);
Expand Down Expand Up @@ -189,14 +200,6 @@ impl Emitter for JsonEmitter {
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(_))
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ mod lock;
pub mod registry;
mod snippet;
mod styled_buffer;
pub mod translation;

pub use snippet::Style;

Expand Down
Loading