diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index b4508368e268..ca174ed5e849 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -704,27 +704,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let (ty::Param(_), ty::PredicateKind::Trait(p)) = (self_ty.kind(), parent_pred.kind().skip_binder()) { - if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() { - let node = def.did.as_local().map(|def_id| { + let node = match p.trait_ref.self_ty().kind() { + ty::Param(_) => { + // Account for `fn` items like in `issue-35677.rs` to + // suggest restricting its type params. + let did = self.tcx.hir().body_owner_def_id(hir::BodyId { + hir_id: self.body_id, + }); + Some( + self.tcx + .hir() + .get(self.tcx.hir().local_def_id_to_hir_id(did)), + ) + } + ty::Adt(def, _) => def.did.as_local().map(|def_id| { self.tcx .hir() .get(self.tcx.hir().local_def_id_to_hir_id(def_id)) - }); - if let Some(hir::Node::Item(hir::Item { kind, .. })) = node { - if let Some(g) = kind.generics() { - let key = match g.where_clause.predicates { - [.., pred] => (pred.span().shrink_to_hi(), false), - [] => ( - g.where_clause - .span_for_predicates_or_empty_place(), - true, - ), - }; - type_params - .entry(key) - .or_insert_with(FxHashSet::default) - .insert(obligation.to_owned()); - } + }), + _ => None, + }; + if let Some(hir::Node::Item(hir::Item { kind, .. })) = node { + if let Some(g) = kind.generics() { + let key = match g.where_clause.predicates { + [.., pred] => (pred.span().shrink_to_hi(), false), + [] => ( + g.where_clause.span_for_predicates_or_empty_place(), + true, + ), + }; + type_params + .entry(key) + .or_insert_with(FxHashSet::default) + .insert(obligation.to_owned()); } } } @@ -875,19 +887,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred)) .filter_map(|(pred, parent_pred, _cause)| { - format_pred(*pred).map(|(p, self_ty)| match parent_pred { - None => format!("`{}`", &p), - Some(parent_pred) => match format_pred(*parent_pred) { + format_pred(*pred).map(|(p, self_ty)| { + collect_type_param_suggestions(self_ty, pred, &p); + match parent_pred { None => format!("`{}`", &p), - Some((parent_p, _)) => { - collect_type_param_suggestions(self_ty, parent_pred, &p); - format!("`{}`\nwhich is required by `{}`", p, parent_p) - } - }, + Some(parent_pred) => match format_pred(*parent_pred) { + None => format!("`{}`", &p), + Some((parent_p, _)) => { + collect_type_param_suggestions( + self_ty, + parent_pred, + &p, + ); + format!("`{}`\nwhich is required by `{}`", p, parent_p) + } + }, + } }) }) .enumerate() .collect::>(); + for ((span, empty_where), obligations) in type_params.into_iter() { restrict_type_params = true; // #74886: Sort here so that the output is always the same. diff --git a/src/test/ui/issues/issue-35677.fixed b/src/test/ui/issues/issue-35677.fixed new file mode 100644 index 000000000000..08174d8d8d53 --- /dev/null +++ b/src/test/ui/issues/issue-35677.fixed @@ -0,0 +1,11 @@ +// run-rustfix +#![allow(dead_code)] +use std::collections::HashSet; +use std::hash::Hash; + +fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash { + this.is_subset(other) + //~^ ERROR the method +} + +fn main() {} diff --git a/src/test/ui/issues/issue-35677.rs b/src/test/ui/issues/issue-35677.rs index 15d139790625..2cb394386b8a 100644 --- a/src/test/ui/issues/issue-35677.rs +++ b/src/test/ui/issues/issue-35677.rs @@ -1,4 +1,7 @@ +// run-rustfix +#![allow(dead_code)] use std::collections::HashSet; +use std::hash::Hash; fn is_subset(this: &HashSet, other: &HashSet) -> bool { this.is_subset(other) diff --git a/src/test/ui/issues/issue-35677.stderr b/src/test/ui/issues/issue-35677.stderr index ab59e5d1acf6..a2201b946a6f 100644 --- a/src/test/ui/issues/issue-35677.stderr +++ b/src/test/ui/issues/issue-35677.stderr @@ -1,5 +1,5 @@ error[E0599]: the method `is_subset` exists for reference `&HashSet`, but its trait bounds were not satisfied - --> $DIR/issue-35677.rs:4:10 + --> $DIR/issue-35677.rs:7:10 | LL | this.is_subset(other) | ^^^^^^^^^ method cannot be called on `&HashSet` due to unsatisfied trait bounds @@ -7,6 +7,10 @@ LL | this.is_subset(other) = note: the following trait bounds were not satisfied: `T: Eq` `T: Hash` +help: consider restricting the type parameters to satisfy the trait bounds + | +LL | fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash { + | ++++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-69725.fixed b/src/test/ui/issues/issue-69725.fixed new file mode 100644 index 000000000000..d57badcfd8cf --- /dev/null +++ b/src/test/ui/issues/issue-69725.fixed @@ -0,0 +1,13 @@ +// run-rustfix +// aux-build:issue-69725.rs +#![allow(dead_code)] + +extern crate issue_69725; +use issue_69725::Struct; + +fn crash() where A: Clone { + let _ = Struct::::new().clone(); + //~^ ERROR: the method +} + +fn main() {} diff --git a/src/test/ui/issues/issue-69725.rs b/src/test/ui/issues/issue-69725.rs index 7c77293945eb..9c88969c5cff 100644 --- a/src/test/ui/issues/issue-69725.rs +++ b/src/test/ui/issues/issue-69725.rs @@ -1,4 +1,6 @@ +// run-rustfix // aux-build:issue-69725.rs +#![allow(dead_code)] extern crate issue_69725; use issue_69725::Struct; diff --git a/src/test/ui/issues/issue-69725.stderr b/src/test/ui/issues/issue-69725.stderr index b1ba89f6cbec..6395bca300c9 100644 --- a/src/test/ui/issues/issue-69725.stderr +++ b/src/test/ui/issues/issue-69725.stderr @@ -1,5 +1,5 @@ error[E0599]: the method `clone` exists for struct `Struct`, but its trait bounds were not satisfied - --> $DIR/issue-69725.rs:7:32 + --> $DIR/issue-69725.rs:9:32 | LL | let _ = Struct::::new().clone(); | ^^^^^ method cannot be called on `Struct` due to unsatisfied trait bounds @@ -12,6 +12,10 @@ LL | pub struct Struct(A); = note: the following trait bounds were not satisfied: `A: Clone` which is required by `Struct: Clone` +help: consider restricting the type parameter to satisfy the trait bound + | +LL | fn crash() where A: Clone { + | ++++++++++++++ error: aborting due to previous error