Skip to content

Nested async closures result in exponential compilation time increase #83031

Description

@blazzy

I've noticed exponential increases in compilation times as I nest async closures within each other.

I tried this code:

macro_rules! compose_middleware_inner {
  ( $route:ident, $first:ident, $second:ident, $($tail:ident), +) => {
    $first(|| async {
        compose_middleware_inner!($route, $second, $($tail),+)
    }).await
  };
  ( $route: ident, $first:ident, $second:ident ) => {
    $first(|| async move { $second($route).await }).await
  };
}

macro_rules! compose_middleware {
    ( $name:ident, $($tail:ident), +) => {
        pub async fn $name<N, Fut>(route: N)
        where
            N: FnOnce() -> Fut,
            Fut: std::future::Future<Output = ()>,
        {
            compose_middleware_inner!(route, $($tail),+)
        }
    }
}

async fn log<N, Fut>(next: N)
where
    N: FnOnce() -> Fut,
    Fut: std::future::Future<Output = ()>,
{
    println!("log start");
    next().await;
    println!("log end");
}

compose_middleware!(
    my_middleware, log, log, log, log, log, log, log, log, log, log, log, log, log
);

That compose_middleware! macro invocation generates a function that looks something like this:

pub async fn my_middleware<N, Fut>(route: N)
where
    N: FnOnce() -> Fut,
    Fut: Future<Output = ()>,
{
    log(|| async { log(|| async { log(|| async move { log(route).await }).await }).await }).await
}

I expected to see this happen: I expected this code to build within seconds

Instead, this happened: At around 3 levels it takes less than a second to build. At around 9 levels it takes around a minute to build. At around 14 levels it takes around 10 minutes to build.

Meta

I've experienced this issue on nightly, stable, and beta. And I've sampled random nightly versions going back as far as 1.39 and still witnessed the problem. There was a good bit of variability in build times, but it generally seemed to increase exponentially.

I threw this little repo up to test the issue: https://github.com/blazzy/slow-rust-async/blob/master/src/lib.rs

I thought it might be related to this issue #72408 with nested closures. Or this issue #75992 with levels of async, but those look to be resolved.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitA-closuresArea: Closures (`|…| { … }`)AsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.C-bugCategory: This is a bug.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.I-compiletimeIssue: Problems and improvements with respect to compile times.P-mediumMedium priorityT-compilerRelevant to the compiler 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