@@ -3,6 +3,7 @@ use std::cmp::max;
3
3
use std:: ops:: Deref ;
4
4
5
5
use rustc_data_structures:: fx:: FxHashSet ;
6
+ use rustc_data_structures:: sso:: SsoHashSet ;
6
7
use rustc_errors:: Applicability ;
7
8
use rustc_hir as hir;
8
9
use rustc_hir:: HirId ;
@@ -33,6 +34,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
33
34
CandidateStep , MethodAutoderefBadTy , MethodAutoderefStepsResult ,
34
35
} ;
35
36
use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCtxt } ;
37
+ use rustc_type_ir:: elaborate:: supertrait_def_ids;
36
38
use smallvec:: { SmallVec , smallvec} ;
37
39
use tracing:: { debug, instrument} ;
38
40
@@ -224,6 +226,9 @@ pub(crate) struct Pick<'tcx> {
224
226
/// to identify this method. Used only for deshadowing errors.
225
227
/// Only applies for inherent impls.
226
228
pub receiver_steps : Option < usize > ,
229
+
230
+ /// Candidates that were shadowed by supertraits.
231
+ pub shadowed_candidates : Vec < ty:: AssocItem > ,
227
232
}
228
233
229
234
#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -1634,6 +1639,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1634
1639
}
1635
1640
1636
1641
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
+
1637
1653
let sources = candidates. iter ( ) . map ( |p| self . candidate_source ( p, self_ty) ) . collect ( ) ;
1638
1654
return Some ( Err ( MethodError :: Ambiguity ( sources) ) ) ;
1639
1655
}
@@ -1672,6 +1688,7 @@ impl<'tcx> Pick<'tcx> {
1672
1688
self_ty,
1673
1689
unstable_candidates : _,
1674
1690
receiver_steps : _,
1691
+ shadowed_candidates : _,
1675
1692
} = * self ;
1676
1693
self_ty != other. self_ty || def_id != other. item . def_id
1677
1694
}
@@ -2081,6 +2098,83 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
2081
2098
self_ty,
2082
2099
unstable_candidates : vec ! [ ] ,
2083
2100
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 ,
2084
2178
} )
2085
2179
}
2086
2180
@@ -2378,6 +2472,7 @@ impl<'tcx> Candidate<'tcx> {
2378
2472
InherentImplCandidate { receiver_steps, .. } => Some ( receiver_steps) ,
2379
2473
_ => None ,
2380
2474
} ,
2475
+ shadowed_candidates : vec ! [ ] ,
2381
2476
}
2382
2477
}
2383
2478
}
0 commit comments