@@ -13,10 +13,14 @@ use borrow_check::nll::type_check::AtLocation;
13
13
use dataflow:: move_paths:: { HasMoveData , MoveData } ;
14
14
use dataflow:: MaybeInitializedPlaces ;
15
15
use dataflow:: { FlowAtLocation , FlowsAtLocation } ;
16
- use rustc:: infer:: InferOk ;
16
+ use rustc:: infer:: region_constraints :: RegionConstraintData ;
17
17
use rustc:: mir:: Local ;
18
18
use rustc:: mir:: { BasicBlock , Location , Mir } ;
19
- use rustc:: ty:: { Ty , TyCtxt , TypeFoldable } ;
19
+ use rustc:: ty:: subst:: Kind ;
20
+ use rustc:: ty:: { Ty , TypeFoldable } ;
21
+ use rustc_data_structures:: fx:: FxHashMap ;
22
+ use std:: rc:: Rc ;
23
+ use syntax:: codemap:: DUMMY_SP ;
20
24
use util:: liveness:: LivenessResults ;
21
25
22
26
use super :: TypeChecker ;
@@ -36,14 +40,13 @@ pub(super) fn generate<'gcx, 'tcx>(
36
40
flow_inits : & mut FlowAtLocation < MaybeInitializedPlaces < ' _ , ' gcx , ' tcx > > ,
37
41
move_data : & MoveData < ' tcx > ,
38
42
) {
39
- let tcx = cx. tcx ( ) ;
40
43
let mut generator = TypeLivenessGenerator {
41
44
cx,
42
- tcx,
43
45
mir,
44
46
liveness,
45
47
flow_inits,
46
48
move_data,
49
+ drop_data : FxHashMap ( ) ,
47
50
} ;
48
51
49
52
for bb in mir. basic_blocks ( ) . indices ( ) {
@@ -59,11 +62,16 @@ where
59
62
' gcx : ' tcx ,
60
63
{
61
64
cx : & ' gen mut TypeChecker < ' typeck , ' gcx , ' tcx > ,
62
- tcx : TyCtxt < ' typeck , ' gcx , ' tcx > ,
63
65
mir : & ' gen Mir < ' tcx > ,
64
66
liveness : & ' gen LivenessResults ,
65
67
flow_inits : & ' gen mut FlowAtLocation < MaybeInitializedPlaces < ' flow , ' gcx , ' tcx > > ,
66
68
move_data : & ' gen MoveData < ' tcx > ,
69
+ drop_data : FxHashMap < Local , DropData < ' tcx > > ,
70
+ }
71
+
72
+ struct DropData < ' tcx > {
73
+ dropped_kinds : Vec < Kind < ' tcx > > ,
74
+ region_constraint_data : Option < Rc < RegionConstraintData < ' tcx > > > ,
67
75
}
68
76
69
77
impl < ' gen , ' typeck , ' flow , ' gcx , ' tcx > TypeLivenessGenerator < ' gen , ' typeck , ' flow , ' gcx , ' tcx > {
@@ -80,7 +88,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
80
88
for live_local in live_locals. iter ( ) {
81
89
let live_local_ty = self . mir . local_decls [ live_local] . ty ;
82
90
let cause = Cause :: LiveVar ( live_local, location) ;
83
- self . push_type_live_constraint ( live_local_ty, location, cause) ;
91
+ Self :: push_type_live_constraint ( & mut self . cx , live_local_ty, location, cause) ;
84
92
}
85
93
} ) ;
86
94
@@ -148,17 +156,21 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
148
156
/// `location` -- i.e., it may be used later. This means that all
149
157
/// regions appearing in the type `live_ty` must be live at
150
158
/// `location`.
151
- fn push_type_live_constraint < T > ( & mut self , value : T , location : Location , cause : Cause )
152
- where
159
+ fn push_type_live_constraint < T > (
160
+ cx : & mut TypeChecker < ' _ , ' gcx , ' tcx > ,
161
+ value : T ,
162
+ location : Location ,
163
+ cause : Cause ,
164
+ ) where
153
165
T : TypeFoldable < ' tcx > ,
154
166
{
155
167
debug ! (
156
168
"push_type_live_constraint(live_ty={:?}, location={:?})" ,
157
169
value, location
158
170
) ;
159
171
160
- self . tcx . for_each_free_region ( & value, |live_region| {
161
- self . cx
172
+ cx . tcx ( ) . for_each_free_region ( & value, |live_region| {
173
+ cx
162
174
. constraints
163
175
. liveness_set
164
176
. push ( ( live_region, location, cause. clone ( ) ) ) ;
@@ -182,53 +194,47 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
182
194
dropped_local, dropped_ty, location
183
195
) ;
184
196
185
- // If we end visiting the same type twice (usually due to a cycle involving
186
- // associated types), we need to ensure that its region types match up with the type
187
- // we added to the 'known' map the first time around. For this reason, we need
188
- // our infcx to hold onto its calculated region constraints after each call
189
- // to dtorck_constraint_for_ty. Otherwise, normalizing the corresponding associated
190
- // type will end up instantiating the type with a new set of inference variables
191
- // Since this new type will never be in 'known', we end up looping forever.
192
- //
193
- // For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
194
- // ourselves in one large 'fully_perform_op' callback.
195
- let kind_constraints = self
196
- . cx
197
- . fully_perform_op (
198
- location. at_self ( ) ,
199
- || format ! ( "add_drop_live_constraint(dropped_ty={:?})" , dropped_ty) ,
200
- |cx| {
201
- let span = cx. last_span ;
197
+ let drop_data = self . drop_data . entry ( dropped_local) . or_insert_with ( {
198
+ let cx = & mut self . cx ;
199
+ move || Self :: compute_drop_data ( cx, dropped_ty)
200
+ } ) ;
202
201
203
- let mut final_obligations = Vec :: new ( ) ;
204
- let mut kind_constraints = Vec :: new ( ) ;
202
+ if let Some ( data) = & drop_data. region_constraint_data {
203
+ self . cx
204
+ . push_region_constraints ( location. at_self ( ) , data. clone ( ) ) ;
205
+ }
205
206
206
- let InferOk {
207
- value : kinds,
208
- obligations,
209
- } = cx
207
+ // All things in the `outlives` array may be touched by
208
+ // the destructor and must be live at this point.
209
+ let cause = Cause :: DropVar ( dropped_local, location) ;
210
+ for & kind in & drop_data. dropped_kinds {
211
+ Self :: push_type_live_constraint ( & mut self . cx , kind, location, cause) ;
212
+ }
213
+ }
214
+
215
+ #[ inline( never) ]
216
+ fn compute_drop_data (
217
+ cx : & mut TypeChecker < ' _ , ' gcx , ' tcx > ,
218
+ dropped_ty : Ty < ' tcx > ,
219
+ ) -> DropData < ' tcx > {
220
+ debug ! ( "compute_drop_data(dropped_ty={:?})" , dropped_ty, ) ;
221
+
222
+ let ( dropped_kinds, region_constraint_data) =
223
+ cx. fully_perform_op_and_get_region_constraint_data (
224
+ || format ! ( "compute_drop_data(dropped_ty={:?})" , dropped_ty) ,
225
+ |cx| {
226
+ // crappy span, but I don't think it really matters
227
+ let span = DUMMY_SP ;
228
+ Ok ( cx
210
229
. infcx
211
230
. at ( & cx. misc ( span) , cx. param_env )
212
- . dropck_outlives ( dropped_ty) ;
213
- for kind in kinds {
214
- // All things in the `outlives` array may be touched by
215
- // the destructor and must be live at this point.
216
- let cause = Cause :: DropVar ( dropped_local, location) ;
217
- kind_constraints. push ( ( kind, location, cause) ) ;
218
- }
219
-
220
- final_obligations. extend ( obligations) ;
221
-
222
- Ok ( InferOk {
223
- value : kind_constraints,
224
- obligations : final_obligations,
225
- } )
231
+ . dropck_outlives ( dropped_ty) )
226
232
} ,
227
- )
228
- . unwrap ( ) ;
233
+ ) . unwrap ( ) ;
229
234
230
- for ( kind, location, cause) in kind_constraints {
231
- self . push_type_live_constraint ( kind, location, cause) ;
235
+ DropData {
236
+ dropped_kinds,
237
+ region_constraint_data,
232
238
}
233
239
}
234
240
}
0 commit comments