impl Emitter for SharedEmitter {
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
- msg: diag.message(),
+ msg: diag.message().to_string(),
code: diag.code.clone(),
lvl: diag.level(),
})));
for child in &diag.children {
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
- msg: child.message(),
+ msg: child.message().to_string(),
code: None,
lvl: child.level,
})));
self.emit_messages_default(
&diag.level,
- diag.message(),
+ diag.message().to_string(),
&diag.code,
&primary_span,
&children,
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
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]
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct Diagnostic {
// outside of what methods in this crate themselves allow.
crate level: Level,
- pub message: Vec<(String, Style)>,
+ pub message: Vec<(DiagnosticMessage, Style)>,
pub code: Option<DiagnosticId>,
pub span: MultiSpan,
pub children: Vec<SubDiagnostic>,
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
pub struct SubDiagnostic {
pub level: Level,
- pub message: Vec<(String, Style)>,
+ pub message: Vec<(DiagnosticMessage, Style)>,
pub span: MultiSpan,
pub render_span: Option<MultiSpan>,
}
pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
Diagnostic {
level,
- message: vec![(message.to_owned(), Style::NoStyle)],
+ message: vec![(DiagnosticMessage::Str(message.to_owned()), Style::NoStyle)],
code,
span: MultiSpan::new(),
children: vec![],
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect(),
}],
- msg: msg.to_owned(),
+ msg: DiagnosticMessage::Str(msg.to_owned()),
style,
applicability,
tool_metadata: Default::default(),
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect(),
}],
- msg: msg.to_owned(),
+ msg: DiagnosticMessage::Str(msg.to_owned()),
style: SuggestionStyle::CompletelyHidden,
applicability,
tool_metadata: Default::default(),
substitutions: vec![Substitution {
parts: vec![SubstitutionPart { snippet: suggestion, span: sp }],
}],
- msg: msg.to_owned(),
+ msg: DiagnosticMessage::Str(msg.to_owned()),
style,
applicability,
tool_metadata: Default::default(),
.collect();
self.push_suggestion(CodeSuggestion {
substitutions,
- msg: msg.to_owned(),
+ msg: DiagnosticMessage::Str(msg.to_owned()),
style: SuggestionStyle::ShowCode,
applicability,
tool_metadata: Default::default(),
.collect(),
})
.collect(),
- msg: msg.to_owned(),
+ msg: DiagnosticMessage::Str(msg.to_owned()),
style: SuggestionStyle::ShowCode,
applicability,
tool_metadata: Default::default(),
) {
self.push_suggestion(CodeSuggestion {
substitutions: vec![],
- msg: msg.to_owned(),
+ msg: DiagnosticMessage::Str(msg.to_owned()),
style: SuggestionStyle::CompletelyHidden,
applicability,
tool_metadata: ToolMetadata::new(tool_metadata),
}
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
}
- pub fn message(&self) -> String {
- self.message.iter().map(|i| i.0.as_str()).collect::<String>()
+ pub fn message(&self) -> DiagnosticMessage {
+ 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
}
) {
let sub = SubDiagnostic {
level,
- message: vec![(message.to_owned(), Style::NoStyle)],
+ message: vec![(DiagnosticMessage::Str(message.to_owned()), Style::NoStyle)],
span,
render_span,
};
fn sub_with_highlights(
&mut self,
level: Level,
- message: Vec<(String, Style)>,
+ mut message: Vec<(String, Style)>,
span: 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 };
self.children.push(sub);
}
&self,
) -> (
&Level,
- &Vec<(String, Style)>,
+ &Vec<(DiagnosticMessage, Style)>,
&Option<DiagnosticId>,
&MultiSpan,
&Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
}
impl SubDiagnostic {
- pub fn message(&self) -> String {
- self.message.iter().map(|i| i.0.as_str()).collect::<String>()
+ pub fn message(&self) -> DiagnosticMessage {
+ 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
}
}
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
use crate::{
- CodeSuggestion, Diagnostic, DiagnosticId, Handler, Level, SubDiagnostic, SubstitutionHighlight,
- SuggestionStyle,
+ CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Handler, Level, SubDiagnostic,
+ SubstitutionHighlight, SuggestionStyle,
};
use rustc_lint_defs::pluralize;
// don't display multipart suggestions as labels
sugg.substitutions[0].parts.len() == 1 &&
// 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
!sugg.substitutions[0].parts[0].snippet.contains('\n') &&
![
let msg = if substitution.is_empty() || sugg.style.hide_inline() {
// 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.
- format!("help: {}", sugg.msg)
+ format!("help: {}", sugg.msg.as_str())
} else {
// Show the default suggestion text with the substitution
format!(
"help: {}{}: `{}`",
- sugg.msg,
+ sugg.msg.as_str(),
if self
.source_map()
.map(|sm| is_case_difference(
children.push(SubDiagnostic {
level: Level::Note,
- message: vec![(msg, Style::NoStyle)],
+ message: vec![(DiagnosticMessage::Str(msg), Style::NoStyle)],
span: MultiSpan::new(),
render_span: None,
});
fn msg_to_buffer(
&self,
buffer: &mut StyledBuffer,
- msg: &[(String, Style)],
+ msg: &[(DiagnosticMessage, Style)],
padding: usize,
label: &str,
override_style: Option<Style>,
// very *weird* formats
// see?
for &(ref text, ref style) in msg.iter() {
+ let text = text.as_str();
let lines = text.split('\n').collect::<Vec<_>>();
if lines.len() > 1 {
for (i, line) in lines.iter().enumerate() {
fn emit_message_default(
&mut self,
msp: &MultiSpan,
- msg: &[(String, Style)],
+ msg: &[(DiagnosticMessage, Style)],
code: &Option<DiagnosticId>,
level: &Level,
max_line_num_len: usize,
label_width += 2;
}
for &(ref text, _) in msg.iter() {
+ let text = text.as_str();
// Account for newlines to align output to its label.
for (line, text) in normalize_whitespace(text).lines().enumerate() {
buffer.append(
fn emit_messages_default(
&mut self,
level: &Level,
- message: &[(String, Style)],
+ message: &[(DiagnosticMessage, Style)],
code: &Option<DiagnosticId>,
span: &MultiSpan,
children: &[SubDiagnostic],
impl Diagnostic {
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
let sugg = diag.suggestions.iter().flatten().map(|sugg| Diagnostic {
- message: sugg.msg.clone(),
+ message: sugg.msg.clone().to_string(),
code: None,
level: "help",
spans: DiagnosticSpan::from_suggestion(sugg, je),
let output = String::from_utf8(output).unwrap();
Diagnostic {
- message: diag.message(),
+ message: diag.message().to_string(),
code: DiagnosticCode::map_opt_string(diag.code.clone(), je),
level: diag.level.to_str(),
spans: DiagnosticSpan::from_multispan(&diag.span, je),
fn from_sub_diagnostic(diag: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic {
Diagnostic {
- message: diag.message(),
+ message: diag.message().to_string(),
code: None,
level: diag.level.to_str(),
spans: diag
/// ]
/// ```
pub substitutions: Vec<Substitution>,
- pub msg: String,
+ pub msg: DiagnosticMessage,
/// Visual representation of this suggestion.
pub style: SuggestionStyle,
/// Whether or not the suggestion is approximate
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};
use std::backtrace::Backtrace;
arm_span: Span,
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() {
// early end of macro arm (#52866)
e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
}
let msg = &e.message[0];
e.message[0] = (
- format!(
+ rustc_errors::DiagnosticMessage::Str(format!(
"macro expansion ends with an incomplete expression: {}",
- msg.0.replace(", found `<eof>`", ""),
- ),
+ msg.0.as_str().replace(", found `<eof>`", ""),
+ )),
msg.1,
);
}
let current_qual_sp = self.prev_token.span;
let current_qual_sp = current_qual_sp.to(sp_start);
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 = self.span_to_snippet(invalid_qual_sp).unwrap();
if has_custom_message {
err.note(&msg);
} else {
- err.message = vec![(msg, Style::NoStyle)];
+ err.message =
+ vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
}
if snippet.starts_with('&') {
// This is already a literal borrow and the obligation is failing
impl Emitter for BufferEmitter {
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
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() {
buffer.has_errors = true;
}