- the borrowck USER_TYPES buffer grows in the kept heap, not the compiler generation the zone swap destroys (Calculator crashed after the swap) - tools/run/fixture/zone_swap.sh forces a swap and fails on a fault, a use-after-destroy, a panic or a nonzero kept-scan - Box::pin(f(n-1)).await in an async fn lowers (no false E0733) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
58 lines
1.7 KiB
Rust
58 lines
1.7 KiB
Rust
// A recursive async fn through Box::pin: the boxed future is a pointer, so the future type does
|
|
// not contain itself (rustc accepts it; E0733 is only for recursion by value). The poll function
|
|
// builds the callee future as a temporary and moves it into the box, which needs the future's
|
|
// layout before its own saved locals are known.
|
|
use std::future::Future;
|
|
use std::pin::Pin;
|
|
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
|
|
|
fn noop_raw() -> RawWaker {
|
|
fn clone(_: *const ()) -> RawWaker { noop_raw() }
|
|
fn noop(_: *const ()) {}
|
|
static VT: RawWakerVTable = RawWakerVTable::new(clone, noop, noop, noop);
|
|
RawWaker::new(std::ptr::null(), &VT)
|
|
}
|
|
|
|
fn block_on<F: Future>(mut f: F) -> F::Output {
|
|
let waker = unsafe { Waker::from_raw(noop_raw()) };
|
|
let mut cx = Context::from_waker(&waker);
|
|
let mut f = unsafe { Pin::new_unchecked(&mut f) };
|
|
loop {
|
|
if let Poll::Ready(v) = f.as_mut().poll(&mut cx) {
|
|
return v;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Yield(bool);
|
|
impl Future for Yield {
|
|
type Output = ();
|
|
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
|
|
if self.0 { Poll::Ready(()) } else { self.0 = true; Poll::Pending }
|
|
}
|
|
}
|
|
|
|
async fn sum(n: u32) -> u32 {
|
|
if n == 0 {
|
|
0
|
|
} else {
|
|
Yield(false).await;
|
|
n + Box::pin(sum(n - 1)).await
|
|
}
|
|
}
|
|
|
|
async fn tree(depth: u32) -> u32 {
|
|
if depth == 0 {
|
|
return 1;
|
|
}
|
|
let left = Box::pin(tree(depth - 1)).await;
|
|
Yield(false).await;
|
|
let right = Box::pin(tree(depth - 1)).await;
|
|
left + right
|
|
}
|
|
|
|
#[test]
|
|
fn boxed_self_recursion() {
|
|
assert_eq!(block_on(sum(10)), 55);
|
|
assert_eq!(block_on(tree(5)), 32);
|
|
}
|