Skip to content

Unclear error message when using recursive future with tokio::spawn #112175

Open
@krtab

Description

@krtab

Code

async fn tokio_fact(n: u32)  -> u32 {
    if n <= 1 {
        return n;
    } else {
        let jh = tokio::spawn(tokio_fact(n-1));
        jh.await.unwrap() * n
    }
}

Current output

error[E0391]: cycle detected when computing type of `tokio_fact::{opaque#0}`
   --> a/src/main.rs:99:33
    |
99  | async fn tokio_fact(n: u32)  -> u32 {
    |                                 ^^^
    |
note: ...which requires borrow-checking `tokio_fact`...
   --> a/src/main.rs:99:1
    |
99  | async fn tokio_fact(n: u32)  -> u32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires promoting constants in MIR for `tokio_fact`...
   --> a/src/main.rs:99:1
    |
99  | async fn tokio_fact(n: u32)  -> u32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires preparing `tokio_fact` for borrow checking...
   --> a/src/main.rs:99:1
    |
99  | async fn tokio_fact(n: u32)  -> u32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `tokio_fact`...
   --> a/src/main.rs:99:1
    |
99  | async fn tokio_fact(n: u32)  -> u32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `tokio_fact`...
   --> a/src/main.rs:99:1
    |
99  | async fn tokio_fact(n: u32)  -> u32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires match-checking `tokio_fact`...
   --> a/src/main.rs:99:1
    |
99  | async fn tokio_fact(n: u32)  -> u32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building THIR for `tokio_fact`...
   --> a/src/main.rs:99:1
    |
99  | async fn tokio_fact(n: u32)  -> u32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `tokio_fact`...
   --> a/src/main.rs:103:18
    |
103 |         let jh = tokio::spawn(tokio_fact(n-1));
    |                  ^^^^^^^^^^^^
    = note: ...which requires evaluating trait selection obligation `tokio_fact::{opaque#0}: core::marker::Send`...
    = note: ...which again requires computing type of `tokio_fact::{opaque#0}`, completing the cycle

Desired output

I'm not sure what should be the proper error message. Because of the tokio::spawn this is not the same problem as in E0733.

The workaround often proposed by @Darksonn on various forums is to use a wrapping non-async function:

async fn tokio_fact_bis(n: u32)  -> u32 {
    if n <= 1 {
        return n;
    } else {
        fn tokio_fact_wrap(n : u32) -> JoinHandle<u32> {
            tokio::spawn(tokio_fact_bis(n))
        }
        let jh = tokio_fact_wrap(n-1);
        jh.await.unwrap() * n
    }
}

Rationale and extra context

No response

Other cases

No response

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-async-awaitArea: Async & AwaitA-diagnosticsArea: Messages for errors, warnings, and lintsAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.E-help-wantedCall for participation: Help is requested to fix this issue.T-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