diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 7faf14a2472..02d076c95ca 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -234,6 +234,48 @@ pub fn fallback_fluent_bundle( /// Identifier for the Fluent message/attribute corresponding to a diagnostic message. type FluentId = Cow<'static, str>; +/// Abstraction over a message in a subdiagnostic (i.e. label, note, help, etc) to support both +/// translatable and non-translatable diagnostic messages. +/// +/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent +/// message so messages of this type must be combined with a `DiagnosticMessage` (using +/// `DiagnosticMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from +/// the `SessionSubdiagnostic` derive refer to Fluent identifiers directly. +pub enum SubdiagnosticMessage { + /// Non-translatable diagnostic message. + // FIXME(davidtwco): can a `Cow<'static, str>` be used here? + Str(String), + /// Identifier of a Fluent message. Instances of this variant are generated by the + /// `SessionSubdiagnostic` derive. + FluentIdentifier(FluentId), + /// Attribute of a Fluent message. Needs to be combined with a Fluent identifier to produce an + /// actual translated message. Instances of this variant are generated by the `fluent_messages` + /// macro. + /// + /// + FluentAttr(FluentId), +} + +impl SubdiagnosticMessage { + /// Create a `SubdiagnosticMessage` for the provided Fluent attribute. + pub fn attr(id: impl Into) -> Self { + SubdiagnosticMessage::FluentAttr(id.into()) + } + + /// Create a `SubdiagnosticMessage` for the provided Fluent identifier. + pub fn message(id: impl Into) -> Self { + SubdiagnosticMessage::FluentIdentifier(id.into()) + } +} + +/// `From` impl that enables existing diagnostic calls to functions which now take +/// `impl Into` to continue to work as before. +impl> From for SubdiagnosticMessage { + fn from(s: S) -> Self { + SubdiagnosticMessage::Str(s.into()) + } +} + /// Abstraction over a message in a diagnostic to support both translatable and non-translatable /// diagnostic messages. /// @@ -252,6 +294,29 @@ pub enum DiagnosticMessage { } impl DiagnosticMessage { + /// Given a `SubdiagnosticMessage` which may contain a Fluent attribute, create a new + /// `DiagnosticMessage` that combines that attribute with the Fluent identifier of `self`. + /// + /// - If the `SubdiagnosticMessage` is non-translatable then return the message as a + /// `DiagnosticMessage`. + /// - If `self` is non-translatable then return `self`'s message. + pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self { + let attr = match sub { + SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s.clone()), + SubdiagnosticMessage::FluentIdentifier(id) => { + return DiagnosticMessage::FluentIdentifier(id, None); + } + SubdiagnosticMessage::FluentAttr(attr) => attr, + }; + + match self { + DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()), + DiagnosticMessage::FluentIdentifier(id, _) => { + DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr)) + } + } + } + /// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that /// this diagnostic message is of the legacy, non-translatable variety. Panics if this /// assumption does not hold. @@ -266,14 +331,9 @@ pub fn expect_str(&self) -> &str { } /// Create a `DiagnosticMessage` for the provided Fluent identifier. - pub fn fluent(id: impl Into) -> Self { + pub fn new(id: impl Into) -> Self { DiagnosticMessage::FluentIdentifier(id.into(), None) } - - /// Create a `DiagnosticMessage` for the provided Fluent identifier and attribute. - pub fn fluent_attr(id: impl Into, attr: impl Into) -> Self { - DiagnosticMessage::FluentIdentifier(id.into(), Some(attr.into())) - } } /// `From` impl that enables existing diagnostic calls to functions which now take diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index f130b5aa9a6..643f3c12134 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,7 +1,7 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DiagnosticMessage, Level, MultiSpan, Substitution, SubstitutionPart, - SuggestionStyle, + CodeSuggestion, DiagnosticMessage, Level, MultiSpan, SubdiagnosticMessage, Substitution, + SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::stable_map::FxHashMap; use rustc_error_messages::FluentValue; @@ -283,8 +283,8 @@ pub fn downgrade_to_delayed_bug(&mut self) -> &mut Self { /// /// This span is *not* considered a ["primary span"][`MultiSpan`]; only /// the `Span` supplied when creating the diagnostic is primary. - pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self { - self.span.push_span_label(span, label.into()); + pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self { + self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label)); self } @@ -401,12 +401,12 @@ pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut } /// Add a note attached to this diagnostic. - pub fn note(&mut self, msg: impl Into) -> &mut Self { + pub fn note(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::Note, msg, MultiSpan::new(), None); self } - pub fn highlighted_note>( + pub fn highlighted_note>( &mut self, msg: Vec<(M, Style)>, ) -> &mut Self { @@ -416,7 +416,7 @@ pub fn highlighted_note>( /// 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: impl Into) -> &mut Self { + pub fn note_once(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::OnceNote, msg, MultiSpan::new(), None); self } @@ -426,7 +426,7 @@ pub fn note_once(&mut self, msg: impl Into) -> &mut Self { pub fn span_note>( &mut self, sp: S, - msg: impl Into, + msg: impl Into, ) -> &mut Self { self.sub(Level::Note, msg, sp.into(), None); self @@ -437,14 +437,14 @@ pub fn span_note>( pub fn span_note_once>( &mut self, sp: S, - msg: impl Into, + msg: impl Into, ) -> &mut Self { self.sub(Level::OnceNote, msg, sp.into(), None); self } /// Add a warning attached to this diagnostic. - pub fn warn(&mut self, msg: impl Into) -> &mut Self { + pub fn warn(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::Warning, msg, MultiSpan::new(), None); self } @@ -454,14 +454,14 @@ pub fn warn(&mut self, msg: impl Into) -> &mut Self { pub fn span_warn>( &mut self, sp: S, - msg: impl Into, + msg: impl Into, ) -> &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: impl Into) -> &mut Self { + pub fn help(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::Help, msg, MultiSpan::new(), None); self } @@ -477,7 +477,7 @@ pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self { pub fn span_help>( &mut self, sp: S, - msg: impl Into, + msg: impl Into, ) -> &mut Self { self.sub(Level::Help, msg, sp.into(), None); self @@ -514,7 +514,7 @@ fn push_suggestion(&mut self, suggestion: CodeSuggestion) { /// In other words, multiple changes need to be applied as part of this suggestion. pub fn multipart_suggestion( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { @@ -530,7 +530,7 @@ pub fn multipart_suggestion( /// In other words, multiple changes need to be applied as part of this suggestion. pub fn multipart_suggestion_verbose( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { @@ -544,7 +544,7 @@ pub fn multipart_suggestion_verbose( /// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`]. pub fn multipart_suggestion_with_style( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, style: SuggestionStyle, @@ -557,7 +557,7 @@ pub fn multipart_suggestion_with_style( .map(|(span, snippet)| SubstitutionPart { snippet, span }) .collect(), }], - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style, applicability, }); @@ -572,7 +572,7 @@ pub fn multipart_suggestion_with_style( /// improve understandability. pub fn tool_only_multipart_suggestion( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { @@ -584,7 +584,7 @@ pub fn tool_only_multipart_suggestion( .map(|(span, snippet)| SubstitutionPart { snippet, span }) .collect(), }], - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style: SuggestionStyle::CompletelyHidden, applicability, }); @@ -611,7 +611,7 @@ pub fn tool_only_multipart_suggestion( pub fn span_suggestion( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -629,7 +629,7 @@ pub fn span_suggestion( pub fn span_suggestion_with_style( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, style: SuggestionStyle, @@ -638,7 +638,7 @@ pub fn span_suggestion_with_style( substitutions: vec![Substitution { parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }], }], - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style, applicability, }); @@ -649,7 +649,7 @@ pub fn span_suggestion_with_style( pub fn span_suggestion_verbose( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -668,7 +668,7 @@ pub fn span_suggestion_verbose( pub fn span_suggestions( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestions: impl Iterator, applicability: Applicability, ) -> &mut Self { @@ -680,7 +680,7 @@ pub fn span_suggestions( .collect(); self.push_suggestion(CodeSuggestion { substitutions, - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style: SuggestionStyle::ShowCode, applicability, }); @@ -691,7 +691,7 @@ pub fn span_suggestions( /// See also [`Diagnostic::span_suggestion()`]. pub fn multipart_suggestions( &mut self, - msg: impl Into, + msg: impl Into, suggestions: impl Iterator>, applicability: Applicability, ) -> &mut Self { @@ -704,7 +704,7 @@ pub fn multipart_suggestions( .collect(), }) .collect(), - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style: SuggestionStyle::ShowCode, applicability, }); @@ -717,7 +717,7 @@ pub fn multipart_suggestions( pub fn span_suggestion_short( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -740,7 +740,7 @@ pub fn span_suggestion_short( pub fn span_suggestion_hidden( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -761,7 +761,7 @@ pub fn span_suggestion_hidden( pub fn tool_only_span_suggestion( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -831,6 +831,18 @@ pub fn styled_message(&self) -> &Vec<(DiagnosticMessage, Style)> { &self.message } + /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by + /// combining it with the primary message of the diagnostic (if translatable, otherwise it just + /// passes the user's string along). + fn subdiagnostic_message_to_diagnostic_message( + &self, + attr: impl Into, + ) -> DiagnosticMessage { + let msg = + self.message.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages"); + msg.with_subdiagnostic_message(attr.into()) + } + /// Convenience function for internal use, clients should use one of the /// public methods above. /// @@ -838,13 +850,16 @@ pub fn styled_message(&self) -> &Vec<(DiagnosticMessage, Style)> { pub fn sub( &mut self, level: Level, - message: impl Into, + message: impl Into, span: MultiSpan, render_span: Option, ) { let sub = SubDiagnostic { level, - message: vec![(message.into(), Style::NoStyle)], + message: vec![( + self.subdiagnostic_message_to_diagnostic_message(message), + Style::NoStyle, + )], span, render_span, }; @@ -853,14 +868,17 @@ pub fn sub( /// Convenience function for internal use, clients should use one of the /// public methods above. - fn sub_with_highlights>( + fn sub_with_highlights>( &mut self, level: Level, mut message: Vec<(M, Style)>, span: MultiSpan, render_span: Option, ) { - let message = message.drain(..).map(|m| (m.0.into(), m.1)).collect(); + let message = message + .drain(..) + .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1)) + .collect(); let sub = SubDiagnostic { level, message, span, render_span }; self.children.push(sub); } diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 6ef2c832c65..9e0a99849a3 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -1,5 +1,8 @@ use crate::diagnostic::IntoDiagnosticArg; -use crate::{Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed}; +use crate::{ + Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed, + SubdiagnosticMessage, +}; use crate::{Handler, Level, MultiSpan, StashKey}; use rustc_lint_defs::Applicability; @@ -395,7 +398,7 @@ pub fn downgrade_to_delayed_bug(&mut self,) -> &mut Self /// the diagnostic was constructed. However, the label span is *not* considered a /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is /// primary. - pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self); + pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self); forward!( /// Labels all the given spans with the provided label. @@ -430,25 +433,29 @@ pub fn span_labels( found: DiagnosticStyledString, ) -> &mut Self); - forward!(pub fn note(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn note_once(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn note(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn note_once(&mut self, msg: impl Into) -> &mut Self); forward!(pub fn span_note( &mut self, sp: impl Into, - msg: impl Into, + msg: impl Into, ) -> &mut Self); forward!(pub fn span_note_once( &mut self, sp: impl Into, - msg: impl Into, + msg: impl Into, ) -> &mut Self); - forward!(pub fn warn(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn span_warn(&mut self, sp: impl Into, msg: &str) -> &mut Self); - forward!(pub fn help(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn warn(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn span_warn( + &mut self, + sp: impl Into, + msg: impl Into, + ) -> &mut Self); + forward!(pub fn help(&mut self, msg: impl Into) -> &mut Self); forward!(pub fn span_help( &mut self, sp: impl Into, - msg: impl Into, + msg: impl Into, ) -> &mut Self); forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self); forward!(pub fn set_is_lint(&mut self,) -> &mut Self); @@ -457,67 +464,67 @@ pub fn span_labels( forward!(pub fn multipart_suggestion( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self); forward!(pub fn multipart_suggestion_verbose( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self); forward!(pub fn tool_only_multipart_suggestion( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestion( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestions( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestions: impl Iterator, applicability: Applicability, ) -> &mut Self); forward!(pub fn multipart_suggestions( &mut self, - msg: impl Into, + msg: impl Into, suggestions: impl Iterator>, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestion_short( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestion_verbose( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestion_hidden( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); forward!(pub fn tool_only_span_suggestion( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5b9b65da343..fb02f1d68eb 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -32,7 +32,8 @@ use rustc_data_structures::AtomicRef; pub use rustc_error_messages::{ fallback_fluent_bundle, fluent, fluent_bundle, DiagnosticMessage, FluentBundle, - LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, DEFAULT_LOCALE_RESOURCES, + LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage, + DEFAULT_LOCALE_RESOURCES, }; pub use rustc_lint_defs::{pluralize, Applicability}; use rustc_span::source_map::SourceMap; diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index d7daee64d79..95ee0d4a060 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -126,14 +126,14 @@ pub(crate) fn into_tokens(self) -> TokenStream { (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => { quote! { let mut #diag = #sess.struct_err( - rustc_errors::DiagnosticMessage::fluent(#slug), + rustc_errors::DiagnosticMessage::new(#slug), ); } } (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => { quote! { let mut #diag = #sess.struct_warn( - rustc_errors::DiagnosticMessage::fluent(#slug), + rustc_errors::DiagnosticMessage::new(#slug), ); } } @@ -254,21 +254,6 @@ fn generate_structure_code( if matches!(name, "help" | "note") && matches!(meta, Meta::Path(_) | Meta::NameValue(_)) { let diag = &self.diag; - let slug = match &self.slug { - Some((slug, _)) => slug.as_str(), - None => throw_span_err!( - span, - &format!( - "`#[{}{}]` must come after `#[error(..)]` or `#[warn(..)]`", - name, - match meta { - Meta::Path(_) => "", - Meta::NameValue(_) => " = ...", - _ => unreachable!(), - } - ) - ), - }; let id = match meta { Meta::Path(..) => quote! { #name }, Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { @@ -279,7 +264,7 @@ fn generate_structure_code( let fn_name = proc_macro2::Ident::new(name, attr.span()); return Ok(quote! { - #diag.#fn_name(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #id)); + #diag.#fn_name(rustc_errors::SubdiagnosticMessage::attr(#id)); }); } @@ -525,13 +510,8 @@ fn generate_inner_field_code( let method = format_ident!("span_{}", name); - let slug = self - .slug - .as_ref() - .map(|(slug, _)| slug.as_str()) - .unwrap_or_else(|| "missing-slug"); let msg = msg.as_deref().unwrap_or("suggestion"); - let msg = quote! { rustc_errors::DiagnosticMessage::fluent_attr(#slug, #msg) }; + let msg = quote! { rustc_errors::SubdiagnosticMessage::attr(#msg) }; let code = code.unwrap_or_else(|| quote! { String::new() }); Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); }) @@ -549,14 +529,11 @@ fn add_spanned_subdiagnostic( fluent_attr_identifier: &str, ) -> TokenStream { let diag = &self.diag; - - let slug = - self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or_else(|| "missing-slug"); let fn_name = format_ident!("span_{}", kind); quote! { #diag.#fn_name( #field_binding, - rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier) + rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier) ); } } @@ -565,9 +542,8 @@ fn add_spanned_subdiagnostic( /// and `fluent_attr_identifier`. fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: &str) -> TokenStream { let diag = &self.diag; - let slug = self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or("missing-slug"); quote! { - #diag.#kind(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier)); + #diag.#kind(rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier)); } } diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 8523d7fa9f9..42a9bf477a4 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -11,7 +11,7 @@ use proc_macro2::TokenStream; use quote::quote; use std::{ - collections::HashMap, + collections::{HashMap, HashSet}, fs::File, io::Read, path::{Path, PathBuf}, @@ -100,6 +100,10 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok let ident_span = res.ident.span().unwrap(); let path_span = res.resource.span().unwrap(); + // Set of Fluent attribute names already output, to avoid duplicate type errors - any given + // constant created for a given attribute is the same. + let mut previous_attrs = HashSet::new(); + let relative_ftl_path = res.resource.value(); let absolute_ftl_path = invocation_relative_path_to_absolute(ident_span, &relative_ftl_path); @@ -199,13 +203,15 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok }); for Attribute { id: Identifier { name: attr_name }, .. } in attributes { - let attr_snake_name = attr_name.replace("-", "_"); - let snake_name = Ident::new(&format!("{snake_name}_{attr_snake_name}"), span); + let snake_name = Ident::new(&attr_name.replace("-", "_"), span); + if !previous_attrs.insert(snake_name.clone()) { + continue; + } + constants.extend(quote! { - pub const #snake_name: crate::DiagnosticMessage = - crate::DiagnosticMessage::FluentIdentifier( - std::borrow::Cow::Borrowed(#name), - Some(std::borrow::Cow::Borrowed(#attr_name)) + pub const #snake_name: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr( + std::borrow::Cow::Borrowed(#attr_name) ); }); } diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index df01419c82a..9aeb484bfd5 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -397,7 +397,7 @@ fn into_tokens(&mut self) -> Result { let diag = &self.diag; let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); - let message = quote! { rustc_errors::DiagnosticMessage::fluent(#slug) }; + let message = quote! { rustc_errors::SubdiagnosticMessage::message(#slug) }; let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) { if let Some(span) = span_field { quote! { #diag.#name(#span, #message, #code, #applicability); } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c9da58aae5c..12302315e90 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -17,10 +17,10 @@ }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed}; use rustc_errors::{ - Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, + fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, }; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident}; @@ -658,13 +658,10 @@ pub fn maybe_suggest_struct_literal( err.delay_as_bug(); self.struct_span_err( expr.span, - DiagnosticMessage::fluent("parser-struct-literal-body-without-path"), + fluent::parser::struct_literal_body_without_path, ) .multipart_suggestion( - DiagnosticMessage::fluent_attr( - "parser-struct-literal-body-without-path", - "suggestion", - ), + fluent::parser::suggestion, vec![ (expr.span.shrink_to_lo(), "{ SomeStruct ".to_string()), (expr.span.shrink_to_hi(), " }".to_string()), diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index d9c9f2920b0..a7f736fed14 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -277,7 +277,7 @@ fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuar .join(", "), ); - err.span_label(self.def_span, rustc_errors::fluent::typeck::missing_type_params_label); + err.span_label(self.def_span, rustc_errors::fluent::typeck::label); let mut suggested = false; if let (Ok(snippet), true) = ( @@ -295,7 +295,7 @@ fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuar // least we can clue them to the correct syntax `Iterator`. err.span_suggestion( self.span, - rustc_errors::fluent::typeck::missing_type_params_suggestion, + rustc_errors::fluent::typeck::suggestion, format!("{}<{}>", snippet, self.missing_type_params.join(", ")), Applicability::HasPlaceholders, ); @@ -303,13 +303,10 @@ fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuar } } if !suggested { - err.span_label( - self.span, - rustc_errors::fluent::typeck::missing_type_params_no_suggestion_label, - ); + err.span_label(self.span, rustc_errors::fluent::typeck::no_suggestion_label); } - err.note(rustc_errors::fluent::typeck::missing_type_params_note); + err.note(rustc_errors::fluent::typeck::note); err } } diff --git a/src/test/ui-fulldeps/fluent-messages/test.rs b/src/test/ui-fulldeps/fluent-messages/test.rs index b05d3d08ccb..0390a07850b 100644 --- a/src/test/ui-fulldeps/fluent-messages/test.rs +++ b/src/test/ui-fulldeps/fluent-messages/test.rs @@ -12,6 +12,12 @@ pub enum DiagnosticMessage { FluentIdentifier(std::borrow::Cow<'static, str>, Option>), } +/// Copy of the relevant `SubdiagnosticMessage` variant constructed by `fluent_messages` as it +/// expects `crate::SubdiagnosticMessage` to exist. +pub enum SubdiagnosticMessage { + FluentAttr(std::borrow::Cow<'static, str>), +} + mod missing_absolute { use super::fluent_messages; diff --git a/src/test/ui-fulldeps/fluent-messages/test.stderr b/src/test/ui-fulldeps/fluent-messages/test.stderr index f88d09bee6e..526bca43f69 100644 --- a/src/test/ui-fulldeps/fluent-messages/test.stderr +++ b/src/test/ui-fulldeps/fluent-messages/test.stderr @@ -1,5 +1,5 @@ error: could not open Fluent resource - --> $DIR/test.rs:19:29 + --> $DIR/test.rs:25:29 | LL | missing_absolute => "/definitely_does_not_exist.ftl", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | missing_absolute => "/definitely_does_not_exist.ftl", = note: os-specific message error: could not open Fluent resource - --> $DIR/test.rs:28:29 + --> $DIR/test.rs:34:29 | LL | missing_relative => "../definitely_does_not_exist.ftl", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | missing_relative => "../definitely_does_not_exist.ftl", = note: os-specific message error: could not parse Fluent resource - --> $DIR/test.rs:37:28 + --> $DIR/test.rs:43:28 | LL | missing_message => "./missing-message.ftl", | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,13 +30,13 @@ error: expected a message field for "missing-message" | error: overrides existing message: `key` - --> $DIR/test.rs:47:9 + --> $DIR/test.rs:53:9 | LL | b => "./duplicate-b.ftl", | ^ | help: previously defined in this resource - --> $DIR/test.rs:46:9 + --> $DIR/test.rs:52:9 | LL | a => "./duplicate-a.ftl", | ^ diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index 1cdc5d18c28..84d5de17309 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -404,7 +404,6 @@ struct ErrorWithHelpCustom { #[derive(SessionDiagnostic)] #[help] -//~^ ERROR `#[help]` must come after `#[error(..)]` or `#[warn(..)]` #[error(code = "E0123", slug = "foo")] struct ErrorWithHelpWrongOrder { val: String, @@ -412,7 +411,6 @@ struct ErrorWithHelpWrongOrder { #[derive(SessionDiagnostic)] #[help = "bar"] -//~^ ERROR `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]` #[error(code = "E0123", slug = "foo")] struct ErrorWithHelpCustomWrongOrder { val: String, @@ -420,7 +418,6 @@ struct ErrorWithHelpCustomWrongOrder { #[derive(SessionDiagnostic)] #[note] -//~^ ERROR `#[note]` must come after `#[error(..)]` or `#[warn(..)]` #[error(code = "E0123", slug = "foo")] struct ErrorWithNoteWrongOrder { val: String, @@ -428,7 +425,6 @@ struct ErrorWithNoteWrongOrder { #[derive(SessionDiagnostic)] #[note = "bar"] -//~^ ERROR `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]` #[error(code = "E0123", slug = "foo")] struct ErrorWithNoteCustomWrongOrder { val: String, diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 2583363120a..85ea44ec278 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -301,38 +301,14 @@ LL | #[label("bar")] | = help: only `suggestion{,_short,_hidden,_verbose}` are valid field attributes -error: `#[help]` must come after `#[error(..)]` or `#[warn(..)]` - --> $DIR/diagnostic-derive.rs:406:1 - | -LL | #[help] - | ^^^^^^^ - -error: `#[help = ...]` must come after `#[error(..)]` or `#[warn(..)]` - --> $DIR/diagnostic-derive.rs:414:1 - | -LL | #[help = "bar"] - | ^^^^^^^^^^^^^^^ - -error: `#[note]` must come after `#[error(..)]` or `#[warn(..)]` - --> $DIR/diagnostic-derive.rs:422:1 - | -LL | #[note] - | ^^^^^^^ - -error: `#[note = ...]` must come after `#[error(..)]` or `#[warn(..)]` - --> $DIR/diagnostic-derive.rs:430:1 - | -LL | #[note = "bar"] - | ^^^^^^^^^^^^^^^ - error: applicability cannot be set in both the field and attribute - --> $DIR/diagnostic-derive.rs:440:49 + --> $DIR/diagnostic-derive.rs:436:49 | LL | #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/diagnostic-derive.rs:448:49 + --> $DIR/diagnostic-derive.rs:444:49 | LL | #[suggestion(message = "bar", code = "...", applicability = "batman")] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -363,12 +339,12 @@ LL | #[derive(SessionDiagnostic)] rustc_middle::ty::Ty<'tcx> usize note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg` - --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:531:19 + --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:538:19 | LL | arg: impl IntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg` = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 43 previous errors +error: aborting due to 39 previous errors For more information about this error, try `rustc --explain E0277`.