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::profiling::VerboseTimingGuard;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::emitter::Emitter;
|
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_fs_util::link_or_copy;
|
||||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
use rustc_incremental::{
|
use rustc_incremental::{
|
||||||
|
@ -1750,7 +1753,7 @@ impl Translate for SharedEmitter {
|
||||||
|
|
||||||
impl Emitter for SharedEmitter {
|
impl Emitter for SharedEmitter {
|
||||||
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
|
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 {
|
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
|
||||||
msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
|
msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
|
||||||
code: diag.code.clone(),
|
code: diag.code.clone(),
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
use crate::emitter::FileWithAnnotatedLines;
|
use crate::emitter::FileWithAnnotatedLines;
|
||||||
use crate::snippet::Line;
|
use crate::snippet::Line;
|
||||||
use crate::translation::Translate;
|
use crate::translation::{to_fluent_args, Translate};
|
||||||
use crate::{
|
use crate::{
|
||||||
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
|
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
|
||||||
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
|
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
|
||||||
|
@ -46,7 +46,7 @@ impl Translate for AnnotateSnippetEmitterWriter {
|
||||||
impl Emitter for AnnotateSnippetEmitterWriter {
|
impl Emitter for AnnotateSnippetEmitterWriter {
|
||||||
/// The entry point for the diagnostics generation
|
/// The entry point for the diagnostics generation
|
||||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
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 children = diag.children.clone();
|
||||||
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
|
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
|
/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
|
||||||
/// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
|
/// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
|
||||||
/// diagnostic emission.
|
/// 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
|
/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
|
||||||
/// to a `FluentValue` by the emitter to be used in diagnostic translation.
|
/// to a `FluentValue` by the emitter to be used in diagnostic translation.
|
||||||
|
@ -229,7 +233,7 @@ pub struct Diagnostic {
|
||||||
pub span: MultiSpan,
|
pub span: MultiSpan,
|
||||||
pub children: Vec<SubDiagnostic>,
|
pub children: Vec<SubDiagnostic>,
|
||||||
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
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
|
/// 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
|
/// 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(),
|
span: MultiSpan::new(),
|
||||||
children: vec![],
|
children: vec![],
|
||||||
suggestions: Ok(vec![]),
|
suggestions: Ok(vec![]),
|
||||||
args: vec![],
|
args: Default::default(),
|
||||||
sort_span: DUMMY_SP,
|
sort_span: DUMMY_SP,
|
||||||
is_lint: false,
|
is_lint: false,
|
||||||
}
|
}
|
||||||
|
@ -956,8 +960,11 @@ impl Diagnostic {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn args(&self) -> &[DiagnosticArg<'static>] {
|
// Exact iteration order of diagnostic arguments shouldn't make a difference to output because
|
||||||
&self.args
|
// 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(
|
pub fn set_arg(
|
||||||
|
@ -965,7 +972,7 @@ impl Diagnostic {
|
||||||
name: impl Into<Cow<'static, str>>,
|
name: impl Into<Cow<'static, str>>,
|
||||||
arg: impl IntoDiagnosticArg,
|
arg: impl IntoDiagnosticArg,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.args.push((name.into(), arg.into_diagnostic_arg()));
|
self.args.insert(name.into(), arg.into_diagnostic_arg());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustc_span::{FileLines, SourceFile, Span};
|
||||||
|
|
||||||
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
|
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
|
||||||
use crate::styled_buffer::StyledBuffer;
|
use crate::styled_buffer::StyledBuffer;
|
||||||
use crate::translation::Translate;
|
use crate::translation::{to_fluent_args, Translate};
|
||||||
use crate::{
|
use crate::{
|
||||||
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
|
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
|
||||||
LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
|
LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
|
||||||
|
@ -535,7 +535,7 @@ impl Emitter for EmitterWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
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 children = diag.children.clone();
|
||||||
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
|
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::emitter::{Emitter, HumanReadableErrorType};
|
||||||
use crate::registry::Registry;
|
use crate::registry::Registry;
|
||||||
use crate::translation::Translate;
|
use crate::translation::{to_fluent_args, Translate};
|
||||||
use crate::DiagnosticId;
|
use crate::DiagnosticId;
|
||||||
use crate::{
|
use crate::{
|
||||||
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
|
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
|
||||||
|
@ -312,7 +312,7 @@ struct UnusedExterns<'a, 'b, 'c> {
|
||||||
|
|
||||||
impl Diagnostic {
|
impl Diagnostic {
|
||||||
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> 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 sugg = diag.suggestions.iter().flatten().map(|sugg| {
|
||||||
let translated_message = je.translate_message(&sugg.msg, &args);
|
let translated_message = je.translate_message(&sugg.msg, &args);
|
||||||
Diagnostic {
|
Diagnostic {
|
||||||
|
|
|
@ -4,6 +4,27 @@ use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_error_messages::FluentArgs;
|
use rustc_error_messages::FluentArgs;
|
||||||
use std::borrow::Cow;
|
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 {
|
pub trait Translate {
|
||||||
/// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
|
/// 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`
|
/// 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.
|
/// unavailable for the requested locale.
|
||||||
fn fallback_fluent_bundle(&self) -> &FluentBundle;
|
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.
|
/// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
|
||||||
fn translate_messages(
|
fn translate_messages(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
//! Validates syntax inside Rust code blocks (\`\`\`rust).
|
//! Validates syntax inside Rust code blocks (\`\`\`rust).
|
||||||
use rustc_data_structures::sync::{Lock, Lrc};
|
use rustc_data_structures::sync::{Lock, Lrc};
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
emitter::Emitter, translation::Translate, Applicability, Diagnostic, Handler,
|
emitter::Emitter,
|
||||||
LazyFallbackBundle,
|
translation::{to_fluent_args, Translate},
|
||||||
|
Applicability, Diagnostic, Handler, LazyFallbackBundle,
|
||||||
};
|
};
|
||||||
use rustc_parse::parse_stream_from_source_str;
|
use rustc_parse::parse_stream_from_source_str;
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
|
@ -193,7 +194,7 @@ impl Emitter for BufferEmitter {
|
||||||
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
|
||||||
let mut buffer = self.buffer.borrow_mut();
|
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);
|
let translated_main_message = self.translate_message(&diag.message[0].0, &fluent_args);
|
||||||
|
|
||||||
buffer.messages.push(format!("error from rustc: {}", translated_main_message));
|
buffer.messages.push(format!("error from rustc: {}", translated_main_message));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue