errors: simplify referring to fluent attributes

To render the message of a Fluent attribute, the identifier of the
Fluent message must be known. `DiagnosticMessage::FluentIdentifier`
contains both the message's identifier and optionally the identifier of
an attribute. Generated constants for each attribute would therefore
need to be named uniquely (amongst all error messages) or be able to
refer to only the attribute identifier which will be combined with a
message identifier later. In this commit, the latter strategy is
implemented as part of the `Diagnostic` type's functions for adding
subdiagnostics of various kinds.

Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
David Wood 2022-05-24 15:09:47 +01:00
parent 855fc022fe
commit f669b78ffc
13 changed files with 190 additions and 150 deletions

View file

@ -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.
///
/// <https://projectfluent.org/fluent/guide/attributes.html>
FluentAttr(FluentId),
}
impl SubdiagnosticMessage {
/// Create a `SubdiagnosticMessage` for the provided Fluent attribute.
pub fn attr(id: impl Into<FluentId>) -> Self {
SubdiagnosticMessage::FluentAttr(id.into())
}
/// Create a `SubdiagnosticMessage` for the provided Fluent identifier.
pub fn message(id: impl Into<FluentId>) -> Self {
SubdiagnosticMessage::FluentIdentifier(id.into())
}
}
/// `From` impl that enables existing diagnostic calls to functions which now take
/// `impl Into<SubdiagnosticMessage>` to continue to work as before.
impl<S: Into<String>> From<S> 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<FluentId>) -> Self {
pub fn new(id: impl Into<FluentId>) -> Self {
DiagnosticMessage::FluentIdentifier(id.into(), None)
}
/// Create a `DiagnosticMessage` for the provided Fluent identifier and attribute.
pub fn fluent_attr(id: impl Into<FluentId>, attr: impl Into<FluentId>) -> Self {
DiagnosticMessage::FluentIdentifier(id.into(), Some(attr.into()))
}
}
/// `From` impl that enables existing diagnostic calls to functions which now take

View file

@ -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<DiagnosticMessage>) -> &mut Self {
self.span.push_span_label(span, label.into());
pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &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<DiagnosticMessage>) -> &mut Self {
pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
self.sub(Level::Note, msg, MultiSpan::new(), None);
self
}
pub fn highlighted_note<M: Into<DiagnosticMessage>>(
pub fn highlighted_note<M: Into<SubdiagnosticMessage>>(
&mut self,
msg: Vec<(M, Style)>,
) -> &mut Self {
@ -416,7 +416,7 @@ pub fn highlighted_note<M: Into<DiagnosticMessage>>(
/// 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<DiagnosticMessage>) -> &mut Self {
pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
self.sub(Level::OnceNote, msg, MultiSpan::new(), None);
self
}
@ -426,7 +426,7 @@ pub fn note_once(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
pub fn span_note<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self {
self.sub(Level::Note, msg, sp.into(), None);
self
@ -437,14 +437,14 @@ pub fn span_note<S: Into<MultiSpan>>(
pub fn span_note_once<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
) -> &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<DiagnosticMessage>) -> &mut Self {
pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
self.sub(Level::Warning, msg, MultiSpan::new(), None);
self
}
@ -454,14 +454,14 @@ pub fn warn(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
pub fn span_warn<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
) -> &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<DiagnosticMessage>) -> &mut Self {
pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &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<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
) -> &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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestions: impl Iterator<Item = String>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestions: impl Iterator<Item = Vec<(Span, String)>>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
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<SubdiagnosticMessage>,
) -> 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<DiagnosticMessage>,
message: impl Into<SubdiagnosticMessage>,
span: MultiSpan,
render_span: Option<MultiSpan>,
) {
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<M: Into<DiagnosticMessage>>(
fn sub_with_highlights<M: Into<SubdiagnosticMessage>>(
&mut self,
level: Level,
mut message: Vec<(M, Style)>,
span: MultiSpan,
render_span: Option<MultiSpan>,
) {
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);
}

View file

@ -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<DiagnosticMessage>) -> &mut Self);
pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &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<DiagnosticMessage>) -> &mut Self);
forward!(pub fn note_once(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn span_note(
&mut self,
sp: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self);
forward!(pub fn span_note_once(
&mut self,
sp: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self);
forward!(pub fn warn(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn span_warn(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> &mut Self);
forward!(pub fn help(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn span_warn(
&mut self,
sp: impl Into<MultiSpan>,
msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self);
forward!(pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn span_help(
&mut self,
sp: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
) -> &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<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn multipart_suggestion_verbose(
&mut self,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn tool_only_multipart_suggestion(
&mut self,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion(
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestions(
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestions: impl Iterator<Item = String>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn multipart_suggestions(
&mut self,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestions: impl Iterator<Item = Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion_short(
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion_verbose(
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion_hidden(
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn tool_only_span_suggestion(
&mut self,
sp: Span,
msg: impl Into<DiagnosticMessage>,
msg: impl Into<SubdiagnosticMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self);

View file

@ -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;

View file

@ -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));
}
}

View file

@ -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)
);
});
}

View file

@ -397,7 +397,7 @@ fn into_tokens(&mut self) -> Result<TokenStream, SessionDiagnosticDeriveError> {
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); }

View file

@ -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()),

View file

@ -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<Type>`.
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
}
}

View file

@ -12,6 +12,12 @@ pub enum DiagnosticMessage {
FluentIdentifier(std::borrow::Cow<'static, str>, Option<std::borrow::Cow<'static, str>>),
}
/// 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;

View file

@ -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",
| ^

View file

@ -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,

View file

@ -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`.