Skip to content

Commit e802180

Browse files
committed
add suggestion for associated function
1 parent f5a5f0f commit e802180

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3369,6 +3369,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
33693369
err.span_label(within_macro_span, "due to this macro variable");
33703370
}
33713371

3372+
// Check if there is an associated function with the same name.
3373+
if let Some(def_id) = base_ty.peel_refs().ty_adt_def().map(|d| d.did()) {
3374+
for impl_def_id in self.tcx.inherent_impls(def_id) {
3375+
for item in self.tcx.associated_items(impl_def_id).in_definition_order() {
3376+
if let ExprKind::Field(base_expr, _) = expr.kind
3377+
&& item.name() == field.name
3378+
&& matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. })
3379+
{
3380+
err.span_label(field.span, "this is an associated function, not a method");
3381+
err.note("found the following associated function; to be used as method, it must have a `self` parameter");
3382+
let impl_ty = self.tcx.type_of(impl_def_id).instantiate_identity();
3383+
err.span_note(
3384+
self.tcx.def_span(item.def_id),
3385+
format!("the candidate is defined in an impl for the type `{impl_ty}`"),
3386+
);
3387+
3388+
let ty_str = match base_ty.peel_refs().kind() {
3389+
ty::Adt(def, args) => self.tcx.def_path_str_with_args(def.did(), args),
3390+
_ => base_ty.peel_refs().to_string(),
3391+
};
3392+
err.multipart_suggestion(
3393+
"use associated function syntax instead",
3394+
vec![
3395+
(base_expr.span, ty_str),
3396+
(base_expr.span.between(field.span), "::".to_string()),
3397+
],
3398+
Applicability::MaybeIncorrect,
3399+
);
3400+
return err;
3401+
}
3402+
}
3403+
}
3404+
}
3405+
33723406
// try to add a suggestion in case the field is a nested field of a field of the Adt
33733407
let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id();
33743408
let (ty, unwrap) = if let ty::Adt(def, args) = base_ty.kind()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
struct S;
2+
impl S {
3+
fn foo() {}
4+
fn bar(&self) {
5+
self.foo(); //~ ERROR no method named `foo` found for reference `&S` in the current scope
6+
let f: fn() = self.foo; //~ ERROR no field `foo` on type `&S`
7+
}
8+
}
9+
10+
fn main() {}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0599]: no method named `foo` found for reference `&S` in the current scope
2+
--> $DIR/assc-func-issue-149038.rs:5:14
3+
|
4+
LL | self.foo();
5+
| ^^^ this is an associated function, not a method
6+
|
7+
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
8+
note: the candidate is defined in an impl for the type `S`
9+
--> $DIR/assc-func-issue-149038.rs:3:5
10+
|
11+
LL | fn foo() {}
12+
| ^^^^^^^^
13+
help: use associated function syntax instead
14+
|
15+
LL - self.foo();
16+
LL + S::foo();
17+
|
18+
19+
error[E0609]: no field `foo` on type `&S`
20+
--> $DIR/assc-func-issue-149038.rs:6:28
21+
|
22+
LL | let f: fn() = self.foo;
23+
| ^^^
24+
| |
25+
| this is an associated function, not a method
26+
| unknown field
27+
|
28+
= note: found the following associated function; to be used as method, it must have a `self` parameter
29+
note: the candidate is defined in an impl for the type `S`
30+
--> $DIR/assc-func-issue-149038.rs:3:5
31+
|
32+
LL | fn foo() {}
33+
| ^^^^^^^^
34+
help: use associated function syntax instead
35+
|
36+
LL - let f: fn() = self.foo;
37+
LL + let f: fn() = S::foo;
38+
|
39+
40+
error: aborting due to 2 previous errors
41+
42+
Some errors have detailed explanations: E0599, E0609.
43+
For more information about an error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)