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:
parent
c45f29595d
commit
7f91697b50
46 changed files with 919 additions and 293 deletions
|
@ -4,10 +4,12 @@ use crate::{
|
|||
SuggestionStyle, ToolMetadata,
|
||||
};
|
||||
use rustc_data_structures::stable_map::FxHashMap;
|
||||
use rustc_error_messages::FluentValue;
|
||||
use rustc_lint_defs::{Applicability, LintExpectationId};
|
||||
use rustc_serialize::json::Json;
|
||||
use rustc_span::edition::LATEST_STABLE_EDITION;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
|
@ -16,6 +18,28 @@ use std::hash::{Hash, Hasher};
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
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>);
|
||||
|
||||
/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
|
||||
/// to a `FluentValue` by the emitter to be used in diagnostic translation.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub enum DiagnosticArgValue<'source> {
|
||||
Str(Cow<'source, str>),
|
||||
Number(usize),
|
||||
}
|
||||
|
||||
impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
|
||||
fn into(self) -> FluentValue<'source> {
|
||||
match self {
|
||||
DiagnosticArgValue::Str(s) => From::from(s),
|
||||
DiagnosticArgValue::Number(n) => From::from(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||
pub struct Diagnostic {
|
||||
|
@ -28,6 +52,7 @@ pub struct Diagnostic {
|
|||
pub span: MultiSpan,
|
||||
pub children: Vec<SubDiagnostic>,
|
||||
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
||||
args: Vec<DiagnosticArg<'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
|
||||
|
@ -103,18 +128,23 @@ impl StringPart {
|
|||
}
|
||||
|
||||
impl Diagnostic {
|
||||
pub fn new(level: Level, message: &str) -> Self {
|
||||
pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
|
||||
Diagnostic::new_with_code(level, None, message)
|
||||
}
|
||||
|
||||
pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
|
||||
pub fn new_with_code<M: Into<DiagnosticMessage>>(
|
||||
level: Level,
|
||||
code: Option<DiagnosticId>,
|
||||
message: M,
|
||||
) -> Self {
|
||||
Diagnostic {
|
||||
level,
|
||||
message: vec![(DiagnosticMessage::Str(message.to_owned()), Style::NoStyle)],
|
||||
message: vec![(message.into(), Style::NoStyle)],
|
||||
code,
|
||||
span: MultiSpan::new(),
|
||||
children: vec![],
|
||||
suggestions: Ok(vec![]),
|
||||
args: vec![],
|
||||
sort_span: DUMMY_SP,
|
||||
is_lint: false,
|
||||
}
|
||||
|
@ -232,7 +262,7 @@ impl Diagnostic {
|
|||
self.set_span(after);
|
||||
for span_label in before.span_labels() {
|
||||
if let Some(label) = span_label.label {
|
||||
self.span.push_span_message(after, label);
|
||||
self.span.push_span_label(after, label);
|
||||
}
|
||||
}
|
||||
self
|
||||
|
@ -326,52 +356,67 @@ impl Diagnostic {
|
|||
}
|
||||
|
||||
/// Add a note attached to this diagnostic.
|
||||
pub fn note(&mut self, msg: &str) -> &mut Self {
|
||||
pub fn note(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
|
||||
self.sub(Level::Note, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
|
||||
pub fn highlighted_note<M: Into<DiagnosticMessage>>(
|
||||
&mut self,
|
||||
msg: Vec<(M, Style)>,
|
||||
) -> &mut Self {
|
||||
self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
||||
/// Prints the span with a note above it.
|
||||
/// This is like [`Diagnostic::note()`], but it gets its own span.
|
||||
pub fn note_once(&mut self, msg: &str) -> &mut Self {
|
||||
pub fn note_once(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
|
||||
self.sub(Level::OnceNote, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
||||
/// Prints the span with a note above it.
|
||||
/// This is like [`Diagnostic::note()`], but it gets its own span.
|
||||
pub fn span_note<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
|
||||
pub fn span_note<S: Into<MultiSpan>>(
|
||||
&mut self,
|
||||
sp: S,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::Note, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
|
||||
/// Prints the span with a note above it.
|
||||
/// This is like [`Diagnostic::note()`], but it gets its own span.
|
||||
pub fn span_note_once<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
|
||||
pub fn span_note_once<S: Into<MultiSpan>>(
|
||||
&mut self,
|
||||
sp: S,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::OnceNote, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a warning attached to this diagnostic.
|
||||
pub fn warn(&mut self, msg: &str) -> &mut Self {
|
||||
pub fn warn(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
|
||||
self.sub(Level::Warning, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
||||
/// Prints the span with a warning above it.
|
||||
/// This is like [`Diagnostic::warn()`], but it gets its own span.
|
||||
pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
|
||||
pub fn span_warn<S: Into<MultiSpan>>(
|
||||
&mut self,
|
||||
sp: S,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::Warning, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a help message attached to this diagnostic.
|
||||
pub fn help(&mut self, msg: &str) -> &mut Self {
|
||||
pub fn help(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
|
||||
self.sub(Level::Help, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
@ -384,7 +429,11 @@ impl Diagnostic {
|
|||
|
||||
/// Prints the span with some help above it.
|
||||
/// This is like [`Diagnostic::help()`], but it gets its own span.
|
||||
pub fn span_help<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
|
||||
pub fn span_help<S: Into<MultiSpan>>(
|
||||
&mut self,
|
||||
sp: S,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::Help, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
|
@ -420,7 +469,7 @@ impl Diagnostic {
|
|||
/// In other words, multiple changes need to be applied as part of this suggestion.
|
||||
pub fn multipart_suggestion(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -436,7 +485,7 @@ impl Diagnostic {
|
|||
/// In other words, multiple changes need to be applied as part of this suggestion.
|
||||
pub fn multipart_suggestion_verbose(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -450,7 +499,7 @@ impl Diagnostic {
|
|||
/// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
|
||||
pub fn multipart_suggestion_with_style(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
style: SuggestionStyle,
|
||||
|
@ -463,7 +512,7 @@ impl Diagnostic {
|
|||
.map(|(span, snippet)| SubstitutionPart { snippet, span })
|
||||
.collect(),
|
||||
}],
|
||||
msg: DiagnosticMessage::Str(msg.to_owned()),
|
||||
msg: msg.into(),
|
||||
style,
|
||||
applicability,
|
||||
tool_metadata: Default::default(),
|
||||
|
@ -479,7 +528,7 @@ impl Diagnostic {
|
|||
/// improve understandability.
|
||||
pub fn tool_only_multipart_suggestion(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -491,7 +540,7 @@ impl Diagnostic {
|
|||
.map(|(span, snippet)| SubstitutionPart { snippet, span })
|
||||
.collect(),
|
||||
}],
|
||||
msg: DiagnosticMessage::Str(msg.to_owned()),
|
||||
msg: msg.into(),
|
||||
style: SuggestionStyle::CompletelyHidden,
|
||||
applicability,
|
||||
tool_metadata: Default::default(),
|
||||
|
@ -519,7 +568,7 @@ impl Diagnostic {
|
|||
pub fn span_suggestion(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -537,7 +586,7 @@ impl Diagnostic {
|
|||
pub fn span_suggestion_with_style(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
style: SuggestionStyle,
|
||||
|
@ -546,7 +595,7 @@ impl Diagnostic {
|
|||
substitutions: vec![Substitution {
|
||||
parts: vec![SubstitutionPart { snippet: suggestion, span: sp }],
|
||||
}],
|
||||
msg: DiagnosticMessage::Str(msg.to_owned()),
|
||||
msg: msg.into(),
|
||||
style,
|
||||
applicability,
|
||||
tool_metadata: Default::default(),
|
||||
|
@ -558,7 +607,7 @@ impl Diagnostic {
|
|||
pub fn span_suggestion_verbose(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -577,7 +626,7 @@ impl Diagnostic {
|
|||
pub fn span_suggestions(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestions: impl Iterator<Item = String>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -589,7 +638,7 @@ impl Diagnostic {
|
|||
.collect();
|
||||
self.push_suggestion(CodeSuggestion {
|
||||
substitutions,
|
||||
msg: DiagnosticMessage::Str(msg.to_owned()),
|
||||
msg: msg.into(),
|
||||
style: SuggestionStyle::ShowCode,
|
||||
applicability,
|
||||
tool_metadata: Default::default(),
|
||||
|
@ -601,7 +650,7 @@ impl Diagnostic {
|
|||
/// See also [`Diagnostic::span_suggestion()`].
|
||||
pub fn multipart_suggestions(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestions: impl Iterator<Item = Vec<(Span, String)>>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -614,7 +663,7 @@ impl Diagnostic {
|
|||
.collect(),
|
||||
})
|
||||
.collect(),
|
||||
msg: DiagnosticMessage::Str(msg.to_owned()),
|
||||
msg: msg.into(),
|
||||
style: SuggestionStyle::ShowCode,
|
||||
applicability,
|
||||
tool_metadata: Default::default(),
|
||||
|
@ -628,7 +677,7 @@ impl Diagnostic {
|
|||
pub fn span_suggestion_short(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -651,7 +700,7 @@ impl Diagnostic {
|
|||
pub fn span_suggestion_hidden(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -672,7 +721,7 @@ impl Diagnostic {
|
|||
pub fn tool_only_span_suggestion(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
|
@ -690,13 +739,13 @@ impl Diagnostic {
|
|||
/// the suggestion in a tool-specific way, as it may not even directly involve Rust code.
|
||||
pub fn tool_only_suggestion_with_metadata(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
applicability: Applicability,
|
||||
tool_metadata: Json,
|
||||
) {
|
||||
self.push_suggestion(CodeSuggestion {
|
||||
substitutions: vec![],
|
||||
msg: DiagnosticMessage::Str(msg.to_owned()),
|
||||
msg: msg.into(),
|
||||
style: SuggestionStyle::CompletelyHidden,
|
||||
applicability,
|
||||
tool_metadata: ToolMetadata::new(tool_metadata),
|
||||
|
@ -730,13 +779,13 @@ impl Diagnostic {
|
|||
self.code.clone()
|
||||
}
|
||||
|
||||
pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self {
|
||||
self.message[0] = (DiagnosticMessage::Str(msg.into()), Style::NoStyle);
|
||||
pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
|
||||
self.message[0] = (msg.into(), Style::NoStyle);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn message(&self) -> DiagnosticMessage {
|
||||
DiagnosticMessage::Str(self.message.iter().map(|i| i.0.as_str()).collect::<String>())
|
||||
pub fn args(&self) -> &[DiagnosticArg<'static>] {
|
||||
&self.args
|
||||
}
|
||||
|
||||
pub fn styled_message(&self) -> &Vec<(DiagnosticMessage, Style)> {
|
||||
|
@ -750,13 +799,13 @@ impl Diagnostic {
|
|||
pub fn sub(
|
||||
&mut self,
|
||||
level: Level,
|
||||
message: &str,
|
||||
message: impl Into<DiagnosticMessage>,
|
||||
span: MultiSpan,
|
||||
render_span: Option<MultiSpan>,
|
||||
) {
|
||||
let sub = SubDiagnostic {
|
||||
level,
|
||||
message: vec![(DiagnosticMessage::Str(message.to_owned()), Style::NoStyle)],
|
||||
message: vec![(message.into(), Style::NoStyle)],
|
||||
span,
|
||||
render_span,
|
||||
};
|
||||
|
@ -765,14 +814,14 @@ impl Diagnostic {
|
|||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// public methods above.
|
||||
fn sub_with_highlights(
|
||||
fn sub_with_highlights<M: Into<DiagnosticMessage>>(
|
||||
&mut self,
|
||||
level: Level,
|
||||
mut message: Vec<(String, Style)>,
|
||||
mut message: Vec<(M, Style)>,
|
||||
span: MultiSpan,
|
||||
render_span: Option<MultiSpan>,
|
||||
) {
|
||||
let message = message.drain(..).map(|m| (DiagnosticMessage::Str(m.0), m.1)).collect();
|
||||
let message = message.drain(..).map(|m| (m.0.into(), m.1)).collect();
|
||||
let sub = SubDiagnostic { level, message, span, render_span };
|
||||
self.children.push(sub);
|
||||
}
|
||||
|
@ -813,13 +862,3 @@ impl PartialEq for Diagnostic {
|
|||
self.keys() == other.keys()
|
||||
}
|
||||
}
|
||||
|
||||
impl SubDiagnostic {
|
||||
pub fn message(&self) -> DiagnosticMessage {
|
||||
DiagnosticMessage::Str(self.message.iter().map(|i| i.0.as_str()).collect::<String>())
|
||||
}
|
||||
|
||||
pub fn styled_message(&self) -> &Vec<(DiagnosticMessage, Style)> {
|
||||
&self.message
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue