diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 02fe8312c4c1f..569e871922732 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -383,6 +383,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } else { span = item_name.span; + + // Don't show generic arguments when the method can't be found in any implementation (#81576). + let mut ty_str_reported = ty_str.clone(); + if let ty::Adt(_, ref generics) = actual.kind() { + if generics.len() > 0 { + let mut autoderef = self.autoderef(span, actual); + let candidate_found = autoderef.any(|(ty, _)| { + if let ty::Adt(ref adt_deref, _) = ty.kind() { + self.tcx + .inherent_impls(adt_deref.did) + .iter() + .filter_map(|def_id| { + self.associated_item( + *def_id, + item_name, + Namespace::ValueNS, + ) + }) + .count() + >= 1 + } else { + false + } + }); + let has_deref = autoderef.step_count() > 0; + if !candidate_found + && !has_deref + && unsatisfied_predicates.is_empty() + { + if let Some((path_string, _)) = ty_str.split_once('<') { + ty_str_reported = path_string.to_string(); + } + } + } + } + let mut err = struct_span_err!( tcx.sess, span, @@ -391,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_kind, item_name, actual.prefix_string(self.tcx), - ty_str, + ty_str_reported, ); if let Mode::MethodCall = mode { if let SelfSource::MethodCall(call) = source { @@ -449,6 +485,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut label_span_not_found = || { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); + if let ty::Adt(ref adt, _) = rcvr_ty.kind() { + let mut inherent_impls_candidate = self + .tcx + .inherent_impls(adt.did) + .iter() + .copied() + .filter(|def_id| { + if let Some(assoc) = + self.associated_item(*def_id, item_name, Namespace::ValueNS) + { + // Check for both mode is the same so we avoid suggesting + // incorrect associated item. + match (mode, assoc.fn_has_self_parameter, source) { + (Mode::MethodCall, true, SelfSource::MethodCall(_)) => { + // We check that the suggest type is actually + // different from the received one + // So we avoid suggestion method with Box + // for instance + self.tcx.at(span).type_of(*def_id) != actual + && self.tcx.at(span).type_of(*def_id) != rcvr_ty + } + (Mode::Path, false, _) => true, + _ => false, + } + } else { + false + } + }) + .collect::>(); + if inherent_impls_candidate.len() > 0 { + inherent_impls_candidate.sort(); + inherent_impls_candidate.dedup(); + + // number of type to shows at most. + let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 }; + let type_candidates = inherent_impls_candidate + .iter() + .take(limit) + .map(|impl_item| { + format!("- `{}`", self.tcx.at(span).type_of(*impl_item)) + }) + .collect::>() + .join("\n"); + let additional_types = if inherent_impls_candidate.len() > limit { + format!( + "\nand {} more types", + inherent_impls_candidate.len() - limit + ) + } else { + "".to_string() + }; + err.note(&format!( + "the {item_kind} was found for\n{}{}", + type_candidates, additional_types + )); + } + } } else { err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds")); } diff --git a/src/test/ui/confuse-field-and-method/issue-18343.stderr b/src/test/ui/confuse-field-and-method/issue-18343.stderr index d6b399acb7330..fe6b12968c110 100644 --- a/src/test/ui/confuse-field-and-method/issue-18343.stderr +++ b/src/test/ui/confuse-field-and-method/issue-18343.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-18343.rs:6:28: 6:33]>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-18343.rs:7:7 | LL | struct Obj where F: FnMut() -> u32 { diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr index 051940bbe9660..0480958e99c05 100644 --- a/src/test/ui/confuse-field-and-method/issue-2392.stderr +++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:36:15 | LL | struct Obj where F: FnOnce() -> u32 { @@ -12,7 +12,7 @@ help: to call the function stored in `closure`, surround the field access with p LL | (o_closure.closure)(); | ^ ^ -error[E0599]: no method named `not_closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope +error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:38:15 | LL | struct Obj where F: FnOnce() -> u32 { @@ -23,7 +23,7 @@ LL | o_closure.not_closure(); | | | field, not a method -error[E0599]: no method named `closure` found for struct `Obj u32 {func}>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:42:12 | LL | struct Obj where F: FnOnce() -> u32 { @@ -65,7 +65,7 @@ help: to call the function stored in `boxed_closure`, surround the field access LL | (boxed_closure.boxed_closure)(); | ^ ^ -error[E0599]: no method named `closure` found for struct `Obj u32 {func}>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:53:12 | LL | struct Obj where F: FnOnce() -> u32 { @@ -79,7 +79,7 @@ help: to call the function stored in `closure`, surround the field access with p LL | (w.wrap.closure)(); | ^ ^ -error[E0599]: no method named `not_closure` found for struct `Obj u32 {func}>` in the current scope +error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:55:12 | LL | struct Obj where F: FnOnce() -> u32 { @@ -90,7 +90,7 @@ LL | w.wrap.not_closure(); | | | field, not a method -error[E0599]: no method named `closure` found for struct `Obj u32 + 'static)>>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:58:24 | LL | struct Obj where F: FnOnce() -> u32 { diff --git a/src/test/ui/issues/issue-30123.stderr b/src/test/ui/issues/issue-30123.stderr index bc6731601f095..e9d934332f171 100644 --- a/src/test/ui/issues/issue-30123.stderr +++ b/src/test/ui/issues/issue-30123.stderr @@ -3,6 +3,9 @@ error[E0599]: no function or associated item named `new_undirected` found for st | LL | let ug = Graph::::new_undirected(); | ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph` + | + = note: the function or associated item was found for + - `issue_30123_aux::Graph` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41880.stderr b/src/test/ui/issues/issue-41880.stderr index 09d5594f73f06..017dd831f712a 100644 --- a/src/test/ui/issues/issue-41880.stderr +++ b/src/test/ui/issues/issue-41880.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `iter` found for struct `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` in the current scope +error[E0599]: no method named `iter` found for struct `Iterate` in the current scope --> $DIR/issue-41880.rs:27:24 | LL | pub struct Iterate { diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.rs b/src/test/ui/methods/method-not-found-generic-arg-elision.rs new file mode 100644 index 0000000000000..3df928b5d804d --- /dev/null +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.rs @@ -0,0 +1,106 @@ +// Test for issue 81576 +// Remove generic arguments if no method is found for all possible generic argument + +use std::marker::PhantomData; + +struct Wrapper2<'a, T, const C: usize> { + x: &'a T, +} + +impl<'a, const C: usize> Wrapper2<'a, i8, C> { + fn method(&self) {} +} + +impl<'a, const C: usize> Wrapper2<'a, i16, C> { + fn method(&self) {} +} + +impl<'a, const C: usize> Wrapper2<'a, i32, C> { + fn method(&self) {} +} +struct Wrapper(T); + +impl Wrapper { + fn method(&self) {} +} + +impl Wrapper { + fn method(&self) {} +} + +impl Wrapper { + fn method(&self) {} +} + +impl Wrapper { + fn method(&self) {} +} + +impl Wrapper { + fn method(&self) {} +} + +impl Wrapper { + fn method(&self) {} +} + +struct Point { + x: T, + y: T, +} + +impl Point { + fn distance(&self) -> f64 { + self.x.hypot(self.y) + } +} + +struct Other; + +impl Other { + fn other(&self) {} +} + +struct Struct{ + _phatom: PhantomData +} + +impl Default for Struct { + fn default() -> Self { + Self{ _phatom: PhantomData } + } +} + +impl Struct { + fn method(&self) {} +} + +fn main() { + let point_f64 = Point{ x: 1_f64, y: 1_f64}; + let d = point_f64.distance(); + let point_i32 = Point{ x: 1_i32, y: 1_i32}; + let d = point_i32.distance(); + //~^ ERROR no method named `distance` found for struct `Point + let d = point_i32.other(); + //~^ ERROR no method named `other` found for struct `Point + let v = vec![1_i32, 2, 3]; + v.iter().map(|x| x * x).extend(std::iter::once(100)); + //~^ ERROR no method named `extend` found for struct `Map + let wrapper = Wrapper(true); + wrapper.method(); + //~^ ERROR no method named `method` found for struct `Wrapper + wrapper.other(); + //~^ ERROR no method named `other` found for struct `Wrapper + let boolean = true; + let wrapper = Wrapper2::<'_, _, 3> {x: &boolean}; + wrapper.method(); + //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3_usize> + wrapper.other(); + //~^ ERROR no method named `other` found for struct `Wrapper2 + let a = vec![1, 2, 3]; + a.not_found(); + //~^ ERROR no method named `not_found` found for struct `Vec + let s = Struct::::default(); + s.method(); + //~^ ERROR the method `method` exists for struct `Struct`, but its trait bounds were not satisfied +} diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr new file mode 100644 index 0000000000000..1671e5e5e64c8 --- /dev/null +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr @@ -0,0 +1,97 @@ +error[E0599]: no method named `distance` found for struct `Point` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:82:23 + | +LL | struct Point { + | --------------- method `distance` not found for this +... +LL | let d = point_i32.distance(); + | ^^^^^^^^ method not found in `Point` + | + = note: the method was found for + - `Point` + +error[E0599]: no method named `other` found for struct `Point` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:84:23 + | +LL | struct Point { + | --------------- method `other` not found for this +... +LL | let d = point_i32.other(); + | ^^^^^ method not found in `Point` + +error[E0599]: no method named `extend` found for struct `Map` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:87:29 + | +LL | v.iter().map(|x| x * x).extend(std::iter::once(100)); + | ^^^^^^ method not found in `Map, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:27]>` + +error[E0599]: no method named `method` found for struct `Wrapper` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:90:13 + | +LL | struct Wrapper(T); + | --------------------- method `method` not found for this +... +LL | wrapper.method(); + | ^^^^^^ method not found in `Wrapper` + | + = note: the method was found for + - `Wrapper` + - `Wrapper` + - `Wrapper` + - `Wrapper` + and 2 more types + +error[E0599]: no method named `other` found for struct `Wrapper` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:92:13 + | +LL | struct Wrapper(T); + | --------------------- method `other` not found for this +... +LL | wrapper.other(); + | ^^^^^ method not found in `Wrapper` + +error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:96:13 + | +LL | struct Wrapper2<'a, T, const C: usize> { + | -------------------------------------- method `method` not found for this +... +LL | wrapper.method(); + | ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>` + | + = note: the method was found for + - `Wrapper2<'a, i8, C>` + - `Wrapper2<'a, i16, C>` + - `Wrapper2<'a, i32, C>` + +error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:98:13 + | +LL | struct Wrapper2<'a, T, const C: usize> { + | -------------------------------------- method `other` not found for this +... +LL | wrapper.other(); + | ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>` + +error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:101:7 + | +LL | a.not_found(); + | ^^^^^^^^^ method not found in `Vec<{integer}>` + +error[E0599]: the method `method` exists for struct `Struct`, but its trait bounds were not satisfied + --> $DIR/method-not-found-generic-arg-elision.rs:104:7 + | +LL | struct Struct{ + | ---------------- method `method` not found for this +... +LL | s.method(); + | ^^^^^^ method cannot be called on `Struct` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `f64: Eq` + `f64: Ord` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0599`.