@@ -24,6 +24,7 @@ use std::{assert_matches, slice};
2424use rustc_abi:: FIRST_VARIANT ;
2525use rustc_ast:: LitKind ;
2626use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
27+ use rustc_data_structures:: sso:: SsoHashSet ;
2728use rustc_errors:: codes:: * ;
2829use rustc_errors:: {
2930 Applicability , Diag , DiagCtxtHandle , ErrorGuaranteed , FatalError , StashKey ,
@@ -1262,6 +1263,69 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12621263 )
12631264 }
12641265
1266+ /// When there are multiple traits which contain an identically named
1267+ /// associated item, this function eliminates any traits which are a
1268+ /// supertrait of another candidate trait.
1269+ ///
1270+ /// This implements RFC #3624.
1271+ fn collapse_candidates_to_subtrait_pick (
1272+ & self ,
1273+ matching_candidates : & [ ty:: PolyTraitRef < ' tcx > ] ,
1274+ ) -> Option < ty:: PolyTraitRef < ' tcx > > {
1275+ if !self . tcx ( ) . features ( ) . supertrait_item_shadowing ( ) {
1276+ return None ;
1277+ }
1278+
1279+ let mut child_trait = matching_candidates[ 0 ] ;
1280+ let mut supertraits: SsoHashSet < _ > =
1281+ traits:: supertrait_def_ids ( self . tcx ( ) , child_trait. def_id ( ) ) . collect ( ) ;
1282+
1283+ let mut remaining_candidates: Vec < _ > = matching_candidates[ 1 ..] . iter ( ) . copied ( ) . collect ( ) ;
1284+ while !remaining_candidates. is_empty ( ) {
1285+ let mut made_progress = false ;
1286+ let mut next_round = vec ! [ ] ;
1287+
1288+ for remaining_trait in remaining_candidates {
1289+ if supertraits. contains ( & remaining_trait. def_id ( ) ) {
1290+ made_progress = true ;
1291+ continue ;
1292+ }
1293+
1294+ // This pick is not a supertrait of the `child_pick`.
1295+ // Check if it's a subtrait of the `child_pick`, instead.
1296+ // If it is, then it must have been a subtrait of every
1297+ // other pick we've eliminated at this point. It will
1298+ // take over at this point.
1299+ let remaining_trait_supertraits: SsoHashSet < _ > =
1300+ traits:: supertrait_def_ids ( self . tcx ( ) , remaining_trait. def_id ( ) ) . collect ( ) ;
1301+ if remaining_trait_supertraits. contains ( & child_trait. def_id ( ) ) {
1302+ child_trait = remaining_trait;
1303+ supertraits = remaining_trait_supertraits;
1304+ made_progress = true ;
1305+ continue ;
1306+ }
1307+
1308+ // `child_pick` is not a supertrait of this pick.
1309+ // Don't bail here, since we may be comparing two supertraits
1310+ // of a common subtrait. These two supertraits won't be related
1311+ // at all, but we will pick them up next round when we find their
1312+ // child as we continue iterating in this round.
1313+ next_round. push ( remaining_trait) ;
1314+ }
1315+
1316+ if made_progress {
1317+ // If we've made progress, iterate again.
1318+ remaining_candidates = next_round;
1319+ } else {
1320+ // Otherwise, we must have at least two candidates which
1321+ // are not related to each other at all.;
1322+ return None ;
1323+ }
1324+ }
1325+
1326+ Some ( child_trait)
1327+ }
1328+
12651329 /// Search for a single trait bound whose trait defines the associated item given by
12661330 /// `assoc_ident`.
12671331 ///
@@ -1296,10 +1360,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12961360 } ;
12971361
12981362 if let Some ( bound2) = matching_candidates. next ( ) {
1363+ let all_matching_candidates: Vec < _ > =
1364+ [ bound1, bound2] . into_iter ( ) . chain ( matching_candidates) . collect ( ) ;
1365+ if let Some ( bound) =
1366+ self . collapse_candidates_to_subtrait_pick ( & all_matching_candidates)
1367+ {
1368+ return Ok ( bound) ;
1369+ }
1370+
12991371 return Err ( self . report_ambiguous_assoc_item (
1300- bound1,
1301- bound2,
1302- matching_candidates,
1372+ & all_matching_candidates,
13031373 qself,
13041374 assoc_tag,
13051375 assoc_ident,
0 commit comments