@@ -24,6 +24,7 @@ use std::slice;
2424use rustc_ast:: LitKind ;
2525use rustc_data_structures:: assert_matches;
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 , struct_span_code_err,
@@ -1176,6 +1177,69 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11761177 )
11771178 }
11781179
1180+ /// When there are multiple traits which contain an identically named
1181+ /// associated item, this function eliminates any traits which are a
1182+ /// supertrait of another candidate trait.
1183+ ///
1184+ /// This implements RFC #3624.
1185+ fn collapse_candidates_to_subtrait_pick (
1186+ & self ,
1187+ matching_candidates : & [ ty:: PolyTraitRef < ' tcx > ] ,
1188+ ) -> Option < ty:: PolyTraitRef < ' tcx > > {
1189+ if !self . tcx ( ) . features ( ) . supertrait_item_shadowing ( ) {
1190+ return None ;
1191+ }
1192+
1193+ let mut child_trait = matching_candidates[ 0 ] ;
1194+ let mut supertraits: SsoHashSet < _ > =
1195+ traits:: supertrait_def_ids ( self . tcx ( ) , child_trait. def_id ( ) ) . collect ( ) ;
1196+
1197+ let mut remaining_candidates: Vec < _ > = matching_candidates[ 1 ..] . iter ( ) . copied ( ) . collect ( ) ;
1198+ while !remaining_candidates. is_empty ( ) {
1199+ let mut made_progress = false ;
1200+ let mut next_round = vec ! [ ] ;
1201+
1202+ for remaining_trait in remaining_candidates {
1203+ if supertraits. contains ( & remaining_trait. def_id ( ) ) {
1204+ made_progress = true ;
1205+ continue ;
1206+ }
1207+
1208+ // This pick is not a supertrait of the `child_pick`.
1209+ // Check if it's a subtrait of the `child_pick`, instead.
1210+ // If it is, then it must have been a subtrait of every
1211+ // other pick we've eliminated at this point. It will
1212+ // take over at this point.
1213+ let remaining_trait_supertraits: SsoHashSet < _ > =
1214+ traits:: supertrait_def_ids ( self . tcx ( ) , remaining_trait. def_id ( ) ) . collect ( ) ;
1215+ if remaining_trait_supertraits. contains ( & child_trait. def_id ( ) ) {
1216+ child_trait = remaining_trait;
1217+ supertraits = remaining_trait_supertraits;
1218+ made_progress = true ;
1219+ continue ;
1220+ }
1221+
1222+ // `child_pick` is not a supertrait of this pick.
1223+ // Don't bail here, since we may be comparing two supertraits
1224+ // of a common subtrait. These two supertraits won't be related
1225+ // at all, but we will pick them up next round when we find their
1226+ // child as we continue iterating in this round.
1227+ next_round. push ( remaining_trait) ;
1228+ }
1229+
1230+ if made_progress {
1231+ // If we've made progress, iterate again.
1232+ remaining_candidates = next_round;
1233+ } else {
1234+ // Otherwise, we must have at least two candidates which
1235+ // are not related to each other at all.;
1236+ return None ;
1237+ }
1238+ }
1239+
1240+ Some ( child_trait)
1241+ }
1242+
11791243 /// Search for a single trait bound whose trait defines the associated item given by
11801244 /// `assoc_ident`.
11811245 ///
@@ -1215,6 +1279,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12151279 if let Some ( bound2) = matching_candidates. next ( ) {
12161280 debug ! ( ?bound2) ;
12171281
1282+ // If the other matching candidates are all from supertraits of one
1283+ // trait, pick the subtrait.
1284+ let matching_candidates: Vec < _ > =
1285+ [ bound, bound2] . into_iter ( ) . chain ( matching_candidates) . collect ( ) ;
1286+ if let Some ( bound) = self . collapse_candidates_to_subtrait_pick ( & matching_candidates) {
1287+ return Ok ( bound) ;
1288+ }
1289+
12181290 let assoc_kind_str = errors:: assoc_tag_str ( assoc_tag) ;
12191291 let qself_str = qself. to_string ( tcx) ;
12201292 let mut err = self . dcx ( ) . create_err ( crate :: errors:: AmbiguousAssocItem {
@@ -1238,7 +1310,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12381310 // predicates!).
12391311 // FIXME: Turn this into a structured, translatable & more actionable suggestion.
12401312 let mut where_bounds = vec ! [ ] ;
1241- for bound in [ bound , bound2 ] . into_iter ( ) . chain ( matching_candidates) {
1313+ for bound in matching_candidates {
12421314 let bound_id = bound. def_id ( ) ;
12431315 let assoc_item = tcx. associated_items ( bound_id) . find_by_ident_and_kind (
12441316 tcx,
0 commit comments