Skip to content

Boxed recursive function should not require trait object #73625

Closed
@jimblandy

Description

@jimblandy

The following code works (playground):

use std::future::Future;
use std::pin::Pin;

async fn recurse(i: usize) {
    if i == 0 {
        println!("Zero!");
        return;
    }
    
    println!("entering {}", i);
    let recursed = Box::pin(recurse(i-1)) as Pin<Box<dyn Future<Output=()>>>;
    recursed.await;
    println!("exiting {}", i);
}

fn main() {
    futures::executor::block_on(recurse(10));
}

but if the trait object is removed, and the construction of recursed is changed to:

    let recursed = Box::pin(recurse(i-1));

then Rust rejects the program:

error[E0733]: recursion in an `async fn` requires boxing
 --> src/main.rs:4:28
  |
4 | async fn recurse(i: usize) {
  |                            ^ recursive `async fn`
  |
  = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`

The future is boxed either way, so the use of a trait object shouldn't be required. In a thread on the internals forum, @withoutboats said:

Note that it should be allowed to just use Box::pin, without casting it into a trait object at all, and the fact that it isn't is an implementation limitation of how current rustc calculates the layout of the future type. It doesn't look like there's a bug tracking this limitation though.

Now there is!

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions