1
+ use syntax_pos:: Span ;
2
+
1
3
use crate :: hir;
2
4
use crate :: hir:: def_id:: DefId ;
3
5
use crate :: traits:: specialize:: specialization_graph:: NodeItem ;
@@ -41,7 +43,6 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
41
43
}
42
44
}
43
45
44
-
45
46
struct PredicateSet < ' a , ' gcx : ' a +' tcx , ' tcx : ' a > {
46
47
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
47
48
set : FxHashSet < ty:: Predicate < ' tcx > > ,
@@ -73,12 +74,11 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
73
74
74
75
/// "Elaboration" is the process of identifying all the predicates that
75
76
/// 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 > {
82
82
stack : Vec < ty:: Predicate < ' tcx > > ,
83
83
visited : PredicateSet < ' a , ' gcx , ' tcx > ,
84
84
}
@@ -96,8 +96,7 @@ pub fn elaborate_trait_refs<'cx, 'gcx, 'tcx>(
96
96
trait_refs : impl Iterator < Item = ty:: PolyTraitRef < ' tcx > > )
97
97
-> Elaborator < ' cx , ' gcx , ' tcx >
98
98
{
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 ( ) ;
101
100
elaborate_predicates ( tcx, predicates)
102
101
}
103
102
@@ -120,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
120
119
let tcx = self . visited . tcx ;
121
120
match * predicate {
122
121
ty:: Predicate :: Trait ( ref data) => {
123
- // Predicates declared on the trait.
122
+ // Get predicates declared on the trait.
124
123
let predicates = tcx. super_predicates_of ( data. def_id ( ) ) ;
125
124
126
125
let mut predicates: Vec < _ > = predicates. predicates
@@ -130,12 +129,11 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
130
129
debug ! ( "super_predicates: data={:?} predicates={:?}" ,
131
130
data, predicates) ;
132
131
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) ) ;
139
137
140
138
self . stack . extend ( predicates) ;
141
139
}
@@ -161,11 +159,9 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
161
159
// Currently, we do not elaborate const-evaluatable
162
160
// predicates.
163
161
}
164
-
165
162
ty:: Predicate :: RegionOutlives ( ..) => {
166
163
// Nothing to elaborate from `'a: 'b`.
167
164
}
168
-
169
165
ty:: Predicate :: TypeOutlives ( ref data) => {
170
166
// We know that `T: 'a` for some type `T`. We can
171
167
// often elaborate this. For example, if we know that
@@ -192,34 +188,35 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
192
188
tcx. push_outlives_components ( ty_max, & mut components) ;
193
189
self . stack . extend (
194
190
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
+ ) ;
223
220
}
224
221
}
225
222
}
@@ -233,16 +230,10 @@ impl<'cx, 'gcx, 'tcx> Iterator for Elaborator<'cx, 'gcx, 'tcx> {
233
230
}
234
231
235
232
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
+ } )
246
237
}
247
238
}
248
239
@@ -254,20 +245,124 @@ pub type Supertraits<'cx, 'gcx, 'tcx> = FilterToTraits<Elaborator<'cx, 'gcx, 'tc
254
245
255
246
pub fn supertraits < ' cx , ' gcx , ' tcx > ( tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
256
247
trait_ref : ty:: PolyTraitRef < ' tcx > )
257
- -> Supertraits < ' cx , ' gcx , ' tcx >
258
- {
248
+ -> Supertraits < ' cx , ' gcx , ' tcx > {
259
249
elaborate_trait_ref ( tcx, trait_ref) . filter_to_traits ( )
260
250
}
261
251
262
252
pub fn transitive_bounds < ' cx , ' gcx , ' tcx > ( tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
263
253
bounds : impl Iterator < Item = ty:: PolyTraitRef < ' tcx > > )
264
- -> Supertraits < ' cx , ' gcx , ' tcx >
265
- {
254
+ -> Supertraits < ' cx , ' gcx , ' tcx > {
266
255
elaborate_trait_refs ( tcx, bounds) . filter_to_traits ( )
267
256
}
268
257
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
+
269
363
///////////////////////////////////////////////////////////////////////////
270
364
// Iterator over def-ids of supertraits
365
+ ///////////////////////////////////////////////////////////////////////////
271
366
272
367
pub struct SupertraitDefIds < ' a , ' gcx : ' a +' tcx , ' tcx : ' a > {
273
368
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
0 commit comments