@@ -14,10 +14,10 @@ use rustc_span::{FileLines, SourceFile, Span};
1414
1515use crate :: snippet:: { Annotation , AnnotationType , Line , MultilineAnnotation , Style , StyledString } ;
1616use crate :: styled_buffer:: StyledBuffer ;
17+ use crate :: translation:: Translate ;
1718use crate :: {
18- CodeSuggestion , Diagnostic , DiagnosticArg , DiagnosticId , DiagnosticMessage , FluentBundle ,
19- Handler , LazyFallbackBundle , Level , MultiSpan , SubDiagnostic , SubstitutionHighlight ,
20- SuggestionStyle ,
19+ CodeSuggestion , Diagnostic , DiagnosticId , DiagnosticMessage , FluentBundle , Handler ,
20+ LazyFallbackBundle , Level , MultiSpan , SubDiagnostic , SubstitutionHighlight , SuggestionStyle ,
2121} ;
2222
2323use rustc_lint_defs:: pluralize;
@@ -200,7 +200,7 @@ impl Margin {
200200const ANONYMIZED_LINE_NUM : & str = "LL" ;
201201
202202/// Emitter trait for emitting errors.
203- pub trait Emitter {
203+ pub trait Emitter : Translate {
204204 /// Emit a structured diagnostic.
205205 fn emit_diagnostic ( & mut self , diag : & Diagnostic ) ;
206206
@@ -231,102 +231,6 @@ pub trait Emitter {
231231
232232 fn source_map ( & self ) -> Option < & Lrc < SourceMap > > ;
233233
234- /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
235- /// language was requested by the user then this will be `None` and `fallback_fluent_bundle`
236- /// should be used.
237- fn fluent_bundle ( & self ) -> Option < & Lrc < FluentBundle > > ;
238-
239- /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler.
240- /// Used when the user has not requested a specific language or when a localized diagnostic is
241- /// unavailable for the requested locale.
242- fn fallback_fluent_bundle ( & self ) -> & FluentBundle ;
243-
244- /// Convert diagnostic arguments (a rustc internal type that exists to implement
245- /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
246- ///
247- /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
248- /// passed around as a reference thereafter.
249- fn to_fluent_args < ' arg > ( & self , args : & [ DiagnosticArg < ' arg > ] ) -> FluentArgs < ' arg > {
250- FromIterator :: from_iter ( args. to_vec ( ) . drain ( ..) )
251- }
252-
253- /// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
254- fn translate_messages (
255- & self ,
256- messages : & [ ( DiagnosticMessage , Style ) ] ,
257- args : & FluentArgs < ' _ > ,
258- ) -> Cow < ' _ , str > {
259- Cow :: Owned (
260- messages. iter ( ) . map ( |( m, _) | self . translate_message ( m, args) ) . collect :: < String > ( ) ,
261- )
262- }
263-
264- /// Convert a `DiagnosticMessage` to a string, performing translation if necessary.
265- fn translate_message < ' a > (
266- & ' a self ,
267- message : & ' a DiagnosticMessage ,
268- args : & ' a FluentArgs < ' _ > ,
269- ) -> Cow < ' _ , str > {
270- trace ! ( ?message, ?args) ;
271- let ( identifier, attr) = match message {
272- DiagnosticMessage :: Str ( msg) => return Cow :: Borrowed ( & msg) ,
273- DiagnosticMessage :: FluentIdentifier ( identifier, attr) => ( identifier, attr) ,
274- } ;
275-
276- let translate_with_bundle = |bundle : & ' a FluentBundle | -> Option < ( Cow < ' _ , str > , Vec < _ > ) > {
277- let message = bundle. get_message ( & identifier) ?;
278- let value = match attr {
279- Some ( attr) => message. get_attribute ( attr) ?. value ( ) ,
280- None => message. value ( ) ?,
281- } ;
282- debug ! ( ?message, ?value) ;
283-
284- let mut errs = vec ! [ ] ;
285- let translated = bundle. format_pattern ( value, Some ( & args) , & mut errs) ;
286- debug ! ( ?translated, ?errs) ;
287- Some ( ( translated, errs) )
288- } ;
289-
290- self . fluent_bundle ( )
291- . and_then ( |bundle| translate_with_bundle ( bundle) )
292- // If `translate_with_bundle` returns `None` with the primary bundle, this is likely
293- // just that the primary bundle doesn't contain the message being translated, so
294- // proceed to the fallback bundle.
295- //
296- // However, when errors are produced from translation, then that means the translation
297- // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided).
298- //
299- // In debug builds, assert so that compiler devs can spot the broken translation and
300- // fix it..
301- . inspect ( |( _, errs) | {
302- debug_assert ! (
303- errs. is_empty( ) ,
304- "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}" ,
305- identifier,
306- attr,
307- args,
308- errs
309- ) ;
310- } )
311- // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so
312- // just hide it and try with the fallback bundle.
313- . filter ( |( _, errs) | errs. is_empty ( ) )
314- . or_else ( || translate_with_bundle ( self . fallback_fluent_bundle ( ) ) )
315- . map ( |( translated, errs) | {
316- // Always bail out for errors with the fallback bundle.
317- assert ! (
318- errs. is_empty( ) ,
319- "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}" ,
320- identifier,
321- attr,
322- args,
323- errs
324- ) ;
325- translated
326- } )
327- . expect ( "failed to find message in primary or fallback fluent bundles" )
328- }
329-
330234 /// Formats the substitutions of the primary_span
331235 ///
332236 /// There are a lot of conditions to this method, but in short:
@@ -616,18 +520,20 @@ pub trait Emitter {
616520 }
617521}
618522
619- impl Emitter for EmitterWriter {
620- fn source_map ( & self ) -> Option < & Lrc < SourceMap > > {
621- self . sm . as_ref ( )
622- }
623-
523+ impl Translate for EmitterWriter {
624524 fn fluent_bundle ( & self ) -> Option < & Lrc < FluentBundle > > {
625525 self . fluent_bundle . as_ref ( )
626526 }
627527
628528 fn fallback_fluent_bundle ( & self ) -> & FluentBundle {
629529 & * * self . fallback_bundle
630530 }
531+ }
532+
533+ impl Emitter for EmitterWriter {
534+ fn source_map ( & self ) -> Option < & Lrc < SourceMap > > {
535+ self . sm . as_ref ( )
536+ }
631537
632538 fn emit_diagnostic ( & mut self , diag : & Diagnostic ) {
633539 let fluent_args = self . to_fluent_args ( diag. args ( ) ) ;
@@ -672,18 +578,20 @@ pub struct SilentEmitter {
672578 pub fatal_note : Option < String > ,
673579}
674580
675- impl Emitter for SilentEmitter {
676- fn source_map ( & self ) -> Option < & Lrc < SourceMap > > {
677- None
678- }
679-
581+ impl Translate for SilentEmitter {
680582 fn fluent_bundle ( & self ) -> Option < & Lrc < FluentBundle > > {
681583 None
682584 }
683585
684586 fn fallback_fluent_bundle ( & self ) -> & FluentBundle {
685587 panic ! ( "silent emitter attempted to translate message" )
686588 }
589+ }
590+
591+ impl Emitter for SilentEmitter {
592+ fn source_map ( & self ) -> Option < & Lrc < SourceMap > > {
593+ None
594+ }
687595
688596 fn emit_diagnostic ( & mut self , d : & Diagnostic ) {
689597 if d. level == Level :: Fatal {
0 commit comments