@@ -1192,19 +1192,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
1192
1192
} ;
1193
1193
let bounds = tcx. item_bounds ( def_id) . subst ( tcx, substs) ;
1194
1194
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
+
1195
1200
let matching_bounds = bounds
1196
1201
. iter ( )
1197
1202
. enumerate ( )
1198
1203
. filter_map ( |( idx, bound) | {
1199
1204
if let ty:: PredicateAtom :: Trait ( pred, _) = bound. skip_binders ( ) {
1200
1205
let bound = ty:: Binder :: bind ( pred. trait_ref ) ;
1201
1206
if self . infcx . probe ( |_| {
1202
- self . match_projection (
1207
+ if let Ok ( normalized_trait ) = self . match_projection (
1203
1208
obligation,
1204
1209
bound,
1205
1210
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
+ }
1208
1224
} ) {
1209
1225
return Some ( idx) ;
1210
1226
}
@@ -1221,34 +1237,41 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
1221
1237
matching_bounds
1222
1238
}
1223
1239
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.
1224
1243
fn match_projection (
1225
1244
& mut self ,
1226
1245
obligation : & TraitObligation < ' tcx > ,
1227
1246
trait_bound : ty:: PolyTraitRef < ' tcx > ,
1228
1247
placeholder_trait_ref : ty:: TraitRef < ' tcx > ,
1229
- ) -> Result < Vec < PredicateObligation < ' tcx > > , ( ) > {
1248
+ ) -> Result < Option < ty :: PolyTraitRef < ' tcx > > , ( ) > {
1230
1249
debug_assert ! ( !placeholder_trait_ref. has_escaping_bound_vars( ) ) ;
1231
1250
if placeholder_trait_ref. def_id != trait_bound. def_id ( ) {
1232
1251
// Avoid unnecessary normalization
1233
1252
return Err ( ( ) ) ;
1234
1253
}
1235
1254
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
+ } ) ;
1246
1264
self . infcx
1247
1265
. at ( & obligation. cause , obligation. param_env )
1248
1266
. 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
+ }
1252
1275
} )
1253
1276
. map_err ( |_| ( ) )
1254
1277
}
0 commit comments