15
15
16
16
use hir:: def_id:: DefId ;
17
17
use middle:: resolve_lifetime as rl;
18
+ use rustc:: dep_graph:: { AssertDepGraphSafe , DepNode } ;
18
19
use rustc:: ty:: subst:: Substs ;
19
20
use rustc:: ty:: { self , Ty , TyCtxt } ;
20
21
use rustc:: hir:: map as hir_map;
21
22
use syntax:: ast;
22
23
use rustc:: hir;
23
24
use rustc:: hir:: itemlikevisit:: ItemLikeVisitor ;
24
25
26
+ use rustc_data_structures:: transitive_relation:: TransitiveRelation ;
27
+
25
28
use super :: terms:: * ;
26
29
use super :: terms:: VarianceTerm :: * ;
27
30
use super :: xform:: * ;
28
31
29
- use dep_graph:: DepNode :: ItemSignature as VarianceDepNode ;
30
-
31
32
pub struct ConstraintContext < ' a , ' tcx : ' a > {
32
33
pub terms_cx : TermsContext < ' a , ' tcx > ,
33
34
@@ -38,6 +39,11 @@ pub struct ConstraintContext<'a, 'tcx: 'a> {
38
39
bivariant : VarianceTermPtr < ' a > ,
39
40
40
41
pub constraints : Vec < Constraint < ' a > > ,
42
+
43
+ /// This relation tracks the dependencies between the variance of
44
+ /// various items. In particular, if `a < b`, then the variance of
45
+ /// `a` depends on the sources of `b`.
46
+ pub dependencies : TransitiveRelation < DefId > ,
41
47
}
42
48
43
49
/// Declares that the variable `decl_id` appears in a location with
@@ -57,7 +63,6 @@ pub struct Constraint<'a> {
57
63
///
58
64
/// then while we are visiting `Bar<T>`, the `CurrentItem` would have
59
65
/// the def-id and generics of `Foo`.
60
- #[ allow( dead_code) ] // TODO -- `def_id` field not used yet
61
66
pub struct CurrentItem < ' a > {
62
67
def_id : DefId ,
63
68
generics : & ' a ty:: Generics ,
@@ -77,10 +82,10 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
77
82
invariant : invariant,
78
83
bivariant : bivariant,
79
84
constraints : Vec :: new ( ) ,
85
+ dependencies : TransitiveRelation :: new ( ) ,
80
86
} ;
81
87
82
- // See README.md for a discussion on dep-graph management.
83
- tcx. visit_all_item_likes_in_krate ( VarianceDepNode , & mut constraint_cx) ;
88
+ tcx. hir . krate ( ) . visit_all_item_likes ( & mut constraint_cx) ;
84
89
85
90
constraint_cx
86
91
}
@@ -90,13 +95,64 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
90
95
let tcx = self . terms_cx . tcx ;
91
96
let def_id = tcx. hir . local_def_id ( item. id ) ;
92
97
98
+ // Encapsulate constructing the constraints into a task we can
99
+ // reference later. This can go away once the red-green
100
+ // algorithm is in place.
101
+ //
102
+ // See README.md for a detailed discussion
103
+ // on dep-graph management.
104
+ match item. node {
105
+ hir:: ItemEnum ( ..) |
106
+ hir:: ItemStruct ( ..) |
107
+ hir:: ItemUnion ( ..) => {
108
+ tcx. dep_graph . with_task ( DepNode :: ItemVarianceConstraints ( def_id) ,
109
+ AssertDepGraphSafe ( self ) ,
110
+ def_id,
111
+ visit_item_task) ;
112
+ }
113
+ _ => {
114
+ // Nothing to do here, skip the task.
115
+ }
116
+ }
117
+
118
+ fn visit_item_task < ' a , ' tcx > ( ccx : AssertDepGraphSafe < & mut ConstraintContext < ' a , ' tcx > > ,
119
+ def_id : DefId )
120
+ {
121
+ ccx. 0 . build_constraints_for_item ( def_id) ;
122
+ }
123
+ }
124
+
125
+ fn visit_trait_item ( & mut self , _trait_item : & hir:: TraitItem ) {
126
+ }
127
+
128
+ fn visit_impl_item ( & mut self , _impl_item : & hir:: ImplItem ) {
129
+ }
130
+ }
131
+
132
+ /// Is `param_id` a lifetime according to `map`?
133
+ fn is_lifetime ( map : & hir_map:: Map , param_id : ast:: NodeId ) -> bool {
134
+ match map. find ( param_id) {
135
+ Some ( hir_map:: NodeLifetime ( ..) ) => true ,
136
+ _ => false ,
137
+ }
138
+ }
139
+
140
+ impl < ' a , ' tcx > ConstraintContext < ' a , ' tcx > {
141
+ fn tcx ( & self ) -> TyCtxt < ' a , ' tcx , ' tcx > {
142
+ self . terms_cx . tcx
143
+ }
144
+
145
+ fn build_constraints_for_item ( & mut self , def_id : DefId ) {
146
+ let tcx = self . tcx ( ) ;
147
+ let id = self . tcx ( ) . hir . as_local_node_id ( def_id) . unwrap ( ) ;
148
+ let item = tcx. hir . expect_item ( id) ;
93
149
debug ! ( "visit_item item={}" , tcx. hir. node_to_string( item. id) ) ;
94
150
95
151
match item. node {
96
152
hir:: ItemEnum ( ..) |
97
153
hir:: ItemStruct ( ..) |
98
154
hir:: ItemUnion ( ..) => {
99
- let generics = tcx. generics_of ( did ) ;
155
+ let generics = tcx. generics_of ( def_id ) ;
100
156
let current_item = & CurrentItem { def_id, generics } ;
101
157
102
158
// Not entirely obvious: constraints on structs/enums do not
@@ -105,24 +161,14 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
105
161
//
106
162
// self.add_constraints_from_generics(generics);
107
163
108
- for field in tcx. adt_def ( did ) . all_fields ( ) {
164
+ for field in tcx. adt_def ( def_id ) . all_fields ( ) {
109
165
self . add_constraints_from_ty ( current_item,
110
- tcx. item_type ( field. did ) ,
166
+ tcx. type_of ( field. did ) ,
111
167
self . covariant ) ;
112
168
}
113
169
}
114
- hir:: ItemTrait ( ..) => {
115
- let generics = tcx. generics_of ( did) ;
116
- let current_item = & CurrentItem { def_id, generics } ;
117
- let trait_ref = ty:: TraitRef {
118
- def_id : def_id,
119
- substs : Substs :: identity_for_item ( tcx, def_id)
120
- } ;
121
- self . add_constraints_from_trait_ref ( current_item,
122
- trait_ref,
123
- self . invariant ) ;
124
- }
125
170
171
+ hir:: ItemTrait ( ..) |
126
172
hir:: ItemExternCrate ( _) |
127
173
hir:: ItemUse ( ..) |
128
174
hir:: ItemStatic ( ..) |
@@ -133,38 +179,25 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
133
179
hir:: ItemGlobalAsm ( ..) |
134
180
hir:: ItemTy ( ..) |
135
181
hir:: ItemImpl ( ..) |
136
- hir:: ItemDefaultImpl ( ..) => { }
182
+ hir:: ItemDefaultImpl ( ..) => {
183
+ span_bug ! ( item. span, "`build_constraints_for_item` invoked for non-type-def" ) ;
184
+ }
137
185
}
138
186
}
139
187
140
- fn visit_trait_item ( & mut self , _trait_item : & hir:: TraitItem ) {
141
- }
142
-
143
- fn visit_impl_item ( & mut self , _impl_item : & hir:: ImplItem ) {
144
- }
145
- }
146
-
147
- /// Is `param_id` a lifetime according to `map`?
148
- fn is_lifetime ( map : & hir_map:: Map , param_id : ast:: NodeId ) -> bool {
149
- match map. find ( param_id) {
150
- Some ( hir_map:: NodeLifetime ( ..) ) => true ,
151
- _ => false ,
152
- }
153
- }
154
-
155
- impl < ' a , ' tcx > ConstraintContext < ' a , ' tcx > {
156
- fn tcx ( & self ) -> TyCtxt < ' a , ' tcx , ' tcx > {
157
- self . terms_cx . tcx
188
+ /// Load the generics for another item, adding a corresponding
189
+ /// relation into the dependencies to indicate that the variance
190
+ /// for `current` relies on `def_id`.
191
+ fn read_generics ( & mut self , current : & CurrentItem , def_id : DefId ) -> & ' tcx ty:: Generics {
192
+ let generics = self . tcx ( ) . generics_of ( def_id) ;
193
+ if self . tcx ( ) . dep_graph . is_fully_enabled ( ) {
194
+ self . dependencies . add ( current. def_id , def_id) ;
195
+ }
196
+ generics
158
197
}
159
198
160
- fn inferred_index ( & self , param_id : ast:: NodeId ) -> InferredIndex {
161
- match self . terms_cx . inferred_map . get ( & param_id) {
162
- Some ( & index) => index,
163
- None => {
164
- bug ! ( "no inferred index entry for {}" ,
165
- self . tcx( ) . hir. node_to_string( param_id) ) ;
166
- }
167
- }
199
+ fn opt_inferred_index ( & self , param_id : ast:: NodeId ) -> Option < & InferredIndex > {
200
+ self . terms_cx . inferred_map . get ( & param_id)
168
201
}
169
202
170
203
fn find_binding_for_lifetime ( & self , param_id : ast:: NodeId ) -> ast:: NodeId {
@@ -245,8 +278,27 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
245
278
// Parameter on an item defined within current crate:
246
279
// variance not yet inferred, so return a symbolic
247
280
// variance.
248
- let InferredIndex ( index) = self . inferred_index ( param_node_id) ;
249
- self . terms_cx . inferred_infos [ index] . term
281
+ if let Some ( & InferredIndex ( index) ) = self . opt_inferred_index ( param_node_id) {
282
+ self . terms_cx . inferred_infos [ index] . term
283
+ } else {
284
+ // If there is no inferred entry for a type parameter,
285
+ // it must be declared on a (locally defiend) trait -- they don't
286
+ // get inferreds because they are always invariant.
287
+ if cfg ! ( debug_assertions) {
288
+ let item_node_id = self . tcx ( ) . hir . as_local_node_id ( item_def_id) . unwrap ( ) ;
289
+ let item = self . tcx ( ) . hir . expect_item ( item_node_id) ;
290
+ let success = match item. node {
291
+ hir:: ItemTrait ( ..) => true ,
292
+ _ => false ,
293
+ } ;
294
+ if !success {
295
+ bug ! ( "parameter {:?} has no inferred, but declared on non-trait: {:?}" ,
296
+ item_def_id,
297
+ item) ;
298
+ }
299
+ }
300
+ self . invariant
301
+ }
250
302
} else {
251
303
// Parameter on an item defined within another crate:
252
304
// variance already inferred, just look it up.
@@ -305,11 +357,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
305
357
306
358
let trait_generics = self . tcx ( ) . generics_of ( trait_ref. def_id ) ;
307
359
308
- // This edge is actually implied by the call to
309
- // `trait_def`, but I'm trying to be future-proof. See
310
- // README.md for a discussion on dep-graph management.
311
- self . tcx ( ) . dep_graph . read ( VarianceDepNode ( trait_ref. def_id ) ) ;
312
-
313
360
self . add_constraints_from_substs ( current,
314
361
trait_ref. def_id ,
315
362
& trait_generics. types ,
@@ -362,12 +409,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
362
409
}
363
410
364
411
ty:: TyAdt ( def, substs) => {
365
- let adt_generics = self . tcx ( ) . generics_of ( def. did ) ;
366
-
367
- // This edge is actually implied by the call to
368
- // `trait_def`, but I'm trying to be future-proof. See
369
- // README.md for a discussion on dep-graph management.
370
- self . tcx ( ) . dep_graph . read ( VarianceDepNode ( def. did ) ) ;
412
+ let adt_generics = self . read_generics ( current, def. did ) ;
371
413
372
414
self . add_constraints_from_substs ( current,
373
415
def. did ,
@@ -381,11 +423,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
381
423
let trait_ref = & data. trait_ref ;
382
424
let trait_generics = self . tcx ( ) . generics_of ( trait_ref. def_id ) ;
383
425
384
- // This edge is actually implied by the call to
385
- // `trait_def`, but I'm trying to be future-proof. See
386
- // README.md for a discussion on dep-graph management.
387
- self . tcx ( ) . dep_graph . read ( VarianceDepNode ( trait_ref. def_id ) ) ;
388
-
389
426
self . add_constraints_from_substs ( current,
390
427
trait_ref. def_id ,
391
428
& trait_generics. types ,
@@ -505,7 +542,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
505
542
let def_id = current. generics . regions [ i] . def_id ;
506
543
let node_id = self . tcx ( ) . hir . as_local_node_id ( def_id) . unwrap ( ) ;
507
544
if self . is_to_be_inferred ( node_id) {
508
- let index = self . inferred_index ( node_id) ;
545
+ let & index = self . opt_inferred_index ( node_id) . unwrap ( ) ;
509
546
self . add_constraint ( index, variance) ;
510
547
}
511
548
}
0 commit comments