about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2022-07-03 03:22:04 +0300
committerAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2022-08-02 15:20:57 +0300
commitf74d06c2d1f36f7fc7b99296d795cd578612b5a6 (patch)
tree549e3fa72a9041b9e53430eae1328ee7699cfa96
parentfe3342816a282949f014caa05ea2e669ff9d3d3c (diff)
downloadrust-f74d06c2d1f36f7fc7b99296d795cd578612b5a6.tar.gz
rust-f74d06c2d1f36f7fc7b99296d795cd578612b5a6.zip
NLL: relate closure to parent fn
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs22
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs17
-rw-r--r--src/test/ui/nll/issue-98589-closures-relate-named-regions.rs36
-rw-r--r--src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr61
4 files changed, 136 insertions, 0 deletions
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 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             );
         }
 
+        // 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 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         .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`.