@@ -13,10 +13,13 @@ use rustc_hir::def_id::DefId;
1313use rustc_hir:: hir_id:: HirIdSet ;
1414use rustc_hir:: intravisit:: { self , Visitor } ;
1515use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind } ;
16+ use rustc_infer:: infer:: RegionVariableOrigin ;
1617use rustc_middle:: middle:: region:: { self , Scope , ScopeData , YieldData } ;
17- use rustc_middle:: ty:: { self , RvalueScopes , Ty , TyCtxt , TypeVisitable } ;
18+ use rustc_middle:: ty:: fold:: FnMutDelegate ;
19+ use rustc_middle:: ty:: { self , BoundVariableKind , RvalueScopes , Ty , TyCtxt , TypeVisitable } ;
1820use rustc_span:: symbol:: sym;
1921use rustc_span:: Span ;
22+ use smallvec:: { smallvec, SmallVec } ;
2023
2124mod drop_ranges;
2225
@@ -211,43 +214,96 @@ pub fn resolve_interior<'a, 'tcx>(
211214
212215 debug ! ( "types in generator {:?}, span = {:?}" , types, body. value. span) ;
213216
214- let mut counter = 0 ;
217+ // We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
218+ // So, we need to actually do two passes: first by type to anonymize (preserving information
219+ // required for diagnostics), then a second pass over all captured types to reassign disjoint
220+ // region indices.
215221 let mut captured_tys = FxHashSet :: default ( ) ;
216222 let type_causes: Vec < _ > = types
217223 . into_iter ( )
218224 . filter_map ( |mut cause| {
219- // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
220- // can.
225+ // Replace all regions inside the generator interior with late bound regions.
226+ // Note that each region slot in the types gets a new fresh late bound region,
227+ // which means that none of the regions inside relate to any other, even if
228+ // typeck had previously found constraints that would cause them to be related.
229+
230+ let mut counter = 0 ;
231+ let mut mk_bound_region = |span| {
232+ let kind = ty:: BrAnon ( counter, span) ;
233+ let var = ty:: BoundVar :: from_u32 ( counter) ;
234+ counter += 1 ;
235+ ty:: BoundRegion { var, kind }
236+ } ;
221237 let ty = fcx. normalize_associated_types_in ( cause. span , cause. ty ) ;
222- let erased = fcx. tcx . erase_regions ( ty) ;
223- if captured_tys. insert ( erased) {
224- // Replace all regions inside the generator interior with late bound regions.
225- // Note that each region slot in the types gets a new fresh late bound region,
226- // which means that none of the regions inside relate to any other, even if
227- // typeck had previously found constraints that would cause them to be related.
228- let folded = fcx. tcx . fold_regions ( erased, |_, current_depth| {
229- let br = ty:: BoundRegion {
230- var : ty:: BoundVar :: from_u32 ( counter) ,
231- kind : ty:: BrAnon ( counter) ,
232- } ;
233- let r = fcx. tcx . mk_region ( ty:: ReLateBound ( current_depth, br) ) ;
234- counter += 1 ;
235- r
236- } ) ;
237-
238- cause. ty = folded;
238+ let ty = fcx. tcx . fold_regions ( ty, |region, current_depth| {
239+ let br = match region. kind ( ) {
240+ ty:: ReVar ( vid) => {
241+ let origin = fcx. region_var_origin ( vid) ;
242+ match origin {
243+ RegionVariableOrigin :: EarlyBoundRegion ( span, _) => {
244+ mk_bound_region ( Some ( span) )
245+ }
246+ _ => mk_bound_region ( None ) ,
247+ }
248+ }
249+ // FIXME: these should use `BrNamed`
250+ ty:: ReEarlyBound ( region) => {
251+ mk_bound_region ( Some ( fcx. tcx . def_span ( region. def_id ) ) )
252+ }
253+ ty:: ReLateBound ( _, ty:: BoundRegion { kind, .. } )
254+ | ty:: ReFree ( ty:: FreeRegion { bound_region : kind, .. } ) => match kind {
255+ ty:: BoundRegionKind :: BrAnon ( _, span) => mk_bound_region ( span) ,
256+ ty:: BoundRegionKind :: BrNamed ( def_id, _) => {
257+ mk_bound_region ( Some ( fcx. tcx . def_span ( def_id) ) )
258+ }
259+ ty:: BoundRegionKind :: BrEnv => mk_bound_region ( None ) ,
260+ } ,
261+ _ => mk_bound_region ( None ) ,
262+ } ;
263+ let r = fcx. tcx . mk_region ( ty:: ReLateBound ( current_depth, br) ) ;
264+ r
265+ } ) ;
266+ if captured_tys. insert ( ty) {
267+ cause. ty = ty;
239268 Some ( cause)
240269 } else {
241270 None
242271 }
243272 } )
244273 . collect ( ) ;
245274
275+ let mut bound_vars: SmallVec < [ BoundVariableKind ; 4 ] > = smallvec ! [ ] ;
276+ let mut counter = 0 ;
277+ // Optimization: If there is only one captured type, then we don't actually
278+ // need to fold and reindex (since the first type doesn't change).
279+ let type_causes = if captured_tys. len ( ) > 0 {
280+ // Optimization: Use `replace_escaping_bound_vars_uncached` instead of
281+ // `fold_regions`, since we only have late bound regions, and it skips
282+ // types without bound regions.
283+ fcx. tcx . replace_escaping_bound_vars_uncached (
284+ type_causes,
285+ FnMutDelegate {
286+ regions : & mut |br| {
287+ let kind = match br. kind {
288+ ty:: BrAnon ( _, span) => ty:: BrAnon ( counter, span) ,
289+ _ => br. kind ,
290+ } ;
291+ let var = ty:: BoundVar :: from_usize ( bound_vars. len ( ) ) ;
292+ bound_vars. push ( ty:: BoundVariableKind :: Region ( kind) ) ;
293+ counter += 1 ;
294+ fcx. tcx . mk_region ( ty:: ReLateBound ( ty:: INNERMOST , ty:: BoundRegion { var, kind } ) )
295+ } ,
296+ types : & mut |b| bug ! ( "unexpected bound ty in binder: {b:?}" ) ,
297+ consts : & mut |b, ty| bug ! ( "unexpected bound ct in binder: {b:?} {ty}" ) ,
298+ } ,
299+ )
300+ } else {
301+ type_causes
302+ } ;
303+
246304 // Extract type components to build the witness type.
247305 let type_list = fcx. tcx . mk_type_list ( type_causes. iter ( ) . map ( |cause| cause. ty ) ) ;
248- let bound_vars = fcx. tcx . mk_bound_variable_kinds (
249- ( 0 ..counter) . map ( |i| ty:: BoundVariableKind :: Region ( ty:: BrAnon ( i) ) ) ,
250- ) ;
306+ let bound_vars = fcx. tcx . mk_bound_variable_kinds ( bound_vars. iter ( ) ) ;
251307 let witness =
252308 fcx. tcx . mk_generator_witness ( ty:: Binder :: bind_with_vars ( type_list, bound_vars. clone ( ) ) ) ;
253309
0 commit comments