errors: use HashMap
to store diagnostic args
Eager translation will enable subdiagnostics to be translated multiple times with different arguments - this requires the ability to replace the value of one argument with a new value, which is better suited to a `HashMap` than the previous storage, a `Vec`. Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
parent
febbf71219
commit
508d7e6d26
7 changed files with 49 additions and 26 deletions
|
@ -15,7 +15,10 @@ 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::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
|
||||
use rustc_errors::{
|
||||
translation::{to_fluent_args, Translate},
|
||||
DiagnosticId, FatalError, Handler, Level,
|
||||
};
|
||||
use rustc_fs_util::link_or_copy;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_incremental::{
|
||||
|
@ -1750,7 +1753,7 @@ impl Translate for SharedEmitter {
|
|||
|
||||
impl Emitter for SharedEmitter {
|
||||
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
|
||||
let fluent_args = self.to_fluent_args(diag.args());
|
||||
let fluent_args = to_fluent_args(diag.args());
|
||||
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
|
||||
msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
|
||||
code: diag.code.clone(),
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
use crate::emitter::FileWithAnnotatedLines;
|
||||
use crate::snippet::Line;
|
||||
use crate::translation::Translate;
|
||||
use crate::translation::{to_fluent_args, Translate};
|
||||
use crate::{
|
||||
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
|
||||
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
|
||||
|
@ -46,7 +46,7 @@ impl Translate for 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 fluent_args = to_fluent_args(diag.args());
|
||||
|
||||
let mut children = diag.children.clone();
|
||||
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
|
||||
|
|
|
@ -27,7 +27,11 @@ pub struct SuggestionsDisabled;
|
|||
/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
|
||||
/// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
|
||||
/// diagnostic emission.
|
||||
pub type DiagnosticArg<'source> = (Cow<'source, str>, DiagnosticArgValue<'source>);
|
||||
pub type DiagnosticArg<'iter, 'source> =
|
||||
(&'iter DiagnosticArgName<'source>, &'iter DiagnosticArgValue<'source>);
|
||||
|
||||
/// Name of a diagnostic argument.
|
||||
pub type DiagnosticArgName<'source> = Cow<'source, str>;
|
||||
|
||||
/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
|
||||
/// to a `FluentValue` by the emitter to be used in diagnostic translation.
|
||||
|
@ -229,7 +233,7 @@ pub struct Diagnostic {
|
|||
pub span: MultiSpan,
|
||||
pub children: Vec<SubDiagnostic>,
|
||||
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
||||
args: Vec<DiagnosticArg<'static>>,
|
||||
args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>,
|
||||
|
||||
/// This is not used for highlighting or rendering any error message. Rather, it can be used
|
||||
/// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
|
||||
|
@ -321,7 +325,7 @@ impl Diagnostic {
|
|||
span: MultiSpan::new(),
|
||||
children: vec![],
|
||||
suggestions: Ok(vec![]),
|
||||
args: vec![],
|
||||
args: Default::default(),
|
||||
sort_span: DUMMY_SP,
|
||||
is_lint: false,
|
||||
}
|
||||
|
@ -956,8 +960,11 @@ impl Diagnostic {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn args(&self) -> &[DiagnosticArg<'static>] {
|
||||
&self.args
|
||||
// Exact iteration order of diagnostic arguments shouldn't make a difference to output because
|
||||
// they're only used in interpolation.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
pub fn args<'a>(&'a self) -> impl Iterator<Item = DiagnosticArg<'a, 'static>> {
|
||||
self.args.iter()
|
||||
}
|
||||
|
||||
pub fn set_arg(
|
||||
|
@ -965,7 +972,7 @@ impl Diagnostic {
|
|||
name: impl Into<Cow<'static, str>>,
|
||||
arg: impl IntoDiagnosticArg,
|
||||
) -> &mut Self {
|
||||
self.args.push((name.into(), arg.into_diagnostic_arg()));
|
||||
self.args.insert(name.into(), arg.into_diagnostic_arg());
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ 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::translation::{to_fluent_args, Translate};
|
||||
use crate::{
|
||||
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
|
||||
LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
|
||||
|
@ -535,7 +535,7 @@ impl Emitter for EmitterWriter {
|
|||
}
|
||||
|
||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
||||
let fluent_args = self.to_fluent_args(diag.args());
|
||||
let fluent_args = to_fluent_args(diag.args());
|
||||
|
||||
let mut children = diag.children.clone();
|
||||
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
|
||||
|
|
|
@ -13,7 +13,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
|
|||
|
||||
use crate::emitter::{Emitter, HumanReadableErrorType};
|
||||
use crate::registry::Registry;
|
||||
use crate::translation::Translate;
|
||||
use crate::translation::{to_fluent_args, Translate};
|
||||
use crate::DiagnosticId;
|
||||
use crate::{
|
||||
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
|
||||
|
@ -312,7 +312,7 @@ struct UnusedExterns<'a, 'b, 'c> {
|
|||
|
||||
impl Diagnostic {
|
||||
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
|
||||
let args = je.to_fluent_args(diag.args());
|
||||
let args = to_fluent_args(diag.args());
|
||||
let sugg = diag.suggestions.iter().flatten().map(|sugg| {
|
||||
let translated_message = je.translate_message(&sugg.msg, &args);
|
||||
Diagnostic {
|
||||
|
|
|
@ -4,6 +4,27 @@ use rustc_data_structures::sync::Lrc;
|
|||
use rustc_error_messages::FluentArgs;
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// 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.
|
||||
pub fn to_fluent_args<'iter, 'arg: 'iter>(
|
||||
iter: impl Iterator<Item = DiagnosticArg<'iter, 'arg>>,
|
||||
) -> FluentArgs<'arg> {
|
||||
let mut args = if let Some(size) = iter.size_hint().1 {
|
||||
FluentArgs::with_capacity(size)
|
||||
} else {
|
||||
FluentArgs::new()
|
||||
};
|
||||
|
||||
for (k, v) in iter {
|
||||
args.set(k.clone(), v.clone());
|
||||
}
|
||||
|
||||
args
|
||||
}
|
||||
|
||||
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`
|
||||
|
@ -15,15 +36,6 @@ pub trait Translate {
|
|||
/// 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.iter().cloned())
|
||||
}
|
||||
|
||||
/// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
|
||||
fn translate_messages(
|
||||
&self,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
//! Validates syntax inside Rust code blocks (\`\`\`rust).
|
||||
use rustc_data_structures::sync::{Lock, Lrc};
|
||||
use rustc_errors::{
|
||||
emitter::Emitter, translation::Translate, Applicability, Diagnostic, Handler,
|
||||
LazyFallbackBundle,
|
||||
emitter::Emitter,
|
||||
translation::{to_fluent_args, Translate},
|
||||
Applicability, Diagnostic, Handler, LazyFallbackBundle,
|
||||
};
|
||||
use rustc_parse::parse_stream_from_source_str;
|
||||
use rustc_session::parse::ParseSess;
|
||||
|
@ -193,7 +194,7 @@ impl Emitter for BufferEmitter {
|
|||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
|
||||
let fluent_args = self.to_fluent_args(diag.args());
|
||||
let fluent_args = to_fluent_args(diag.args());
|
||||
let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args);
|
||||
|
||||
buffer.messages.push(format!("error from rustc: {}", translated_main_message));
|
||||
|
|
Loading…
Add table
Reference in a new issue