Skip to content

Commit f2810d5

Browse files
authored
Rollup merge of #84221 - ABouttefeux:generic-arg-elision, r=estebank
E0599 suggestions and elision of generic argument if no canditate is found fixes #81576 changes: In error E0599 (method not found) generic argument are eluded if the method was not found anywhere. If the method was found in another inherent implementation suggest that it was found elsewhere. Example ```rust struct Wrapper<T>(T); struct Wrapper2<T> { x: T, } impl Wrapper2<i8> { fn method(&self) {} } fn main() { let wrapper = Wrapper(i32); wrapper.method(); let wrapper2 = Wrapper2{x: i32}; wrapper2.method(); } ``` ``` Error[E0599]: no method named `method` found for struct `Wrapper<_>` in the current scope .... error[E0599]: no method named `method` found for struct `Wrapper2<i32>` in the current scope ... = note: The method was found for Wrapper2<i8>. ``` I am not very happy with the ```no method named `test` found for struct `Vec<_, _>` in the current scope```. I think it might be better to show only one generic argument `Vec<_>` if there is a default one. But I haven't yet found a way to do that,
2 parents 9111b8a + 5d8e6ea commit f2810d5

File tree

7 files changed

+308
-9
lines changed

7 files changed

+308
-9
lines changed

Diff for: compiler/rustc_typeck/src/check/method/suggest.rs

+94-1
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
383383
return None;
384384
} else {
385385
span = item_name.span;
386+
387+
// Don't show generic arguments when the method can't be found in any implementation (#81576).
388+
let mut ty_str_reported = ty_str.clone();
389+
if let ty::Adt(_, ref generics) = actual.kind() {
390+
if generics.len() > 0 {
391+
let mut autoderef = self.autoderef(span, actual);
392+
let candidate_found = autoderef.any(|(ty, _)| {
393+
if let ty::Adt(ref adt_deref, _) = ty.kind() {
394+
self.tcx
395+
.inherent_impls(adt_deref.did)
396+
.iter()
397+
.filter_map(|def_id| {
398+
self.associated_item(
399+
*def_id,
400+
item_name,
401+
Namespace::ValueNS,
402+
)
403+
})
404+
.count()
405+
>= 1
406+
} else {
407+
false
408+
}
409+
});
410+
let has_deref = autoderef.step_count() > 0;
411+
if !candidate_found
412+
&& !has_deref
413+
&& unsatisfied_predicates.is_empty()
414+
{
415+
if let Some((path_string, _)) = ty_str.split_once('<') {
416+
ty_str_reported = path_string.to_string();
417+
}
418+
}
419+
}
420+
}
421+
386422
let mut err = struct_span_err!(
387423
tcx.sess,
388424
span,
@@ -391,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
391427
item_kind,
392428
item_name,
393429
actual.prefix_string(self.tcx),
394-
ty_str,
430+
ty_str_reported,
395431
);
396432
if let Mode::MethodCall = mode {
397433
if let SelfSource::MethodCall(call) = source {
@@ -449,6 +485,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
449485
let mut label_span_not_found = || {
450486
if unsatisfied_predicates.is_empty() {
451487
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
488+
if let ty::Adt(ref adt, _) = rcvr_ty.kind() {
489+
let mut inherent_impls_candidate = self
490+
.tcx
491+
.inherent_impls(adt.did)
492+
.iter()
493+
.copied()
494+
.filter(|def_id| {
495+
if let Some(assoc) =
496+
self.associated_item(*def_id, item_name, Namespace::ValueNS)
497+
{
498+
// Check for both mode is the same so we avoid suggesting
499+
// incorrect associated item.
500+
match (mode, assoc.fn_has_self_parameter, source) {
501+
(Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
502+
// We check that the suggest type is actually
503+
// different from the received one
504+
// So we avoid suggestion method with Box<Self>
505+
// for instance
506+
self.tcx.at(span).type_of(*def_id) != actual
507+
&& self.tcx.at(span).type_of(*def_id) != rcvr_ty
508+
}
509+
(Mode::Path, false, _) => true,
510+
_ => false,
511+
}
512+
} else {
513+
false
514+
}
515+
})
516+
.collect::<Vec<_>>();
517+
if inherent_impls_candidate.len() > 0 {
518+
inherent_impls_candidate.sort();
519+
inherent_impls_candidate.dedup();
520+
521+
// number of type to shows at most.
522+
let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
523+
let type_candidates = inherent_impls_candidate
524+
.iter()
525+
.take(limit)
526+
.map(|impl_item| {
527+
format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
528+
})
529+
.collect::<Vec<_>>()
530+
.join("\n");
531+
let additional_types = if inherent_impls_candidate.len() > limit {
532+
format!(
533+
"\nand {} more types",
534+
inherent_impls_candidate.len() - limit
535+
)
536+
} else {
537+
"".to_string()
538+
};
539+
err.note(&format!(
540+
"the {item_kind} was found for\n{}{}",
541+
type_candidates, additional_types
542+
));
543+
}
544+
}
452545
} else {
453546
err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
454547
}

Diff for: src/test/ui/confuse-field-and-method/issue-18343.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-18343.rs:6:28: 6:33]>` in the current scope
1+
error[E0599]: no method named `closure` found for struct `Obj` in the current scope
22
--> $DIR/issue-18343.rs:7:7
33
|
44
LL | struct Obj<F> where F: FnMut() -> u32 {

Diff for: src/test/ui/confuse-field-and-method/issue-2392.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
1+
error[E0599]: no method named `closure` found for struct `Obj` in the current scope
22
--> $DIR/issue-2392.rs:36:15
33
|
44
LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -12,7 +12,7 @@ help: to call the function stored in `closure`, surround the field access with p
1212
LL | (o_closure.closure)();
1313
| ^ ^
1414

15-
error[E0599]: no method named `not_closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
15+
error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
1616
--> $DIR/issue-2392.rs:38:15
1717
|
1818
LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -23,7 +23,7 @@ LL | o_closure.not_closure();
2323
| |
2424
| field, not a method
2525

26-
error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
26+
error[E0599]: no method named `closure` found for struct `Obj` in the current scope
2727
--> $DIR/issue-2392.rs:42:12
2828
|
2929
LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -65,7 +65,7 @@ help: to call the function stored in `boxed_closure`, surround the field access
6565
LL | (boxed_closure.boxed_closure)();
6666
| ^ ^
6767

68-
error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
68+
error[E0599]: no method named `closure` found for struct `Obj` in the current scope
6969
--> $DIR/issue-2392.rs:53:12
7070
|
7171
LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -79,7 +79,7 @@ help: to call the function stored in `closure`, surround the field access with p
7979
LL | (w.wrap.closure)();
8080
| ^ ^
8181

82-
error[E0599]: no method named `not_closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
82+
error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
8383
--> $DIR/issue-2392.rs:55:12
8484
|
8585
LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -90,7 +90,7 @@ LL | w.wrap.not_closure();
9090
| |
9191
| field, not a method
9292

93-
error[E0599]: no method named `closure` found for struct `Obj<Box<(dyn FnOnce() -> u32 + 'static)>>` in the current scope
93+
error[E0599]: no method named `closure` found for struct `Obj` in the current scope
9494
--> $DIR/issue-2392.rs:58:24
9595
|
9696
LL | struct Obj<F> where F: FnOnce() -> u32 {

Diff for: src/test/ui/issues/issue-30123.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ error[E0599]: no function or associated item named `new_undirected` found for st
33
|
44
LL | let ug = Graph::<i32, i32>::new_undirected();
55
| ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>`
6+
|
7+
= note: the function or associated item was found for
8+
- `issue_30123_aux::Graph<N, E, Undirected>`
69

710
error: aborting due to previous error
811

Diff for: src/test/ui/issues/issue-41880.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0599]: no method named `iter` found for struct `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` in the current scope
1+
error[E0599]: no method named `iter` found for struct `Iterate` in the current scope
22
--> $DIR/issue-41880.rs:27:24
33
|
44
LL | pub struct Iterate<T, F> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Test for issue 81576
2+
// Remove generic arguments if no method is found for all possible generic argument
3+
4+
use std::marker::PhantomData;
5+
6+
struct Wrapper2<'a, T, const C: usize> {
7+
x: &'a T,
8+
}
9+
10+
impl<'a, const C: usize> Wrapper2<'a, i8, C> {
11+
fn method(&self) {}
12+
}
13+
14+
impl<'a, const C: usize> Wrapper2<'a, i16, C> {
15+
fn method(&self) {}
16+
}
17+
18+
impl<'a, const C: usize> Wrapper2<'a, i32, C> {
19+
fn method(&self) {}
20+
}
21+
struct Wrapper<T>(T);
22+
23+
impl Wrapper<i8> {
24+
fn method(&self) {}
25+
}
26+
27+
impl Wrapper<i16> {
28+
fn method(&self) {}
29+
}
30+
31+
impl Wrapper<i32> {
32+
fn method(&self) {}
33+
}
34+
35+
impl Wrapper<i64> {
36+
fn method(&self) {}
37+
}
38+
39+
impl Wrapper<u8> {
40+
fn method(&self) {}
41+
}
42+
43+
impl Wrapper<u16> {
44+
fn method(&self) {}
45+
}
46+
47+
struct Point<T> {
48+
x: T,
49+
y: T,
50+
}
51+
52+
impl Point<f64> {
53+
fn distance(&self) -> f64 {
54+
self.x.hypot(self.y)
55+
}
56+
}
57+
58+
struct Other;
59+
60+
impl Other {
61+
fn other(&self) {}
62+
}
63+
64+
struct Struct<T>{
65+
_phatom: PhantomData<T>
66+
}
67+
68+
impl<T> Default for Struct<T> {
69+
fn default() -> Self {
70+
Self{ _phatom: PhantomData }
71+
}
72+
}
73+
74+
impl<T: Clone + Copy + PartialEq + Eq + PartialOrd + Ord> Struct<T> {
75+
fn method(&self) {}
76+
}
77+
78+
fn main() {
79+
let point_f64 = Point{ x: 1_f64, y: 1_f64};
80+
let d = point_f64.distance();
81+
let point_i32 = Point{ x: 1_i32, y: 1_i32};
82+
let d = point_i32.distance();
83+
//~^ ERROR no method named `distance` found for struct `Point<i32>
84+
let d = point_i32.other();
85+
//~^ ERROR no method named `other` found for struct `Point
86+
let v = vec![1_i32, 2, 3];
87+
v.iter().map(|x| x * x).extend(std::iter::once(100));
88+
//~^ ERROR no method named `extend` found for struct `Map
89+
let wrapper = Wrapper(true);
90+
wrapper.method();
91+
//~^ ERROR no method named `method` found for struct `Wrapper<bool>
92+
wrapper.other();
93+
//~^ ERROR no method named `other` found for struct `Wrapper
94+
let boolean = true;
95+
let wrapper = Wrapper2::<'_, _, 3> {x: &boolean};
96+
wrapper.method();
97+
//~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>
98+
wrapper.other();
99+
//~^ ERROR no method named `other` found for struct `Wrapper2
100+
let a = vec![1, 2, 3];
101+
a.not_found();
102+
//~^ ERROR no method named `not_found` found for struct `Vec
103+
let s = Struct::<f64>::default();
104+
s.method();
105+
//~^ ERROR the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
106+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
error[E0599]: no method named `distance` found for struct `Point<i32>` in the current scope
2+
--> $DIR/method-not-found-generic-arg-elision.rs:82:23
3+
|
4+
LL | struct Point<T> {
5+
| --------------- method `distance` not found for this
6+
...
7+
LL | let d = point_i32.distance();
8+
| ^^^^^^^^ method not found in `Point<i32>`
9+
|
10+
= note: the method was found for
11+
- `Point<f64>`
12+
13+
error[E0599]: no method named `other` found for struct `Point` in the current scope
14+
--> $DIR/method-not-found-generic-arg-elision.rs:84:23
15+
|
16+
LL | struct Point<T> {
17+
| --------------- method `other` not found for this
18+
...
19+
LL | let d = point_i32.other();
20+
| ^^^^^ method not found in `Point<i32>`
21+
22+
error[E0599]: no method named `extend` found for struct `Map` in the current scope
23+
--> $DIR/method-not-found-generic-arg-elision.rs:87:29
24+
|
25+
LL | v.iter().map(|x| x * x).extend(std::iter::once(100));
26+
| ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:27]>`
27+
28+
error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
29+
--> $DIR/method-not-found-generic-arg-elision.rs:90:13
30+
|
31+
LL | struct Wrapper<T>(T);
32+
| --------------------- method `method` not found for this
33+
...
34+
LL | wrapper.method();
35+
| ^^^^^^ method not found in `Wrapper<bool>`
36+
|
37+
= note: the method was found for
38+
- `Wrapper<i8>`
39+
- `Wrapper<i16>`
40+
- `Wrapper<i32>`
41+
- `Wrapper<i64>`
42+
and 2 more types
43+
44+
error[E0599]: no method named `other` found for struct `Wrapper` in the current scope
45+
--> $DIR/method-not-found-generic-arg-elision.rs:92:13
46+
|
47+
LL | struct Wrapper<T>(T);
48+
| --------------------- method `other` not found for this
49+
...
50+
LL | wrapper.other();
51+
| ^^^^^ method not found in `Wrapper<bool>`
52+
53+
error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>` in the current scope
54+
--> $DIR/method-not-found-generic-arg-elision.rs:96:13
55+
|
56+
LL | struct Wrapper2<'a, T, const C: usize> {
57+
| -------------------------------------- method `method` not found for this
58+
...
59+
LL | wrapper.method();
60+
| ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
61+
|
62+
= note: the method was found for
63+
- `Wrapper2<'a, i8, C>`
64+
- `Wrapper2<'a, i16, C>`
65+
- `Wrapper2<'a, i32, C>`
66+
67+
error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope
68+
--> $DIR/method-not-found-generic-arg-elision.rs:98:13
69+
|
70+
LL | struct Wrapper2<'a, T, const C: usize> {
71+
| -------------------------------------- method `other` not found for this
72+
...
73+
LL | wrapper.other();
74+
| ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
75+
76+
error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope
77+
--> $DIR/method-not-found-generic-arg-elision.rs:101:7
78+
|
79+
LL | a.not_found();
80+
| ^^^^^^^^^ method not found in `Vec<{integer}>`
81+
82+
error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
83+
--> $DIR/method-not-found-generic-arg-elision.rs:104:7
84+
|
85+
LL | struct Struct<T>{
86+
| ---------------- method `method` not found for this
87+
...
88+
LL | s.method();
89+
| ^^^^^^ method cannot be called on `Struct<f64>` due to unsatisfied trait bounds
90+
|
91+
= note: the following trait bounds were not satisfied:
92+
`f64: Eq`
93+
`f64: Ord`
94+
95+
error: aborting due to 9 previous errors
96+
97+
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)