@@ -15,7 +15,10 @@ use dataflow::move_paths::{HasMoveData, MoveData};
1515use rustc:: mir:: { BasicBlock , Location , Mir } ;
1616use rustc:: mir:: Local ;
1717use rustc:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
18+ use rustc:: traits;
19+ use rustc:: infer:: InferOk ;
1820use rustc:: util:: common:: ErrorReported ;
21+ use borrow_check:: nll:: type_check:: AtLocation ;
1922use rustc_data_structures:: fx:: FxHashSet ;
2023use syntax:: codemap:: DUMMY_SP ;
2124use util:: liveness:: LivenessResults ;
@@ -184,48 +187,86 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
184187 location
185188 ) ;
186189
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 ( ) ;
210211
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 ;
222220 }
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+ }
223234
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+ }
227256 }
228257 }
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) ;
229270 }
230271 }
231272}
0 commit comments