Suggest constraining fn type params when appropriate

This commit is contained in:
Esteban Kuber 2021-10-13 16:07:22 +00:00
parent 9fa165d11b
commit cecbd7657a
7 changed files with 85 additions and 28 deletions

View file

@ -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::<Vec<(usize, String)>>();
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.

View file

@ -0,0 +1,11 @@
// run-rustfix
#![allow(dead_code)]
use std::collections::HashSet;
use std::hash::Hash;
fn is_subset<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool where T: Eq, T: Hash {
this.is_subset(other)
//~^ ERROR the method
}
fn main() {}

View file

@ -1,4 +1,7 @@
// run-rustfix
#![allow(dead_code)]
use std::collections::HashSet;
use std::hash::Hash;
fn is_subset<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool {
this.is_subset(other)

View file

@ -1,5 +1,5 @@
error[E0599]: the method `is_subset` exists for reference `&HashSet<T>`, 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<T>` 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<T>(this: &HashSet<T>, other: &HashSet<T>) -> bool where T: Eq, T: Hash {
| ++++++++++++++++++++
error: aborting due to previous error

View file

@ -0,0 +1,13 @@
// run-rustfix
// aux-build:issue-69725.rs
#![allow(dead_code)]
extern crate issue_69725;
use issue_69725::Struct;
fn crash<A>() where A: Clone {
let _ = Struct::<A>::new().clone();
//~^ ERROR: the method
}
fn main() {}

View file

@ -1,4 +1,6 @@
// run-rustfix
// aux-build:issue-69725.rs
#![allow(dead_code)]
extern crate issue_69725;
use issue_69725::Struct;

View file

@ -1,5 +1,5 @@
error[E0599]: the method `clone` exists for struct `Struct<A>`, but its trait bounds were not satisfied
--> $DIR/issue-69725.rs:7:32
--> $DIR/issue-69725.rs:9:32
|
LL | let _ = Struct::<A>::new().clone();
| ^^^^^ method cannot be called on `Struct<A>` due to unsatisfied trait bounds
@ -12,6 +12,10 @@ LL | pub struct Struct<A>(A);
= note: the following trait bounds were not satisfied:
`A: Clone`
which is required by `Struct<A>: Clone`
help: consider restricting the type parameter to satisfy the trait bound
|
LL | fn crash<A>() where A: Clone {
| ++++++++++++++
error: aborting due to previous error