about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs30
-rw-r--r--compiler/rustc_resolve/src/late.rs28
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs38
-rw-r--r--compiler/rustc_resolve/src/lib.rs6
-rw-r--r--src/test/ui/error-codes/E0407.stderr5
-rw-r--r--src/test/ui/hygiene/assoc_item_ctxt.stderr5
-rw-r--r--src/test/ui/suggestions/suggest-trait-items.rs48
-rw-r--r--src/test/ui/suggestions/suggest-trait-items.stderr74
8 files changed, 216 insertions, 18 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 435c79d2daf..b1d02f90be1 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -198,7 +198,7 @@ impl<'a> Resolver<'a> {
                 err.span_label(first_use_span, format!("first use of `{}`", name));
                 err
             }
-            ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
+            ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
@@ -208,9 +208,17 @@ impl<'a> Resolver<'a> {
                     trait_
                 );
                 err.span_label(span, format!("not a member of trait `{}`", trait_));
+                if let Some(candidate) = candidate {
+                    err.span_suggestion(
+                        method.span,
+                        "there is an associated function with a similar name",
+                        candidate.to_ident_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
                 err
             }
-            ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
+            ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
@@ -220,9 +228,17 @@ impl<'a> Resolver<'a> {
                     trait_
                 );
                 err.span_label(span, format!("not a member of trait `{}`", trait_));
+                if let Some(candidate) = candidate {
+                    err.span_suggestion(
+                        type_.span,
+                        "there is an associated type with a similar name",
+                        candidate.to_ident_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
                 err
             }
-            ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
+            ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
@@ -232,6 +248,14 @@ impl<'a> Resolver<'a> {
                     trait_
                 );
                 err.span_label(span, format!("not a member of trait `{}`", trait_));
+                if let Some(candidate) = candidate {
+                    err.span_suggestion(
+                        const_.span,
+                        "there is an associated constant with a similar name",
+                        candidate.to_ident_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
                 err
             }
             ResolutionError::VariableNotBoundInPattern(binding_error) => {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 3c48a76224f..95633257965 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1309,14 +1309,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                     use crate::ResolutionError::*;
                                     match &item.kind {
                                         AssocItemKind::Const(_default, _ty, _expr) => {
-                                            debug!("resolve_implementation AssocItemKind::Const",);
+                                            debug!("resolve_implementation AssocItemKind::Const");
                                             // If this is a trait impl, ensure the const
                                             // exists in trait
                                             this.check_trait_item(
                                                 item.ident,
+                                                &item.kind,
                                                 ValueNS,
                                                 item.span,
-                                                |n, s| ConstNotMemberOfTrait(n, s),
+                                                |i, s, c| ConstNotMemberOfTrait(i, s, c),
                                             );
 
                                             // We allow arbitrary const expressions inside of associated consts,
@@ -1338,6 +1339,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                             );
                                         }
                                         AssocItemKind::Fn(box FnKind(.., generics, _)) => {
+                                            debug!("resolve_implementation AssocItemKind::Fn");
                                             // We also need a new scope for the impl item type parameters.
                                             this.with_generic_param_rib(
                                                 generics,
@@ -1347,9 +1349,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                                     // exists in trait
                                                     this.check_trait_item(
                                                         item.ident,
+                                                        &item.kind,
                                                         ValueNS,
                                                         item.span,
-                                                        |n, s| MethodNotMemberOfTrait(n, s),
+                                                        |i, s, c| MethodNotMemberOfTrait(i, s, c),
                                                     );
 
                                                     visit::walk_assoc_item(
@@ -1366,6 +1369,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                             _,
                                             _,
                                         )) => {
+                                            debug!("resolve_implementation AssocItemKind::TyAlias");
                                             // We also need a new scope for the impl item type parameters.
                                             this.with_generic_param_rib(
                                                 generics,
@@ -1375,9 +1379,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                                     // exists in trait
                                                     this.check_trait_item(
                                                         item.ident,
+                                                        &item.kind,
                                                         TypeNS,
                                                         item.span,
-                                                        |n, s| TypeNotMemberOfTrait(n, s),
+                                                        |i, s, c| TypeNotMemberOfTrait(i, s, c),
                                                     );
 
                                                     visit::walk_assoc_item(
@@ -1401,9 +1406,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         });
     }
 
-    fn check_trait_item<F>(&mut self, ident: Ident, ns: Namespace, span: Span, err: F)
-    where
-        F: FnOnce(Symbol, &str) -> ResolutionError<'_>,
+    fn check_trait_item<F>(
+        &mut self,
+        ident: Ident,
+        kind: &AssocItemKind,
+        ns: Namespace,
+        span: Span,
+        err: F,
+    ) where
+        F: FnOnce(Ident, &str, Option<Symbol>) -> ResolutionError<'_>,
     {
         // If there is a TraitRef in scope for an impl, then the method must be in the
         // trait.
@@ -1420,8 +1431,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 )
                 .is_err()
             {
+                let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
                 let path = &self.current_trait_ref.as_ref().unwrap().1.path;
-                self.report_error(span, err(ident.name, &path_names_to_string(path)));
+                self.report_error(span, err(ident, &path_names_to_string(path), candidate));
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 19136c6ceeb..0e6ca1856bb 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -7,8 +7,8 @@ use crate::{PathResult, PathSource, Segment};
 
 use rustc_ast::visit::FnKind;
 use rustc_ast::{
-    self as ast, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, NodeId, Path, Ty,
-    TyKind,
+    self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind,
+    NodeId, Path, Ty, TyKind,
 };
 use rustc_ast_pretty::pprust::path_segment_to_string;
 use rustc_data_structures::fx::FxHashSet;
@@ -1144,6 +1144,40 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         true
     }
 
+    /// Given the target `ident` and `kind`, search for the similarly named associated item
+    /// in `self.current_trait_ref`.
+    crate fn find_similarly_named_assoc_item(
+        &mut self,
+        ident: Symbol,
+        kind: &AssocItemKind,
+    ) -> Option<Symbol> {
+        let module = if let Some((module, _)) = self.current_trait_ref {
+            module
+        } else {
+            return None;
+        };
+        if ident == kw::Underscore {
+            // We do nothing for `_`.
+            return None;
+        }
+
+        let resolutions = self.r.resolutions(module);
+        let targets = resolutions
+            .borrow()
+            .iter()
+            .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res())))
+            .filter(|(_, res)| match (kind, res) {
+                (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
+                (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
+                (AssocItemKind::TyAlias(..), Res::Def(DefKind::AssocTy, _)) => true,
+                _ => false,
+            })
+            .map(|(key, _)| key.ident.name)
+            .collect::<Vec<_>>();
+
+        find_best_match_for_name(&targets, ident, None)
+    }
+
     fn lookup_assoc_candidate<FilterFn>(
         &mut self,
         ident: Ident,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 68db06370ff..22d77d44321 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -202,11 +202,11 @@ enum ResolutionError<'a> {
     /// parameter list.
     NameAlreadyUsedInParameterList(Symbol, Span),
     /// Error E0407: method is not a member of trait.
-    MethodNotMemberOfTrait(Symbol, &'a str),
+    MethodNotMemberOfTrait(Ident, &'a str, Option<Symbol>),
     /// Error E0437: type is not a member of trait.
-    TypeNotMemberOfTrait(Symbol, &'a str),
+    TypeNotMemberOfTrait(Ident, &'a str, Option<Symbol>),
     /// Error E0438: const is not a member of trait.
-    ConstNotMemberOfTrait(Symbol, &'a str),
+    ConstNotMemberOfTrait(Ident, &'a str, Option<Symbol>),
     /// Error E0408: variable `{}` is not bound in all patterns.
     VariableNotBoundInPattern(&'a BindingError),
     /// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm.
diff --git a/src/test/ui/error-codes/E0407.stderr b/src/test/ui/error-codes/E0407.stderr
index 567fc879040..6f6d1ff6a8f 100644
--- a/src/test/ui/error-codes/E0407.stderr
+++ b/src/test/ui/error-codes/E0407.stderr
@@ -2,7 +2,10 @@ error[E0407]: method `b` is not a member of trait `Foo`
   --> $DIR/E0407.rs:9:5
    |
 LL |     fn b() {}
-   |     ^^^^^^^^^ not a member of trait `Foo`
+   |     ^^^-^^^^^
+   |     |  |
+   |     |  help: there is an associated function with a similar name: `a`
+   |     not a member of trait `Foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hygiene/assoc_item_ctxt.stderr b/src/test/ui/hygiene/assoc_item_ctxt.stderr
index 6e4fecf0ce4..517b1ff5988 100644
--- a/src/test/ui/hygiene/assoc_item_ctxt.stderr
+++ b/src/test/ui/hygiene/assoc_item_ctxt.stderr
@@ -2,7 +2,10 @@ error[E0407]: method `method` is not a member of trait `Tr`
   --> $DIR/assoc_item_ctxt.rs:35:13
    |
 LL |             fn method() {}
-   |             ^^^^^^^^^^^^^^ not a member of trait `Tr`
+   |             ^^^------^^^^^
+   |             |  |
+   |             |  help: there is an associated function with a similar name: `method`
+   |             not a member of trait `Tr`
 ...
 LL |     mac_trait_impl!();
    |     ------------------ in this macro invocation
diff --git a/src/test/ui/suggestions/suggest-trait-items.rs b/src/test/ui/suggestions/suggest-trait-items.rs
new file mode 100644
index 00000000000..9d42a734260
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-trait-items.rs
@@ -0,0 +1,48 @@
+trait Foo {
+    type Type;
+
+    fn foo();
+    fn bar();
+    fn qux();
+}
+
+struct A;
+
+impl Foo for A {
+//~^ ERROR not all trait items implemented
+    type Typ = ();
+    //~^ ERROR type `Typ` is not a member of trait
+    //~| HELP there is an associated type with a similar name
+
+    fn fooo() {}
+    //~^ ERROR method `fooo` is not a member of trait
+    //~| HELP there is an associated function with a similar name
+
+    fn barr() {}
+    //~^ ERROR method `barr` is not a member of trait
+    //~| HELP there is an associated function with a similar name
+
+    fn quux() {}
+    //~^ ERROR method `quux` is not a member of trait
+    //~| HELP there is an associated function with a similar name
+}
+//~^ HELP implement the missing item
+//~| HELP implement the missing item
+//~| HELP implement the missing item
+//~| HELP implement the missing item
+
+trait Bar {
+    const Const: i32;
+}
+
+struct B;
+
+impl Bar for B {
+//~^ ERROR not all trait items implemented
+    const Cnst: i32 = 0;
+    //~^ ERROR const `Cnst` is not a member of trait
+    //~| HELP there is an associated constant with a similar name
+}
+//~^ HELP implement the missing item
+
+fn main() {}
diff --git a/src/test/ui/suggestions/suggest-trait-items.stderr b/src/test/ui/suggestions/suggest-trait-items.stderr
new file mode 100644
index 00000000000..151bae7d1b9
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-trait-items.stderr
@@ -0,0 +1,74 @@
+error[E0437]: type `Typ` is not a member of trait `Foo`
+  --> $DIR/suggest-trait-items.rs:13:5
+   |
+LL |     type Typ = ();
+   |     ^^^^^---^^^^^^
+   |     |    |
+   |     |    help: there is an associated type with a similar name: `Type`
+   |     not a member of trait `Foo`
+
+error[E0407]: method `fooo` is not a member of trait `Foo`
+  --> $DIR/suggest-trait-items.rs:17:5
+   |
+LL |     fn fooo() {}
+   |     ^^^----^^^^^
+   |     |  |
+   |     |  help: there is an associated function with a similar name: `foo`
+   |     not a member of trait `Foo`
+
+error[E0407]: method `barr` is not a member of trait `Foo`
+  --> $DIR/suggest-trait-items.rs:21:5
+   |
+LL |     fn barr() {}
+   |     ^^^----^^^^^
+   |     |  |
+   |     |  help: there is an associated function with a similar name: `bar`
+   |     not a member of trait `Foo`
+
+error[E0407]: method `quux` is not a member of trait `Foo`
+  --> $DIR/suggest-trait-items.rs:25:5
+   |
+LL |     fn quux() {}
+   |     ^^^----^^^^^
+   |     |  |
+   |     |  help: there is an associated function with a similar name: `qux`
+   |     not a member of trait `Foo`
+
+error[E0438]: const `Cnst` is not a member of trait `Bar`
+  --> $DIR/suggest-trait-items.rs:42:5
+   |
+LL |     const Cnst: i32 = 0;
+   |     ^^^^^^----^^^^^^^^^^
+   |     |     |
+   |     |     help: there is an associated constant with a similar name: `Const`
+   |     not a member of trait `Bar`
+
+error[E0046]: not all trait items implemented, missing: `Type`, `foo`, `bar`, `qux`
+  --> $DIR/suggest-trait-items.rs:11:1
+   |
+LL |     type Type;
+   |     ---------- `Type` from trait
+LL | 
+LL |     fn foo();
+   |     --------- `foo` from trait
+LL |     fn bar();
+   |     --------- `bar` from trait
+LL |     fn qux();
+   |     --------- `qux` from trait
+...
+LL | impl Foo for A {
+   | ^^^^^^^^^^^^^^ missing `Type`, `foo`, `bar`, `qux` in implementation
+
+error[E0046]: not all trait items implemented, missing: `Const`
+  --> $DIR/suggest-trait-items.rs:40:1
+   |
+LL |     const Const: i32;
+   |     ----------------- `Const` from trait
+...
+LL | impl Bar for B {
+   | ^^^^^^^^^^^^^^ missing `Const` in implementation
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0046, E0407, E0437, E0438.
+For more information about an error, try `rustc --explain E0046`.