summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_builtin_macros/src/deriving/default.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_builtin_macros/src/deriving/default.rs')
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs134
1 files changed, 50 insertions, 84 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 4d753a2ed..33fe98b40 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -1,8 +1,8 @@
use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
+use crate::errors;
use rustc_ast as ast;
-use rustc_ast::{walk_list, EnumDef, VariantData};
-use rustc_errors::Applicability;
+use rustc_ast::{attr, walk_list, EnumDef, VariantData};
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
use rustc_span::symbol::Ident;
use rustc_span::symbol::{kw, sym};
@@ -106,7 +106,7 @@ fn extract_default_variant<'a>(
let default_variants: SmallVec<[_; 1]> = enum_def
.variants
.iter()
- .filter(|variant| cx.sess.contains_name(&variant.attrs, kw::Default))
+ .filter(|variant| attr::contains_name(&variant.attrs, kw::Default))
.collect();
let variant = match default_variants.as_slice() {
@@ -116,69 +116,52 @@ fn extract_default_variant<'a>(
.variants
.iter()
.filter(|variant| matches!(variant.data, VariantData::Unit(..)))
- .filter(|variant| !cx.sess.contains_name(&variant.attrs, sym::non_exhaustive));
+ .filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive));
- let mut diag = cx.struct_span_err(trait_span, "no default declared");
- diag.help("make a unit variant default by placing `#[default]` above it");
- for variant in possible_defaults {
- // Suggest making each unit variant default.
- diag.tool_only_span_suggestion(
- variant.span,
- &format!("make `{}` default", variant.ident),
- format!("#[default] {}", variant.ident),
- Applicability::MaybeIncorrect,
- );
- }
- diag.emit();
+ let suggs = possible_defaults
+ .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident })
+ .collect();
+ cx.emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
return Err(());
}
[first, rest @ ..] => {
- let mut diag = cx.struct_span_err(trait_span, "multiple declared defaults");
- diag.span_label(first.span, "first default");
- diag.span_labels(rest.iter().map(|variant| variant.span), "additional default");
- diag.note("only one variant can be default");
- for variant in &default_variants {
- // Suggest making each variant already tagged default.
- let suggestion = default_variants
- .iter()
- .filter_map(|v| {
- if v.span == variant.span {
- None
- } else {
- Some((cx.sess.find_by_name(&v.attrs, kw::Default)?.span, String::new()))
- }
- })
- .collect();
-
- diag.tool_only_multipart_suggestion(
- &format!("make `{}` default", variant.ident),
- suggestion,
- Applicability::MaybeIncorrect,
- );
- }
- diag.emit();
-
+ let suggs = default_variants
+ .iter()
+ .map(|variant| {
+ let spans = default_variants
+ .iter()
+ .filter_map(|v| {
+ if v.span == variant.span {
+ None
+ } else {
+ Some(attr::find_by_name(&v.attrs, kw::Default)?.span)
+ }
+ })
+ .collect();
+ errors::MultipleDefaultsSugg { spans, ident: variant.ident }
+ })
+ .collect();
+ cx.emit_err(errors::MultipleDefaults {
+ span: trait_span,
+ first: first.span,
+ additional: rest.iter().map(|v| v.span).collect(),
+ suggs,
+ });
return Err(());
}
};
if !matches!(variant.data, VariantData::Unit(..)) {
- cx.struct_span_err(
- variant.ident.span,
- "the `#[default]` attribute may only be used on unit enum variants",
- )
- .help("consider a manual implementation of `Default`")
- .emit();
-
+ cx.emit_err(errors::NonUnitDefault { span: variant.ident.span });
return Err(());
}
- if let Some(non_exhaustive_attr) = cx.sess.find_by_name(&variant.attrs, sym::non_exhaustive) {
- cx.struct_span_err(variant.ident.span, "default variant must be exhaustive")
- .span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here")
- .help("consider a manual implementation of `Default`")
- .emit();
+ if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) {
+ cx.emit_err(errors::NonExhaustiveDefault {
+ span: variant.ident.span,
+ non_exhaustive: non_exhaustive_attr.span,
+ });
return Err(());
}
@@ -191,7 +174,7 @@ fn validate_default_attribute(
default_variant: &rustc_ast::Variant,
) -> Result<(), ()> {
let attrs: SmallVec<[_; 1]> =
- cx.sess.filter_by_name(&default_variant.attrs, kw::Default).collect();
+ attr::filter_by_name(&default_variant.attrs, kw::Default).collect();
let attr = match attrs.as_slice() {
[attr] => attr,
@@ -199,35 +182,23 @@ fn validate_default_attribute(
"this method must only be called with a variant that has a `#[default]` attribute",
),
[first, rest @ ..] => {
- let suggestion_text =
- if rest.len() == 1 { "try removing this" } else { "try removing these" };
-
- cx.struct_span_err(default_variant.ident.span, "multiple `#[default]` attributes")
- .note("only one `#[default]` attribute is needed")
- .span_label(first.span, "`#[default]` used here")
- .span_label(rest[0].span, "`#[default]` used again here")
- .span_help(rest.iter().map(|attr| attr.span).collect::<Vec<_>>(), suggestion_text)
- // This would otherwise display the empty replacement, hence the otherwise
- // repetitive `.span_help` call above.
- .tool_only_multipart_suggestion(
- suggestion_text,
- rest.iter().map(|attr| (attr.span, String::new())).collect(),
- Applicability::MachineApplicable,
- )
- .emit();
+ let sugg = errors::MultipleDefaultAttrsSugg {
+ spans: rest.iter().map(|attr| attr.span).collect(),
+ };
+ cx.emit_err(errors::MultipleDefaultAttrs {
+ span: default_variant.ident.span,
+ first: first.span,
+ first_rest: rest[0].span,
+ rest: rest.iter().map(|attr| attr.span).collect::<Vec<_>>().into(),
+ only_one: rest.len() == 1,
+ sugg,
+ });
return Err(());
}
};
if !attr.is_word() {
- cx.struct_span_err(attr.span, "`#[default]` attribute does not accept a value")
- .span_suggestion_hidden(
- attr.span,
- "try using `#[default]`",
- "#[default]",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ cx.emit_err(errors::DefaultHasArg { span: attr.span });
return Err(());
}
@@ -241,12 +212,7 @@ struct DetectNonVariantDefaultAttr<'a, 'b> {
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> {
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) {
if attr.has_name(kw::Default) {
- self.cx
- .struct_span_err(
- attr.span,
- "the `#[default]` attribute may only be used on unit enum variants",
- )
- .emit();
+ self.cx.emit_err(errors::NonUnitDefault { span: attr.span });
}
rustc_ast::visit::walk_attribute(self, attr);