@@ -270,13 +270,17 @@ impl<'tcx> UniversalRegions<'tcx> {
270
270
tcx : TyCtxt < ' _ , ' _ , ' tcx > ,
271
271
closure_ty : Ty < ' tcx > ,
272
272
expected_num_vars : usize ,
273
+ closure_base_def_id : DefId ,
273
274
) -> IndexVec < RegionVid , ty:: Region < ' tcx > > {
274
275
let mut region_mapping = IndexVec :: with_capacity ( expected_num_vars) ;
275
276
region_mapping. push ( tcx. types . re_static ) ;
276
277
tcx. for_each_free_region ( & closure_ty, |fr| {
277
278
region_mapping. push ( fr) ;
278
279
} ) ;
279
280
281
+ for_each_late_bound_region_defined_on (
282
+ tcx, closure_base_def_id, |r| { region_mapping. push ( r) ; } ) ;
283
+
280
284
assert_eq ! (
281
285
region_mapping. len( ) ,
282
286
expected_num_vars,
@@ -479,6 +483,20 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
479
483
let mut indices = self . compute_indices ( fr_static, defining_ty) ;
480
484
debug ! ( "build: indices={:?}" , indices) ;
481
485
486
+ let closure_base_def_id = self . infcx . tcx . closure_base_def_id ( self . mir_def_id ) ;
487
+
488
+ // If this is a closure or generator, then the late-bound regions from the enclosing
489
+ // function are actually external regions to us. For example, here, 'a is not local
490
+ // to the closure c (although it is local to the fn foo):
491
+ // fn foo<'a>() {
492
+ // let c = || { let x: &'a u32 = ...; }
493
+ // }
494
+ if self . mir_def_id != closure_base_def_id {
495
+ self . infcx . replace_late_bound_regions_with_nll_infer_vars (
496
+ self . mir_def_id ,
497
+ & mut indices)
498
+ }
499
+
482
500
let bound_inputs_and_output = self . compute_inputs_and_output ( & indices, defining_ty) ;
483
501
484
502
// "Liberate" the late-bound regions. These correspond to
@@ -490,6 +508,14 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
490
508
& bound_inputs_and_output,
491
509
& mut indices,
492
510
) ;
511
+ // Converse of above, if this is a function then the late-bound regions declared on its
512
+ // signature are local to the fn.
513
+ if self . mir_def_id == closure_base_def_id {
514
+ self . infcx . replace_late_bound_regions_with_nll_infer_vars (
515
+ self . mir_def_id ,
516
+ & mut indices) ;
517
+ }
518
+
493
519
let fr_fn_body = self . infcx . next_nll_region_var ( FR ) . to_region_vid ( ) ;
494
520
let num_universals = self . infcx . num_region_vars ( ) ;
495
521
@@ -782,6 +808,13 @@ trait InferCtxtExt<'tcx> {
782
808
) -> T
783
809
where
784
810
T : TypeFoldable < ' tcx > ;
811
+
812
+
813
+ fn replace_late_bound_regions_with_nll_infer_vars (
814
+ & self ,
815
+ mir_def_id : DefId ,
816
+ indices : & mut UniversalRegionIndices < ' tcx >
817
+ ) ;
785
818
}
786
819
787
820
impl < ' cx , ' gcx , ' tcx > InferCtxtExt < ' tcx > for InferCtxt < ' cx , ' gcx , ' tcx > {
@@ -827,6 +860,28 @@ impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> {
827
860
} ) ;
828
861
value
829
862
}
863
+
864
+ /// Finds late-bound regions that do not appear in the parameter listing and adds them to the
865
+ /// indices vector. Typically, we identify late-bound regions as we process the inputs and
866
+ /// outputs of the closure/function. However, sometimes there are late-bound regions which do
867
+ /// not appear in the fn parameters but which are nonetheless in scope. The simplest case of
868
+ /// this are unused functions, like fn foo<'a>() { } (see eg., #51351). Despite not being used,
869
+ /// users can still reference these regions (e.g., let x: &'a u32 = &22;), so we need to create
870
+ /// entries for them and store them in the indices map. This code iterates over the complete
871
+ /// set of late-bound regions and checks for any that we have not yet seen, adding them to the
872
+ /// inputs vector.
873
+ fn replace_late_bound_regions_with_nll_infer_vars (
874
+ & self ,
875
+ mir_def_id : DefId ,
876
+ indices : & mut UniversalRegionIndices < ' tcx > ,
877
+ ) {
878
+ let closure_base_def_id = self . tcx . closure_base_def_id ( mir_def_id) ;
879
+ for_each_late_bound_region_defined_on ( self . tcx , closure_base_def_id, |r| {
880
+ if !indices. indices . contains_key ( & r) {
881
+ let region_vid = self . next_nll_region_var ( FR ) ;
882
+ indices. insert_late_bound_region ( r, region_vid. to_region_vid ( ) ) ;
883
+ } } ) ;
884
+ }
830
885
}
831
886
832
887
impl < ' tcx > UniversalRegionIndices < ' tcx > {
@@ -882,3 +937,25 @@ impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegions<'tcx> {
882
937
self . outlives ( longer, shorter)
883
938
}
884
939
}
940
+
941
+ /// Iterates over the late-bound regions defined on fn_def_id and
942
+ /// invokes `f` with the liberated form of each one.
943
+ fn for_each_late_bound_region_defined_on < ' tcx > (
944
+ tcx : TyCtxt < ' _ , ' _ , ' tcx > ,
945
+ fn_def_id : DefId ,
946
+ mut f : impl FnMut ( ty:: Region < ' tcx > )
947
+ ) {
948
+ if let Some ( late_bounds) = tcx. is_late_bound_map ( fn_def_id. index ) {
949
+ for late_bound in late_bounds. iter ( ) {
950
+ let hir_id = HirId { owner : fn_def_id. index , local_id : * late_bound } ;
951
+ let region_node_id = tcx. hir . hir_to_node_id ( hir_id) ;
952
+ let name = tcx. hir . name ( region_node_id) . as_interned_str ( ) ;
953
+ let region_def_id = tcx. hir . local_def_id ( region_node_id) ;
954
+ let liberated_region = tcx. mk_region ( ty:: ReFree ( ty:: FreeRegion {
955
+ scope : fn_def_id,
956
+ bound_region : ty:: BoundRegion :: BrNamed ( region_def_id, name) ,
957
+ } ) ) ;
958
+ f ( liberated_region) ;
959
+ }
960
+ }
961
+ }
0 commit comments