@@ -3,6 +3,7 @@ use std::cmp::max;
33use std:: ops:: Deref ;
44
55use rustc_data_structures:: fx:: FxHashSet ;
6+ use rustc_data_structures:: sso:: SsoHashSet ;
67use rustc_errors:: Applicability ;
78use rustc_hir as hir;
89use rustc_hir:: HirId ;
@@ -33,6 +34,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
3334 CandidateStep , MethodAutoderefBadTy , MethodAutoderefStepsResult ,
3435} ;
3536use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCtxt } ;
37+ use rustc_type_ir:: elaborate:: supertrait_def_ids;
3638use smallvec:: { SmallVec , smallvec} ;
3739use tracing:: { debug, instrument} ;
3840
@@ -224,6 +226,9 @@ pub(crate) struct Pick<'tcx> {
224226 /// to identify this method. Used only for deshadowing errors.
225227 /// Only applies for inherent impls.
226228 pub receiver_steps : Option < usize > ,
229+
230+ /// Candidates that were shadowed by supertraits.
231+ pub shadowed_candidates : Vec < ty:: AssocItem > ,
227232}
228233
229234#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -1634,6 +1639,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
16341639 }
16351640
16361641 if applicable_candidates. len ( ) > 1 {
1642+ // We collapse to a subtrait pick *after* filtering unstable candidates
1643+ // to make sure we don't prefer a unstable subtrait method over a stable
1644+ // supertrait method.
1645+ if self . tcx . features ( ) . supertrait_item_shadowing ( ) {
1646+ if let Some ( pick) =
1647+ self . collapse_candidates_to_subtrait_pick ( self_ty, & applicable_candidates)
1648+ {
1649+ return Some ( Ok ( pick) ) ;
1650+ }
1651+ }
1652+
16371653 let sources = candidates. iter ( ) . map ( |p| self . candidate_source ( p, self_ty) ) . collect ( ) ;
16381654 return Some ( Err ( MethodError :: Ambiguity ( sources) ) ) ;
16391655 }
@@ -1672,6 +1688,7 @@ impl<'tcx> Pick<'tcx> {
16721688 self_ty,
16731689 unstable_candidates : _,
16741690 receiver_steps : _,
1691+ shadowed_candidates : _,
16751692 } = * self ;
16761693 self_ty != other. self_ty || def_id != other. item . def_id
16771694 }
@@ -2081,6 +2098,83 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
20812098 self_ty,
20822099 unstable_candidates : vec ! [ ] ,
20832100 receiver_steps : None ,
2101+ shadowed_candidates : vec ! [ ] ,
2102+ } )
2103+ }
2104+
2105+ /// Much like `collapse_candidates_to_trait_pick`, this method allows us to collapse
2106+ /// multiple conflicting picks if there is one pick whose trait container is a subtrait
2107+ /// of the trait containers of all of the other picks.
2108+ ///
2109+ /// This implements RFC #3624.
2110+ fn collapse_candidates_to_subtrait_pick (
2111+ & self ,
2112+ self_ty : Ty < ' tcx > ,
2113+ probes : & [ ( & Candidate < ' tcx > , ProbeResult ) ] ,
2114+ ) -> Option < Pick < ' tcx > > {
2115+ let mut child_candidate = probes[ 0 ] . 0 ;
2116+ let mut child_trait = child_candidate. item . trait_container ( self . tcx ) ?;
2117+ let mut supertraits: SsoHashSet < _ > = supertrait_def_ids ( self . tcx , child_trait) . collect ( ) ;
2118+
2119+ let mut remaining_candidates: Vec < _ > = probes[ 1 ..] . iter ( ) . map ( |& ( p, _) | p) . collect ( ) ;
2120+ while !remaining_candidates. is_empty ( ) {
2121+ let mut made_progress = false ;
2122+ let mut next_round = vec ! [ ] ;
2123+
2124+ for remaining_candidate in remaining_candidates {
2125+ let remaining_trait = remaining_candidate. item . trait_container ( self . tcx ) ?;
2126+ if supertraits. contains ( & remaining_trait) {
2127+ made_progress = true ;
2128+ continue ;
2129+ }
2130+
2131+ // This pick is not a supertrait of the `child_pick`.
2132+ // Check if it's a subtrait of the `child_pick`, instead.
2133+ // If it is, then it must have been a subtrait of every
2134+ // other pick we've eliminated at this point. It will
2135+ // take over at this point.
2136+ let remaining_trait_supertraits: SsoHashSet < _ > =
2137+ supertrait_def_ids ( self . tcx , remaining_trait) . collect ( ) ;
2138+ if remaining_trait_supertraits. contains ( & child_trait) {
2139+ child_candidate = remaining_candidate;
2140+ child_trait = remaining_trait;
2141+ supertraits = remaining_trait_supertraits;
2142+ made_progress = true ;
2143+ continue ;
2144+ }
2145+
2146+ // `child_pick` is not a supertrait of this pick.
2147+ // Don't bail here, since we may be comparing two supertraits
2148+ // of a common subtrait. These two supertraits won't be related
2149+ // at all, but we will pick them up next round when we find their
2150+ // child as we continue iterating in this round.
2151+ next_round. push ( remaining_candidate) ;
2152+ }
2153+
2154+ if made_progress {
2155+ // If we've made progress, iterate again.
2156+ remaining_candidates = next_round;
2157+ } else {
2158+ // Otherwise, we must have at least two candidates which
2159+ // are not related to each other at all.
2160+ return None ;
2161+ }
2162+ }
2163+
2164+ Some ( Pick {
2165+ item : child_candidate. item ,
2166+ kind : TraitPick ,
2167+ import_ids : child_candidate. import_ids . clone ( ) ,
2168+ autoderefs : 0 ,
2169+ autoref_or_ptr_adjustment : None ,
2170+ self_ty,
2171+ unstable_candidates : vec ! [ ] ,
2172+ shadowed_candidates : probes
2173+ . iter ( )
2174+ . map ( |( c, _) | c. item )
2175+ . filter ( |item| item. def_id != child_candidate. item . def_id )
2176+ . collect ( ) ,
2177+ receiver_steps : None ,
20842178 } )
20852179 }
20862180
@@ -2378,6 +2472,7 @@ impl<'tcx> Candidate<'tcx> {
23782472 InherentImplCandidate { receiver_steps, .. } => Some ( receiver_steps) ,
23792473 _ => None ,
23802474 } ,
2475+ shadowed_candidates : vec ! [ ] ,
23812476 }
23822477 }
23832478}
0 commit comments