diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f7d35da0259..48cf7666f2c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -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) } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index c45850c6d84..7ccd5da6b91 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -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> { diff --git a/src/test/ui/nll/issue-98589-closures-relate-named-regions.rs b/src/test/ui/nll/issue-98589-closures-relate-named-regions.rs new file mode 100644 index 00000000000..6cc4340bbd7 --- /dev/null +++ b/src/test/ui/nll/issue-98589-closures-relate-named-regions.rs @@ -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() {} diff --git a/src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr b/src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr new file mode 100644 index 00000000000..6def5602e70 --- /dev/null +++ b/src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr @@ -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`.