NLL: relate closure to parent fn

This commit is contained in:
Ali MJ Al-Nasrawy 2022-07-03 03:22:04 +03:00
parent fe3342816a
commit f74d06c2d1
4 changed files with 136 additions and 0 deletions

View File

@ -2619,6 +2619,28 @@ fn prove_closure_bounds(
);
}
// Now equate closure substs to regions inherited from `typeck_root_def_id`. Fixes #98589.
let typeck_root_def_id = tcx.typeck_root_def_id(self.body.source.def_id());
let typeck_root_substs = ty::InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
let parent_substs = match tcx.def_kind(def_id) {
DefKind::Closure => substs.as_closure().parent_substs(),
DefKind::Generator => substs.as_generator().parent_substs(),
DefKind::InlineConst => substs.as_inline_const().parent_substs(),
other => bug!("unexpected item {:?}", other),
};
let parent_substs = tcx.mk_substs(parent_substs.iter());
assert_eq!(typeck_root_substs.len(), parent_substs.len());
if let Err(_) = self.eq_substs(
typeck_root_substs,
parent_substs,
Locations::Single(location),
ConstraintCategory::BoringNoLocation,
) {
bug!("we shouldn't error, this should only impose region constraints");
}
tcx.predicates_of(def_id).instantiate(tcx, substs)
}

View File

@ -38,6 +38,23 @@ pub(super) fn relate_types(
.relate(a, b)?;
Ok(())
}
/// Add sufficient constraints to ensure `a == b`. See also [Self::relate_types].
pub(super) fn eq_substs(
&mut self,
a: ty::SubstsRef<'tcx>,
b: ty::SubstsRef<'tcx>,
locations: Locations,
category: ConstraintCategory<'tcx>,
) -> Fallible<()> {
let mut relation = TypeRelating::new(
self.infcx,
NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()),
ty::Variance::Invariant,
);
ty::relate::relate_substs(&mut relation, a, b)?;
Ok(())
}
}
struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {

View File

@ -0,0 +1,36 @@
// Regression test for #98589.
// Previously, named lifetime `'a` that appears in the closure was unrelated to `'a`
// that appears in the parent function iff `'a` is early-bound.
// This made the following tests pass borrowck.
// check-fail
// The bound `'a: 'a` ensures that `'a` is early-bound.
fn test_early_early<'a: 'a, 'b: 'b>() {
|| { None::<&'a &'b ()>; };
//~^ ERROR lifetime may not live long enough
}
fn test_early_late<'a: 'a, 'b>() {
|| { None::<&'a &'b ()>; };
//~^ ERROR lifetime may not live long enough
}
// No early-bound lifetime; included for completeness.
fn test_late_late<'a, 'b>() {
|| { None::<&'a &'b ()>; };
//~^ ERROR lifetime may not live long enough
}
fn test_early_type<'a: 'a, T>() {
|| { None::<&'a T>; };
//~^ ERROR the parameter type `T` may not live long enough
}
// No early-bound lifetime; included for completeness.
fn test_late_type<'a, T>() {
|| { None::<&'a T>; };
//~^ ERROR the parameter type `T` may not live long enough
}
fn main() {}

View File

@ -0,0 +1,61 @@
error: lifetime may not live long enough
--> $DIR/issue-98589-closures-relate-named-regions.rs:10:5
|
LL | fn test_early_early<'a: 'a, 'b: 'b>() {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | || { None::<&'a &'b ()>; };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
--> $DIR/issue-98589-closures-relate-named-regions.rs:15:10
|
LL | fn test_early_late<'a: 'a, 'b>() {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | || { None::<&'a &'b ()>; };
| ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
--> $DIR/issue-98589-closures-relate-named-regions.rs:21:10
|
LL | fn test_late_late<'a, 'b>() {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | || { None::<&'a &'b ()>; };
| ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/issue-98589-closures-relate-named-regions.rs:26:5
|
LL | || { None::<&'a T>; };
| ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
LL | fn test_early_type<'a: 'a, T: 'a>() {
| ++++
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/issue-98589-closures-relate-named-regions.rs:32:5
|
LL | || { None::<&'a T>; };
| ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
LL | fn test_late_type<'a, T: 'a>() {
| ++++
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0309`.