diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7517ab66170a2..9fe42590d3eae 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -353,8 +353,8 @@ impl<'a> PathSource<'a> { #[derive(Default)] struct DiagnosticMetadata<'ast> { - /// The current trait's associated types' ident, used for diagnostic suggestions. - current_trait_assoc_types: Vec, + /// The current trait's associated items' ident, used for diagnostic suggestions. + current_trait_assoc_items: Option<&'ast [P]>, /// The current self type if inside an impl (used for better errors). current_self_type: Option, @@ -1148,26 +1148,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { result } - /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412. + /// When evaluating a `trait` use its associated types' idents for suggestions in E0412. fn with_trait_items( &mut self, - trait_items: &Vec>, + trait_items: &'ast Vec>, f: impl FnOnce(&mut Self) -> T, ) -> T { - let trait_assoc_types = replace( - &mut self.diagnostic_metadata.current_trait_assoc_types, - trait_items - .iter() - .filter_map(|item| match &item.kind { - AssocItemKind::TyAlias(_, _, bounds, _) if bounds.is_empty() => { - Some(item.ident) - } - _ => None, - }) - .collect(), + let trait_assoc_items = replace( + &mut self.diagnostic_metadata.current_trait_assoc_items, + Some(&trait_items[..]), ); let result = f(self); - self.diagnostic_metadata.current_trait_assoc_types = trait_assoc_types; + self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items; result } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c24b383f3b811..75dc54e4d6531 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -30,7 +30,21 @@ type Res = def::Res; enum AssocSuggestion { Field, MethodWithSelf, - AssocItem, + AssocFn, + AssocType, + AssocConst, +} + +impl AssocSuggestion { + fn action(&self) -> &'static str { + match self { + AssocSuggestion::Field => "use the available field", + AssocSuggestion::MethodWithSelf => "call the method with the fully-qualified path", + AssocSuggestion::AssocFn => "call the associated function", + AssocSuggestion::AssocConst => "use the associated `const`", + AssocSuggestion::AssocType => "use the associated type", + } + } } crate enum MissingLifetimeSpot<'tcx> { @@ -386,15 +400,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { AssocSuggestion::MethodWithSelf if self_is_available => { err.span_suggestion( span, - "try", + "you might have meant to call the method", format!("self.{}", path_str), Applicability::MachineApplicable, ); } - AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { + AssocSuggestion::MethodWithSelf + | AssocSuggestion::AssocFn + | AssocSuggestion::AssocConst + | AssocSuggestion::AssocType => { err.span_suggestion( span, - "try", + &format!("you might have meant to {}", candidate.action()), format!("Self::{}", path_str), Applicability::MachineApplicable, ); @@ -1048,9 +1065,19 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } - for assoc_type_ident in &self.diagnostic_metadata.current_trait_assoc_types { - if *assoc_type_ident == ident { - return Some(AssocSuggestion::AssocItem); + if let Some(items) = self.diagnostic_metadata.current_trait_assoc_items { + for assoc_item in &items[..] { + if assoc_item.ident == ident { + return Some(match &assoc_item.kind { + ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst, + ast::AssocItemKind::Fn(_, sig, ..) if sig.decl.has_self() => { + AssocSuggestion::MethodWithSelf + } + ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn, + ast::AssocItemKind::TyAlias(..) => AssocSuggestion::AssocType, + ast::AssocItemKind::MacCall(_) => continue, + }); + } } } @@ -1066,11 +1093,20 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { ) { let res = binding.res(); if filter_fn(res) { - return Some(if self.r.has_self.contains(&res.def_id()) { - AssocSuggestion::MethodWithSelf + if self.r.has_self.contains(&res.def_id()) { + return Some(AssocSuggestion::MethodWithSelf); } else { - AssocSuggestion::AssocItem - }); + match res { + Res::Def(DefKind::AssocFn, _) => return Some(AssocSuggestion::AssocFn), + Res::Def(DefKind::AssocConst, _) => { + return Some(AssocSuggestion::AssocConst); + } + Res::Def(DefKind::AssocTy, _) => { + return Some(AssocSuggestion::AssocType); + } + _ => {} + } + } } } } diff --git a/src/test/ui/resolve/associated-fn-called-as-fn.rs b/src/test/ui/resolve/associated-fn-called-as-fn.rs new file mode 100644 index 0000000000000..f31f3d67b5be5 --- /dev/null +++ b/src/test/ui/resolve/associated-fn-called-as-fn.rs @@ -0,0 +1,32 @@ +struct S; +impl Foo for S { + fn parse(s:&str) { + for c in s.chars() { + match c { + '0'..='9' => collect_primary(&c), //~ ERROR cannot find function `collect_primary` + //~^ HELP you might have meant to call the associated function + '+' | '-' => println!("We got a sign: {}", c), + _ => println!("Not a number!") + } + } + } +} +trait Foo { + fn collect_primary(ch:&char) { } + fn parse(s:&str); +} +trait Bar { + fn collect_primary(ch:&char) { } + fn parse(s:&str) { + for c in s.chars() { + match c { + '0'..='9' => collect_primary(&c), //~ ERROR cannot find function `collect_primary` + //~^ HELP you might have meant to call the associated function + '+' | '-' => println!("We got a sign: {}", c), + _ => println!("Not a number!") + } + } + } +} + +fn main() {} diff --git a/src/test/ui/resolve/associated-fn-called-as-fn.stderr b/src/test/ui/resolve/associated-fn-called-as-fn.stderr new file mode 100644 index 0000000000000..fbdea30d551fd --- /dev/null +++ b/src/test/ui/resolve/associated-fn-called-as-fn.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find function `collect_primary` in this scope + --> $DIR/associated-fn-called-as-fn.rs:6:30 + | +LL | '0'..='9' => collect_primary(&c), + | ^^^^^^^^^^^^^^^ help: you might have meant to call the associated function: `Self::collect_primary` + +error[E0425]: cannot find function `collect_primary` in this scope + --> $DIR/associated-fn-called-as-fn.rs:23:30 + | +LL | '0'..='9' => collect_primary(&c), + | ^^^^^^^^^^^^^^^ help: you might have meant to call the associated function: `Self::collect_primary` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/resolve/issue-14254.stderr b/src/test/ui/resolve/issue-14254.stderr index 97d42aa8ef4a5..b1f45adb8b714 100644 --- a/src/test/ui/resolve/issue-14254.stderr +++ b/src/test/ui/resolve/issue-14254.stderr @@ -2,7 +2,7 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:19:9 | LL | baz(); - | ^^^ help: try: `self.baz` + | ^^^ help: you might have meant to call the method: `self.baz` error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:21:9 @@ -14,7 +14,7 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:28:9 | LL | baz(); - | ^^^ help: try: `self.baz` + | ^^^ help: you might have meant to call the method: `self.baz` error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:30:9 @@ -38,7 +38,7 @@ error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:36:9 | LL | bah; - | ^^^ help: try: `Self::bah` + | ^^^ help: you might have meant to call the associated function: `Self::bah` error[E0425]: cannot find value `b` in this scope --> $DIR/issue-14254.rs:38:9 @@ -50,7 +50,7 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:45:9 | LL | baz(); - | ^^^ help: try: `self.baz` + | ^^^ help: you might have meant to call the method: `self.baz` error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:47:9 @@ -74,7 +74,7 @@ error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:53:9 | LL | bah; - | ^^^ help: try: `Self::bah` + | ^^^ help: you might have meant to call the associated function: `Self::bah` error[E0425]: cannot find value `b` in this scope --> $DIR/issue-14254.rs:55:9 @@ -86,61 +86,61 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:62:9 | LL | baz(); - | ^^^ help: try: `self.baz` + | ^^^ help: you might have meant to call the method: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:64:9 | LL | bah; - | ^^^ help: try: `Self::bah` + | ^^^ help: you might have meant to call the associated function: `Self::bah` error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:71:9 | LL | baz(); - | ^^^ help: try: `self.baz` + | ^^^ help: you might have meant to call the method: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:73:9 | LL | bah; - | ^^^ help: try: `Self::bah` + | ^^^ help: you might have meant to call the associated function: `Self::bah` error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:80:9 | LL | baz(); - | ^^^ help: try: `self.baz` + | ^^^ help: you might have meant to call the method: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:82:9 | LL | bah; - | ^^^ help: try: `Self::bah` + | ^^^ help: you might have meant to call the associated function: `Self::bah` error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:89:9 | LL | baz(); - | ^^^ help: try: `self.baz` + | ^^^ help: you might have meant to call the method: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:91:9 | LL | bah; - | ^^^ help: try: `Self::bah` + | ^^^ help: you might have meant to call the associated function: `Self::bah` error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:98:9 | LL | baz(); - | ^^^ help: try: `self.baz` + | ^^^ help: you might have meant to call the method: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:100:9 | LL | bah; - | ^^^ help: try: `Self::bah` + | ^^^ help: you might have meant to call the associated function: `Self::bah` error: aborting due to 24 previous errors diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index 0339daa0d6a18..8083233c01b92 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -8,7 +8,7 @@ error[E0425]: cannot find function `clone` in this scope --> $DIR/issue-2356.rs:24:5 | LL | clone(); - | ^^^^^ help: try: `self.clone` + | ^^^^^ help: you might have meant to call the method: `self.clone` error[E0425]: cannot find function `default` in this scope --> $DIR/issue-2356.rs:31:5 @@ -16,7 +16,7 @@ error[E0425]: cannot find function `default` in this scope LL | default(); | ^^^^^^^ | -help: try +help: you might have meant to call the associated function | LL | Self::default(); | ^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ error[E0425]: cannot find function `shave` in this scope --> $DIR/issue-2356.rs:41:5 | LL | shave(4); - | ^^^^^ help: try: `Self::shave` + | ^^^^^ help: you might have meant to call the associated function: `Self::shave` error[E0425]: cannot find function `purr` in this scope --> $DIR/issue-2356.rs:43:5 diff --git a/src/test/ui/resolve/resolve-assoc-suggestions.stderr b/src/test/ui/resolve/resolve-assoc-suggestions.stderr index a05ac0f854395..b6acaeb8cc232 100644 --- a/src/test/ui/resolve/resolve-assoc-suggestions.stderr +++ b/src/test/ui/resolve/resolve-assoc-suggestions.stderr @@ -20,7 +20,7 @@ error[E0412]: cannot find type `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:23:16 | LL | let _: Type; - | ^^^^ help: try: `Self::Type` + | ^^^^ help: you might have meant to use the associated type: `Self::Type` error[E0531]: cannot find tuple struct or tuple variant `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:25:13 @@ -50,7 +50,7 @@ error[E0425]: cannot find value `method` in this scope --> $DIR/resolve-assoc-suggestions.rs:34:9 | LL | method; - | ^^^^^^ help: try: `self.method` + | ^^^^^^ help: you might have meant to call the method: `self.method` error: aborting due to 9 previous errors diff --git a/src/test/ui/resolve/resolve-speculative-adjustment.stderr b/src/test/ui/resolve/resolve-speculative-adjustment.stderr index 892b50309a905..1c34af6d0ffe5 100644 --- a/src/test/ui/resolve/resolve-speculative-adjustment.stderr +++ b/src/test/ui/resolve/resolve-speculative-adjustment.stderr @@ -20,7 +20,7 @@ error[E0425]: cannot find function `method` in this scope --> $DIR/resolve-speculative-adjustment.rs:25:9 | LL | method(); - | ^^^^^^ help: try: `self.method` + | ^^^^^^ help: you might have meant to call the method: `self.method` error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/assoc-type-in-method-return.stderr b/src/test/ui/suggestions/assoc-type-in-method-return.stderr index bf908d36d2e3f..202e4a16eada7 100644 --- a/src/test/ui/suggestions/assoc-type-in-method-return.stderr +++ b/src/test/ui/suggestions/assoc-type-in-method-return.stderr @@ -2,7 +2,7 @@ error[E0412]: cannot find type `Bla` in this scope --> $DIR/assoc-type-in-method-return.rs:3:25 | LL | fn to_bla(&self) -> Bla; - | ^^^ help: try: `Self::Bla` + | ^^^ help: you might have meant to use the associated type: `Self::Bla` error: aborting due to previous error