@@ -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