1+ use syntax_pos:: Span ;
2+
13use crate :: hir;
24use crate :: hir:: def_id:: DefId ;
35use crate :: traits:: specialize:: specialization_graph:: NodeItem ;
@@ -41,7 +43,6 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
4143 }
4244}
4345
44-
4546struct PredicateSet < ' a , ' gcx : ' a +' tcx , ' tcx : ' a > {
4647 tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
4748 set : FxHashSet < ty:: Predicate < ' tcx > > ,
@@ -73,12 +74,11 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
7374
7475/// "Elaboration" is the process of identifying all the predicates that
7576/// are implied by a source predicate. Currently this basically means
76- /// walking the "supertraits" and other similar assumptions. For
77- /// example, if we know that `T : Ord`, the elaborator would deduce
78- /// that `T : PartialOrd` holds as well. Similarly, if we have `trait
79- /// Foo : 'static`, and we know that `T : Foo`, then we know that `T :
80- /// 'static`.
81- pub struct Elaborator < ' a , ' gcx : ' a +' tcx , ' tcx : ' a > {
77+ /// walking the "supertraits" and other similar assumptions. For example,
78+ /// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
79+ /// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
80+ /// `T: Foo`, then we know that `T: 'static`.
81+ pub struct Elaborator < ' a , ' gcx : ' a + ' tcx , ' tcx : ' a > {
8282 stack : Vec < ty:: Predicate < ' tcx > > ,
8383 visited : PredicateSet < ' a , ' gcx , ' tcx > ,
8484}
@@ -96,8 +96,7 @@ pub fn elaborate_trait_refs<'cx, 'gcx, 'tcx>(
9696 trait_refs : impl Iterator < Item = ty:: PolyTraitRef < ' tcx > > )
9797 -> Elaborator < ' cx , ' gcx , ' tcx >
9898{
99- let predicates = trait_refs. map ( |trait_ref| trait_ref. to_predicate ( ) )
100- . collect ( ) ;
99+ let predicates = trait_refs. map ( |trait_ref| trait_ref. to_predicate ( ) ) . collect ( ) ;
101100 elaborate_predicates ( tcx, predicates)
102101}
103102
@@ -120,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
120119 let tcx = self . visited . tcx ;
121120 match * predicate {
122121 ty:: Predicate :: Trait ( ref data) => {
123- // Predicates declared on the trait.
122+ // Get predicates declared on the trait.
124123 let predicates = tcx. super_predicates_of ( data. def_id ( ) ) ;
125124
126125 let mut predicates: Vec < _ > = predicates. predicates
@@ -130,12 +129,11 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
130129 debug ! ( "super_predicates: data={:?} predicates={:?}" ,
131130 data, predicates) ;
132131
133- // Only keep those bounds that we haven't already
134- // seen. This is necessary to prevent infinite
135- // recursion in some cases. One common case is when
136- // people define `trait Sized: Sized { }` rather than `trait
137- // Sized { }`.
138- predicates. retain ( |r| self . visited . insert ( r) ) ;
132+ // Only keep those bounds that we haven't already seen.
133+ // This is necessary to prevent infinite recursion in some
134+ // cases. One common case is when people define
135+ // `trait Sized: Sized { }` rather than `trait Sized { }`.
136+ predicates. retain ( |p| self . visited . insert ( p) ) ;
139137
140138 self . stack . extend ( predicates) ;
141139 }
@@ -161,11 +159,9 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
161159 // Currently, we do not elaborate const-evaluatable
162160 // predicates.
163161 }
164-
165162 ty:: Predicate :: RegionOutlives ( ..) => {
166163 // Nothing to elaborate from `'a: 'b`.
167164 }
168-
169165 ty:: Predicate :: TypeOutlives ( ref data) => {
170166 // We know that `T: 'a` for some type `T`. We can
171167 // often elaborate this. For example, if we know that
@@ -192,34 +188,35 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
192188 tcx. push_outlives_components ( ty_max, & mut components) ;
193189 self . stack . extend (
194190 components
195- . into_iter ( )
196- . filter_map ( |component| match component {
197- Component :: Region ( r) => if r. is_late_bound ( ) {
198- None
199- } else {
200- Some ( ty:: Predicate :: RegionOutlives (
201- ty:: Binder :: dummy ( ty:: OutlivesPredicate ( r, r_min) ) ) )
202- } ,
203-
204- Component :: Param ( p) => {
205- let ty = tcx. mk_ty_param ( p. index , p. name ) ;
206- Some ( ty:: Predicate :: TypeOutlives (
207- ty:: Binder :: dummy ( ty:: OutlivesPredicate ( ty, r_min) ) ) )
208- } ,
209-
210- Component :: UnresolvedInferenceVariable ( _) => {
211- None
212- } ,
213-
214- Component :: Projection ( _) |
215- Component :: EscapingProjection ( _) => {
216- // We can probably do more here. This
217- // corresponds to a case like `<T as
218- // Foo<'a>>::U: 'b`.
219- None
220- } ,
221- } )
222- . filter ( |p| visited. insert ( p) ) ) ;
191+ . into_iter ( )
192+ . filter_map ( |component| match component {
193+ Component :: Region ( r) => if r. is_late_bound ( ) {
194+ None
195+ } else {
196+ Some ( ty:: Predicate :: RegionOutlives (
197+ ty:: Binder :: dummy ( ty:: OutlivesPredicate ( r, r_min) ) ) )
198+ }
199+
200+ Component :: Param ( p) => {
201+ let ty = tcx. mk_ty_param ( p. index , p. name ) ;
202+ Some ( ty:: Predicate :: TypeOutlives (
203+ ty:: Binder :: dummy ( ty:: OutlivesPredicate ( ty, r_min) ) ) )
204+ }
205+
206+ Component :: UnresolvedInferenceVariable ( _) => {
207+ None
208+ }
209+
210+ Component :: Projection ( _) |
211+ Component :: EscapingProjection ( _) => {
212+ // We can probably do more here. This
213+ // corresponds to a case like `<T as
214+ // Foo<'a>>::U: 'b`.
215+ None
216+ }
217+ } )
218+ . filter ( |p| visited. insert ( p) )
219+ ) ;
223220 }
224221 }
225222 }
@@ -233,16 +230,10 @@ impl<'cx, 'gcx, 'tcx> Iterator for Elaborator<'cx, 'gcx, 'tcx> {
233230 }
234231
235232 fn next ( & mut self ) -> Option < ty:: Predicate < ' tcx > > {
236- // Extract next item from top-most stack frame, if any.
237- let next_predicate = match self . stack . pop ( ) {
238- Some ( predicate) => predicate,
239- None => {
240- // No more stack frames. Done.
241- return None ;
242- }
243- } ;
244- self . push ( & next_predicate) ;
245- return Some ( next_predicate) ;
233+ self . stack . pop ( ) . map ( |item| {
234+ self . push ( & item) ;
235+ item
236+ } )
246237 }
247238}
248239
@@ -254,20 +245,124 @@ pub type Supertraits<'cx, 'gcx, 'tcx> = FilterToTraits<Elaborator<'cx, 'gcx, 'tc
254245
255246pub fn supertraits < ' cx , ' gcx , ' tcx > ( tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
256247 trait_ref : ty:: PolyTraitRef < ' tcx > )
257- -> Supertraits < ' cx , ' gcx , ' tcx >
258- {
248+ -> Supertraits < ' cx , ' gcx , ' tcx > {
259249 elaborate_trait_ref ( tcx, trait_ref) . filter_to_traits ( )
260250}
261251
262252pub fn transitive_bounds < ' cx , ' gcx , ' tcx > ( tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
263253 bounds : impl Iterator < Item = ty:: PolyTraitRef < ' tcx > > )
264- -> Supertraits < ' cx , ' gcx , ' tcx >
265- {
254+ -> Supertraits < ' cx , ' gcx , ' tcx > {
266255 elaborate_trait_refs ( tcx, bounds) . filter_to_traits ( )
267256}
268257
258+ ///////////////////////////////////////////////////////////////////////////
259+ // `TraitRefExpander` iterator
260+ ///////////////////////////////////////////////////////////////////////////
261+
262+ /// "Trait reference expansion" is the process of expanding a sequence of trait
263+ /// references into another sequence by transitively following all trait
264+ /// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
265+ /// `trait Foo = Bar + Sync;`, and another trait alias
266+ /// `trait Bar = Read + Write`, then the bounds would expand to
267+ /// `Read + Write + Sync + Send`.
268+ pub struct TraitRefExpander < ' a , ' gcx : ' a + ' tcx , ' tcx : ' a > {
269+ stack : Vec < TraitRefExpansionInfo < ' tcx > > ,
270+ visited : PredicateSet < ' a , ' gcx , ' tcx > ,
271+ }
272+
273+ #[ derive( Debug , Clone ) ]
274+ pub struct TraitRefExpansionInfo < ' tcx > {
275+ pub top_level_trait_ref : ty:: PolyTraitRef < ' tcx > ,
276+ pub top_level_span : Span ,
277+ pub trait_ref : ty:: PolyTraitRef < ' tcx > ,
278+ pub span : Span ,
279+ }
280+
281+ pub fn expand_trait_refs < ' cx , ' gcx , ' tcx > (
282+ tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
283+ trait_refs : impl IntoIterator < Item = ( ty:: PolyTraitRef < ' tcx > , Span ) >
284+ ) -> TraitRefExpander < ' cx , ' gcx , ' tcx > {
285+ let mut visited = PredicateSet :: new ( tcx) ;
286+ let mut items: Vec < _ > =
287+ trait_refs
288+ . into_iter ( )
289+ . map ( |( tr, sp) | TraitRefExpansionInfo {
290+ top_level_trait_ref : tr. clone ( ) ,
291+ top_level_span : sp,
292+ trait_ref : tr,
293+ span : sp,
294+ } )
295+ . collect ( ) ;
296+ items. retain ( |item| visited. insert ( & item. trait_ref . to_predicate ( ) ) ) ;
297+ TraitRefExpander { stack : items, visited : visited, }
298+ }
299+
300+ impl < ' cx , ' gcx , ' tcx > TraitRefExpander < ' cx , ' gcx , ' tcx > {
301+ // Returns `true` if `item` refers to a trait.
302+ fn push ( & mut self , item : & TraitRefExpansionInfo < ' tcx > ) -> bool {
303+ let tcx = self . visited . tcx ;
304+
305+ if !tcx. is_trait_alias ( item. trait_ref . def_id ( ) ) {
306+ return true ;
307+ }
308+
309+ // Get predicates declared on the trait.
310+ let predicates = tcx. super_predicates_of ( item. trait_ref . def_id ( ) ) ;
311+
312+ let mut items: Vec < _ > = predicates. predicates
313+ . iter ( )
314+ . rev ( )
315+ . filter_map ( |( pred, sp) | {
316+ pred. subst_supertrait ( tcx, & item. trait_ref )
317+ . to_opt_poly_trait_ref ( )
318+ . map ( |trait_ref|
319+ TraitRefExpansionInfo {
320+ trait_ref,
321+ span : * sp,
322+ ..* item
323+ }
324+ )
325+ } )
326+ . collect ( ) ;
327+
328+ debug ! ( "expand_trait_refs: trait_ref={:?} items={:?}" ,
329+ item. trait_ref, items) ;
330+
331+ // Only keep those items that we haven't already seen.
332+ items. retain ( |i| self . visited . insert ( & i. trait_ref . to_predicate ( ) ) ) ;
333+
334+ self . stack . extend ( items) ;
335+ false
336+ }
337+ }
338+
339+ impl < ' cx , ' gcx , ' tcx > Iterator for TraitRefExpander < ' cx , ' gcx , ' tcx > {
340+ type Item = TraitRefExpansionInfo < ' tcx > ;
341+
342+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
343+ ( self . stack . len ( ) , None )
344+ }
345+
346+ fn next ( & mut self ) -> Option < TraitRefExpansionInfo < ' tcx > > {
347+ loop {
348+ let item = self . stack . pop ( ) ;
349+ match item {
350+ Some ( item) => {
351+ if self . push ( & item) {
352+ return Some ( item) ;
353+ }
354+ }
355+ None => {
356+ return None ;
357+ }
358+ }
359+ }
360+ }
361+ }
362+
269363///////////////////////////////////////////////////////////////////////////
270364// Iterator over def-ids of supertraits
365+ ///////////////////////////////////////////////////////////////////////////
271366
272367pub struct SupertraitDefIds < ' a , ' gcx : ' a +' tcx , ' tcx : ' a > {
273368 tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
0 commit comments