Skip to content

Commit da588e6

Browse files
committed
Attempt to fix arguments of associated functions
1 parent 02025b5 commit da588e6

File tree

6 files changed

+126
-61
lines changed

6 files changed

+126
-61
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_hir as hir;
1313
use rustc_hir::def::DefKind;
1414
use rustc_hir::def_id::DefId;
1515
use rustc_hir::lang_items::LangItem;
16-
use rustc_hir::{ExprKind, Node, QPath};
16+
use rustc_hir::{Expr, ExprKind, Node, QPath};
1717
use rustc_infer::infer::{
1818
type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
1919
RegionVariableOrigin,
@@ -397,6 +397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
397397
custom_span_label = true;
398398
}
399399
if static_candidates.len() == 1 {
400+
let mut has_unsuggestable_args = false;
400401
let ty_str = if let Some(CandidateSource::Impl(impl_did)) =
401402
static_candidates.get(0)
402403
{
@@ -412,6 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
412413
.into_iter()
413414
.map(|arg| {
414415
if !arg.is_suggestable(tcx, true) {
416+
has_unsuggestable_args = true;
415417
match arg.unpack() {
416418
GenericArgKind::Lifetime(_) => self
417419
.next_region_var(RegionVariableOrigin::MiscVariable(
@@ -450,12 +452,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
450452
} else {
451453
self.ty_to_value_string(actual.peel_refs())
452454
};
453-
if let SelfSource::MethodCall(expr) = source {
455+
if let SelfSource::MethodCall(_) = source {
456+
let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_sources.get(0) &&
457+
let Some(assoc) = self.associated_value(*impl_did, item_name) {
458+
let sig = self.tcx.fn_sig(assoc.def_id);
459+
if let Some(first) = sig.inputs().skip_binder().get(0) {
460+
if first.peel_refs() == rcvr_ty.peel_refs() {
461+
None
462+
} else {
463+
Some(if first.is_region_ptr() {
464+
if first.is_mutable_ptr() { "&mut " } else { "&" }
465+
} else {
466+
""
467+
})
468+
}
469+
} else {
470+
None
471+
}
472+
} else {
473+
None
474+
};
475+
let mut applicability = Applicability::MachineApplicable;
476+
let args = if let Some((receiver, args)) = args {
477+
// The first arg is the same kind as the receiver
478+
let it = if first_arg.is_some() {
479+
Box::new(std::iter::once(receiver).chain(args.iter()))
480+
as Box<dyn Iterator<Item = &Expr<'_>>>
481+
} else {
482+
// There is no `Self` kind to infer the arguments from
483+
if has_unsuggestable_args {
484+
applicability = Applicability::HasPlaceholders;
485+
}
486+
Box::new(args.iter()) as _
487+
};
488+
format!(
489+
"({}{})",
490+
first_arg.unwrap_or(""),
491+
it.map(|arg| tcx
492+
.sess
493+
.source_map()
494+
.span_to_snippet(arg.span)
495+
.unwrap_or_else(|_| {
496+
applicability = Applicability::HasPlaceholders;
497+
"_".to_owned()
498+
}))
499+
.collect::<Vec<_>>()
500+
.join(", "),
501+
)
502+
} else {
503+
applicability = Applicability::HasPlaceholders;
504+
"(...)".to_owned()
505+
};
454506
err.span_suggestion(
455-
expr.span.to(span),
507+
sugg_span,
456508
"use associated function syntax instead",
457-
format!("{}::{}", ty_str, item_name),
458-
Applicability::MachineApplicable,
509+
format!("{}::{}{}", ty_str, item_name, args),
510+
applicability,
459511
);
460512
} else {
461513
err.help(&format!("try with `{}::{}`", ty_str, item_name,));

src/test/ui/issues/issue-3707.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ error[E0599]: no method named `boom` found for reference `&Obj` in the current s
22
--> $DIR/issue-3707.rs:10:14
33
|
44
LL | self.boom();
5-
| -----^^^^
5+
| -----^^^^--
66
| | |
77
| | this is an associated function, not a method
8-
| help: use associated function syntax instead: `Obj::boom`
8+
| help: use associated function syntax instead: `Obj::boom()`
99
|
1010
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
1111
note: the candidate is defined in an impl for the type `Obj`

src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ error[E0599]: no method named `hello` found for struct `RefMut<'_, HasAssocMetho
22
--> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11
33
|
44
LL | state.hello();
5-
| ------^^^^^
5+
| ------^^^^^--
66
| | |
77
| | this is an associated function, not a method
8-
| help: use associated function syntax instead: `HasAssocMethod::hello`
8+
| help: use associated function syntax instead: `HasAssocMethod::hello()`
99
|
1010
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
1111
note: the candidate is defined in an impl for the type `HasAssocMethod`
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// run-rustfix
2+
3+
struct GenericAssocMethod<T>(T);
4+
5+
impl<T> GenericAssocMethod<T> {
6+
fn default_hello() {}
7+
fn self_ty_hello(_: Self) {}
8+
fn self_ty_ref_hello(_: &Self) {}
9+
}
10+
11+
fn main() {
12+
// Test for inferred types
13+
let x = GenericAssocMethod(33);
14+
// This particular case is unfixable without more information by the user,
15+
// but `cargo fix --broken-code` reports a bug if
16+
// x.default_hello();
17+
GenericAssocMethod::<_>::self_ty_ref_hello(&x);
18+
//~^ ERROR no method named `self_ty_ref_hello` found
19+
GenericAssocMethod::<_>::self_ty_hello(x);
20+
//~^ ERROR no method named `self_ty_hello` found
21+
// Test for known types
22+
let y = GenericAssocMethod(33i32);
23+
GenericAssocMethod::<i32>::default_hello();
24+
//~^ ERROR no method named `default_hello` found
25+
GenericAssocMethod::<i32>::self_ty_ref_hello(&y);
26+
//~^ ERROR no method named `self_ty_ref_hello` found
27+
GenericAssocMethod::<i32>::self_ty_hello(y);
28+
//~^ ERROR no method named `self_ty_hello` found
29+
}

src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1+
// run-rustfix
2+
13
struct GenericAssocMethod<T>(T);
24

35
impl<T> GenericAssocMethod<T> {
46
fn default_hello() {}
5-
fn self_ty_hello(_: T) {}
6-
fn self_ty_ref_hello(_: &T) {}
7+
fn self_ty_hello(_: Self) {}
8+
fn self_ty_ref_hello(_: &Self) {}
79
}
810

911
fn main() {
1012
// Test for inferred types
1113
let x = GenericAssocMethod(33);
12-
x.default_hello();
13-
//~^ ERROR no method named `default_hello` found
14+
// This particular case is unfixable without more information by the user,
15+
// but `cargo fix --broken-code` reports a bug if
16+
// x.default_hello();
1417
x.self_ty_ref_hello();
1518
//~^ ERROR no method named `self_ty_ref_hello` found
1619
x.self_ty_hello();
Lines changed: 29 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,98 @@
1-
error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope
2-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:12:7
3-
|
4-
LL | struct GenericAssocMethod<T>(T);
5-
| ---------------------------- method `default_hello` not found for this struct
6-
...
7-
LL | x.default_hello();
8-
| --^^^^^^^^^^^^^
9-
| | |
10-
| | this is an associated function, not a method
11-
| help: use associated function syntax instead: `GenericAssocMethod::<_>::default_hello`
12-
|
13-
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
14-
note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
15-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:4:5
16-
|
17-
LL | fn default_hello() {}
18-
| ^^^^^^^^^^^^^^^^^^
19-
201
error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope
21-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:14:7
2+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:17:7
223
|
234
LL | struct GenericAssocMethod<T>(T);
245
| ---------------------------- method `self_ty_ref_hello` not found for this struct
256
...
267
LL | x.self_ty_ref_hello();
27-
| --^^^^^^^^^^^^^^^^^
8+
| --^^^^^^^^^^^^^^^^^--
289
| | |
2910
| | this is an associated function, not a method
30-
| help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_ref_hello`
11+
| help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_ref_hello(&x)`
3112
|
3213
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
3314
note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
34-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:6:5
15+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:8:5
3516
|
36-
LL | fn self_ty_ref_hello(_: &T) {}
37-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
LL | fn self_ty_ref_hello(_: &Self) {}
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3819

3920
error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope
40-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:16:7
21+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:19:7
4122
|
4223
LL | struct GenericAssocMethod<T>(T);
4324
| ---------------------------- method `self_ty_hello` not found for this struct
4425
...
4526
LL | x.self_ty_hello();
46-
| --^^^^^^^^^^^^^
27+
| --^^^^^^^^^^^^^--
4728
| | |
4829
| | this is an associated function, not a method
49-
| help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_hello`
30+
| help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_hello(x)`
5031
|
5132
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
5233
note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
53-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:5:5
34+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:7:5
5435
|
55-
LL | fn self_ty_hello(_: T) {}
56-
| ^^^^^^^^^^^^^^^^^^^^^^
36+
LL | fn self_ty_hello(_: Self) {}
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
5738

5839
error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod<i32>` in the current scope
59-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:20:7
40+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:23:7
6041
|
6142
LL | struct GenericAssocMethod<T>(T);
6243
| ---------------------------- method `default_hello` not found for this struct
6344
...
6445
LL | y.default_hello();
65-
| --^^^^^^^^^^^^^
46+
| --^^^^^^^^^^^^^--
6647
| | |
6748
| | this is an associated function, not a method
68-
| help: use associated function syntax instead: `GenericAssocMethod::<i32>::default_hello`
49+
| help: use associated function syntax instead: `GenericAssocMethod::<i32>::default_hello()`
6950
|
7051
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
7152
note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
72-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:4:5
53+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:6:5
7354
|
7455
LL | fn default_hello() {}
7556
| ^^^^^^^^^^^^^^^^^^
7657

7758
error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod<i32>` in the current scope
78-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:22:7
59+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:25:7
7960
|
8061
LL | struct GenericAssocMethod<T>(T);
8162
| ---------------------------- method `self_ty_ref_hello` not found for this struct
8263
...
8364
LL | y.self_ty_ref_hello();
84-
| --^^^^^^^^^^^^^^^^^
65+
| --^^^^^^^^^^^^^^^^^--
8566
| | |
8667
| | this is an associated function, not a method
87-
| help: use associated function syntax instead: `GenericAssocMethod::<i32>::self_ty_ref_hello`
68+
| help: use associated function syntax instead: `GenericAssocMethod::<i32>::self_ty_ref_hello(&y)`
8869
|
8970
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
9071
note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
91-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:6:5
72+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:8:5
9273
|
93-
LL | fn self_ty_ref_hello(_: &T) {}
94-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
74+
LL | fn self_ty_ref_hello(_: &Self) {}
75+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9576

9677
error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod<i32>` in the current scope
97-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:24:7
78+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:27:7
9879
|
9980
LL | struct GenericAssocMethod<T>(T);
10081
| ---------------------------- method `self_ty_hello` not found for this struct
10182
...
10283
LL | y.self_ty_hello();
103-
| --^^^^^^^^^^^^^
84+
| --^^^^^^^^^^^^^--
10485
| | |
10586
| | this is an associated function, not a method
106-
| help: use associated function syntax instead: `GenericAssocMethod::<i32>::self_ty_hello`
87+
| help: use associated function syntax instead: `GenericAssocMethod::<i32>::self_ty_hello(y)`
10788
|
10889
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
10990
note: the candidate is defined in an impl for the type `GenericAssocMethod<T>`
110-
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:5:5
91+
--> $DIR/suggest-assoc-fn-call-with-turbofish.rs:7:5
11192
|
112-
LL | fn self_ty_hello(_: T) {}
113-
| ^^^^^^^^^^^^^^^^^^^^^^
93+
LL | fn self_ty_hello(_: Self) {}
94+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
11495

115-
error: aborting due to 6 previous errors
96+
error: aborting due to 5 previous errors
11697

11798
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)