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 fn trait's method's future does not implement Send trait bound #114142

Closed
GlenDC opened this issue Jul 27, 2023 · 10 comments
Closed

async fn trait's method's future does not implement Send trait bound #114142

GlenDC opened this issue Jul 27, 2023 · 10 comments
Labels
C-bug Category: This is a bug. F-async_fn_in_trait Static async fn in traits requires-nightly This issue requires a nightly compiler in some way. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@GlenDC
Copy link
Contributor

GlenDC commented Jul 27, 2023

I tried this code:

#![feature(async_fn_in_trait)]
#![feature(return_type_notation)]

trait Service<Request> {
    type Output;
    type Error;

    async fn call(&mut self, req: Request) -> Result<Self::Output, Self::Error>;
}

struct EchoService;

impl<Request> Service<Request> for EchoService {
    type Output = Request;
    type Error = std::convert::Infallible;

    async fn call(&mut self, req: Request) -> Result<Self::Output, Self::Error> {
        Ok(req)
    }
}

async fn higher_order_async_fn<S, Request>(mut svc: S, req: Request)
where
    S: Service<Request, call(): Send> + Send + 'static,
    S::Output: std::fmt::Debug + Send + 'static,
    S::Error: std::fmt::Debug + Send + 'static,
    Request: Send + 'static,
{
    tokio::spawn(async move {
        let output = svc.call(req).await.unwrap();
        println!("{:?}", output);
    })
    .await
    .unwrap();
}

#[tokio::main]
async fn main() {
    higher_order_async_fn(EchoService, "Hello, World!").await;
}

Playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=b8b7d938b1f7ab5cfe4284e0cc6ab09c

I expected to see this happen: it should work and print "Hello, World!" to the stdout.

Instead, this happened: I get a compile error:

error[[E0277]](https://doc.rust-lang.org/nightly/error_codes/E0277.html): `impl Future<Output = Result<<_ as Service<_>>::Output, <_ as Service<_>>::Error>>` cannot be sent between threads safely
  --> src/main.rs:39:27
   |
39 |     higher_order_async_fn(EchoService, "Hello, World!").await;
   |     --------------------- ^^^^^^^^^^^ `impl Future<Output = Result<<_ as Service<_>>::Output, <_ as Service<_>>::Error>>` cannot be sent between threads safely
   |     |
   |     required by a bound introduced by this call
   |
   = help: the trait `for<'a> Send` is not implemented for `impl Future<Output = Result<<_ as Service<_>>::Output, <_ as Service<_>>::Error>>`
note: required by a bound in `higher_order_async_fn`
  --> src/main.rs:24:33
   |
22 | async fn higher_order_async_fn<S, Request>(mut svc: S, req: Request)
   |          --------------------- required by a bound in this function
23 | where
24 |     S: Service<Request, call(): Send> + Send + 'static,
   |                                 ^^^^ required by this bound in `higher_order_async_fn`

For more information about this error, try `rustc --explain E0277`.

and E0277 refers to:

rustc --explain E0277
You tried to use a type which doesn't implement some trait in a place which expected that trait.

which is not really more helpful then the error msg itself.

Meta

Playground:

Nightly channel
Build using the Nightly version: 1.73.0-nightly

(2023-07-26 0d95f9132909ae7c5f24)

Local version:

rustc --version --verbose:

rustc --version --verbose
rustc 1.72.0-nightly (cb80ff132 2023-07-07)
binary: rustc
commit-hash: cb80ff132a0e9aa71529b701427e4e6c243b58df
commit-date: 2023-07-07
host: aarch64-apple-darwin
release: 1.72.0-nightly
LLVM version: 16.0.5

Background

I also track this issue in plabayo/tower-async#9, an issue in the tower-async repo, which is a monorepo of a fork of the https://github.com/tower-rs/tower and https://github.com/tower-rs/tower-http libraries that I made and maintain, making use of the new upcoming async support as advertised in https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html, which got me very excited and very invested in starting to prepare for that future.

tower-async is then used by me in another project of mine, https://github.com/plabayo/rama, which is a going to be a general proxy framework with data extraction in mind.

Problem is however that it seems that the futures produced by the tower-async Service does not implement Send. And without my higher order functions requiring themethod(): Send trait bound it won't compile either.

So:

  • in worst case this is a bug in the current incomplete async-fn trait support
  • or in best case it is me missing something obvious, or in other words not knowing how to use this properly. In which case I guess the error message could never the less still use some work as a solution is not immediately clear to me.

Similar to the other F-async_fn_in_trait Static async fn in traits issues I am more then willing to help out where you can make use of me, as I am invested in making this work and thus also be able to run one day this kind of code back in the safer Rust lands of stable rustc :)

Thanks upfront!

@GlenDC GlenDC added the C-bug Category: This is a bug. label Jul 27, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jul 27, 2023
@compiler-errors
Copy link
Member

I'm like 72.5% sure that this is a duplicate of #109924.

@compiler-errors compiler-errors added requires-nightly This issue requires a nightly compiler in some way. F-async_fn_in_trait Static async fn in traits T-types Relevant to the types team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Jul 27, 2023
@GlenDC
Copy link
Contributor Author

GlenDC commented Jul 27, 2023

Yes I am sorry. Totally missed that, was looking for it, but couldn't immediately spot it.
You can close this as a duplicate, as I think you're right.

What 's the status on #109924? Is that do-able to fix, or is it a can of worms situation? And can I help to progress this, as this is one of few problems that really is a blocker, as until then I cannot really spawn tasks for each incoming connection? Or is there a work around available?

@compiler-errors
Copy link
Member

Totally missed that

I'm just noting for the record. It's not obvious what the root cause is from the error message, since it kinda sucks.

Is that do-able to fix, or is it a can of worms situation?

It's essentially impossible to fix in the old trait solver. It's one of the reasons we are working on the new trait solver -- because we need deferred projection equality (#107507) to solve this problem in general.

You can probably work around this by turbofishing higher_order_async_fn, e.g. higher_order_async_fn::<EchoService, _>(.....)

@compiler-errors
Copy link
Member

@GlenDC
Copy link
Contributor Author

GlenDC commented Jul 27, 2023

Very cool. I can confirm that this indeed works in my actual code as well. Not ideal, but okay, this does unblock me.
Is there any ETA on when that trait solver would ship in nightly, or is that not for immediate? Just so I manage my own expectations.

@compiler-errors
Copy link
Member

Not soon is all I can say, unfortunately. It takes a lot of work to rewrite one of the most delicate + fundamental parts of Rust 😃

@GlenDC
Copy link
Contributor Author

GlenDC commented Jul 27, 2023

Hahaha, got you. That's def. a nasty one. Thanks, appreciate it.

@GlenDC
Copy link
Contributor Author

GlenDC commented Jul 28, 2023

For now I added the workaround to my FAQ pages, eg https://github.com/plabayo/tower-async#faq

Is there btw somewhere where I can follow progress on the active work regarding the trait resolver rewrite?

@compiler-errors compiler-errors moved this from Blocked to Non-blocking in return position impl trait in traits Sep 7, 2023
@compiler-errors
Copy link
Member

compiler-errors commented Sep 11, 2023

I'm gonna close this as a dupe of #109924 (edit: wrong issue, sorry), since that's the exact same root cause.

@GlenDC
Copy link
Contributor Author

GlenDC commented Sep 12, 2023

For a second you got my hopes up, thought it was fixed :')
Seems not, but that's okay, I know this isn't an easy one!
If there's something I can do to help do let me know :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. F-async_fn_in_trait Static async fn in traits requires-nightly This issue requires a nightly compiler in some way. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
Development

No branches or pull requests

3 participants