Rollup merge of #103780 - compiler-errors:bound-closure-lifetimes, r=jackh726
Fix late-bound lifetime closure ICEs in HIR typeck and MIR borrowck During HIR typeck, we need to teach astconv to treat late-bound regions within a closure body as free, fixing escaping bound vars ICEs in both of the issues below. However, this then gets us to MIR borrowck, which itself needs to be taught how to instantiate free region vids for late-bound regions that come from items that _aren't_ the typeck root (for now, just closures). Fixes #103771 Fixes #103736
This commit is contained in:
commit
d10187f040
@ -2314,7 +2314,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
|
||||
tcx,
|
||||
closure_substs,
|
||||
self.num_external_vids,
|
||||
tcx.typeck_root_def_id(closure_def_id),
|
||||
closure_def_id.expect_local(),
|
||||
);
|
||||
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
|
||||
|
||||
|
@ -22,7 +22,9 @@ use rustc_hir::{BodyOwnerKind, HirId};
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{
|
||||
self, DefIdTree, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_middle::ty::{InternalSubsts, SubstsRef};
|
||||
use std::iter;
|
||||
|
||||
@ -241,7 +243,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
closure_substs: SubstsRef<'tcx>,
|
||||
expected_num_vars: usize,
|
||||
typeck_root_def_id: DefId,
|
||||
closure_def_id: LocalDefId,
|
||||
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
|
||||
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
|
||||
region_mapping.push(tcx.lifetimes.re_static);
|
||||
@ -249,7 +251,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
region_mapping.push(fr);
|
||||
});
|
||||
|
||||
for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
|
||||
for_each_late_bound_region_in_recursive_scope(tcx, tcx.local_parent(closure_def_id), |r| {
|
||||
region_mapping.push(r);
|
||||
});
|
||||
|
||||
@ -339,9 +341,8 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
// tests, and the resulting print-outs include def-ids
|
||||
// and other things that are not stable across tests!
|
||||
// So we just include the region-vid. Annoying.
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
|
||||
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
|
||||
for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {
|
||||
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r)));
|
||||
});
|
||||
}
|
||||
DefiningTy::Generator(def_id, substs, _) => {
|
||||
@ -354,9 +355,8 @@ impl<'tcx> UniversalRegions<'tcx> {
|
||||
// FIXME: As above, we'd like to print out the region
|
||||
// `r` but doing so is not stable across architectures
|
||||
// and so forth.
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||
for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
|
||||
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
|
||||
for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {
|
||||
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r)));
|
||||
});
|
||||
}
|
||||
DefiningTy::FnDef(def_id, substs) => {
|
||||
@ -421,13 +421,24 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
first_extern_index
|
||||
} else {
|
||||
// If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing
|
||||
// function are actually external regions to us. For example, here, 'a is not local
|
||||
// function/closures are actually external regions to us. For example, here, 'a is not local
|
||||
// to the closure c (although it is local to the fn foo):
|
||||
// fn foo<'a>() {
|
||||
// let c = || { let x: &'a u32 = ...; }
|
||||
// }
|
||||
self.infcx
|
||||
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
|
||||
for_each_late_bound_region_in_recursive_scope(
|
||||
self.infcx.tcx,
|
||||
self.infcx.tcx.local_parent(self.mir_def.did),
|
||||
|r| {
|
||||
debug!(?r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = self.infcx.next_nll_region_var(FR);
|
||||
debug!(?region_vid);
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Any regions created during the execution of `defining_ty` or during the above
|
||||
// late-bound region replacement are all considered 'extern' regions
|
||||
self.infcx.num_region_vars()
|
||||
@ -444,12 +455,16 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
bound_inputs_and_output,
|
||||
&mut indices,
|
||||
);
|
||||
// Converse of above, if this is a function then the late-bound regions declared on its
|
||||
// signature are local to the fn.
|
||||
if self.mir_def.did.to_def_id() == typeck_root_def_id {
|
||||
self.infcx
|
||||
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &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.did, |r| {
|
||||
debug!(?r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = self.infcx.next_nll_region_var(FR);
|
||||
debug!(?region_vid);
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
}
|
||||
});
|
||||
|
||||
let (unnormalized_output_ty, mut unnormalized_input_tys) =
|
||||
inputs_and_output.split_last().unwrap();
|
||||
@ -692,7 +707,13 @@ trait InferCtxtExt<'tcx> {
|
||||
where
|
||||
T: TypeFoldable<'tcx>;
|
||||
|
||||
fn replace_late_bound_regions_with_nll_infer_vars(
|
||||
fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
);
|
||||
|
||||
fn replace_late_bound_regions_with_nll_infer_vars_in_item(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
@ -746,13 +767,28 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
|
||||
/// inputs vector.
|
||||
#[instrument(skip(self, indices))]
|
||||
fn replace_late_bound_regions_with_nll_infer_vars(
|
||||
fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
) {
|
||||
let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
|
||||
for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
|
||||
for_each_late_bound_region_in_recursive_scope(self.tcx, mir_def_id, |r| {
|
||||
debug!(?r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = self.next_nll_region_var(FR);
|
||||
debug!(?region_vid);
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[instrument(skip(self, indices))]
|
||||
fn replace_late_bound_regions_with_nll_infer_vars_in_item(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
) {
|
||||
for_each_late_bound_region_in_item(self.tcx, mir_def_id, |r| {
|
||||
debug!(?r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = self.next_nll_region_var(FR);
|
||||
@ -803,21 +839,44 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterates over the late-bound regions defined on fn_def_id and
|
||||
/// invokes `f` with the liberated form of each one.
|
||||
fn for_each_late_bound_region_defined_on<'tcx>(
|
||||
/// Iterates over the late-bound regions defined on `mir_def_id` and all of its
|
||||
/// parents, up to the typeck root, and invokes `f` with the liberated form
|
||||
/// of each one.
|
||||
fn for_each_late_bound_region_in_recursive_scope<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_def_id: DefId,
|
||||
mut mir_def_id: LocalDefId,
|
||||
mut f: impl FnMut(ty::Region<'tcx>),
|
||||
) {
|
||||
if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
|
||||
for ®ion_def_id in late_bounds.iter() {
|
||||
let name = tcx.item_name(region_def_id.to_def_id());
|
||||
let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
|
||||
scope: fn_def_id,
|
||||
bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
|
||||
}));
|
||||
f(liberated_region);
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(mir_def_id.to_def_id());
|
||||
|
||||
// Walk up the tree, collecting late-bound regions until we hit the typeck root
|
||||
loop {
|
||||
for_each_late_bound_region_in_item(tcx, mir_def_id, &mut f);
|
||||
|
||||
if mir_def_id.to_def_id() == typeck_root_def_id {
|
||||
break;
|
||||
} else {
|
||||
mir_def_id = tcx.local_parent(mir_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterates over the late-bound regions defined on `mir_def_id` and all of its
|
||||
/// parents, up to the typeck root, and invokes `f` with the liberated form
|
||||
/// of each one.
|
||||
fn for_each_late_bound_region_in_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mir_def_id: LocalDefId,
|
||||
mut f: impl FnMut(ty::Region<'tcx>),
|
||||
) {
|
||||
if !tcx.def_kind(mir_def_id).is_fn_like() {
|
||||
return;
|
||||
}
|
||||
|
||||
for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) {
|
||||
let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; };
|
||||
let liberated_region = tcx
|
||||
.mk_region(ty::ReFree(ty::FreeRegion { scope: mir_def_id.to_def_id(), bound_region }));
|
||||
f(liberated_region);
|
||||
}
|
||||
}
|
||||
|
@ -1377,11 +1377,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
} else if let Some(body_id) = outermost_body {
|
||||
let fn_id = self.tcx.hir().body_owner(body_id);
|
||||
match self.tcx.hir().get(fn_id) {
|
||||
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. })
|
||||
| Node::TraitItem(&hir::TraitItem {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
|
||||
| Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(..), ..
|
||||
})
|
||||
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
|
||||
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. })
|
||||
| Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
|
||||
let scope = self.tcx.hir().local_def_id(fn_id);
|
||||
def = Region::Free(scope.to_def_id(), def.id().unwrap());
|
||||
}
|
||||
|
9
src/test/ui/closures/binder/late-bound-in-body.rs
Normal file
9
src/test/ui/closures/binder/late-bound-in-body.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(closure_lifetime_binder)]
|
||||
|
||||
fn main() {
|
||||
let _ = for<'a> || -> () {
|
||||
let _: &'a bool = &true;
|
||||
};
|
||||
}
|
9
src/test/ui/closures/binder/nested-closures-regions.rs
Normal file
9
src/test/ui/closures/binder/nested-closures-regions.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(closure_lifetime_binder)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_regions]
|
||||
fn main() {
|
||||
for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
|
||||
}
|
38
src/test/ui/closures/binder/nested-closures-regions.stderr
Normal file
38
src/test/ui/closures/binder/nested-closures-regions.stderr
Normal file
@ -0,0 +1,38 @@
|
||||
note: external requirements
|
||||
--> $DIR/nested-closures-regions.rs:8:24
|
||||
|
|
||||
LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: main::{closure#0}::{closure#0} with closure substs [
|
||||
i8,
|
||||
extern "rust-call" fn((&(),)),
|
||||
(),
|
||||
]
|
||||
= note: late-bound region is '_#4r
|
||||
= note: late-bound region is '_#2r
|
||||
= note: number of external vids: 3
|
||||
= note: where '_#1r: '_#2r
|
||||
= note: where '_#2r: '_#1r
|
||||
|
||||
note: no external requirements
|
||||
--> $DIR/nested-closures-regions.rs:8:5
|
||||
|
|
||||
LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: main::{closure#0} with closure substs [
|
||||
i8,
|
||||
extern "rust-call" fn(()),
|
||||
(),
|
||||
]
|
||||
= note: late-bound region is '_#2r
|
||||
|
||||
note: no external requirements
|
||||
--> $DIR/nested-closures-regions.rs:7:1
|
||||
|
|
||||
LL | fn main() {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: defining type: main
|
||||
|
7
src/test/ui/closures/binder/nested-closures.rs
Normal file
7
src/test/ui/closures/binder/nested-closures.rs
Normal file
@ -0,0 +1,7 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(closure_lifetime_binder)]
|
||||
|
||||
fn main() {
|
||||
for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user