Skip to content

Commit 8d443ea

Browse files
committed
Suggest constraining fn type params when appropriate
1 parent 70e8240 commit 8d443ea

File tree

7 files changed

+85
-28
lines changed

7 files changed

+85
-28
lines changed

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

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -700,27 +700,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
700700
if let (ty::Param(_), ty::PredicateKind::Trait(p)) =
701701
(self_ty.kind(), parent_pred.kind().skip_binder())
702702
{
703-
if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() {
704-
let node = def.did.as_local().map(|def_id| {
703+
let node = match p.trait_ref.self_ty().kind() {
704+
ty::Param(_) => {
705+
// Account for `fn` items like in `issue-35677.rs` to
706+
// suggest restricting its type params.
707+
let did = self.tcx.hir().body_owner_def_id(hir::BodyId {
708+
hir_id: self.body_id,
709+
});
710+
Some(
711+
self.tcx
712+
.hir()
713+
.get(self.tcx.hir().local_def_id_to_hir_id(did)),
714+
)
715+
}
716+
ty::Adt(def, _) => def.did.as_local().map(|def_id| {
705717
self.tcx
706718
.hir()
707719
.get(self.tcx.hir().local_def_id_to_hir_id(def_id))
708-
});
709-
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
710-
if let Some(g) = kind.generics() {
711-
let key = match g.where_clause.predicates {
712-
[.., pred] => (pred.span().shrink_to_hi(), false),
713-
[] => (
714-
g.where_clause
715-
.span_for_predicates_or_empty_place(),
716-
true,
717-
),
718-
};
719-
type_params
720-
.entry(key)
721-
.or_insert_with(FxHashSet::default)
722-
.insert(obligation.to_owned());
723-
}
720+
}),
721+
_ => None,
722+
};
723+
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
724+
if let Some(g) = kind.generics() {
725+
let key = match g.where_clause.predicates {
726+
[.., pred] => (pred.span().shrink_to_hi(), false),
727+
[] => (
728+
g.where_clause.span_for_predicates_or_empty_place(),
729+
true,
730+
),
731+
};
732+
type_params
733+
.entry(key)
734+
.or_insert_with(FxHashSet::default)
735+
.insert(obligation.to_owned());
724736
}
725737
}
726738
}
@@ -871,19 +883,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
871883
.iter()
872884
.filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred))
873885
.filter_map(|(pred, parent_pred, _cause)| {
874-
format_pred(*pred).map(|(p, self_ty)| match parent_pred {
875-
None => format!("`{}`", &p),
876-
Some(parent_pred) => match format_pred(*parent_pred) {
886+
format_pred(*pred).map(|(p, self_ty)| {
887+
collect_type_param_suggestions(self_ty, pred, &p);
888+
match parent_pred {
877889
None => format!("`{}`", &p),
878-
Some((parent_p, _)) => {
879-
collect_type_param_suggestions(self_ty, parent_pred, &p);
880-
format!("`{}`\nwhich is required by `{}`", p, parent_p)
881-
}
882-
},
890+
Some(parent_pred) => match format_pred(*parent_pred) {
891+
None => format!("`{}`", &p),
892+
Some((parent_p, _)) => {
893+
collect_type_param_suggestions(
894+
self_ty,
895+
parent_pred,
896+
&p,
897+
);
898+
format!("`{}`\nwhich is required by `{}`", p, parent_p)
899+
}
900+
},
901+
}
883902
})
884903
})
885904
.enumerate()
886905
.collect::<Vec<(usize, String)>>();
906+
887907
for ((span, empty_where), obligations) in type_params.into_iter() {
888908
restrict_type_params = true;
889909
// #74886: Sort here so that the output is always the same.

src/test/ui/issues/issue-35677.fixed

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
3+
use std::collections::HashSet;
4+
use std::hash::Hash;
5+
6+
fn is_subset<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool where T: Eq, T: Hash {
7+
this.is_subset(other)
8+
//~^ ERROR the method
9+
}
10+
11+
fn main() {}

src/test/ui/issues/issue-35677.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
// run-rustfix
2+
#![allow(dead_code)]
13
use std::collections::HashSet;
4+
use std::hash::Hash;
25

36
fn is_subset<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool {
47
this.is_subset(other)

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
error[E0599]: the method `is_subset` exists for reference `&HashSet<T>`, but its trait bounds were not satisfied
2-
--> $DIR/issue-35677.rs:4:10
2+
--> $DIR/issue-35677.rs:7:10
33
|
44
LL | this.is_subset(other)
55
| ^^^^^^^^^ method cannot be called on `&HashSet<T>` due to unsatisfied trait bounds
66
|
77
= note: the following trait bounds were not satisfied:
88
`T: Eq`
99
`T: Hash`
10+
help: consider restricting the type parameters to satisfy the trait bounds
11+
|
12+
LL | fn is_subset<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool where T: Eq, T: Hash {
13+
| ++++++++++++++++++++
1014

1115
error: aborting due to previous error
1216

src/test/ui/issues/issue-69725.fixed

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// run-rustfix
2+
// aux-build:issue-69725.rs
3+
#![allow(dead_code)]
4+
5+
extern crate issue_69725;
6+
use issue_69725::Struct;
7+
8+
fn crash<A>() where A: Clone {
9+
let _ = Struct::<A>::new().clone();
10+
//~^ ERROR: the method
11+
}
12+
13+
fn main() {}

src/test/ui/issues/issue-69725.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
// run-rustfix
12
// aux-build:issue-69725.rs
3+
#![allow(dead_code)]
24

35
extern crate issue_69725;
46
use issue_69725::Struct;

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0599]: the method `clone` exists for struct `Struct<A>`, but its trait bounds were not satisfied
2-
--> $DIR/issue-69725.rs:7:32
2+
--> $DIR/issue-69725.rs:9:32
33
|
44
LL | let _ = Struct::<A>::new().clone();
55
| ^^^^^ method cannot be called on `Struct<A>` due to unsatisfied trait bounds
@@ -12,6 +12,10 @@ LL | pub struct Struct<A>(A);
1212
= note: the following trait bounds were not satisfied:
1313
`A: Clone`
1414
which is required by `Struct<A>: Clone`
15+
help: consider restricting the type parameter to satisfy the trait bound
16+
|
17+
LL | fn crash<A>() where A: Clone {
18+
| ++++++++++++++
1519

1620
error: aborting due to previous error
1721

0 commit comments

Comments
 (0)