@@ -13,10 +13,13 @@ use rustc_hir::def_id::DefId;
13
13
use rustc_hir:: hir_id:: HirIdSet ;
14
14
use rustc_hir:: intravisit:: { self , Visitor } ;
15
15
use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind } ;
16
+ use rustc_infer:: infer:: RegionVariableOrigin ;
16
17
use 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 } ;
18
20
use rustc_span:: symbol:: sym;
19
21
use rustc_span:: Span ;
22
+ use smallvec:: { smallvec, SmallVec } ;
20
23
21
24
mod drop_ranges;
22
25
@@ -211,43 +214,96 @@ pub fn resolve_interior<'a, 'tcx>(
211
214
212
215
debug ! ( "types in generator {:?}, span = {:?}" , types, body. value. span) ;
213
216
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.
215
221
let mut captured_tys = FxHashSet :: default ( ) ;
216
222
let type_causes: Vec < _ > = types
217
223
. into_iter ( )
218
224
. 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
+ } ;
221
237
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;
239
268
Some ( cause)
240
269
} else {
241
270
None
242
271
}
243
272
} )
244
273
. collect ( ) ;
245
274
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
+
246
304
// Extract type components to build the witness type.
247
305
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 ( ) ) ;
251
307
let witness =
252
308
fcx. tcx . mk_generator_witness ( ty:: Binder :: bind_with_vars ( type_list, bound_vars. clone ( ) ) ) ;
253
309
0 commit comments