Skip to content

Commit

Permalink
Auto merge of rust-lang#135783 - compiler-errors:cache-in-closure-bin…
Browse files Browse the repository at this point in the history
…der, r=lcnr

Add cache to `FoldEscapingRegions`

Fixes rust-lang#135780

ty `@lqd` for the tests
  • Loading branch information
bors committed Jan 26, 2025
2 parents 01a26c0 + d7a6fdc commit f85c6de
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 1 deletion.
20 changes: 19 additions & 1 deletion compiler/rustc_type_ir/src/ty_kind/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -498,13 +500,29 @@ 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> {
fn cx(&self) -> 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>,
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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;
});
}
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit f85c6de

Please sign in to comment.