Skip to content

mir borrowck: cleanup late-bound region handling #135479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion compiler/rustc_borrowck/src/renumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ pub(crate) enum RegionCtxt {
Location(Location),
TyContext(TyContext),
Free(Symbol),
Bound(Symbol),
LateBound(Symbol),
Existential(Option<Symbol>),
Placeholder(Symbol),
Expand Down
65 changes: 26 additions & 39 deletions compiler/rustc_borrowck/src/universal_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,15 +467,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
self.infcx.tcx.local_parent(self.mir_def),
|r| {
debug!(?r);
if !indices.indices.contains_key(&r) {
let region_vid = {
let name = r.get_name_or_anon();
self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};

debug!(?region_vid);
indices.insert_late_bound_region(r, region_vid.as_var());
}
let region_vid = {
let name = r.get_name_or_anon();
self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};

debug!(?region_vid);
indices.insert_late_bound_region(r, region_vid.as_var());
},
);

Expand All @@ -484,21 +482,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
self.infcx.num_region_vars()
};

// "Liberate" the late-bound regions. These correspond to
// "local" free regions.
// Converse of above, if this is a function/closure then the late-bound regions declared
// on its signature are local.
//
// We manually loop over `bound_inputs_and_output` instead of using
// `for_each_late_bound_region_in_item` as we may need to add the otherwise
// implicit `ClosureEnv` region.
let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);

let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
FR,
self.mir_def,
bound_inputs_and_output,
&mut indices,
);
// Converse of above, if this is a function/closure then the late-bound regions declared on its
// signature are local.
for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def, |r| {
debug!(?r);
if !indices.indices.contains_key(&r) {
for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() {
if let ty::BoundVariableKind::Region(kind) = bound_var {
let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind);
let r = ty::Region::new_late_param(self.infcx.tcx, self.mir_def.to_def_id(), kind);
let region_vid = {
let name = r.get_name_or_anon();
self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
Expand All @@ -507,7 +501,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
debug!(?region_vid);
indices.insert_late_bound_region(r, region_vid.as_var());
}
});
}
let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
self.mir_def,
bound_inputs_and_output,
&indices,
);

let (unnormalized_output_ty, mut unnormalized_input_tys) =
inputs_and_output.split_last().unwrap();
Expand Down Expand Up @@ -832,10 +831,9 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
#[instrument(level = "debug", skip(self, indices))]
fn replace_bound_regions_with_nll_infer_vars<T>(
&self,
origin: NllRegionVariableOrigin,
all_outlive_scope: LocalDefId,
value: ty::Binder<'tcx, T>,
indices: &mut UniversalRegionIndices<'tcx>,
indices: &UniversalRegionIndices<'tcx>,
) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
Expand All @@ -845,18 +843,7 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
let kind = ty::LateParamRegionKind::from_bound(br.var, br.kind);
let liberated_region =
ty::Region::new_late_param(self.tcx, all_outlive_scope.to_def_id(), kind);
let region_vid = {
let name = match br.kind.get_name() {
Some(name) => name,
_ => sym::anon,
};

self.next_nll_region_var(origin, || RegionCtxt::Bound(name))
};

indices.insert_late_bound_region(liberated_region, region_vid.as_var());
debug!(?liberated_region, ?region_vid);
region_vid
ty::Region::new_var(self.tcx, indices.to_region_vid(liberated_region))
});
value
}
Expand All @@ -870,7 +857,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
/// well. These are used for error reporting.
fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) {
debug!("insert_late_bound_region({:?}, {:?})", r, vid);
self.indices.insert(r, vid);
assert_eq!(self.indices.insert(r, vid), None);
}

/// Converts `r` into a local inference variable: `r` can either
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/closures/binder/nested-closures-regions.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
extern "rust-call" fn((&(),)),
(),
]
= note: late-bound region is '?4
= note: late-bound region is '?3
= note: late-bound region is '?2
= note: number of external vids: 3
= note: where '?1: '?2
Expand All @@ -26,7 +26,7 @@ LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
extern "rust-call" fn(()),
(),
]
= note: late-bound region is '?2
= note: late-bound region is '?1

note: no external requirements
--> $DIR/nested-closures-regions.rs:7:1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y);
| - - ^^^^^^ assignment requires that `'1` must outlive `'2`
| | |
| | has type `&'1 i32`
| has type `&'?2 mut &'2 i32`
| has type `&'?1 mut &'2 i32`

note: no external requirements
--> $DIR/escape-argument-callee.rs:20:1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ LL | foo(cell, |cell_a, cell_x| {
LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
| ^^^^^^^^^^^^^^^^^^^^^^^^ `cell_x` escapes the closure body here
|
= note: requirement occurs because of the type `Cell<&'?8 u32>`, which makes the generic argument `&'?8 u32` invariant
= note: requirement occurs because of the type `Cell<&'?9 u32>`, which makes the generic argument `&'?9 u32` invariant
= note: the struct `Cell<T>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ error: lifetime may not live long enough
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9
|
LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
| --------- - has type `&'?7 Cell<&'1 u32>`
| --------- - has type `&'?6 Cell<&'1 u32>`
| |
| has type `&'?5 Cell<&'2 &'?1 u32>`
| has type `&'?4 Cell<&'2 &'?1 u32>`
LL | // Only works if 'x: 'y:
LL | demand_y(x, y, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ error: lifetime may not live long enough
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9
|
LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
| ---------- ---------- has type `&'?8 Cell<&'2 &'?2 u32>`
| ---------- ---------- has type `&'?7 Cell<&'2 &'?2 u32>`
| |
| has type `&'?6 Cell<&'1 &'?1 u32>`
| has type `&'?5 Cell<&'1 &'?1 u32>`
LL | // Only works if 'x: 'y:
LL | demand_y(x, y, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
Expand Down
Loading