about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src/late
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2020-10-12 16:43:49 +0100
committerDavid Wood <david@davidtw.co>2020-10-15 17:57:57 +0100
commitadf31e95e44ff0b7fbc798fe2b8cc5a42a3abf4b (patch)
tree40f3bb50f4b92979017a51442472d7ddfe61871c /compiler/rustc_resolve/src/late
parent7f587168102498a488abf608a86c7fdfa62fb7bb (diff)
downloadrust-adf31e95e44ff0b7fbc798fe2b8cc5a42a3abf4b.tar.gz
rust-adf31e95e44ff0b7fbc798fe2b8cc5a42a3abf4b.zip
resolve: suggest variants with placeholders
This commit improves the diagnostic modified in rust-lang/rust#77341 to
suggest not only those variants which do not have fields, but those with
fields (by suggesting with placeholders).

Signed-off-by: David Wood <david@davidtw.co>
Diffstat (limited to 'compiler/rustc_resolve/src/late')
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs146
1 files changed, 86 insertions, 60 deletions
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index bee05e77382..8ef99f36a04 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1330,58 +1330,32 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
 
         let suggest_only_tuple_variants =
             matches!(source, PathSource::TupleStruct(..)) || source.is_call();
-        let mut suggestable_variants = if suggest_only_tuple_variants {
+        if suggest_only_tuple_variants {
             // Suggest only tuple variants regardless of whether they have fields and do not
             // suggest path with added parenthesis.
-            variants
+            let mut suggestable_variants = variants
                 .iter()
                 .filter(|(.., kind)| *kind == CtorKind::Fn)
                 .map(|(variant, ..)| path_names_to_string(variant))
-                .collect::<Vec<_>>()
-        } else {
-            variants
-                .iter()
-                .filter(|(_, def_id, kind)| {
-                    // Suggest only variants that have no fields (these can definitely
-                    // be constructed).
-                    let has_fields =
-                        self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false);
-                    match kind {
-                        CtorKind::Const => true,
-                        CtorKind::Fn | CtorKind::Fictive if has_fields => true,
-                        _ => false,
-                    }
-                })
-                .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
-                .map(|(variant_str, kind)| {
-                    // Add constructor syntax where appropriate.
-                    match kind {
-                        CtorKind::Const => variant_str,
-                        CtorKind::Fn => format!("({}())", variant_str),
-                        CtorKind::Fictive => format!("({} {{}})", variant_str),
-                    }
-                })
-                .collect::<Vec<_>>()
-        };
+                .collect::<Vec<_>>();
 
-        let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
+            let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
 
-        if !suggestable_variants.is_empty() {
-            let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
-                "try using the enum's variant"
-            } else {
-                "try using one of the enum's variants"
-            };
+            if !suggestable_variants.is_empty() {
+                let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
+                    "try using the enum's variant"
+                } else {
+                    "try using one of the enum's variants"
+                };
 
-            err.span_suggestions(
-                span,
-                msg,
-                suggestable_variants.drain(..),
-                Applicability::MaybeIncorrect,
-            );
-        }
+                err.span_suggestions(
+                    span,
+                    msg,
+                    suggestable_variants.drain(..),
+                    Applicability::MaybeIncorrect,
+                );
+            }
 
-        if suggest_only_tuple_variants {
             let source_msg = if source.is_call() {
                 "to construct"
             } else if matches!(source, PathSource::TupleStruct(..)) {
@@ -1408,24 +1382,76 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 ));
             }
         } else {
-            let made_suggestion = non_suggestable_variant_count != variants.len();
-            if made_suggestion {
-                if non_suggestable_variant_count == 1 {
-                    err.help(
-                        "you might have meant to use the enum's other variant that has fields",
-                    );
-                } else if non_suggestable_variant_count >= 1 {
-                    err.help(
-                        "you might have meant to use one of the enum's other variants that \
-                         have fields",
-                    );
-                }
-            } else {
-                if non_suggestable_variant_count == 1 {
-                    err.help("you might have meant to use the enum's variant");
-                } else if non_suggestable_variant_count >= 1 {
-                    err.help("you might have meant to use one of the enum's variants");
+            let needs_placeholder = |def_id: DefId, kind: CtorKind| {
+                let has_no_fields =
+                    self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false);
+                match kind {
+                    CtorKind::Const => false,
+                    CtorKind::Fn | CtorKind::Fictive if has_no_fields => false,
+                    _ => true,
                 }
+            };
+
+            let mut suggestable_variants = variants
+                .iter()
+                .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
+                .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
+                .map(|(variant, kind)| match kind {
+                    CtorKind::Const => variant,
+                    CtorKind::Fn => format!("({}())", variant),
+                    CtorKind::Fictive => format!("({} {{}})", variant),
+                })
+                .collect::<Vec<_>>();
+
+            if !suggestable_variants.is_empty() {
+                let msg = if suggestable_variants.len() == 1 {
+                    "you might have meant to use the following enum variant"
+                } else {
+                    "you might have meant to use one of the following enum variants"
+                };
+
+                err.span_suggestions(
+                    span,
+                    msg,
+                    suggestable_variants.drain(..),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+
+            let mut suggestable_variants_with_placeholders = variants
+                .iter()
+                .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
+                .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
+                .filter_map(|(variant, kind)| match kind {
+                    CtorKind::Fn => Some(format!("({}(/* fields */))", variant)),
+                    CtorKind::Fictive => Some(format!("({} {{ /* fields */ }})", variant)),
+                    _ => None,
+                })
+                .collect::<Vec<_>>();
+
+            if !suggestable_variants_with_placeholders.is_empty() {
+                let msg = match (
+                    suggestable_variants.is_empty(),
+                    suggestable_variants_with_placeholders.len(),
+                ) {
+                    (true, 1) => "the following enum variant is available",
+                    (true, _) => "the following enum variants are available",
+                    (false, 1) => "alternatively, the following enum variant is available",
+                    (false, _) => "alternatively, the following enum variants are also available",
+                };
+
+                err.span_suggestions(
+                    span,
+                    msg,
+                    suggestable_variants_with_placeholders.drain(..),
+                    Applicability::HasPlaceholders,
+                );
+            }
+        };
+
+        if def_id.is_local() {
+            if let Some(span) = self.def_span(def_id) {
+                err.span_note(span, "the enum is defined here");
             }
         }
     }