1111// #![warn(deprecated_mode)]
1212
1313use 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 } ;
1819
20+ use std:: rc:: Rc ;
1921use syntax:: ast;
22+ use syntax:: codemap:: Span ;
2023
24+ use util:: common:: ErrorReported ;
2125use util:: ppaux:: Repr ;
2226
2327// Helper functions related to manipulating region types.
2428
2529pub enum Implication < ' tcx > {
2630 RegionSubRegion ( Option < Ty < ' tcx > > , ty:: Region , ty:: Region ) ,
2731 RegionSubGeneric ( Option < Ty < ' tcx > > , ty:: Region , GenericKind < ' tcx > ) ,
32+ Predicate ( ast:: DefId , ty:: Predicate < ' tcx > ) ,
2833}
2934
3035struct 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 ,
3239 stack : Vec < ( ty:: Region , Option < Ty < ' tcx > > ) > ,
40+ span : Span ,
3341 out : Vec < Implication < ' tcx > > ,
3442}
3543
3644/// This routine computes the well-formedness constraints that must hold for the type `ty` to
3745/// 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 ,
4050 ty : Ty < ' tcx > ,
41- outer_region : ty:: Region )
51+ outer_region : ty:: Region ,
52+ span : Span )
4253 -> Vec < Implication < ' tcx > >
4354{
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+
4460 let mut stack = Vec :: new ( ) ;
4561 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 ( ) } ;
4968 wf. accumulate_from_ty ( ty) ;
69+ debug ! ( "implications: out={}" , wf. out. repr( closure_typer. tcx( ) ) ) ;
5070 wf. out
5171}
5272
5373impl < ' a , ' tcx > Implicator < ' a , ' tcx > {
74+ fn tcx ( & self ) -> & ' a ty:: ctxt < ' tcx > {
75+ self . infcx . tcx
76+ }
77+
5478 fn accumulate_from_ty ( & mut self , ty : Ty < ' tcx > ) {
5579 debug ! ( "accumulate_from_ty(ty={})" ,
56- ty. repr( self . tcx) ) ;
80+ ty. repr( self . tcx( ) ) ) ;
5781
5882 match ty. sty {
5983 ty:: ty_bool |
@@ -94,13 +118,13 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
94118
95119 ty:: ty_trait( ref t) => {
96120 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 ) ;
98122 self . accumulate_from_object_ty ( ty, t. bounds . region_bound , required_region_bounds)
99123 }
100124
101125 ty:: ty_enum( def_id, substs) |
102126 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) ;
104128 self . accumulate_from_adt ( ty, def_id, & item_scheme. generics , substs)
105129 }
106130
@@ -139,9 +163,9 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
139163 }
140164
141165 ty:: ty_open( _) => {
142- self . tcx . sess . bug (
166+ self . tcx ( ) . sess . bug (
143167 & format ! ( "Unexpected type encountered while doing wf check: {}" ,
144- ty. repr( self . tcx) ) [ ] ) ;
168+ ty. repr( self . tcx( ) ) ) [ ] ) ;
145169 }
146170 }
147171 }
@@ -225,103 +249,113 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
225249 fn accumulate_from_adt ( & mut self ,
226250 ty : Ty < ' tcx > ,
227251 def_id : ast:: DefId ,
228- generics : & ty:: Generics < ' tcx > ,
252+ _generics : & ty:: Generics < ' tcx > ,
229253 substs : & Substs < ' tcx > )
230254 {
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+ }
271275 }
272276 }
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+ }
286286 }
287287 }
288+ }
288289
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) ;
308294
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)
312303 }
304+ ty:: Covariant | ty:: Bivariant => { }
305+ }
306+ }
313307
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 ) ;
320314 }
315+ ty:: Contravariant | ty:: Bivariant => { }
321316 }
322317 }
323318 }
324319
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+
325359 fn accumulate_from_object_ty ( & mut self ,
326360 ty : Ty < ' tcx > ,
327361 region_bound : ty:: Region ,
@@ -373,6 +407,28 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
373407 self . out . push ( Implication :: RegionSubRegion ( Some ( ty) , r_d, r_c) ) ;
374408 }
375409 }
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+ }
376432}
377433
378434impl < ' tcx > Repr < ' tcx > for Implication < ' tcx > {
@@ -389,6 +445,12 @@ impl<'tcx> Repr<'tcx> for Implication<'tcx> {
389445 r. repr( tcx) ,
390446 p. repr( tcx) )
391447 }
448+
449+ Implication :: Predicate ( ref def_id, ref p) => {
450+ format ! ( "Predicate({}, {})" ,
451+ def_id. repr( tcx) ,
452+ p. repr( tcx) )
453+ }
392454 }
393455 }
394456}
0 commit comments