@@ -4,6 +4,7 @@ use std::iter;
44use std:: ops:: Deref ;
55
66use rustc_data_structures:: fx:: FxHashSet ;
7+ use rustc_data_structures:: sso:: SsoHashSet ;
78use rustc_errors:: Applicability ;
89use rustc_hir as hir;
910use rustc_hir:: HirId ;
@@ -35,6 +36,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
3536 CandidateStep , MethodAutoderefBadTy , MethodAutoderefStepsResult ,
3637} ;
3738use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCtxt } ;
39+ use rustc_type_ir:: elaborate:: supertrait_def_ids;
3840use smallvec:: { SmallVec , smallvec} ;
3941use tracing:: { debug, instrument} ;
4042
@@ -1317,10 +1319,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13171319 debug ! ( "applicable_candidates: {:?}" , applicable_candidates) ;
13181320
13191321 if applicable_candidates. len ( ) > 1 {
1320- if let Some ( pick) =
1321- self . collapse_candidates_to_trait_pick ( self_ty, & applicable_candidates)
1322- {
1323- return Some ( Ok ( pick) ) ;
1322+ if self . tcx . features ( ) . supertrait_item_shadowing {
1323+ if let Some ( pick) =
1324+ self . collapse_candidates_to_subtrait_pick ( self_ty, & applicable_candidates)
1325+ {
1326+ return Some ( Ok ( pick) ) ;
1327+ }
1328+ } else {
1329+ if let Some ( pick) =
1330+ self . collapse_candidates_to_trait_pick ( self_ty, & applicable_candidates)
1331+ {
1332+ return Some ( Ok ( pick) ) ;
1333+ }
13241334 }
13251335 }
13261336
@@ -1754,6 +1764,51 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
17541764 } )
17551765 }
17561766
1767+ /// Much like `collapse_candidates_to_trait_pick`, this method allows us to collapse
1768+ /// multiple conflicting picks if there is one pick whose trait container is a subtrait
1769+ /// of the trait containers of all of the other picks.
1770+ ///
1771+ /// This implements RFC #3624.
1772+ fn collapse_candidates_to_subtrait_pick (
1773+ & self ,
1774+ self_ty : Ty < ' tcx > ,
1775+ probes : & [ ( & Candidate < ' tcx > , ProbeResult ) ] ,
1776+ ) -> Option < Pick < ' tcx > > {
1777+ let mut child_pick = probes[ 0 ] . 0 ;
1778+ let mut supertraits: SsoHashSet < _ > =
1779+ supertrait_def_ids ( self . tcx , child_pick. item . trait_container ( self . tcx ) ?) . collect ( ) ;
1780+
1781+ // All other picks should be a supertrait of the `child_pick`.
1782+ // If it's not, then we update the `child_pick` and the `supertraits`
1783+ // list.
1784+ for ( p, _) in & probes[ 1 ..] {
1785+ let p_container = p. item . trait_container ( self . tcx ) ?;
1786+ if !supertraits. contains ( & p_container) {
1787+ // This pick is not a supertrait of the `child_pick`.
1788+ // Check if it's a subtrait of the `child_pick`, which
1789+ // is sufficient to imply that all of the previous picks
1790+ // are also supertraits of this pick.
1791+ supertraits = supertrait_def_ids ( self . tcx , p_container) . collect ( ) ;
1792+ if supertraits. contains ( & child_pick. item . trait_container ( self . tcx ) . unwrap ( ) ) {
1793+ child_pick = * p;
1794+ } else {
1795+ // `child_pick` is not a supertrait of this pick. Bail.
1796+ return None ;
1797+ }
1798+ }
1799+ }
1800+
1801+ Some ( Pick {
1802+ item : child_pick. item ,
1803+ kind : TraitPick ,
1804+ import_ids : child_pick. import_ids . clone ( ) ,
1805+ autoderefs : 0 ,
1806+ autoref_or_ptr_adjustment : None ,
1807+ self_ty,
1808+ unstable_candidates : vec ! [ ] ,
1809+ } )
1810+ }
1811+
17571812 /// Similarly to `probe_for_return_type`, this method attempts to find the best matching
17581813 /// candidate method where the method name may have been misspelled. Similarly to other
17591814 /// edit distance based suggestions, we provide at most one such suggestion.
0 commit comments