Skip to content

Commit 852073a

Browse files
committed
Deduplicate item bounds after normalization
1 parent e42c979 commit 852073a

File tree

1 file changed

+40
-17
lines changed
  • compiler/rustc_trait_selection/src/traits/select

1 file changed

+40
-17
lines changed

compiler/rustc_trait_selection/src/traits/select/mod.rs

+40-17
Original file line numberDiff line numberDiff line change
@@ -1192,19 +1192,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11921192
};
11931193
let bounds = tcx.item_bounds(def_id).subst(tcx, substs);
11941194

1195+
// The bounds returned by `item_bounds` may contain duplicates after
1196+
// normalization, so try to deduplicate when possible to avoid
1197+
// unnecessary ambiguity.
1198+
let mut distinct_normalized_bounds = FxHashSet::default();
1199+
11951200
let matching_bounds = bounds
11961201
.iter()
11971202
.enumerate()
11981203
.filter_map(|(idx, bound)| {
11991204
if let ty::PredicateAtom::Trait(pred, _) = bound.skip_binders() {
12001205
let bound = ty::Binder::bind(pred.trait_ref);
12011206
if self.infcx.probe(|_| {
1202-
self.match_projection(
1207+
if let Ok(normalized_trait) = self.match_projection(
12031208
obligation,
12041209
bound,
12051210
placeholder_trait_predicate.trait_ref,
1206-
)
1207-
.is_ok()
1211+
) {
1212+
match normalized_trait {
1213+
None => true,
1214+
Some(normalized_trait)
1215+
if distinct_normalized_bounds.insert(normalized_trait) =>
1216+
{
1217+
true
1218+
}
1219+
_ => false,
1220+
}
1221+
} else {
1222+
false
1223+
}
12081224
}) {
12091225
return Some(idx);
12101226
}
@@ -1221,34 +1237,41 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12211237
matching_bounds
12221238
}
12231239

1240+
/// Equates the trait in `obligation` with trait bound. If the two traits
1241+
/// can be equated and the normalized trait bound doesn't contain inference
1242+
/// variables or placeholders, the normalized bound is returned.
12241243
fn match_projection(
12251244
&mut self,
12261245
obligation: &TraitObligation<'tcx>,
12271246
trait_bound: ty::PolyTraitRef<'tcx>,
12281247
placeholder_trait_ref: ty::TraitRef<'tcx>,
1229-
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
1248+
) -> Result<Option<ty::PolyTraitRef<'tcx>>, ()> {
12301249
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
12311250
if placeholder_trait_ref.def_id != trait_bound.def_id() {
12321251
// Avoid unnecessary normalization
12331252
return Err(());
12341253
}
12351254

1236-
let Normalized { value: trait_bound, obligations: mut nested_obligations } =
1237-
ensure_sufficient_stack(|| {
1238-
project::normalize_with_depth(
1239-
self,
1240-
obligation.param_env,
1241-
obligation.cause.clone(),
1242-
obligation.recursion_depth + 1,
1243-
&trait_bound,
1244-
)
1245-
});
1255+
let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
1256+
project::normalize_with_depth(
1257+
self,
1258+
obligation.param_env,
1259+
obligation.cause.clone(),
1260+
obligation.recursion_depth + 1,
1261+
&trait_bound,
1262+
)
1263+
});
12461264
self.infcx
12471265
.at(&obligation.cause, obligation.param_env)
12481266
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
1249-
.map(|InferOk { obligations, .. }| {
1250-
nested_obligations.extend(obligations);
1251-
nested_obligations
1267+
.map(|InferOk { obligations: _, value: () }| {
1268+
// This method is called within a probe, so we can't have
1269+
// inference variables and placeholders escape.
1270+
if !trait_bound.needs_infer() && !trait_bound.has_placeholders() {
1271+
Some(trait_bound)
1272+
} else {
1273+
None
1274+
}
12521275
})
12531276
.map_err(|_| ())
12541277
}

0 commit comments

Comments
 (0)