1
Fork 0

errors: introduce DiagnosticMessage

Introduce a `DiagnosticMessage` type that will enable diagnostic
messages to be simple strings or Fluent identifiers.
`DiagnosticMessage` is now used in the implementation of the standard
`DiagnosticBuilder` APIs.

Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
David Wood 2022-03-23 07:34:20 +00:00
parent a22cf2af05
commit 8c684563a5
10 changed files with 79 additions and 43 deletions

View file

@ -1708,13 +1708,13 @@ impl 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) {
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
msg: diag.message(), msg: diag.message().to_string(),
code: diag.code.clone(), code: diag.code.clone(),
lvl: diag.level(), lvl: diag.level(),
}))); })));
for child in &diag.children { for child in &diag.children {
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
msg: child.message(), msg: child.message().to_string(),
code: None, code: None,
lvl: child.level, lvl: child.level,
}))); })));

View file

@ -41,7 +41,7 @@ impl Emitter for AnnotateSnippetEmitterWriter {
self.emit_messages_default( self.emit_messages_default(
&diag.level, &diag.level,
diag.message(), diag.message().to_string(),
&diag.code, &diag.code,
&primary_span, &primary_span,
&children, &children,

View file

@ -18,6 +18,34 @@ use std::hash::{Hash, Hasher};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub struct SuggestionsDisabled; pub struct SuggestionsDisabled;
/// Abstraction over a message in a diagnostic to support both translatable and non-translatable
/// diagnostic messages.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum DiagnosticMessage {
/// Non-translatable diagnostic message.
Str(String),
/// Identifier for a Fluent message corresponding to the diagnostic message.
FluentIdentifier(String),
}
impl DiagnosticMessage {
/// Convert `DiagnosticMessage` to a `&str`.
pub fn as_str(&self) -> &str {
match self {
DiagnosticMessage::Str(msg) => msg,
DiagnosticMessage::FluentIdentifier(..) => unimplemented!(),
}
}
/// Convert `DiagnosticMessage` to an owned `String`.
pub fn to_string(self) -> String {
match self {
DiagnosticMessage::Str(msg) => msg,
DiagnosticMessage::FluentIdentifier(..) => unimplemented!(),
}
}
}
#[must_use] #[must_use]
#[derive(Clone, Debug, Encodable, Decodable)] #[derive(Clone, Debug, Encodable, Decodable)]
pub struct Diagnostic { pub struct Diagnostic {
@ -25,7 +53,7 @@ pub struct Diagnostic {
// outside of what methods in this crate themselves allow. // outside of what methods in this crate themselves allow.
crate level: Level, crate level: Level,
pub message: Vec<(String, Style)>, pub message: Vec<(DiagnosticMessage, Style)>,
pub code: Option<DiagnosticId>, pub code: Option<DiagnosticId>,
pub span: MultiSpan, pub span: MultiSpan,
pub children: Vec<SubDiagnostic>, pub children: Vec<SubDiagnostic>,
@ -52,7 +80,7 @@ pub enum DiagnosticId {
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
pub struct SubDiagnostic { pub struct SubDiagnostic {
pub level: Level, pub level: Level,
pub message: Vec<(String, Style)>, pub message: Vec<(DiagnosticMessage, Style)>,
pub span: MultiSpan, pub span: MultiSpan,
pub render_span: Option<MultiSpan>, pub render_span: Option<MultiSpan>,
} }
@ -112,7 +140,7 @@ impl Diagnostic {
pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self { pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
Diagnostic { Diagnostic {
level, level,
message: vec![(message.to_owned(), Style::NoStyle)], message: vec![(DiagnosticMessage::Str(message.to_owned()), Style::NoStyle)],
code, code,
span: MultiSpan::new(), span: MultiSpan::new(),
children: vec![], children: vec![],
@ -465,7 +493,7 @@ impl Diagnostic {
.map(|(span, snippet)| SubstitutionPart { snippet, span }) .map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect(), .collect(),
}], }],
msg: msg.to_owned(), msg: DiagnosticMessage::Str(msg.to_owned()),
style, style,
applicability, applicability,
tool_metadata: Default::default(), tool_metadata: Default::default(),
@ -493,7 +521,7 @@ impl Diagnostic {
.map(|(span, snippet)| SubstitutionPart { snippet, span }) .map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect(), .collect(),
}], }],
msg: msg.to_owned(), msg: DiagnosticMessage::Str(msg.to_owned()),
style: SuggestionStyle::CompletelyHidden, style: SuggestionStyle::CompletelyHidden,
applicability, applicability,
tool_metadata: Default::default(), tool_metadata: Default::default(),
@ -548,7 +576,7 @@ impl Diagnostic {
substitutions: vec![Substitution { substitutions: vec![Substitution {
parts: vec![SubstitutionPart { snippet: suggestion, span: sp }], parts: vec![SubstitutionPart { snippet: suggestion, span: sp }],
}], }],
msg: msg.to_owned(), msg: DiagnosticMessage::Str(msg.to_owned()),
style, style,
applicability, applicability,
tool_metadata: Default::default(), tool_metadata: Default::default(),
@ -591,7 +619,7 @@ impl Diagnostic {
.collect(); .collect();
self.push_suggestion(CodeSuggestion { self.push_suggestion(CodeSuggestion {
substitutions, substitutions,
msg: msg.to_owned(), msg: DiagnosticMessage::Str(msg.to_owned()),
style: SuggestionStyle::ShowCode, style: SuggestionStyle::ShowCode,
applicability, applicability,
tool_metadata: Default::default(), tool_metadata: Default::default(),
@ -616,7 +644,7 @@ impl Diagnostic {
.collect(), .collect(),
}) })
.collect(), .collect(),
msg: msg.to_owned(), msg: DiagnosticMessage::Str(msg.to_owned()),
style: SuggestionStyle::ShowCode, style: SuggestionStyle::ShowCode,
applicability, applicability,
tool_metadata: Default::default(), tool_metadata: Default::default(),
@ -698,7 +726,7 @@ impl Diagnostic {
) { ) {
self.push_suggestion(CodeSuggestion { self.push_suggestion(CodeSuggestion {
substitutions: vec![], substitutions: vec![],
msg: msg.to_owned(), msg: DiagnosticMessage::Str(msg.to_owned()),
style: SuggestionStyle::CompletelyHidden, style: SuggestionStyle::CompletelyHidden,
applicability, applicability,
tool_metadata: ToolMetadata::new(tool_metadata), tool_metadata: ToolMetadata::new(tool_metadata),
@ -733,15 +761,15 @@ impl Diagnostic {
} }
pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self { pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self {
self.message[0] = (msg.into(), Style::NoStyle); self.message[0] = (DiagnosticMessage::Str(msg.into()), Style::NoStyle);
self self
} }
pub fn message(&self) -> String { pub fn message(&self) -> DiagnosticMessage {
self.message.iter().map(|i| i.0.as_str()).collect::<String>() DiagnosticMessage::Str(self.message.iter().map(|i| i.0.as_str()).collect::<String>())
} }
pub fn styled_message(&self) -> &Vec<(String, Style)> { pub fn styled_message(&self) -> &Vec<(DiagnosticMessage, Style)> {
&self.message &self.message
} }
@ -758,7 +786,7 @@ impl Diagnostic {
) { ) {
let sub = SubDiagnostic { let sub = SubDiagnostic {
level, level,
message: vec![(message.to_owned(), Style::NoStyle)], message: vec![(DiagnosticMessage::Str(message.to_owned()), Style::NoStyle)],
span, span,
render_span, render_span,
}; };
@ -770,10 +798,11 @@ impl Diagnostic {
fn sub_with_highlights( fn sub_with_highlights(
&mut self, &mut self,
level: Level, level: Level,
message: Vec<(String, Style)>, mut message: Vec<(String, Style)>,
span: MultiSpan, span: MultiSpan,
render_span: Option<MultiSpan>, render_span: Option<MultiSpan>,
) { ) {
let message = message.drain(..).map(|m| (DiagnosticMessage::Str(m.0), m.1)).collect();
let sub = SubDiagnostic { level, message, span, render_span }; let sub = SubDiagnostic { level, message, span, render_span };
self.children.push(sub); self.children.push(sub);
} }
@ -783,7 +812,7 @@ impl Diagnostic {
&self, &self,
) -> ( ) -> (
&Level, &Level,
&Vec<(String, Style)>, &Vec<(DiagnosticMessage, Style)>,
&Option<DiagnosticId>, &Option<DiagnosticId>,
&MultiSpan, &MultiSpan,
&Result<Vec<CodeSuggestion>, SuggestionsDisabled>, &Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
@ -816,11 +845,11 @@ impl PartialEq for Diagnostic {
} }
impl SubDiagnostic { impl SubDiagnostic {
pub fn message(&self) -> String { pub fn message(&self) -> DiagnosticMessage {
self.message.iter().map(|i| i.0.as_str()).collect::<String>() DiagnosticMessage::Str(self.message.iter().map(|i| i.0.as_str()).collect::<String>())
} }
pub fn styled_message(&self) -> &Vec<(String, Style)> { pub fn styled_message(&self) -> &Vec<(DiagnosticMessage, Style)> {
&self.message &self.message
} }
} }

View file

@ -15,8 +15,8 @@ use rustc_span::{MultiSpan, 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::{ use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, Handler, Level, SubDiagnostic, SubstitutionHighlight, CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Handler, Level, SubDiagnostic,
SuggestionStyle, SubstitutionHighlight, SuggestionStyle,
}; };
use rustc_lint_defs::pluralize; use rustc_lint_defs::pluralize;
@ -236,7 +236,7 @@ pub trait Emitter {
// don't display multipart suggestions as labels // don't display multipart suggestions as labels
sugg.substitutions[0].parts.len() == 1 && sugg.substitutions[0].parts.len() == 1 &&
// don't display long messages as labels // don't display long messages as labels
sugg.msg.split_whitespace().count() < 10 && sugg.msg.as_str().split_whitespace().count() < 10 &&
// don't display multiline suggestions as labels // don't display multiline suggestions as labels
!sugg.substitutions[0].parts[0].snippet.contains('\n') && !sugg.substitutions[0].parts[0].snippet.contains('\n') &&
![ ![
@ -252,12 +252,12 @@ pub trait Emitter {
let msg = if substitution.is_empty() || sugg.style.hide_inline() { let msg = if substitution.is_empty() || sugg.style.hide_inline() {
// This substitution is only removal OR we explicitly don't want to show the // This substitution is only removal OR we explicitly don't want to show the
// code inline (`hide_inline`). Therefore, we don't show the substitution. // code inline (`hide_inline`). Therefore, we don't show the substitution.
format!("help: {}", sugg.msg) format!("help: {}", sugg.msg.as_str())
} else { } else {
// Show the default suggestion text with the substitution // Show the default suggestion text with the substitution
format!( format!(
"help: {}{}: `{}`", "help: {}{}: `{}`",
sugg.msg, sugg.msg.as_str(),
if self if self
.source_map() .source_map()
.map(|sm| is_case_difference( .map(|sm| is_case_difference(
@ -333,7 +333,7 @@ pub trait Emitter {
children.push(SubDiagnostic { children.push(SubDiagnostic {
level: Level::Note, level: Level::Note,
message: vec![(msg, Style::NoStyle)], message: vec![(DiagnosticMessage::Str(msg), Style::NoStyle)],
span: MultiSpan::new(), span: MultiSpan::new(),
render_span: None, render_span: None,
}); });
@ -1176,7 +1176,7 @@ impl EmitterWriter {
fn msg_to_buffer( fn msg_to_buffer(
&self, &self,
buffer: &mut StyledBuffer, buffer: &mut StyledBuffer,
msg: &[(String, Style)], msg: &[(DiagnosticMessage, Style)],
padding: usize, padding: usize,
label: &str, label: &str,
override_style: Option<Style>, override_style: Option<Style>,
@ -1229,6 +1229,7 @@ impl EmitterWriter {
// very *weird* formats // very *weird* formats
// see? // see?
for &(ref text, ref style) in msg.iter() { for &(ref text, ref style) in msg.iter() {
let text = text.as_str();
let lines = text.split('\n').collect::<Vec<_>>(); let lines = text.split('\n').collect::<Vec<_>>();
if lines.len() > 1 { if lines.len() > 1 {
for (i, line) in lines.iter().enumerate() { for (i, line) in lines.iter().enumerate() {
@ -1247,7 +1248,7 @@ impl EmitterWriter {
fn emit_message_default( fn emit_message_default(
&mut self, &mut self,
msp: &MultiSpan, msp: &MultiSpan,
msg: &[(String, Style)], msg: &[(DiagnosticMessage, Style)],
code: &Option<DiagnosticId>, code: &Option<DiagnosticId>,
level: &Level, level: &Level,
max_line_num_len: usize, max_line_num_len: usize,
@ -1287,6 +1288,7 @@ impl EmitterWriter {
label_width += 2; label_width += 2;
} }
for &(ref text, _) in msg.iter() { for &(ref text, _) in msg.iter() {
let text = text.as_str();
// Account for newlines to align output to its label. // Account for newlines to align output to its label.
for (line, text) in normalize_whitespace(text).lines().enumerate() { for (line, text) in normalize_whitespace(text).lines().enumerate() {
buffer.append( buffer.append(
@ -1852,7 +1854,7 @@ impl EmitterWriter {
fn emit_messages_default( fn emit_messages_default(
&mut self, &mut self,
level: &Level, level: &Level,
message: &[(String, Style)], message: &[(DiagnosticMessage, Style)],
code: &Option<DiagnosticId>, code: &Option<DiagnosticId>,
span: &MultiSpan, span: &MultiSpan,
children: &[SubDiagnostic], children: &[SubDiagnostic],

View file

@ -346,7 +346,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 sugg = diag.suggestions.iter().flatten().map(|sugg| Diagnostic { let sugg = diag.suggestions.iter().flatten().map(|sugg| Diagnostic {
message: sugg.msg.clone(), message: sugg.msg.clone().to_string(),
code: None, code: None,
level: "help", level: "help",
spans: DiagnosticSpan::from_suggestion(sugg, je), spans: DiagnosticSpan::from_suggestion(sugg, je),
@ -385,7 +385,7 @@ impl Diagnostic {
let output = String::from_utf8(output).unwrap(); let output = String::from_utf8(output).unwrap();
Diagnostic { Diagnostic {
message: diag.message(), message: diag.message().to_string(),
code: DiagnosticCode::map_opt_string(diag.code.clone(), je), code: DiagnosticCode::map_opt_string(diag.code.clone(), je),
level: diag.level.to_str(), level: diag.level.to_str(),
spans: DiagnosticSpan::from_multispan(&diag.span, je), spans: DiagnosticSpan::from_multispan(&diag.span, je),
@ -402,7 +402,7 @@ impl Diagnostic {
fn from_sub_diagnostic(diag: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic { fn from_sub_diagnostic(diag: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic {
Diagnostic { Diagnostic {
message: diag.message(), message: diag.message().to_string(),
code: None, code: None,
level: diag.level.to_str(), level: diag.level.to_str(),
spans: diag spans: diag

View file

@ -145,7 +145,7 @@ pub struct CodeSuggestion {
/// ] /// ]
/// ``` /// ```
pub substitutions: Vec<Substitution>, pub substitutions: Vec<Substitution>,
pub msg: String, pub msg: DiagnosticMessage,
/// Visual representation of this suggestion. /// Visual representation of this suggestion.
pub style: SuggestionStyle, pub style: SuggestionStyle,
/// Whether or not the suggestion is approximate /// Whether or not the suggestion is approximate
@ -400,7 +400,9 @@ impl fmt::Display for ExplicitBug {
impl error::Error for ExplicitBug {} impl error::Error for ExplicitBug {}
pub use diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, SubDiagnostic}; pub use diagnostic::{
Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, SubDiagnostic,
};
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee}; pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
use std::backtrace::Backtrace; use std::backtrace::Backtrace;

View file

@ -68,17 +68,18 @@ fn emit_frag_parse_err(
arm_span: Span, arm_span: Span,
kind: AstFragmentKind, kind: AstFragmentKind,
) { ) {
if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") { // FIXME(davidtwco): avoid depending on the error message text
if parser.token == token::Eof && e.message().as_str().ends_with(", found `<eof>`") {
if !e.span.is_dummy() { if !e.span.is_dummy() {
// early end of macro arm (#52866) // early end of macro arm (#52866)
e.replace_span_with(parser.sess.source_map().next_point(parser.token.span)); e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
} }
let msg = &e.message[0]; let msg = &e.message[0];
e.message[0] = ( e.message[0] = (
format!( rustc_errors::DiagnosticMessage::Str(format!(
"macro expansion ends with an incomplete expression: {}", "macro expansion ends with an incomplete expression: {}",
msg.0.replace(", found `<eof>`", ""), msg.0.as_str().replace(", found `<eof>`", ""),
), )),
msg.1, msg.1,
); );
} }

View file

@ -1010,7 +1010,8 @@ impl<'a> Parser<'a> {
let current_qual_sp = self.prev_token.span; let current_qual_sp = self.prev_token.span;
let current_qual_sp = current_qual_sp.to(sp_start); let current_qual_sp = current_qual_sp.to(sp_start);
if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) { if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) {
if err.message() == "expected `{`, found keyword `unsafe`" { // FIXME(davidtwco): avoid depending on the error message text
if err.message().as_str() == "expected `{`, found keyword `unsafe`" {
let invalid_qual_sp = self.token.uninterpolated_span(); let invalid_qual_sp = self.token.uninterpolated_span();
let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap(); let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap();

View file

@ -780,7 +780,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
if has_custom_message { if has_custom_message {
err.note(&msg); err.note(&msg);
} else { } else {
err.message = vec![(msg, Style::NoStyle)]; err.message =
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
} }
if snippet.starts_with('&') { if snippet.starts_with('&') {
// This is already a literal borrow and the obligation is failing // This is already a literal borrow and the obligation is failing

View file

@ -176,7 +176,7 @@ struct BufferEmitter {
impl Emitter for BufferEmitter { 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();
buffer.messages.push(format!("error from rustc: {}", diag.message[0].0)); buffer.messages.push(format!("error from rustc: {}", diag.message[0].0.as_str()));
if diag.is_error() { if diag.is_error() {
buffer.has_errors = true; buffer.has_errors = true;
} }