Skip to content

Commit c64a2ed

Browse files
committed
elision of generic argument in E0599 if the methode has not been found anywhere and sugetion of type with method when found.
1 parent 0894d1e commit c64a2ed

File tree

11 files changed

+310
-25
lines changed

11 files changed

+310
-25
lines changed

compiler/rustc_typeck/src/check/method/suggest.rs

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_hir::{ExprKind, Node, QPath};
1313
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1414
use rustc_middle::ty::fast_reject::simplify_type;
1515
use rustc_middle::ty::print::with_crate_prefix;
16+
use rustc_middle::ty::subst::GenericArgKind;
1617
use rustc_middle::ty::{
1718
self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
1819
};
@@ -383,6 +384,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
383384
return None;
384385
} else {
385386
span = item_name.span;
387+
388+
// issue #81576, elision of generic argument when no methode can be found in any implementation
389+
let mut ty_str_reported = ty_str.clone();
390+
if let ty::Adt(_, ref generics) = actual.kind() {
391+
if generics.len() > 0 {
392+
let candidate_numbers: usize = self
393+
.autoderef(span, actual)
394+
.map(|(ty, _)| {
395+
if let ty::Adt(ref adt_deref, _) = ty.kind() {
396+
self.tcx
397+
.inherent_impls(adt_deref.did)
398+
.iter()
399+
.filter_map(|def_id| {
400+
self.associated_item(
401+
*def_id,
402+
item_name,
403+
Namespace::ValueNS,
404+
)
405+
})
406+
.count()
407+
} else {
408+
0
409+
}
410+
})
411+
.sum();
412+
if candidate_numbers == 0 && unsatisfied_predicates.is_empty() {
413+
if let Some((path_string, _)) = ty_str.split_once('<') {
414+
ty_str_reported = format!("{}<", path_string);
415+
for (index, arg) in generics.iter().enumerate() {
416+
let arg_replace = match arg.unpack() {
417+
GenericArgKind::Lifetime(_) => "'_",
418+
GenericArgKind::Type(_)
419+
| GenericArgKind::Const(_) => "_",
420+
};
421+
ty_str_reported =
422+
format!("{}{}", ty_str_reported, arg_replace);
423+
if index < generics.len() - 1 {
424+
ty_str_reported = format!("{}, ", ty_str_reported);
425+
}
426+
}
427+
ty_str_reported = format!("{}>", ty_str_reported);
428+
}
429+
}
430+
}
431+
}
432+
386433
let mut err = struct_span_err!(
387434
tcx.sess,
388435
span,
@@ -391,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
391438
item_kind,
392439
item_name,
393440
actual.prefix_string(self.tcx),
394-
ty_str,
441+
ty_str_reported,
395442
);
396443
if let Mode::MethodCall = mode {
397444
if let SelfSource::MethodCall(call) = source {
@@ -449,6 +496,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
449496
let mut label_span_not_found = || {
450497
if unsatisfied_predicates.is_empty() {
451498
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
499+
if let ty::Adt(ref adt, _) = rcvr_ty.kind() {
500+
let mut inherent_impls_candidate = self
501+
.tcx
502+
.inherent_impls(adt.did)
503+
.iter()
504+
.copied()
505+
.filter(|def_id| {
506+
if let Some(assoc) =
507+
self.associated_item(*def_id, item_name, Namespace::ValueNS)
508+
{
509+
// Check for both mode is the same so we avoid suggesting
510+
// incorect associated item.
511+
match (mode, assoc.fn_has_self_parameter) {
512+
(Mode::MethodCall, true) => {
513+
if let SelfSource::MethodCall(_) = source {
514+
// We check that the suggest type is actually
515+
// different from the received one
516+
// So we avoid suggestion method with Box<Self>
517+
// for instance
518+
self.tcx.at(span).type_of(*def_id) != actual
519+
&& self.tcx.at(span).type_of(*def_id)
520+
!= rcvr_ty
521+
} else {
522+
false
523+
}
524+
}
525+
(Mode::Path, false) => true,
526+
_ => false,
527+
}
528+
} else {
529+
false
530+
}
531+
})
532+
.collect::<Vec<_>>();
533+
if inherent_impls_candidate.len() > 0 {
534+
inherent_impls_candidate.sort();
535+
inherent_impls_candidate.dedup();
536+
// number of type to shows at most.
537+
const LIMIT: usize = 3;
538+
let mut note = format!("The {item_kind} was found for");
539+
if inherent_impls_candidate.len() > 1 {
540+
for impl_item in inherent_impls_candidate.iter().take(LIMIT - 2)
541+
{
542+
let impl_ty = self.tcx.at(span).type_of(*impl_item);
543+
note = format!("{} {},", note, impl_ty);
544+
}
545+
let impl_ty = self.tcx.at(span).type_of(
546+
inherent_impls_candidate
547+
[inherent_impls_candidate.len() - 1],
548+
);
549+
if inherent_impls_candidate.len() > LIMIT {
550+
note = format!("{} {},", note, impl_ty);
551+
} else {
552+
note = format!("{} {} and", note, impl_ty);
553+
}
554+
}
555+
let impl_ty = self
556+
.tcx
557+
.at(span)
558+
.type_of(*inherent_impls_candidate.last().unwrap());
559+
note = format!("{} {}", note, impl_ty);
560+
if inherent_impls_candidate.len() > LIMIT {
561+
note = format!(
562+
"{} and {} more",
563+
note,
564+
inherent_impls_candidate.len() - LIMIT
565+
);
566+
}
567+
err.note(&format!("{}.", note));
568+
}
569+
}
452570
} else {
453571
err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
454572
}

src/test/ui/auto-ref-slice-plus-ref.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0599]: no method named `test_mut` found for struct `Vec<{integer}>` in the current scope
1+
error[E0599]: no method named `test_mut` found for struct `Vec<_, _>` in the current scope
22
--> $DIR/auto-ref-slice-plus-ref.rs:7:7
33
|
44
LL | a.test_mut();
@@ -11,7 +11,7 @@ note: `MyIter` defines an item `test_mut`, perhaps you need to implement it
1111
LL | trait MyIter {
1212
| ^^^^^^^^^^^^
1313

14-
error[E0599]: no method named `test` found for struct `Vec<{integer}>` in the current scope
14+
error[E0599]: no method named `test` found for struct `Vec<_, _>` in the current scope
1515
--> $DIR/auto-ref-slice-plus-ref.rs:8:7
1616
|
1717
LL | a.test();

src/test/ui/class-cast-to-trait.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0599]: no method named `eat` found for struct `Box<dyn Noisy>` in the current scope
1+
error[E0599]: no method named `eat` found for struct `Box<_, _>` in the current scope
22
--> $DIR/class-cast-to-trait.rs:53:8
33
|
44
LL | nyan.eat();

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

Lines changed: 1 addition & 1 deletion
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 {

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

Lines changed: 6 additions & 6 deletions
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 {

src/test/ui/impl-trait/no-method-suggested-traits.stderr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ LL | use no_method_suggested_traits::qux::PrivPub;
1616
LL | use no_method_suggested_traits::Reexported;
1717
|
1818

19-
error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope
19+
error[E0599]: no method named `method` found for struct `Rc<_>` in the current scope
2020
--> $DIR/no-method-suggested-traits.rs:26:44
2121
|
2222
LL | std::rc::Rc::new(&mut Box::new(&1u32)).method();
@@ -46,7 +46,7 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
4646
LL | use foo::Bar;
4747
|
4848

49-
error[E0599]: no method named `method` found for struct `Rc<&mut Box<&char>>` in the current scope
49+
error[E0599]: no method named `method` found for struct `Rc<_>` in the current scope
5050
--> $DIR/no-method-suggested-traits.rs:32:43
5151
|
5252
LL | std::rc::Rc::new(&mut Box::new(&'a')).method();
@@ -70,7 +70,7 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
7070
LL | use no_method_suggested_traits::foo::PubPub;
7171
|
7272

73-
error[E0599]: no method named `method` found for struct `Rc<&mut Box<&i32>>` in the current scope
73+
error[E0599]: no method named `method` found for struct `Rc<_>` in the current scope
7474
--> $DIR/no-method-suggested-traits.rs:37:44
7575
|
7676
LL | std::rc::Rc::new(&mut Box::new(&1i32)).method();
@@ -98,7 +98,7 @@ LL | Foo.method();
9898
candidate #3: `no_method_suggested_traits::qux::PrivPub`
9999
candidate #4: `Reexported`
100100

101-
error[E0599]: no method named `method` found for struct `Rc<&mut Box<&Foo>>` in the current scope
101+
error[E0599]: no method named `method` found for struct `Rc<_>` in the current scope
102102
--> $DIR/no-method-suggested-traits.rs:42:43
103103
|
104104
LL | std::rc::Rc::new(&mut Box::new(&Foo)).method();
@@ -124,7 +124,7 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
124124
LL | pub trait Bar {
125125
| ^^^^^^^^^^^^^
126126

127-
error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&u64>>` in the current scope
127+
error[E0599]: no method named `method2` found for struct `Rc<_>` in the current scope
128128
--> $DIR/no-method-suggested-traits.rs:47:44
129129
|
130130
LL | std::rc::Rc::new(&mut Box::new(&1u64)).method2();
@@ -150,7 +150,7 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
150150
LL | pub trait Bar {
151151
| ^^^^^^^^^^^^^
152152

153-
error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
153+
error[E0599]: no method named `method2` found for struct `Rc<_>` in the current scope
154154
--> $DIR/no-method-suggested-traits.rs:52:71
155155
|
156156
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
@@ -176,7 +176,7 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it
176176
LL | pub trait Bar {
177177
| ^^^^^^^^^^^^^
178178

179-
error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
179+
error[E0599]: no method named `method2` found for struct `Rc<_>` in the current scope
180180
--> $DIR/no-method-suggested-traits.rs:56:74
181181
|
182182
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
@@ -202,7 +202,7 @@ LL | Foo.method3();
202202
= note: the following trait defines an item `method3`, perhaps you need to implement it:
203203
candidate #1: `PubPub`
204204

205-
error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Foo>>` in the current scope
205+
error[E0599]: no method named `method3` found for struct `Rc<_>` in the current scope
206206
--> $DIR/no-method-suggested-traits.rs:61:43
207207
|
208208
LL | std::rc::Rc::new(&mut Box::new(&Foo)).method3();
@@ -225,7 +225,7 @@ LL | Bar::X.method3();
225225
= note: the following trait defines an item `method3`, perhaps you need to implement it:
226226
candidate #1: `PubPub`
227227

228-
error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Bar>>` in the current scope
228+
error[E0599]: no method named `method3` found for struct `Rc<_>` in the current scope
229229
--> $DIR/no-method-suggested-traits.rs:65:46
230230
|
231231
LL | std::rc::Rc::new(&mut Box::new(&Bar::X)).method3();
@@ -241,7 +241,7 @@ error[E0599]: no method named `method3` found for type `usize` in the current sc
241241
LL | 1_usize.method3();
242242
| ^^^^^^^ method not found in `usize`
243243

244-
error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&usize>>` in the current scope
244+
error[E0599]: no method named `method3` found for struct `Rc<_>` in the current scope
245245
--> $DIR/no-method-suggested-traits.rs:70:47
246246
|
247247
LL | std::rc::Rc::new(&mut Box::new(&1_usize)).method3();
@@ -253,7 +253,7 @@ error[E0599]: no method named `method3` found for struct `no_method_suggested_tr
253253
LL | no_method_suggested_traits::Foo.method3();
254254
| ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
255255

256-
error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope
256+
error[E0599]: no method named `method3` found for struct `Rc<_>` in the current scope
257257
--> $DIR/no-method-suggested-traits.rs:72:71
258258
|
259259
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
@@ -265,7 +265,7 @@ error[E0599]: no method named `method3` found for enum `no_method_suggested_trai
265265
LL | no_method_suggested_traits::Bar::X.method3();
266266
| ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
267267

268-
error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope
268+
error[E0599]: no method named `method3` found for struct `Rc<_>` in the current scope
269269
--> $DIR/no-method-suggested-traits.rs:75:74
270270
|
271271
LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ 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 issue_30123_aux::Graph<N, E, Undirected>.
68

79
error: aborting due to previous error
810

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

Lines changed: 1 addition & 1 deletion
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> {

0 commit comments

Comments
 (0)