Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async/await incorrectly interprets builder pattern #14844

Closed
stevenroose opened this issue Nov 20, 2024 · 2 comments
Closed

async/await incorrectly interprets builder pattern #14844

stevenroose opened this issue Nov 20, 2024 · 2 comments
Labels
C-bug Category: bug S-triage Status: This issue is waiting on initial triage.

Comments

@stevenroose
Copy link

Problem

I think this playground example sums it up pretty well: (also provided below just in case playground doesn't have good memory)

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d44511c27085218a34240258a2835ff6

The short summary:

Imagine a builder type that is not Send. Builders have methods with following signature: fn xxx(&mut self) -> &mut Self. The compiler seems to think that the &mut Self can stay around, even after a method with signature fn finish(self) is called, which clearly consumes the builder variable and invalidates all the mutable references that might live on.

Steps

use std::rc::Rc;

// A builder pattern that is not `Send`.
struct Builder(Rc<usize>);

impl Builder {
    fn new() -> Self {
        Builder(Rc::new(35))
    }
    // Builder pattern methods return &mut Self
    fn build_something(&mut self) -> &mut Self {
        self
    }
    // But the finish method consumes self!
    fn finish(self) -> usize {
        Rc::try_unwrap(self.0).unwrap()
    }
}

async fn something_async(i: usize) -> Result<(), ()> {
    println!("{i}");
    Ok(())
}

async fn async_main() {
    let mut b = Builder::new();
    b.build_something();
    // this method consumes b!
    let my_int = b.finish();
    
    let _ = something_async(my_int).await;
    
    // compiler things b might be used here.
    
    println!("{my_int}");
}

fn main() {
    tokio::spawn(async {
        async_main().await;
    });
}

gives the following compiler error:

   Compiling playground v0.0.1 (/playground)
error: future cannot be sent between threads safely
   --> src/main.rs:41:5
    |
41  | /     tokio::spawn(async {
42  | |         async_main().await;
43  | |     });
    | |______^ future created by async block is not `Send`
    |
    = help: within `{async block@src/main.rs:41:18: 41:23}`, the trait `Send` is not implemented for `Rc<usize>`, which is required by `{async block@src/main.rs:41:18: 41:23}: Send`
note: future is not `Send` as this value is used across an await
   --> src/main.rs:33:37
    |
28  |     let mut b = Builder::new();
    |         ----- has type `Builder` which is not `Send`
...
33  |     let _ = something_async(my_int).await;
    |                                     ^^^^^ await occurs here, with `mut b` maybe used later
note: required by a bound in `tokio::spawn`
   --> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.41.1/src/task/spawn.rs:168:21
    |
166 |     pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
    |            ----- required by a bound in this function
167 |     where
168 |         F: Future + Send + 'static,
    |                     ^^^^ required by this bound in `spawn`

error: could not compile `playground` (bin "playground") due to 1 previous error

Possible Solution(s)

No response

Notes

No response

Version

Discovered on 1.77.2, but playground (supposedly running latest) has the same problem.
@stevenroose stevenroose added C-bug Category: bug S-triage Status: This issue is waiting on initial triage. labels Nov 20, 2024
@weihanglo
Copy link
Member

Guess you meant to submit an issue to rust-lang/rust?

Anyway, rust-lang/rust#63768 and rust-lang/rust#128095 seems most relevant, so close this in favor of them.

@weihanglo weihanglo closed this as not planned Won't fix, can't repro, duplicate, stale Nov 20, 2024
@stevenroose
Copy link
Author

Ah, sorry forgot the rust repo was separate. Fair enough, they seem like the same issue, yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: bug S-triage Status: This issue is waiting on initial triage.
Projects
None yet
Development

No branches or pull requests

2 participants