1
Fork 0

Auto merge of #114602 - compiler-errors:rpit-outlives-sadness, r=oli-obk

Map RPIT duplicated lifetimes back to fn captured lifetimes

Use the [`lifetime_mapping`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.OpaqueTy.html#structfield.lifetime_mapping) to map an RPIT's captured lifetimes back to the early- or late-bound lifetimes from its parent function. We may be going thru several layers of mapping, since opaques can be nested, so we introduce `TyCtxt::map_rpit_lifetime_to_fn_lifetime` to loop through several opaques worth of mapping, and handle turning it into a `ty::Region` as well.

We can then use this instead of the identity substs for RPITs in `check_opaque_meets_bounds` to address #114285.

We can then also use `map_rpit_lifetime_to_fn_lifetime` to properly install bidirectional-outlives predicates for both RPITs and RPITITs. This addresses #114601.

I based this on #114574, but I don't actually know how much of that PR we still need, so some code may be redundant now... 🤷

---

Fixes #114597
Fixes #114579
Fixes #114285

Also fixes #114601, since it turns out we had other bugs with RPITITs and their duplicated lifetime params 😅.

Supersedes #114574

r? `@oli-obk`
This commit is contained in:
bors 2023-08-08 13:03:10 +00:00
commit bf62436bce
9 changed files with 194 additions and 218 deletions

View file

@ -1931,6 +1931,84 @@ impl<'tcx> TyCtxt<'tcx> {
)
}
/// Given the def-id of an early-bound lifetime on an RPIT corresponding to
/// a duplicated captured lifetime, map it back to the early- or late-bound
/// lifetime of the function from which it originally as captured. If it is
/// a late-bound lifetime, this will represent the liberated (`ReFree`) lifetime
/// of the signature.
// FIXME(RPITIT): if we ever synthesize new lifetimes for RPITITs and not just
// re-use the generics of the opaque, this function will need to be tweaked slightly.
pub fn map_rpit_lifetime_to_fn_lifetime(
self,
mut rpit_lifetime_param_def_id: LocalDefId,
) -> ty::Region<'tcx> {
debug_assert!(
matches!(self.def_kind(rpit_lifetime_param_def_id), DefKind::LifetimeParam),
"{rpit_lifetime_param_def_id:?} is a {}",
self.def_descr(rpit_lifetime_param_def_id.to_def_id())
);
loop {
let parent = self.local_parent(rpit_lifetime_param_def_id);
let hir::OpaqueTy { lifetime_mapping, .. } =
self.hir().get_by_def_id(parent).expect_item().expect_opaque_ty();
let Some((lifetime, _)) = lifetime_mapping
.iter()
.find(|(_, duplicated_param)| *duplicated_param == rpit_lifetime_param_def_id)
else {
bug!("duplicated lifetime param should be present");
};
match self.named_bound_var(lifetime.hir_id) {
Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => {
let new_parent = self.parent(ebv);
// If we map to another opaque, then it should be a parent
// of the opaque we mapped from. Continue mapping.
if matches!(self.def_kind(new_parent), DefKind::OpaqueTy) {
debug_assert_eq!(self.parent(parent.to_def_id()), new_parent);
rpit_lifetime_param_def_id = ebv.expect_local();
continue;
}
let generics = self.generics_of(new_parent);
return ty::Region::new_early_bound(
self,
ty::EarlyBoundRegion {
def_id: ebv,
index: generics
.param_def_id_to_index(self, ebv)
.expect("early-bound var should be present in fn generics"),
name: self.hir().name(self.local_def_id_to_hir_id(ebv.expect_local())),
},
);
}
Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => {
let new_parent = self.parent(lbv);
return ty::Region::new_free(
self,
new_parent,
ty::BoundRegionKind::BrNamed(
lbv,
self.hir().name(self.local_def_id_to_hir_id(lbv.expect_local())),
),
);
}
Some(resolve_bound_vars::ResolvedArg::Error(guar)) => {
return ty::Region::new_error(self, guar);
}
_ => {
return ty::Region::new_error_with_message(
self,
lifetime.ident.span,
"cannot resolve lifetime",
);
}
}
}
}
/// Whether the `def_id` counts as const fn in the current crate, considering all active
/// feature gates
pub fn is_const_fn(self, def_id: DefId) -> bool {