Suggest calling associated fn
inside trait
s
When calling a function that doesn't exist inside of a trait's associated `fn`, and another associated `fn` in that trait has that name, suggest calling it with the appropriate fully-qualified path. Expand the label to be more descriptive. Prompted by the following user experience: https://users.rust-lang.org/t/cannot-find-function/50663
This commit is contained in:
parent
9f6c670c4b
commit
9e16213610
9 changed files with 124 additions and 49 deletions
|
@ -353,8 +353,8 @@ impl<'a> PathSource<'a> {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct DiagnosticMetadata<'ast> {
|
struct DiagnosticMetadata<'ast> {
|
||||||
/// The current trait's associated types' ident, used for diagnostic suggestions.
|
/// The current trait's associated items' ident, used for diagnostic suggestions.
|
||||||
current_trait_assoc_types: Vec<Ident>,
|
current_trait_assoc_items: Option<&'ast [P<AssocItem>]>,
|
||||||
|
|
||||||
/// The current self type if inside an impl (used for better errors).
|
/// The current self type if inside an impl (used for better errors).
|
||||||
current_self_type: Option<Ty>,
|
current_self_type: Option<Ty>,
|
||||||
|
@ -1148,26 +1148,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
result
|
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<T>(
|
fn with_trait_items<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
trait_items: &Vec<P<AssocItem>>,
|
trait_items: &'ast Vec<P<AssocItem>>,
|
||||||
f: impl FnOnce(&mut Self) -> T,
|
f: impl FnOnce(&mut Self) -> T,
|
||||||
) -> T {
|
) -> T {
|
||||||
let trait_assoc_types = replace(
|
let trait_assoc_items = replace(
|
||||||
&mut self.diagnostic_metadata.current_trait_assoc_types,
|
&mut self.diagnostic_metadata.current_trait_assoc_items,
|
||||||
trait_items
|
Some(&trait_items[..]),
|
||||||
.iter()
|
|
||||||
.filter_map(|item| match &item.kind {
|
|
||||||
AssocItemKind::TyAlias(_, _, bounds, _) if bounds.is_empty() => {
|
|
||||||
Some(item.ident)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
);
|
);
|
||||||
let result = f(self);
|
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
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,21 @@ type Res = def::Res<ast::NodeId>;
|
||||||
enum AssocSuggestion {
|
enum AssocSuggestion {
|
||||||
Field,
|
Field,
|
||||||
MethodWithSelf,
|
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> {
|
crate enum MissingLifetimeSpot<'tcx> {
|
||||||
|
@ -386,15 +400,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
AssocSuggestion::MethodWithSelf if self_is_available => {
|
AssocSuggestion::MethodWithSelf if self_is_available => {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
span,
|
span,
|
||||||
"try",
|
"you might have meant to call the method",
|
||||||
format!("self.{}", path_str),
|
format!("self.{}", path_str),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
|
AssocSuggestion::MethodWithSelf
|
||||||
|
| AssocSuggestion::AssocFn
|
||||||
|
| AssocSuggestion::AssocConst
|
||||||
|
| AssocSuggestion::AssocType => {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
span,
|
span,
|
||||||
"try",
|
&format!("you might have meant to {}", candidate.action()),
|
||||||
format!("Self::{}", path_str),
|
format!("Self::{}", path_str),
|
||||||
Applicability::MachineApplicable,
|
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 let Some(items) = self.diagnostic_metadata.current_trait_assoc_items {
|
||||||
if *assoc_type_ident == ident {
|
for assoc_item in &items[..] {
|
||||||
return Some(AssocSuggestion::AssocItem);
|
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();
|
let res = binding.res();
|
||||||
if filter_fn(res) {
|
if filter_fn(res) {
|
||||||
return Some(if self.r.has_self.contains(&res.def_id()) {
|
if self.r.has_self.contains(&res.def_id()) {
|
||||||
AssocSuggestion::MethodWithSelf
|
return Some(AssocSuggestion::MethodWithSelf);
|
||||||
} else {
|
} 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);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
32
src/test/ui/resolve/associated-fn-called-as-fn.rs
Normal file
32
src/test/ui/resolve/associated-fn-called-as-fn.rs
Normal file
|
@ -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() {}
|
15
src/test/ui/resolve/associated-fn-called-as-fn.stderr
Normal file
15
src/test/ui/resolve/associated-fn-called-as-fn.stderr
Normal file
|
@ -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`.
|
|
@ -2,7 +2,7 @@ error[E0425]: cannot find function `baz` in this scope
|
||||||
--> $DIR/issue-14254.rs:19:9
|
--> $DIR/issue-14254.rs:19:9
|
||||||
|
|
|
|
||||||
LL | baz();
|
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
|
error[E0425]: cannot find value `a` in this scope
|
||||||
--> $DIR/issue-14254.rs:21:9
|
--> $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
|
--> $DIR/issue-14254.rs:28:9
|
||||||
|
|
|
|
||||||
LL | baz();
|
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
|
error[E0425]: cannot find value `x` in this scope
|
||||||
--> $DIR/issue-14254.rs:30:9
|
--> $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
|
--> $DIR/issue-14254.rs:36:9
|
||||||
|
|
|
|
||||||
LL | bah;
|
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
|
error[E0425]: cannot find value `b` in this scope
|
||||||
--> $DIR/issue-14254.rs:38:9
|
--> $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
|
--> $DIR/issue-14254.rs:45:9
|
||||||
|
|
|
|
||||||
LL | baz();
|
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
|
error[E0425]: cannot find value `x` in this scope
|
||||||
--> $DIR/issue-14254.rs:47:9
|
--> $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
|
--> $DIR/issue-14254.rs:53:9
|
||||||
|
|
|
|
||||||
LL | bah;
|
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
|
error[E0425]: cannot find value `b` in this scope
|
||||||
--> $DIR/issue-14254.rs:55:9
|
--> $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
|
--> $DIR/issue-14254.rs:62:9
|
||||||
|
|
|
|
||||||
LL | baz();
|
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
|
error[E0425]: cannot find value `bah` in this scope
|
||||||
--> $DIR/issue-14254.rs:64:9
|
--> $DIR/issue-14254.rs:64:9
|
||||||
|
|
|
|
||||||
LL | bah;
|
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
|
error[E0425]: cannot find function `baz` in this scope
|
||||||
--> $DIR/issue-14254.rs:71:9
|
--> $DIR/issue-14254.rs:71:9
|
||||||
|
|
|
|
||||||
LL | baz();
|
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
|
error[E0425]: cannot find value `bah` in this scope
|
||||||
--> $DIR/issue-14254.rs:73:9
|
--> $DIR/issue-14254.rs:73:9
|
||||||
|
|
|
|
||||||
LL | bah;
|
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
|
error[E0425]: cannot find function `baz` in this scope
|
||||||
--> $DIR/issue-14254.rs:80:9
|
--> $DIR/issue-14254.rs:80:9
|
||||||
|
|
|
|
||||||
LL | baz();
|
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
|
error[E0425]: cannot find value `bah` in this scope
|
||||||
--> $DIR/issue-14254.rs:82:9
|
--> $DIR/issue-14254.rs:82:9
|
||||||
|
|
|
|
||||||
LL | bah;
|
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
|
error[E0425]: cannot find function `baz` in this scope
|
||||||
--> $DIR/issue-14254.rs:89:9
|
--> $DIR/issue-14254.rs:89:9
|
||||||
|
|
|
|
||||||
LL | baz();
|
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
|
error[E0425]: cannot find value `bah` in this scope
|
||||||
--> $DIR/issue-14254.rs:91:9
|
--> $DIR/issue-14254.rs:91:9
|
||||||
|
|
|
|
||||||
LL | bah;
|
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
|
error[E0425]: cannot find function `baz` in this scope
|
||||||
--> $DIR/issue-14254.rs:98:9
|
--> $DIR/issue-14254.rs:98:9
|
||||||
|
|
|
|
||||||
LL | baz();
|
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
|
error[E0425]: cannot find value `bah` in this scope
|
||||||
--> $DIR/issue-14254.rs:100:9
|
--> $DIR/issue-14254.rs:100:9
|
||||||
|
|
|
|
||||||
LL | bah;
|
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
|
error: aborting due to 24 previous errors
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ error[E0425]: cannot find function `clone` in this scope
|
||||||
--> $DIR/issue-2356.rs:24:5
|
--> $DIR/issue-2356.rs:24:5
|
||||||
|
|
|
|
||||||
LL | clone();
|
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
|
error[E0425]: cannot find function `default` in this scope
|
||||||
--> $DIR/issue-2356.rs:31:5
|
--> $DIR/issue-2356.rs:31:5
|
||||||
|
@ -16,7 +16,7 @@ error[E0425]: cannot find function `default` in this scope
|
||||||
LL | default();
|
LL | default();
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
help: try
|
help: you might have meant to call the associated function
|
||||||
|
|
|
|
||||||
LL | Self::default();
|
LL | Self::default();
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
@ -35,7 +35,7 @@ error[E0425]: cannot find function `shave` in this scope
|
||||||
--> $DIR/issue-2356.rs:41:5
|
--> $DIR/issue-2356.rs:41:5
|
||||||
|
|
|
|
||||||
LL | shave(4);
|
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
|
error[E0425]: cannot find function `purr` in this scope
|
||||||
--> $DIR/issue-2356.rs:43:5
|
--> $DIR/issue-2356.rs:43:5
|
||||||
|
|
|
@ -20,7 +20,7 @@ error[E0412]: cannot find type `Type` in this scope
|
||||||
--> $DIR/resolve-assoc-suggestions.rs:23:16
|
--> $DIR/resolve-assoc-suggestions.rs:23:16
|
||||||
|
|
|
|
||||||
LL | let _: Type;
|
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
|
error[E0531]: cannot find tuple struct or tuple variant `Type` in this scope
|
||||||
--> $DIR/resolve-assoc-suggestions.rs:25:13
|
--> $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
|
--> $DIR/resolve-assoc-suggestions.rs:34:9
|
||||||
|
|
|
|
||||||
LL | method;
|
LL | method;
|
||||||
| ^^^^^^ help: try: `self.method`
|
| ^^^^^^ help: you might have meant to call the method: `self.method`
|
||||||
|
|
||||||
error: aborting due to 9 previous errors
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ error[E0425]: cannot find function `method` in this scope
|
||||||
--> $DIR/resolve-speculative-adjustment.rs:25:9
|
--> $DIR/resolve-speculative-adjustment.rs:25:9
|
||||||
|
|
|
|
||||||
LL | method();
|
LL | method();
|
||||||
| ^^^^^^ help: try: `self.method`
|
| ^^^^^^ help: you might have meant to call the method: `self.method`
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ error[E0412]: cannot find type `Bla` in this scope
|
||||||
--> $DIR/assoc-type-in-method-return.rs:3:25
|
--> $DIR/assoc-type-in-method-return.rs:3:25
|
||||||
|
|
|
|
||||||
LL | fn to_bla(&self) -> Bla;
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue