errors: implement fallback diagnostic translation

This commit updates the signatures of all diagnostic functions to accept
types that can be converted into a `DiagnosticMessage`. This enables
existing diagnostic calls to continue to work as before and Fluent
identifiers to be provided. The `SessionDiagnostic` derive just
generates normal diagnostic calls, so these APIs had to be modified to
accept Fluent identifiers.

In addition, loading of the "fallback" Fluent bundle, which contains the
built-in English messages, has been implemented.

Each diagnostic now has "arguments" which correspond to variables in the
Fluent messages (necessary to render a Fluent message) but no API for
adding arguments has been added yet. Therefore, diagnostics (that do not
require interpolation) can be converted to use Fluent identifiers and
will be output as before.
This commit is contained in:
David Wood 2022-03-26 07:27:43 +00:00
parent c45f29595d
commit 7f91697b50
46 changed files with 919 additions and 293 deletions

View file

@ -7,16 +7,22 @@
use crate::emitter::FileWithAnnotatedLines;
use crate::snippet::Line;
use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Emitter, Level, MultiSpan, SubDiagnostic};
use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle, Level,
MultiSpan, Style, SubDiagnostic,
};
use annotate_snippets::display_list::{DisplayList, FormatOptions};
use annotate_snippets::snippet::*;
use rustc_data_structures::sync::Lrc;
use rustc_error_messages::FluentArgs;
use rustc_span::source_map::SourceMap;
use rustc_span::SourceFile;
/// Generates diagnostics using annotate-snippet
pub struct AnnotateSnippetEmitterWriter {
source_map: Option<Lrc<SourceMap>>,
fallback_bundle: Lrc<FluentBundle>,
/// If true, hides the longer explanation text
short_message: bool,
/// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs.
@ -28,8 +34,10 @@ pub struct AnnotateSnippetEmitterWriter {
impl Emitter for AnnotateSnippetEmitterWriter {
/// The entry point for the diagnostics generation
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
let fluent_args = self.to_fluent_args(diag.args());
let mut children = diag.children.clone();
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag);
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
&self.source_map,
@ -41,7 +49,8 @@ impl Emitter for AnnotateSnippetEmitterWriter {
self.emit_messages_default(
&diag.level,
diag.message().to_string(),
&diag.message,
&fluent_args,
&diag.code,
&primary_span,
&children,
@ -53,6 +62,14 @@ impl Emitter for AnnotateSnippetEmitterWriter {
self.source_map.as_ref()
}
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
None
}
fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle> {
&self.fallback_bundle
}
fn should_show_explain(&self) -> bool {
!self.short_message
}
@ -82,10 +99,11 @@ fn annotation_type_for_level(level: Level) -> AnnotationType {
impl AnnotateSnippetEmitterWriter {
pub fn new(
source_map: Option<Lrc<SourceMap>>,
fallback_bundle: Lrc<FluentBundle>,
short_message: bool,
macro_backtrace: bool,
) -> Self {
Self { source_map, short_message, ui_testing: false, macro_backtrace }
Self { source_map, fallback_bundle, short_message, ui_testing: false, macro_backtrace }
}
/// Allows to modify `Self` to enable or disable the `ui_testing` flag.
@ -99,12 +117,14 @@ impl AnnotateSnippetEmitterWriter {
fn emit_messages_default(
&mut self,
level: &Level,
message: String,
messages: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
code: &Option<DiagnosticId>,
msp: &MultiSpan,
_children: &[SubDiagnostic],
_suggestions: &[CodeSuggestion],
) {
let message = self.translate_messages(messages, args);
if let Some(source_map) = &self.source_map {
// Make sure our primary file comes first
let primary_lo = if let Some(ref primary_span) = msp.primary_span().as_ref() {
@ -120,8 +140,7 @@ impl AnnotateSnippetEmitterWriter {
// should be done if it happens
return;
};
let mut annotated_files =
FileWithAnnotatedLines::collect_annotations(msp, &self.source_map);
let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp);
if let Ok(pos) =
annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name))
{