Skip to content

Commit d7a6fdc

Browse files
Add cache to FoldEscapingRegions
1 parent 01a26c0 commit d7a6fdc

File tree

5 files changed

+144
-1
lines changed

5 files changed

+144
-1
lines changed

Diff for: compiler/rustc_type_ir/src/ty_kind/closure.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use std::ops::ControlFlow;
33
use derive_where::derive_where;
44
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
55

6+
use crate::data_structures::DelayedMap;
67
use crate::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region};
78
use crate::inherent::*;
8-
use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
9+
use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
910
use crate::{self as ty, Interner};
1011

1112
/// A closure can be modeled as a struct that looks like:
@@ -471,6 +472,7 @@ impl<I: Interner> CoroutineClosureSignature<I> {
471472
interner: cx,
472473
region: env_region,
473474
debruijn: ty::INNERMOST,
475+
cache: Default::default(),
474476
});
475477
Ty::new_tup_from_iter(
476478
cx,
@@ -498,13 +500,29 @@ struct FoldEscapingRegions<I: Interner> {
498500
interner: I,
499501
debruijn: ty::DebruijnIndex,
500502
region: I::Region,
503+
504+
// Depends on `debruijn` because we may have types with regions of different
505+
// debruijn depths depending on the binders we've entered.
506+
cache: DelayedMap<(ty::DebruijnIndex, I::Ty), I::Ty>,
501507
}
502508

503509
impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
504510
fn cx(&self) -> I {
505511
self.interner
506512
}
507513

514+
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
515+
if !t.has_vars_bound_at_or_above(self.debruijn) {
516+
t
517+
} else if let Some(&t) = self.cache.get(&(self.debruijn, t)) {
518+
t
519+
} else {
520+
let res = t.super_fold_with(self);
521+
assert!(self.cache.insert((self.debruijn, t), res));
522+
res
523+
}
524+
}
525+
508526
fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
509527
where
510528
T: TypeFoldable<I>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ edition: 2021
2+
//@ build-fail
3+
4+
// Regression test for <https://github.com/rust-lang/rust/issues/135780>.
5+
6+
use std::future::Future;
7+
use std::ops::AsyncFn;
8+
use std::pin::Pin;
9+
10+
fn recur<'l>(closure: &'l impl AsyncFn()) -> Pin<Box<dyn Future<Output = ()> + 'l>> {
11+
Box::pin(async move {
12+
let _ = closure();
13+
let _ = recur(&async || {
14+
//~^ ERROR reached the recursion limit
15+
let _ = closure();
16+
});
17+
})
18+
}
19+
20+
fn main() {
21+
let closure = async || {};
22+
let _ = recur(&closure);
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: reached the recursion limit while instantiating `recur::<{async closure@$DIR/post-mono-higher-ranked-hang-2.rs:13:24: 13:32}>`
2+
--> $DIR/post-mono-higher-ranked-hang-2.rs:13:17
3+
|
4+
LL | let _ = recur(&async || {
5+
| _________________^
6+
LL | |
7+
LL | | let _ = closure();
8+
LL | | });
9+
| |__________^
10+
|
11+
note: `recur` defined here
12+
--> $DIR/post-mono-higher-ranked-hang-2.rs:10:1
13+
|
14+
LL | fn recur<'l>(closure: &'l impl AsyncFn()) -> Pin<Box<dyn Future<Output = ()> + 'l>> {
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error: aborting due to 1 previous error
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//@ build-fail
2+
//@ aux-build:block-on.rs
3+
//@ edition:2021
4+
5+
// Regression test for <https://github.com/rust-lang/rust/issues/135780>.
6+
7+
extern crate block_on;
8+
9+
use std::future::Future;
10+
use std::ops::AsyncFnMut;
11+
use std::pin::{Pin, pin};
12+
use std::task::*;
13+
14+
trait Db {}
15+
16+
impl Db for () {}
17+
18+
struct Env<'db> {
19+
db: &'db (),
20+
}
21+
22+
#[derive(Debug)]
23+
enum SymPerm<'db> {
24+
Dummy(&'db ()),
25+
Apply(Box<SymPerm<'db>>, Box<SymPerm<'db>>),
26+
}
27+
28+
pub struct ToChain<'env, 'db> {
29+
db: &'db dyn crate::Db,
30+
env: &'env Env<'db>,
31+
}
32+
33+
impl<'env, 'db> ToChain<'env, 'db> {
34+
fn perm_pairs<'l>(
35+
&'l self,
36+
perm: &'l SymPerm<'db>,
37+
yield_chain: &'l mut impl AsyncFnMut(&SymPerm<'db>),
38+
) -> Pin<Box<dyn std::future::Future<Output = ()> + 'l>> {
39+
Box::pin(async move {
40+
match perm {
41+
SymPerm::Dummy(_) => yield_chain(perm).await,
42+
SymPerm::Apply(l, r) => {
43+
self.perm_pairs(l, &mut async move |left_pair| {
44+
//~^ ERROR reached the recursion limit while instantiating
45+
self.perm_pairs(r, yield_chain).await
46+
})
47+
.await
48+
}
49+
}
50+
})
51+
}
52+
}
53+
54+
fn main() {
55+
block_on::block_on(async {
56+
let pair = SymPerm::Apply(Box::new(SymPerm::Dummy(&())), Box::new(SymPerm::Dummy(&())));
57+
ToChain { db: &(), env: &Env { db: &() } }
58+
.perm_pairs(&pair, &mut async |p| {
59+
eprintln!("{p:?}");
60+
})
61+
.await;
62+
});
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error: reached the recursion limit while instantiating `ToChain::<'_, '_>::perm_pairs::<{async closure@$DIR/post-mono-higher-ranked-hang.rs:43:45: 43:67}>`
2+
--> $DIR/post-mono-higher-ranked-hang.rs:43:21
3+
|
4+
LL | / self.perm_pairs(l, &mut async move |left_pair| {
5+
LL | |
6+
LL | | self.perm_pairs(r, yield_chain).await
7+
LL | | })
8+
| |______________________^
9+
|
10+
note: `ToChain::<'env, 'db>::perm_pairs` defined here
11+
--> $DIR/post-mono-higher-ranked-hang.rs:34:5
12+
|
13+
LL | / fn perm_pairs<'l>(
14+
LL | | &'l self,
15+
LL | | perm: &'l SymPerm<'db>,
16+
LL | | yield_chain: &'l mut impl AsyncFnMut(&SymPerm<'db>),
17+
LL | | ) -> Pin<Box<dyn std::future::Future<Output = ()> + 'l>> {
18+
| |____________________________________________________________^
19+
20+
error: aborting due to 1 previous error
21+

0 commit comments

Comments
 (0)