about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorJacob Pratt <jacob@jhpratt.dev>2021-07-12 02:26:14 -0400
committerJacob Pratt <jacob@jhpratt.dev>2021-07-27 15:47:49 -0400
commiteef2856eaf63bfaa39b4a124ecc691cf9a0306e8 (patch)
tree4c433ba1936aa3b405764c9ed5ecccab5c399ec9 /compiler
parentc70147fd66e08962ab06adf12eb6a41bc1ea7f08 (diff)
downloadrust-eef2856eaf63bfaa39b4a124ecc691cf9a0306e8.tar.gz
rust-eef2856eaf63bfaa39b4a124ecc691cf9a0306e8.zip
Add machine-applicable suggestions
This avoids the need for tools like rust-analyzer to implement these
suggestions themselves.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs50
1 files changed, 42 insertions, 8 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 7c1dc5e5365..8f672bb7d65 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -132,18 +132,52 @@ fn extract_default_variant<'a>(
     let variant = match default_variants.as_slice() {
         [variant] => variant,
         [] => {
-            cx.struct_span_err(trait_span, "no default declared")
-                .help("make a unit variant default by placing `#[default]` above it")
-                .emit();
+            let possible_defaults = enum_def
+                .variants
+                .iter()
+                .filter(|variant| matches!(variant.data, VariantData::Unit(..)))
+                .filter(|variant| !cx.sess.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();
 
             return Err(());
         }
         [first, rest @ ..] => {
-            cx.struct_span_err(trait_span, "multiple declared defaults")
-                .span_label(first.span, "first default")
-                .span_labels(rest.iter().map(|variant| variant.span), "additional default")
-                .note("only one variant can be default")
-                .emit();
+            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.ident == variant.ident {
+                            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();
 
             return Err(());
         }