Skip to content

Commit 9e2d625

Browse files
authored
Rollup merge of rust-lang#78420 - estebank:suggest-assoc-fn, r=petrochenkov
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
2 parents 286e295 + 9e16213 commit 9e2d625

9 files changed

+124
-49
lines changed

compiler/rustc_resolve/src/late.rs

+8-16
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,8 @@ impl<'a> PathSource<'a> {
339339

340340
#[derive(Default)]
341341
struct DiagnosticMetadata<'ast> {
342-
/// The current trait's associated types' ident, used for diagnostic suggestions.
343-
current_trait_assoc_types: Vec<Ident>,
342+
/// The current trait's associated items' ident, used for diagnostic suggestions.
343+
current_trait_assoc_items: Option<&'ast [P<AssocItem>]>,
344344

345345
/// The current self type if inside an impl (used for better errors).
346346
current_self_type: Option<Ty>,
@@ -1157,26 +1157,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
11571157
result
11581158
}
11591159

1160-
/// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412.
1160+
/// When evaluating a `trait` use its associated types' idents for suggestions in E0412.
11611161
fn with_trait_items<T>(
11621162
&mut self,
1163-
trait_items: &Vec<P<AssocItem>>,
1163+
trait_items: &'ast Vec<P<AssocItem>>,
11641164
f: impl FnOnce(&mut Self) -> T,
11651165
) -> T {
1166-
let trait_assoc_types = replace(
1167-
&mut self.diagnostic_metadata.current_trait_assoc_types,
1168-
trait_items
1169-
.iter()
1170-
.filter_map(|item| match &item.kind {
1171-
AssocItemKind::TyAlias(_, _, bounds, _) if bounds.is_empty() => {
1172-
Some(item.ident)
1173-
}
1174-
_ => None,
1175-
})
1176-
.collect(),
1166+
let trait_assoc_items = replace(
1167+
&mut self.diagnostic_metadata.current_trait_assoc_items,
1168+
Some(&trait_items[..]),
11771169
);
11781170
let result = f(self);
1179-
self.diagnostic_metadata.current_trait_assoc_types = trait_assoc_types;
1171+
self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items;
11801172
result
11811173
}
11821174

compiler/rustc_resolve/src/late/diagnostics.rs

+47-11
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,21 @@ type Res = def::Res<ast::NodeId>;
3030
enum AssocSuggestion {
3131
Field,
3232
MethodWithSelf,
33-
AssocItem,
33+
AssocFn,
34+
AssocType,
35+
AssocConst,
36+
}
37+
38+
impl AssocSuggestion {
39+
fn action(&self) -> &'static str {
40+
match self {
41+
AssocSuggestion::Field => "use the available field",
42+
AssocSuggestion::MethodWithSelf => "call the method with the fully-qualified path",
43+
AssocSuggestion::AssocFn => "call the associated function",
44+
AssocSuggestion::AssocConst => "use the associated `const`",
45+
AssocSuggestion::AssocType => "use the associated type",
46+
}
47+
}
3448
}
3549

3650
crate enum MissingLifetimeSpot<'tcx> {
@@ -386,15 +400,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
386400
AssocSuggestion::MethodWithSelf if self_is_available => {
387401
err.span_suggestion(
388402
span,
389-
"try",
403+
"you might have meant to call the method",
390404
format!("self.{}", path_str),
391405
Applicability::MachineApplicable,
392406
);
393407
}
394-
AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
408+
AssocSuggestion::MethodWithSelf
409+
| AssocSuggestion::AssocFn
410+
| AssocSuggestion::AssocConst
411+
| AssocSuggestion::AssocType => {
395412
err.span_suggestion(
396413
span,
397-
"try",
414+
&format!("you might have meant to {}", candidate.action()),
398415
format!("Self::{}", path_str),
399416
Applicability::MachineApplicable,
400417
);
@@ -1062,9 +1079,19 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
10621079
}
10631080
}
10641081

1065-
for assoc_type_ident in &self.diagnostic_metadata.current_trait_assoc_types {
1066-
if *assoc_type_ident == ident {
1067-
return Some(AssocSuggestion::AssocItem);
1082+
if let Some(items) = self.diagnostic_metadata.current_trait_assoc_items {
1083+
for assoc_item in &items[..] {
1084+
if assoc_item.ident == ident {
1085+
return Some(match &assoc_item.kind {
1086+
ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
1087+
ast::AssocItemKind::Fn(_, sig, ..) if sig.decl.has_self() => {
1088+
AssocSuggestion::MethodWithSelf
1089+
}
1090+
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
1091+
ast::AssocItemKind::TyAlias(..) => AssocSuggestion::AssocType,
1092+
ast::AssocItemKind::MacCall(_) => continue,
1093+
});
1094+
}
10681095
}
10691096
}
10701097

@@ -1080,11 +1107,20 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
10801107
) {
10811108
let res = binding.res();
10821109
if filter_fn(res) {
1083-
return Some(if self.r.has_self.contains(&res.def_id()) {
1084-
AssocSuggestion::MethodWithSelf
1110+
if self.r.has_self.contains(&res.def_id()) {
1111+
return Some(AssocSuggestion::MethodWithSelf);
10851112
} else {
1086-
AssocSuggestion::AssocItem
1087-
});
1113+
match res {
1114+
Res::Def(DefKind::AssocFn, _) => return Some(AssocSuggestion::AssocFn),
1115+
Res::Def(DefKind::AssocConst, _) => {
1116+
return Some(AssocSuggestion::AssocConst);
1117+
}
1118+
Res::Def(DefKind::AssocTy, _) => {
1119+
return Some(AssocSuggestion::AssocType);
1120+
}
1121+
_ => {}
1122+
}
1123+
}
10881124
}
10891125
}
10901126
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
struct S;
2+
impl Foo for S {
3+
fn parse(s:&str) {
4+
for c in s.chars() {
5+
match c {
6+
'0'..='9' => collect_primary(&c), //~ ERROR cannot find function `collect_primary`
7+
//~^ HELP you might have meant to call the associated function
8+
'+' | '-' => println!("We got a sign: {}", c),
9+
_ => println!("Not a number!")
10+
}
11+
}
12+
}
13+
}
14+
trait Foo {
15+
fn collect_primary(ch:&char) { }
16+
fn parse(s:&str);
17+
}
18+
trait Bar {
19+
fn collect_primary(ch:&char) { }
20+
fn parse(s:&str) {
21+
for c in s.chars() {
22+
match c {
23+
'0'..='9' => collect_primary(&c), //~ ERROR cannot find function `collect_primary`
24+
//~^ HELP you might have meant to call the associated function
25+
'+' | '-' => println!("We got a sign: {}", c),
26+
_ => println!("Not a number!")
27+
}
28+
}
29+
}
30+
}
31+
32+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0425]: cannot find function `collect_primary` in this scope
2+
--> $DIR/associated-fn-called-as-fn.rs:6:30
3+
|
4+
LL | '0'..='9' => collect_primary(&c),
5+
| ^^^^^^^^^^^^^^^ help: you might have meant to call the associated function: `Self::collect_primary`
6+
7+
error[E0425]: cannot find function `collect_primary` in this scope
8+
--> $DIR/associated-fn-called-as-fn.rs:23:30
9+
|
10+
LL | '0'..='9' => collect_primary(&c),
11+
| ^^^^^^^^^^^^^^^ help: you might have meant to call the associated function: `Self::collect_primary`
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0425`.

src/test/ui/resolve/issue-14254.stderr

+15-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0425]: cannot find function `baz` in this scope
22
--> $DIR/issue-14254.rs:19:9
33
|
44
LL | baz();
5-
| ^^^ help: try: `self.baz`
5+
| ^^^ help: you might have meant to call the method: `self.baz`
66

77
error[E0425]: cannot find value `a` in this scope
88
--> $DIR/issue-14254.rs:21:9
@@ -14,7 +14,7 @@ error[E0425]: cannot find function `baz` in this scope
1414
--> $DIR/issue-14254.rs:28:9
1515
|
1616
LL | baz();
17-
| ^^^ help: try: `self.baz`
17+
| ^^^ help: you might have meant to call the method: `self.baz`
1818

1919
error[E0425]: cannot find value `x` in this scope
2020
--> $DIR/issue-14254.rs:30:9
@@ -38,7 +38,7 @@ error[E0425]: cannot find value `bah` in this scope
3838
--> $DIR/issue-14254.rs:36:9
3939
|
4040
LL | bah;
41-
| ^^^ help: try: `Self::bah`
41+
| ^^^ help: you might have meant to call the associated function: `Self::bah`
4242

4343
error[E0425]: cannot find value `b` in this scope
4444
--> $DIR/issue-14254.rs:38:9
@@ -50,7 +50,7 @@ error[E0425]: cannot find function `baz` in this scope
5050
--> $DIR/issue-14254.rs:45:9
5151
|
5252
LL | baz();
53-
| ^^^ help: try: `self.baz`
53+
| ^^^ help: you might have meant to call the method: `self.baz`
5454

5555
error[E0425]: cannot find value `x` in this scope
5656
--> $DIR/issue-14254.rs:47:9
@@ -74,7 +74,7 @@ error[E0425]: cannot find value `bah` in this scope
7474
--> $DIR/issue-14254.rs:53:9
7575
|
7676
LL | bah;
77-
| ^^^ help: try: `Self::bah`
77+
| ^^^ help: you might have meant to call the associated function: `Self::bah`
7878

7979
error[E0425]: cannot find value `b` in this scope
8080
--> $DIR/issue-14254.rs:55:9
@@ -86,61 +86,61 @@ error[E0425]: cannot find function `baz` in this scope
8686
--> $DIR/issue-14254.rs:62:9
8787
|
8888
LL | baz();
89-
| ^^^ help: try: `self.baz`
89+
| ^^^ help: you might have meant to call the method: `self.baz`
9090

9191
error[E0425]: cannot find value `bah` in this scope
9292
--> $DIR/issue-14254.rs:64:9
9393
|
9494
LL | bah;
95-
| ^^^ help: try: `Self::bah`
95+
| ^^^ help: you might have meant to call the associated function: `Self::bah`
9696

9797
error[E0425]: cannot find function `baz` in this scope
9898
--> $DIR/issue-14254.rs:71:9
9999
|
100100
LL | baz();
101-
| ^^^ help: try: `self.baz`
101+
| ^^^ help: you might have meant to call the method: `self.baz`
102102

103103
error[E0425]: cannot find value `bah` in this scope
104104
--> $DIR/issue-14254.rs:73:9
105105
|
106106
LL | bah;
107-
| ^^^ help: try: `Self::bah`
107+
| ^^^ help: you might have meant to call the associated function: `Self::bah`
108108

109109
error[E0425]: cannot find function `baz` in this scope
110110
--> $DIR/issue-14254.rs:80:9
111111
|
112112
LL | baz();
113-
| ^^^ help: try: `self.baz`
113+
| ^^^ help: you might have meant to call the method: `self.baz`
114114

115115
error[E0425]: cannot find value `bah` in this scope
116116
--> $DIR/issue-14254.rs:82:9
117117
|
118118
LL | bah;
119-
| ^^^ help: try: `Self::bah`
119+
| ^^^ help: you might have meant to call the associated function: `Self::bah`
120120

121121
error[E0425]: cannot find function `baz` in this scope
122122
--> $DIR/issue-14254.rs:89:9
123123
|
124124
LL | baz();
125-
| ^^^ help: try: `self.baz`
125+
| ^^^ help: you might have meant to call the method: `self.baz`
126126

127127
error[E0425]: cannot find value `bah` in this scope
128128
--> $DIR/issue-14254.rs:91:9
129129
|
130130
LL | bah;
131-
| ^^^ help: try: `Self::bah`
131+
| ^^^ help: you might have meant to call the associated function: `Self::bah`
132132

133133
error[E0425]: cannot find function `baz` in this scope
134134
--> $DIR/issue-14254.rs:98:9
135135
|
136136
LL | baz();
137-
| ^^^ help: try: `self.baz`
137+
| ^^^ help: you might have meant to call the method: `self.baz`
138138

139139
error[E0425]: cannot find value `bah` in this scope
140140
--> $DIR/issue-14254.rs:100:9
141141
|
142142
LL | bah;
143-
| ^^^ help: try: `Self::bah`
143+
| ^^^ help: you might have meant to call the associated function: `Self::bah`
144144

145145
error: aborting due to 24 previous errors
146146

src/test/ui/resolve/issue-2356.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ error[E0425]: cannot find function `clone` in this scope
88
--> $DIR/issue-2356.rs:24:5
99
|
1010
LL | clone();
11-
| ^^^^^ help: try: `self.clone`
11+
| ^^^^^ help: you might have meant to call the method: `self.clone`
1212

1313
error[E0425]: cannot find function `default` in this scope
1414
--> $DIR/issue-2356.rs:31:5
1515
|
1616
LL | default();
1717
| ^^^^^^^
1818
|
19-
help: try
19+
help: you might have meant to call the associated function
2020
|
2121
LL | Self::default();
2222
| ^^^^^^^^^^^^^
@@ -35,7 +35,7 @@ error[E0425]: cannot find function `shave` in this scope
3535
--> $DIR/issue-2356.rs:41:5
3636
|
3737
LL | shave(4);
38-
| ^^^^^ help: try: `Self::shave`
38+
| ^^^^^ help: you might have meant to call the associated function: `Self::shave`
3939

4040
error[E0425]: cannot find function `purr` in this scope
4141
--> $DIR/issue-2356.rs:43:5

src/test/ui/resolve/resolve-assoc-suggestions.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ error[E0412]: cannot find type `Type` in this scope
2020
--> $DIR/resolve-assoc-suggestions.rs:23:16
2121
|
2222
LL | let _: Type;
23-
| ^^^^ help: try: `Self::Type`
23+
| ^^^^ help: you might have meant to use the associated type: `Self::Type`
2424

2525
error[E0531]: cannot find tuple struct or tuple variant `Type` in this scope
2626
--> $DIR/resolve-assoc-suggestions.rs:25:13
@@ -50,7 +50,7 @@ error[E0425]: cannot find value `method` in this scope
5050
--> $DIR/resolve-assoc-suggestions.rs:34:9
5151
|
5252
LL | method;
53-
| ^^^^^^ help: try: `self.method`
53+
| ^^^^^^ help: you might have meant to call the method: `self.method`
5454

5555
error: aborting due to 9 previous errors
5656

src/test/ui/resolve/resolve-speculative-adjustment.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ error[E0425]: cannot find function `method` in this scope
2020
--> $DIR/resolve-speculative-adjustment.rs:25:9
2121
|
2222
LL | method();
23-
| ^^^^^^ help: try: `self.method`
23+
| ^^^^^^ help: you might have meant to call the method: `self.method`
2424

2525
error: aborting due to 4 previous errors
2626

src/test/ui/suggestions/assoc-type-in-method-return.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0412]: cannot find type `Bla` in this scope
22
--> $DIR/assoc-type-in-method-return.rs:3:25
33
|
44
LL | fn to_bla(&self) -> Bla;
5-
| ^^^ help: try: `Self::Bla`
5+
| ^^^ help: you might have meant to use the associated type: `Self::Bla`
66

77
error: aborting due to previous error
88

0 commit comments

Comments
 (0)