]> git.lizzy.rs Git - rust.git/commitdiff
errors: introduce `DiagnosticMessage`
authorDavid Wood <david.wood@huawei.com>
Wed, 23 Mar 2022 07:34:20 +0000 (07:34 +0000)
committerDavid Wood <david.wood@huawei.com>
Tue, 5 Apr 2022 05:53:39 +0000 (06:53 +0100)
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>
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/json.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
src/librustdoc/passes/check_code_block_syntax.rs

index 9417874ffb40bb5fcd3f6f4277d8173961f1ddf5..8aa18b8e37ce2f060d895b4e1d51ee99ee7cec56 100644 (file)
@@ -1708,13 +1708,13 @@ pub fn fatal(&self, msg: &str) {
 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,
             })));
index 5f59eba23f8e9317a5a648d36e314262250178e5..76c8396cf9179d58c9329c54d55eb077729cdb2b 100644 (file)
@@ -41,7 +41,7 @@ fn emit_diagnostic(&mut self, diag: &Diagnostic) {
 
         self.emit_messages_default(
             &diag.level,
-            diag.message(),
+            diag.message().to_string(),
             &diag.code,
             &primary_span,
             &children,
index 32c52a6a8a6d92069238e0725a1ed93b50654a54..d31593a132bc88d8d334e2952aa8abe14c4e702c 100644 (file)
 #[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 {
@@ -25,7 +53,7 @@ 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>,
@@ -52,7 +80,7 @@ pub enum DiagnosticId {
 #[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>,
 }
@@ -112,7 +140,7 @@ pub fn new(level: Level, message: &str) -> Self {
     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![],
@@ -465,7 +493,7 @@ pub fn multipart_suggestion_with_style(
                     .map(|(span, snippet)| SubstitutionPart { snippet, span })
                     .collect(),
             }],
-            msg: msg.to_owned(),
+            msg: DiagnosticMessage::Str(msg.to_owned()),
             style,
             applicability,
             tool_metadata: Default::default(),
@@ -493,7 +521,7 @@ pub fn tool_only_multipart_suggestion(
                     .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(),
@@ -548,7 +576,7 @@ pub fn span_suggestion_with_style(
             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(),
@@ -591,7 +619,7 @@ pub fn span_suggestions(
             .collect();
         self.push_suggestion(CodeSuggestion {
             substitutions,
-            msg: msg.to_owned(),
+            msg: DiagnosticMessage::Str(msg.to_owned()),
             style: SuggestionStyle::ShowCode,
             applicability,
             tool_metadata: Default::default(),
@@ -616,7 +644,7 @@ pub fn multipart_suggestions(
                         .collect(),
                 })
                 .collect(),
-            msg: msg.to_owned(),
+            msg: DiagnosticMessage::Str(msg.to_owned()),
             style: SuggestionStyle::ShowCode,
             applicability,
             tool_metadata: Default::default(),
@@ -698,7 +726,7 @@ pub fn tool_only_suggestion_with_metadata(
     ) {
         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),
@@ -733,15 +761,15 @@ pub fn get_code(&self) -> Option<DiagnosticId> {
     }
 
     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
     }
 
@@ -758,7 +786,7 @@ pub fn sub(
     ) {
         let sub = SubDiagnostic {
             level,
-            message: vec![(message.to_owned(), Style::NoStyle)],
+            message: vec![(DiagnosticMessage::Str(message.to_owned()), Style::NoStyle)],
             span,
             render_span,
         };
@@ -770,10 +798,11 @@ pub fn sub(
     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);
     }
@@ -783,7 +812,7 @@ fn keys(
         &self,
     ) -> (
         &Level,
-        &Vec<(String, Style)>,
+        &Vec<(DiagnosticMessage, Style)>,
         &Option<DiagnosticId>,
         &MultiSpan,
         &Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
@@ -816,11 +845,11 @@ fn eq(&self, other: &Self) -> bool {
 }
 
 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
     }
 }
index 93b7201023a496290c77b74e549e16fc58c45cbc..1f26b002f6a6552206e021dfb7a6d0ae0f9df123 100644 (file)
@@ -15,8 +15,8 @@
 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;
@@ -236,7 +236,7 @@ fn primary_span_formatted<'a>(
                // 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') &&
                ![
@@ -252,12 +252,12 @@ fn primary_span_formatted<'a>(
                 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(
@@ -333,7 +333,7 @@ fn fix_multispans_in_extern_macros_and_render_macro_backtrace(
 
                 children.push(SubDiagnostic {
                     level: Level::Note,
-                    message: vec![(msg, Style::NoStyle)],
+                    message: vec![(DiagnosticMessage::Str(msg), Style::NoStyle)],
                     span: MultiSpan::new(),
                     render_span: None,
                 });
@@ -1176,7 +1176,7 @@ fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) ->
     fn msg_to_buffer(
         &self,
         buffer: &mut StyledBuffer,
-        msg: &[(String, Style)],
+        msg: &[(DiagnosticMessage, Style)],
         padding: usize,
         label: &str,
         override_style: Option<Style>,
@@ -1229,6 +1229,7 @@ fn style_or_override(style: Style, override_: Option<Style>) -> 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() {
@@ -1247,7 +1248,7 @@ fn style_or_override(style: Style, override_: Option<Style>) -> Style {
     fn emit_message_default(
         &mut self,
         msp: &MultiSpan,
-        msg: &[(String, Style)],
+        msg: &[(DiagnosticMessage, Style)],
         code: &Option<DiagnosticId>,
         level: &Level,
         max_line_num_len: usize,
@@ -1287,6 +1288,7 @@ fn emit_message_default(
                 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(
@@ -1852,7 +1854,7 @@ enum DisplaySuggestion {
     fn emit_messages_default(
         &mut self,
         level: &Level,
-        message: &[(String, Style)],
+        message: &[(DiagnosticMessage, Style)],
         code: &Option<DiagnosticId>,
         span: &MultiSpan,
         children: &[SubDiagnostic],
index dc28d1bb4523496cf09107f8310fb658c6ae6565..90f6df2d5712b88f41613b21cbd258e683a95963 100644 (file)
@@ -346,7 +346,7 @@ struct UnusedExterns<'a, 'b, 'c> {
 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),
@@ -385,7 +385,7 @@ fn flush(&mut self) -> io::Result<()> {
         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),
@@ -402,7 +402,7 @@ fn flush(&mut self) -> io::Result<()> {
 
     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
index ec00910ec8bb7e01b67a2a6e31a6406a7e2fcc6c..0f55ef7a9ec21524d6f770fa2965a8d7b90cf62a 100644 (file)
@@ -145,7 +145,7 @@ pub struct CodeSuggestion {
     /// ]
     /// ```
     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
@@ -400,7 +400,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 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;
 
index 10b2b9f07e2a57dc423c392487d9e342c52b2b0c..2ed11204ef6f5713145a1f45f9b49b88d32f2cc2 100644 (file)
@@ -68,17 +68,18 @@ fn emit_frag_parse_err(
     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,
         );
     }
index e55bdb0e5536526dec0aeaeb6bbda25663914776..fd4b00de39226fd4e85ac81e7ed6a03f00167606 100644 (file)
@@ -1010,7 +1010,8 @@ fn parse_item_foreign_mod(
                 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();
 
index c5324bf85a71dace4f2f28edf7878f5a25f03e52..f3c975c8a2c485db6de74db851019fa957e092d5 100644 (file)
@@ -780,7 +780,8 @@ fn suggest_add_reference_to_arg(
                     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
index 8d9b3377a698691a9df7c0a58708cb371cda2b53..636018dbb22828f6d5002b23c692b6871adb7f44 100644 (file)
@@ -176,7 +176,7 @@ struct BufferEmitter {
 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;
         }