Deduplicate item bounds after normalization
This commit is contained in:
parent
e42c97919c
commit
852073a7d2
1 changed files with 40 additions and 17 deletions
|
@ -1192,6 +1192,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
};
|
};
|
||||||
let bounds = tcx.item_bounds(def_id).subst(tcx, substs);
|
let bounds = tcx.item_bounds(def_id).subst(tcx, substs);
|
||||||
|
|
||||||
|
// The bounds returned by `item_bounds` may contain duplicates after
|
||||||
|
// normalization, so try to deduplicate when possible to avoid
|
||||||
|
// unnecessary ambiguity.
|
||||||
|
let mut distinct_normalized_bounds = FxHashSet::default();
|
||||||
|
|
||||||
let matching_bounds = bounds
|
let matching_bounds = bounds
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -1199,12 +1204,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
if let ty::PredicateAtom::Trait(pred, _) = bound.skip_binders() {
|
if let ty::PredicateAtom::Trait(pred, _) = bound.skip_binders() {
|
||||||
let bound = ty::Binder::bind(pred.trait_ref);
|
let bound = ty::Binder::bind(pred.trait_ref);
|
||||||
if self.infcx.probe(|_| {
|
if self.infcx.probe(|_| {
|
||||||
self.match_projection(
|
if let Ok(normalized_trait) = self.match_projection(
|
||||||
obligation,
|
obligation,
|
||||||
bound,
|
bound,
|
||||||
placeholder_trait_predicate.trait_ref,
|
placeholder_trait_predicate.trait_ref,
|
||||||
)
|
) {
|
||||||
.is_ok()
|
match normalized_trait {
|
||||||
|
None => true,
|
||||||
|
Some(normalized_trait)
|
||||||
|
if distinct_normalized_bounds.insert(normalized_trait) =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}) {
|
}) {
|
||||||
return Some(idx);
|
return Some(idx);
|
||||||
}
|
}
|
||||||
|
@ -1221,20 +1237,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
matching_bounds
|
matching_bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Equates the trait in `obligation` with trait bound. If the two traits
|
||||||
|
/// can be equated and the normalized trait bound doesn't contain inference
|
||||||
|
/// variables or placeholders, the normalized bound is returned.
|
||||||
fn match_projection(
|
fn match_projection(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
trait_bound: ty::PolyTraitRef<'tcx>,
|
trait_bound: ty::PolyTraitRef<'tcx>,
|
||||||
placeholder_trait_ref: ty::TraitRef<'tcx>,
|
placeholder_trait_ref: ty::TraitRef<'tcx>,
|
||||||
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
|
) -> Result<Option<ty::PolyTraitRef<'tcx>>, ()> {
|
||||||
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
|
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
|
||||||
if placeholder_trait_ref.def_id != trait_bound.def_id() {
|
if placeholder_trait_ref.def_id != trait_bound.def_id() {
|
||||||
// Avoid unnecessary normalization
|
// Avoid unnecessary normalization
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let Normalized { value: trait_bound, obligations: mut nested_obligations } =
|
let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
|
||||||
ensure_sufficient_stack(|| {
|
|
||||||
project::normalize_with_depth(
|
project::normalize_with_depth(
|
||||||
self,
|
self,
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
|
@ -1246,9 +1264,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
self.infcx
|
self.infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.at(&obligation.cause, obligation.param_env)
|
||||||
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
|
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
|
||||||
.map(|InferOk { obligations, .. }| {
|
.map(|InferOk { obligations: _, value: () }| {
|
||||||
nested_obligations.extend(obligations);
|
// This method is called within a probe, so we can't have
|
||||||
nested_obligations
|
// inference variables and placeholders escape.
|
||||||
|
if !trait_bound.needs_infer() && !trait_bound.has_placeholders() {
|
||||||
|
Some(trait_bound)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue