@@ -15,7 +15,10 @@ use dataflow::move_paths::{HasMoveData, MoveData};
15
15
use rustc:: mir:: { BasicBlock , Location , Mir } ;
16
16
use rustc:: mir:: Local ;
17
17
use rustc:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
18
+ use rustc:: traits;
19
+ use rustc:: infer:: InferOk ;
18
20
use rustc:: util:: common:: ErrorReported ;
21
+ use borrow_check:: nll:: type_check:: AtLocation ;
19
22
use rustc_data_structures:: fx:: FxHashSet ;
20
23
use syntax:: codemap:: DUMMY_SP ;
21
24
use util:: liveness:: LivenessResults ;
@@ -184,48 +187,86 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
184
187
location
185
188
) ;
186
189
187
- let tcx = self . cx . infcx . tcx ;
188
- let mut types = vec ! [ ( dropped_ty, 0 ) ] ;
189
- let mut known = FxHashSet ( ) ;
190
- while let Some ( ( ty, depth) ) = types. pop ( ) {
191
- let span = DUMMY_SP ; // FIXME
192
- let result = match tcx. dtorck_constraint_for_ty ( span, dropped_ty, depth, ty) {
193
- Ok ( result) => result,
194
- Err ( ErrorReported ) => {
195
- continue ;
196
- }
197
- } ;
198
-
199
- let ty:: DtorckConstraint {
200
- outlives,
201
- dtorck_types,
202
- } = result;
203
-
204
- // All things in the `outlives` array may be touched by
205
- // the destructor and must be live at this point.
206
- for outlive in outlives {
207
- let cause = Cause :: DropVar ( dropped_local, location) ;
208
- self . push_type_live_constraint ( outlive, location, cause) ;
209
- }
190
+ // If we end visiting the same type twice (usually due to a cycle involving
191
+ // associated types), we need to ensure that its region types match up with the type
192
+ // we added to the 'known' map the first time around. For this reason, we need
193
+ // our infcx to hold onto its calculated region constraints after each call
194
+ // to dtorck_constraint_for_ty. Otherwise, normalizing the corresponding associated
195
+ // type will end up instantiating the type with a new set of inference variables
196
+ // Since this new type will never be in 'known', we end up looping forever.
197
+ //
198
+ // For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
199
+ // ourselves in one large 'fully_perform_op' callback.
200
+ let ( type_constraints, kind_constraints) = self . cx . fully_perform_op ( location. at_self ( ) ,
201
+ |cx| {
202
+
203
+ let tcx = cx. infcx . tcx ;
204
+ let mut selcx = traits:: SelectionContext :: new ( cx. infcx ) ;
205
+ let cause = cx. misc ( cx. last_span ) ;
206
+
207
+ let mut types = vec ! [ ( dropped_ty, 0 ) ] ;
208
+ let mut final_obligations = Vec :: new ( ) ;
209
+ let mut type_constraints = Vec :: new ( ) ;
210
+ let mut kind_constraints = Vec :: new ( ) ;
210
211
211
- // However, there may also be some types that
212
- // `dtorck_constraint_for_ty` could not resolve (e.g.,
213
- // associated types and parameters). We need to normalize
214
- // associated types here and possibly recursively process.
215
- for ty in dtorck_types {
216
- let ty = self . cx . normalize ( & ty, location) ;
217
- let ty = self . cx . infcx . resolve_type_and_region_vars_if_possible ( & ty) ;
218
- match ty. sty {
219
- ty:: TyParam ( ..) | ty:: TyProjection ( ..) | ty:: TyAnon ( ..) => {
220
- let cause = Cause :: DropVar ( dropped_local, location) ;
221
- self . push_type_live_constraint ( ty, location, cause) ;
212
+ let mut known = FxHashSet ( ) ;
213
+
214
+ while let Some ( ( ty, depth) ) = types. pop ( ) {
215
+ let span = DUMMY_SP ; // FIXME
216
+ let result = match tcx. dtorck_constraint_for_ty ( span, dropped_ty, depth, ty) {
217
+ Ok ( result) => result,
218
+ Err ( ErrorReported ) => {
219
+ continue ;
222
220
}
221
+ } ;
222
+
223
+ let ty:: DtorckConstraint {
224
+ outlives,
225
+ dtorck_types,
226
+ } = result;
227
+
228
+ // All things in the `outlives` array may be touched by
229
+ // the destructor and must be live at this point.
230
+ for outlive in outlives {
231
+ let cause = Cause :: DropVar ( dropped_local, location) ;
232
+ kind_constraints. push ( ( outlive, location, cause) ) ;
233
+ }
223
234
224
- _ => if known. insert ( ty) {
225
- types. push ( ( ty, depth + 1 ) ) ;
226
- } ,
235
+ // However, there may also be some types that
236
+ // `dtorck_constraint_for_ty` could not resolve (e.g.,
237
+ // associated types and parameters). We need to normalize
238
+ // associated types here and possibly recursively process.
239
+ for ty in dtorck_types {
240
+ let traits:: Normalized { value : ty, obligations } =
241
+ traits:: normalize ( & mut selcx, cx. param_env , cause. clone ( ) , & ty) ;
242
+
243
+ final_obligations. extend ( obligations) ;
244
+
245
+ let ty = cx. infcx . resolve_type_and_region_vars_if_possible ( & ty) ;
246
+ match ty. sty {
247
+ ty:: TyParam ( ..) | ty:: TyProjection ( ..) | ty:: TyAnon ( ..) => {
248
+ let cause = Cause :: DropVar ( dropped_local, location) ;
249
+ type_constraints. push ( ( ty, location, cause) ) ;
250
+ }
251
+
252
+ _ => if known. insert ( ty) {
253
+ types. push ( ( ty, depth + 1 ) ) ;
254
+ } ,
255
+ }
227
256
}
228
257
}
258
+
259
+ Ok ( InferOk {
260
+ value : ( type_constraints, kind_constraints) , obligations : final_obligations
261
+ } )
262
+ } ) . unwrap ( ) ;
263
+
264
+ for ( ty, location, cause) in type_constraints {
265
+ self . push_type_live_constraint ( ty, location, cause) ;
266
+ }
267
+
268
+ for ( kind, location, cause) in kind_constraints {
269
+ self . push_type_live_constraint ( kind, location, cause) ;
229
270
}
230
271
}
231
272
}
0 commit comments