11
11
// #![warn(deprecated_mode)]
12
12
13
13
use astconv:: object_region_bounds;
14
- use middle:: infer:: GenericKind ;
15
- use middle:: subst:: { ParamSpace , Subst , Substs } ;
16
- use middle:: ty:: { self , Ty } ;
17
- use middle:: ty_fold:: { TypeFolder } ;
14
+ use middle:: infer:: { InferCtxt , GenericKind } ;
15
+ use middle:: subst:: { Substs } ;
16
+ use middle:: traits;
17
+ use middle:: ty:: { self , ToPolyTraitRef , Ty } ;
18
+ use middle:: ty_fold:: { TypeFoldable , TypeFolder } ;
18
19
20
+ use std:: rc:: Rc ;
19
21
use syntax:: ast;
22
+ use syntax:: codemap:: Span ;
20
23
24
+ use util:: common:: ErrorReported ;
21
25
use util:: ppaux:: Repr ;
22
26
23
27
// Helper functions related to manipulating region types.
24
28
25
29
pub enum Implication < ' tcx > {
26
30
RegionSubRegion ( Option < Ty < ' tcx > > , ty:: Region , ty:: Region ) ,
27
31
RegionSubGeneric ( Option < Ty < ' tcx > > , ty:: Region , GenericKind < ' tcx > ) ,
32
+ Predicate ( ast:: DefId , ty:: Predicate < ' tcx > ) ,
28
33
}
29
34
30
35
struct Implicator < ' a , ' tcx : ' a > {
31
- tcx : & ' a ty:: ctxt < ' tcx > ,
36
+ infcx : & ' a InferCtxt < ' a , ' tcx > ,
37
+ closure_typer : & ' a ( ty:: ClosureTyper < ' tcx > +' a ) ,
38
+ body_id : ast:: NodeId ,
32
39
stack : Vec < ( ty:: Region , Option < Ty < ' tcx > > ) > ,
40
+ span : Span ,
33
41
out : Vec < Implication < ' tcx > > ,
34
42
}
35
43
36
44
/// This routine computes the well-formedness constraints that must hold for the type `ty` to
37
45
/// appear in a context with lifetime `outer_region`
38
- pub fn implications < ' tcx > (
39
- tcx : & ty:: ctxt < ' tcx > ,
46
+ pub fn implications < ' a , ' tcx > (
47
+ infcx : & ' a InferCtxt < ' a , ' tcx > ,
48
+ closure_typer : & ty:: ClosureTyper < ' tcx > ,
49
+ body_id : ast:: NodeId ,
40
50
ty : Ty < ' tcx > ,
41
- outer_region : ty:: Region )
51
+ outer_region : ty:: Region ,
52
+ span : Span )
42
53
-> Vec < Implication < ' tcx > >
43
54
{
55
+ debug ! ( "implications(body_id={}, ty={}, outer_region={})" ,
56
+ body_id,
57
+ ty. repr( closure_typer. tcx( ) ) ,
58
+ outer_region. repr( closure_typer. tcx( ) ) ) ;
59
+
44
60
let mut stack = Vec :: new ( ) ;
45
61
stack. push ( ( outer_region, None ) ) ;
46
- let mut wf = Implicator { tcx : tcx,
47
- stack : stack,
48
- out : Vec :: new ( ) } ;
62
+ let mut wf = Implicator { closure_typer : closure_typer,
63
+ infcx : infcx,
64
+ body_id : body_id,
65
+ span : span,
66
+ stack : stack,
67
+ out : Vec :: new ( ) } ;
49
68
wf. accumulate_from_ty ( ty) ;
69
+ debug ! ( "implications: out={}" , wf. out. repr( closure_typer. tcx( ) ) ) ;
50
70
wf. out
51
71
}
52
72
53
73
impl < ' a , ' tcx > Implicator < ' a , ' tcx > {
74
+ fn tcx ( & self ) -> & ' a ty:: ctxt < ' tcx > {
75
+ self . infcx . tcx
76
+ }
77
+
54
78
fn accumulate_from_ty ( & mut self , ty : Ty < ' tcx > ) {
55
79
debug ! ( "accumulate_from_ty(ty={})" ,
56
- ty. repr( self . tcx) ) ;
80
+ ty. repr( self . tcx( ) ) ) ;
57
81
58
82
match ty. sty {
59
83
ty:: ty_bool |
@@ -94,13 +118,13 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
94
118
95
119
ty:: ty_trait( ref t) => {
96
120
let required_region_bounds =
97
- object_region_bounds ( self . tcx , & t. principal , t. bounds . builtin_bounds ) ;
121
+ object_region_bounds ( self . tcx ( ) , & t. principal , t. bounds . builtin_bounds ) ;
98
122
self . accumulate_from_object_ty ( ty, t. bounds . region_bound , required_region_bounds)
99
123
}
100
124
101
125
ty:: ty_enum( def_id, substs) |
102
126
ty:: ty_struct( def_id, substs) => {
103
- let item_scheme = ty:: lookup_item_type ( self . tcx , def_id) ;
127
+ let item_scheme = ty:: lookup_item_type ( self . tcx ( ) , def_id) ;
104
128
self . accumulate_from_adt ( ty, def_id, & item_scheme. generics , substs)
105
129
}
106
130
@@ -139,9 +163,9 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
139
163
}
140
164
141
165
ty:: ty_open( _) => {
142
- self . tcx . sess . bug (
166
+ self . tcx ( ) . sess . bug (
143
167
& format ! ( "Unexpected type encountered while doing wf check: {}" ,
144
- ty. repr( self . tcx) ) [ ] ) ;
168
+ ty. repr( self . tcx( ) ) ) [ ] ) ;
145
169
}
146
170
}
147
171
}
@@ -225,103 +249,113 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
225
249
fn accumulate_from_adt ( & mut self ,
226
250
ty : Ty < ' tcx > ,
227
251
def_id : ast:: DefId ,
228
- generics : & ty:: Generics < ' tcx > ,
252
+ _generics : & ty:: Generics < ' tcx > ,
229
253
substs : & Substs < ' tcx > )
230
254
{
231
- // The generic declarations from the type, appropriately
232
- // substituted for the actual substitutions.
233
- let generics = generics. subst ( self . tcx , substs) ;
234
-
235
- // Variance of each type/region parameter.
236
- let variances = ty:: item_variances ( self . tcx , def_id) ;
237
-
238
- for & space in & ParamSpace :: all ( ) {
239
- let region_params = substs. regions ( ) . get_slice ( space) ;
240
- let region_variances = variances. regions . get_slice ( space) ;
241
- let region_param_defs = generics. regions . get_slice ( space) ;
242
- assert_eq ! ( region_params. len( ) , region_variances. len( ) ) ;
243
- for ( & region_param, ( & region_variance, region_param_def) ) in
244
- region_params. iter ( ) . zip (
245
- region_variances. iter ( ) . zip (
246
- region_param_defs. iter ( ) ) )
247
- {
248
- match region_variance {
249
- ty:: Covariant | ty:: Bivariant => {
250
- // Ignore covariant or bivariant region
251
- // parameters. To understand why, consider a
252
- // struct `Foo<'a>`. If `Foo` contains any
253
- // references with lifetime `'a`, then `'a` must
254
- // be at least contravariant (and possibly
255
- // invariant). The only way to have a covariant
256
- // result is if `Foo` contains only a field with a
257
- // type like `fn() -> &'a T`; i.e., a bare
258
- // function that can produce a reference of
259
- // lifetime `'a`. In this case, there is no
260
- // *actual data* with lifetime `'a` that is
261
- // reachable. (Presumably this bare function is
262
- // really returning static data.)
263
- }
264
-
265
- ty:: Contravariant | ty:: Invariant => {
266
- // If the parameter is contravariant or
267
- // invariant, there may indeed be reachable
268
- // data with this lifetime. See other case for
269
- // more details.
270
- self . push_region_constraint_from_top ( region_param) ;
255
+ let predicates =
256
+ ty:: lookup_predicates ( self . tcx ( ) , def_id) . instantiate ( self . tcx ( ) , substs) ;
257
+ let predicates = match self . fully_normalize ( & predicates) {
258
+ Ok ( predicates) => predicates,
259
+ Err ( ErrorReported ) => { return ; }
260
+ } ;
261
+
262
+ for predicate in predicates. predicates . as_slice ( ) {
263
+ match * predicate {
264
+ ty:: Predicate :: Trait ( ref data) => {
265
+ self . accumulate_from_assoc_types_transitive ( data) ;
266
+ }
267
+ ty:: Predicate :: Equate ( ..) => { }
268
+ ty:: Predicate :: Projection ( ..) => { }
269
+ ty:: Predicate :: RegionOutlives ( ref data) => {
270
+ match ty:: no_late_bound_regions ( self . tcx ( ) , data) {
271
+ None => { }
272
+ Some ( ty:: OutlivesPredicate ( r_a, r_b) ) => {
273
+ self . push_sub_region_constraint ( Some ( ty) , r_b, r_a) ;
274
+ }
271
275
}
272
276
}
273
-
274
- for & region_bound in & region_param_def. bounds {
275
- // The type declared a constraint like
276
- //
277
- // 'b : 'a
278
- //
279
- // which means that `'a <= 'b` (after
280
- // substitution). So take the region we
281
- // substituted for `'a` (`region_bound`) and make
282
- // it a subregion of the region we substituted
283
- // `'b` (`region_param`).
284
- self . push_sub_region_constraint (
285
- Some ( ty) , region_bound, region_param) ;
277
+ ty:: Predicate :: TypeOutlives ( ref data) => {
278
+ match ty:: no_late_bound_regions ( self . tcx ( ) , data) {
279
+ None => { }
280
+ Some ( ty:: OutlivesPredicate ( ty_a, r_b) ) => {
281
+ self . stack . push ( ( r_b, Some ( ty) ) ) ;
282
+ self . accumulate_from_ty ( ty_a) ;
283
+ self . stack . pop ( ) . unwrap ( ) ;
284
+ }
285
+ }
286
286
}
287
287
}
288
+ }
288
289
289
- let types = substs. types . get_slice ( space) ;
290
- let type_variances = variances. types . get_slice ( space) ;
291
- let type_param_defs = generics. types . get_slice ( space) ;
292
- assert_eq ! ( types. len( ) , type_variances. len( ) ) ;
293
- for ( & type_param_ty, ( & variance, type_param_def) ) in
294
- types. iter ( ) . zip (
295
- type_variances. iter ( ) . zip (
296
- type_param_defs. iter ( ) ) )
297
- {
298
- debug ! ( "type_param_ty={} variance={}" ,
299
- type_param_ty. repr( self . tcx) ,
300
- variance. repr( self . tcx) ) ;
301
-
302
- match variance {
303
- ty:: Contravariant | ty:: Bivariant => {
304
- // As above, except that in this it is a
305
- // *contravariant* reference that indices that no
306
- // actual data of type T is reachable.
307
- }
290
+ let obligations = predicates. predicates
291
+ . into_iter ( )
292
+ . map ( |pred| Implication :: Predicate ( def_id, pred) ) ;
293
+ self . out . extend ( obligations) ;
308
294
309
- ty:: Covariant | ty:: Invariant => {
310
- self . accumulate_from_ty ( type_param_ty) ;
311
- }
295
+ let variances = ty:: item_variances ( self . tcx ( ) , def_id) ;
296
+
297
+ for ( & region, & variance) in substs. regions ( ) . iter ( ) . zip ( variances. regions . iter ( ) ) {
298
+ match variance {
299
+ ty:: Contravariant | ty:: Invariant => {
300
+ // If any data with this lifetime is reachable
301
+ // within, it must be at least contravariant.
302
+ self . push_region_constraint_from_top ( region)
312
303
}
304
+ ty:: Covariant | ty:: Bivariant => { }
305
+ }
306
+ }
313
307
314
- // Inspect bounds on this type parameter for any
315
- // region bounds.
316
- for & r in & type_param_def . bounds . region_bounds {
317
- self . stack . push ( ( r , Some ( ty ) ) ) ;
318
- self . accumulate_from_ty ( type_param_ty ) ;
319
- self . stack . pop ( ) . unwrap ( ) ;
308
+ for ( & ty , & variance ) in substs . types . iter ( ) . zip ( variances . types . iter ( ) ) {
309
+ match variance {
310
+ ty :: Covariant | ty :: Invariant => {
311
+ // If any data of this type is reachable within,
312
+ // it must be at least covariant.
313
+ self . accumulate_from_ty ( ty ) ;
320
314
}
315
+ ty:: Contravariant | ty:: Bivariant => { }
321
316
}
322
317
}
323
318
}
324
319
320
+ /// Given that there is a requirement that `Foo<X> : 'a`, where
321
+ /// `Foo` is declared like `struct Foo<T> where T : SomeTrait`,
322
+ /// this code finds all the associated types defined in
323
+ /// `SomeTrait` (and supertraits) and adds a requirement that `<X
324
+ /// as SomeTrait>::N : 'a` (where `N` is some associated type
325
+ /// defined in `SomeTrait`). This rule only applies to
326
+ /// trait-bounds that are not higher-ranked, because we cannot
327
+ /// project out of a HRTB. This rule helps code using associated
328
+ /// types to compile, see Issue #22246 for an example.
329
+ fn accumulate_from_assoc_types_transitive ( & mut self ,
330
+ data : & ty:: PolyTraitPredicate < ' tcx > )
331
+ {
332
+ for poly_trait_ref in traits:: supertraits ( self . tcx ( ) , data. to_poly_trait_ref ( ) ) {
333
+ match ty:: no_late_bound_regions ( self . tcx ( ) , & poly_trait_ref) {
334
+ Some ( trait_ref) => { self . accumulate_from_assoc_types ( trait_ref) ; }
335
+ None => { }
336
+ }
337
+ }
338
+ }
339
+
340
+ fn accumulate_from_assoc_types ( & mut self ,
341
+ trait_ref : Rc < ty:: TraitRef < ' tcx > > )
342
+ {
343
+ let trait_def_id = trait_ref. def_id ;
344
+ let trait_def = ty:: lookup_trait_def ( self . tcx ( ) , trait_def_id) ;
345
+ let assoc_type_projections: Vec < _ > =
346
+ trait_def. associated_type_names
347
+ . iter ( )
348
+ . map ( |& name| ty:: mk_projection ( self . tcx ( ) , trait_ref. clone ( ) , name) )
349
+ . collect ( ) ;
350
+ let tys = match self . fully_normalize ( & assoc_type_projections) {
351
+ Ok ( tys) => { tys }
352
+ Err ( ErrorReported ) => { return ; }
353
+ } ;
354
+ for ty in tys {
355
+ self . accumulate_from_ty ( ty) ;
356
+ }
357
+ }
358
+
325
359
fn accumulate_from_object_ty ( & mut self ,
326
360
ty : Ty < ' tcx > ,
327
361
region_bound : ty:: Region ,
@@ -373,6 +407,28 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
373
407
self . out . push ( Implication :: RegionSubRegion ( Some ( ty) , r_d, r_c) ) ;
374
408
}
375
409
}
410
+
411
+ fn fully_normalize < T > ( & self , value : & T ) -> Result < T , ErrorReported >
412
+ where T : TypeFoldable < ' tcx > + ty:: HasProjectionTypes + Clone + Repr < ' tcx >
413
+ {
414
+ let value =
415
+ traits:: fully_normalize ( self . infcx ,
416
+ self . closure_typer ,
417
+ traits:: ObligationCause :: misc ( self . span , self . body_id ) ,
418
+ value) ;
419
+ match value {
420
+ Ok ( value) => Ok ( value) ,
421
+ Err ( errors) => {
422
+ // I don't like reporting these errors here, but I
423
+ // don't know where else to report them just now. And
424
+ // I don't really expect errors to arise here
425
+ // frequently. I guess the best option would be to
426
+ // propagate them out.
427
+ traits:: report_fulfillment_errors ( self . infcx , & errors) ;
428
+ Err ( ErrorReported )
429
+ }
430
+ }
431
+ }
376
432
}
377
433
378
434
impl < ' tcx > Repr < ' tcx > for Implication < ' tcx > {
@@ -389,6 +445,12 @@ impl<'tcx> Repr<'tcx> for Implication<'tcx> {
389
445
r. repr( tcx) ,
390
446
p. repr( tcx) )
391
447
}
448
+
449
+ Implication :: Predicate ( ref def_id, ref p) => {
450
+ format ! ( "Predicate({}, {})" ,
451
+ def_id. repr( tcx) ,
452
+ p. repr( tcx) )
453
+ }
392
454
}
393
455
}
394
456
}
0 commit comments