1
Fork 0

Use translatable diagnostics in rustc_const_eval

This commit is contained in:
Deadbeef 2023-05-17 10:30:14 +00:00
parent 642c92e630
commit 4f83717cf7
93 changed files with 2375 additions and 1123 deletions

View file

@ -14,6 +14,8 @@ use syn::Token;
use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type};
use synstructure::{BindingInfo, Structure, VariantInfo};
use super::utils::SubdiagnosticVariant;
/// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
#[derive(Clone, PartialEq, Eq)]
pub(crate) enum DiagnosticDeriveKind {
@ -150,19 +152,19 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
fn parse_subdiag_attribute(
&self,
attr: &Attribute,
) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
let Some((subdiag, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
) -> Result<Option<(SubdiagnosticKind, Path, bool)>, DiagnosticDeriveError> {
let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, self)? else {
// Some attributes aren't errors - like documentation comments - but also aren't
// subdiagnostics.
return Ok(None);
};
if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag {
if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag.kind {
throw_invalid_attr!(attr, |diag| diag
.help("consider creating a `Subdiagnostic` instead"));
}
let slug = slug.unwrap_or_else(|| match subdiag {
let slug = subdiag.slug.unwrap_or_else(|| match subdiag.kind {
SubdiagnosticKind::Label => parse_quote! { _subdiag::label },
SubdiagnosticKind::Note => parse_quote! { _subdiag::note },
SubdiagnosticKind::Help => parse_quote! { _subdiag::help },
@ -171,7 +173,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
});
Ok(Some((subdiag, slug)))
Ok(Some((subdiag.kind, slug, subdiag.no_span)))
}
/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
@ -229,7 +231,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
return Ok(tokens);
}
let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
let Some((subdiag, slug, _no_span)) = self.parse_subdiag_attribute(attr)? else {
// Some attributes aren't errors - like documentation comments - but also aren't
// subdiagnostics.
return Ok(quote! {});
@ -380,7 +382,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
_ => (),
}
let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
let Some((subdiag, slug, _no_span)) = self.parse_subdiag_attribute(attr)? else {
// Some attributes aren't errors - like documentation comments - but also aren't
// subdiagnostics.
return Ok(quote! {});

View file

@ -14,6 +14,8 @@ use quote::{format_ident, quote};
use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
use synstructure::{BindingInfo, Structure, VariantInfo};
use super::utils::SubdiagnosticVariant;
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
pub(crate) struct SubdiagnosticDeriveBuilder {
diag: syn::Ident,
@ -180,11 +182,13 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
}
impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
fn identify_kind(
&mut self,
) -> Result<Vec<(SubdiagnosticKind, Path, bool)>, DiagnosticDeriveError> {
let mut kind_slugs = vec![];
for attr in self.variant.ast().attrs {
let Some((kind, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
let Some(SubdiagnosticVariant { kind, slug, no_span }) = SubdiagnosticVariant::from_attr(attr, self)? else {
// Some attributes aren't errors - like documentation comments - but also aren't
// subdiagnostics.
continue;
@ -202,7 +206,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
);
};
kind_slugs.push((kind, slug));
kind_slugs.push((kind, slug, no_span));
}
Ok(kind_slugs)
@ -487,7 +491,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
}
};
let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect();
let kind_stats: KindsStatistics =
kind_slugs.iter().map(|(kind, _slug, _no_span)| kind).collect();
let init = if kind_stats.has_multipart_suggestion {
quote! { let mut suggestions = Vec::new(); }
@ -508,13 +513,17 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
let diag = &self.parent.diag;
let f = &self.parent.f;
let mut calls = TokenStream::new();
for (kind, slug) in kind_slugs {
for (kind, slug, no_span) in kind_slugs {
let message = format_ident!("__message");
calls.extend(
quote! { let #message = #f(#diag, crate::fluent_generated::#slug.into()); },
);
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
let name = format_ident!(
"{}{}",
if span_field.is_some() && !no_span { "span_" } else { "" },
kind
);
let call = match kind {
SubdiagnosticKind::Suggestion {
suggestion_kind,
@ -566,7 +575,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
}
}
_ => {
if let Some(span) = span_field {
if let Some(span) = span_field && !no_span {
quote! { #diag.#name(#span, #message); }
} else {
quote! { #diag.#name(#message); }

View file

@ -597,14 +597,20 @@ pub(super) enum SubdiagnosticKind {
},
}
impl SubdiagnosticKind {
/// Constructs a `SubdiagnosticKind` from a field or type attribute such as `#[note]`,
/// `#[error(parser::add_paren)]` or `#[suggestion(code = "...")]`. Returns the
pub(super) struct SubdiagnosticVariant {
pub(super) kind: SubdiagnosticKind,
pub(super) slug: Option<Path>,
pub(super) no_span: bool,
}
impl SubdiagnosticVariant {
/// Constructs a `SubdiagnosticVariant` from a field or type attribute such as `#[note]`,
/// `#[error(parser::add_paren, no_span)]` or `#[suggestion(code = "...")]`. Returns the
/// `SubdiagnosticKind` and the diagnostic slug, if specified.
pub(super) fn from_attr(
attr: &Attribute,
fields: &impl HasFieldMap,
) -> Result<Option<(SubdiagnosticKind, Option<Path>)>, DiagnosticDeriveError> {
) -> Result<Option<SubdiagnosticVariant>, DiagnosticDeriveError> {
// Always allow documentation comments.
if is_doc_comment(attr) {
return Ok(None);
@ -679,7 +685,7 @@ impl SubdiagnosticKind {
| SubdiagnosticKind::Help
| SubdiagnosticKind::Warn
| SubdiagnosticKind::MultipartSuggestion { .. } => {
return Ok(Some((kind, None)));
return Ok(Some(SubdiagnosticVariant { kind, slug: None, no_span: false }));
}
SubdiagnosticKind::Suggestion { .. } => {
throw_span_err!(span, "suggestion without `code = \"...\"`")
@ -696,11 +702,14 @@ impl SubdiagnosticKind {
let mut first = true;
let mut slug = None;
let mut no_span = false;
list.parse_nested_meta(|nested| {
if nested.input.is_empty() || nested.input.peek(Token![,]) {
if first {
slug = Some(nested.path);
} else if nested.path.is_ident("no_span") {
no_span = true;
} else {
span_err(nested.input.span().unwrap(), "a diagnostic slug must be the first argument to the attribute").emit();
}
@ -775,19 +784,19 @@ impl SubdiagnosticKind {
(_, SubdiagnosticKind::Suggestion { .. }) => {
span_err(path_span, "invalid nested attribute")
.help(
"only `style`, `code` and `applicability` are valid nested attributes",
"only `no_span`, `style`, `code` and `applicability` are valid nested attributes",
)
.emit();
has_errors = true;
}
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
span_err(path_span, "invalid nested attribute")
.help("only `style` and `applicability` are valid nested attributes")
.help("only `no_span`, `style` and `applicability` are valid nested attributes")
.emit();
has_errors = true;
}
_ => {
span_err(path_span, "invalid nested attribute").emit();
span_err(path_span, "only `no_span` is a valid nested attribute").emit();
has_errors = true;
}
}
@ -831,7 +840,7 @@ impl SubdiagnosticKind {
| SubdiagnosticKind::Warn => {}
}
Ok(Some((kind, slug)))
Ok(Some(SubdiagnosticVariant { kind, slug, no_span }))
}
}