diff --git a/examples/07_05_recursion/src/lib.rs b/examples/07_05_recursion/src/lib.rs index 7811cfb3..5be179c5 100644 --- a/examples/07_05_recursion/src/lib.rs +++ b/examples/07_05_recursion/src/lib.rs @@ -11,3 +11,10 @@ fn recursive() -> BoxFuture<'static, ()> { }.boxed() } // ANCHOR_END: example + +// ANCHOR: example_pinned +async fn recursive_pinned() { + Box::pin(recursive_pinned()).await; + Box::pin(recursive_pinned()).await; +} +// ANCHOR_END: example_pinned diff --git a/src/07_workarounds/04_recursion.md b/src/07_workarounds/04_recursion.md index 24468ff8..6f1ba65b 100644 --- a/src/07_workarounds/04_recursion.md +++ b/src/07_workarounds/04_recursion.md @@ -37,17 +37,18 @@ This won't work—we've created an infinitely-sized type! The compiler will complain: ``` -error[E0733]: recursion in an `async fn` requires boxing - --> src/lib.rs:1:22 +error[E0733]: recursion in an async fn requires boxing + --> src/lib.rs:1:1 | 1 | async fn recursive() { - | ^ an `async fn` cannot invoke itself directly + | ^^^^^^^^^^^^^^^^^^^^ | - = note: a recursive `async fn` must be rewritten to return a boxed future. + = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future ``` In order to allow this, we have to introduce an indirection using `Box`. -Unfortunately, compiler limitations mean that just wrapping the calls to + +Prior to Rust 1.77, due to compiler limitations, just wrapping the calls to `recursive()` in `Box::pin` isn't enough. To make this work, we have to make `recursive` into a non-`async` function which returns a `.boxed()` `async` block: @@ -55,3 +56,19 @@ to make `recursive` into a non-`async` function which returns a `.boxed()` ```rust,edition2018 {{#include ../../examples/07_05_recursion/src/lib.rs:example}} ``` + +In newer version of Rust, [that compiler limitation has been lifted]. + +Since Rust 1.77, support for recursion in `async fn` with allocation +indirection [becomes stable], so recursive calls are permitted so long as they +use some form of indirection to avoid an infinite size for the state of the +function. + +This means that code like this now works: + +```rust,edition2021 +{{#include ../../examples/07_05_recursion/src/lib.rs:example_pinned}} +``` + +[becomes stable]: https://blog.rust-lang.org/2024/03/21/Rust-1.77.0.html#support-for-recursion-in-async-fn +[that compiler limitation has been lifted]: https://github.com/rust-lang/rust/pull/117703/