about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_type_ir/src/ty_kind/closure.rs20
-rw-r--r--tests/ui/async-await/async-closures/post-mono-higher-ranked-hang-2.rs23
-rw-r--r--tests/ui/async-await/async-closures/post-mono-higher-ranked-hang-2.stderr18
-rw-r--r--tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs63
-rw-r--r--tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr21
5 files changed, 144 insertions, 1 deletions
diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs
index 10b164eae02..74e4e035c87 100644
--- a/compiler/rustc_type_ir/src/ty_kind/closure.rs
+++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs
@@ -3,9 +3,10 @@ use std::ops::ControlFlow;
 use derive_where::derive_where;
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
+use crate::data_structures::DelayedMap;
 use crate::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region};
 use crate::inherent::*;
-use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 use crate::{self as ty, Interner};
 
 /// A closure can be modeled as a struct that looks like:
@@ -471,6 +472,7 @@ impl<I: Interner> CoroutineClosureSignature<I> {
                         interner: cx,
                         region: env_region,
                         debruijn: ty::INNERMOST,
+                        cache: Default::default(),
                     });
                 Ty::new_tup_from_iter(
                     cx,
@@ -498,6 +500,10 @@ struct FoldEscapingRegions<I: Interner> {
     interner: I,
     debruijn: ty::DebruijnIndex,
     region: I::Region,
+
+    // Depends on `debruijn` because we may have types with regions of different
+    // debruijn depths depending on the binders we've entered.
+    cache: DelayedMap<(ty::DebruijnIndex, I::Ty), I::Ty>,
 }
 
 impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
@@ -505,6 +511,18 @@ impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
         self.interner
     }
 
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
+        if !t.has_vars_bound_at_or_above(self.debruijn) {
+            t
+        } else if let Some(&t) = self.cache.get(&(self.debruijn, t)) {
+            t
+        } else {
+            let res = t.super_fold_with(self);
+            assert!(self.cache.insert((self.debruijn, t), res));
+            res
+        }
+    }
+
     fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
     where
         T: TypeFoldable<I>,
diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang-2.rs b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang-2.rs
new file mode 100644
index 00000000000..4cdf4bf8def
--- /dev/null
+++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang-2.rs
@@ -0,0 +1,23 @@
+//@ edition: 2021
+//@ build-fail
+
+// Regression test for <https://github.com/rust-lang/rust/issues/135780>.
+
+use std::future::Future;
+use std::ops::AsyncFn;
+use std::pin::Pin;
+
+fn recur<'l>(closure: &'l impl AsyncFn()) -> Pin<Box<dyn Future<Output = ()> + 'l>> {
+    Box::pin(async move {
+        let _ = closure();
+        let _ = recur(&async || {
+            //~^ ERROR reached the recursion limit
+            let _ = closure();
+        });
+    })
+}
+
+fn main() {
+    let closure = async || {};
+    let _ = recur(&closure);
+}
diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang-2.stderr b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang-2.stderr
new file mode 100644
index 00000000000..64f4665225f
--- /dev/null
+++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang-2.stderr
@@ -0,0 +1,18 @@
+error: reached the recursion limit while instantiating `recur::<{async closure@$DIR/post-mono-higher-ranked-hang-2.rs:13:24: 13:32}>`
+  --> $DIR/post-mono-higher-ranked-hang-2.rs:13:17
+   |
+LL |           let _ = recur(&async || {
+   |  _________________^
+LL | |
+LL | |             let _ = closure();
+LL | |         });
+   | |__________^
+   |
+note: `recur` defined here
+  --> $DIR/post-mono-higher-ranked-hang-2.rs:10:1
+   |
+LL | fn recur<'l>(closure: &'l impl AsyncFn()) -> Pin<Box<dyn Future<Output = ()> + 'l>> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs
new file mode 100644
index 00000000000..f6ebf787f81
--- /dev/null
+++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs
@@ -0,0 +1,63 @@
+//@ build-fail
+//@ aux-build:block-on.rs
+//@ edition:2021
+
+// Regression test for <https://github.com/rust-lang/rust/issues/135780>.
+
+extern crate block_on;
+
+use std::future::Future;
+use std::ops::AsyncFnMut;
+use std::pin::{Pin, pin};
+use std::task::*;
+
+trait Db {}
+
+impl Db for () {}
+
+struct Env<'db> {
+    db: &'db (),
+}
+
+#[derive(Debug)]
+enum SymPerm<'db> {
+    Dummy(&'db ()),
+    Apply(Box<SymPerm<'db>>, Box<SymPerm<'db>>),
+}
+
+pub struct ToChain<'env, 'db> {
+    db: &'db dyn crate::Db,
+    env: &'env Env<'db>,
+}
+
+impl<'env, 'db> ToChain<'env, 'db> {
+    fn perm_pairs<'l>(
+        &'l self,
+        perm: &'l SymPerm<'db>,
+        yield_chain: &'l mut impl AsyncFnMut(&SymPerm<'db>),
+    ) -> Pin<Box<dyn std::future::Future<Output = ()> + 'l>> {
+        Box::pin(async move {
+            match perm {
+                SymPerm::Dummy(_) => yield_chain(perm).await,
+                SymPerm::Apply(l, r) => {
+                    self.perm_pairs(l, &mut async move |left_pair| {
+                        //~^ ERROR reached the recursion limit while instantiating
+                        self.perm_pairs(r, yield_chain).await
+                    })
+                    .await
+                }
+            }
+        })
+    }
+}
+
+fn main() {
+    block_on::block_on(async {
+        let pair = SymPerm::Apply(Box::new(SymPerm::Dummy(&())), Box::new(SymPerm::Dummy(&())));
+        ToChain { db: &(), env: &Env { db: &() } }
+            .perm_pairs(&pair, &mut async |p| {
+                eprintln!("{p:?}");
+            })
+            .await;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr
new file mode 100644
index 00000000000..486e5f94165
--- /dev/null
+++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr
@@ -0,0 +1,21 @@
+error: reached the recursion limit while instantiating `ToChain::<'_, '_>::perm_pairs::<{async closure@$DIR/post-mono-higher-ranked-hang.rs:43:45: 43:67}>`
+  --> $DIR/post-mono-higher-ranked-hang.rs:43:21
+   |
+LL | /                     self.perm_pairs(l, &mut async move |left_pair| {
+LL | |
+LL | |                         self.perm_pairs(r, yield_chain).await
+LL | |                     })
+   | |______________________^
+   |
+note: `ToChain::<'env, 'db>::perm_pairs` defined here
+  --> $DIR/post-mono-higher-ranked-hang.rs:34:5
+   |
+LL | /     fn perm_pairs<'l>(
+LL | |         &'l self,
+LL | |         perm: &'l SymPerm<'db>,
+LL | |         yield_chain: &'l mut impl AsyncFnMut(&SymPerm<'db>),
+LL | |     ) -> Pin<Box<dyn std::future::Future<Output = ()> + 'l>> {
+   | |____________________________________________________________^
+
+error: aborting due to 1 previous error
+