Why doesn’t this future implement `Send`?

I got “impl Sync cannot be sent between threads safely” error from the following code:

use futures::lock::Mutex;

fn f(value: &(Mutex<()>, impl Sync)) -> impl Send + '_ {
    async move {
        Mutex::lock(&value.0).await;
    }
}

As far as I know, in function f, there can never be a impl Sync object transferred between threads. f can only accesses impl Sync through references, and &impl Sync is, by definition, Send. So what’s the problem?

I also noticed that if I split off the await part, the function compiles successfully:

use futures::lock::Mutex;

fn f(value: &(Mutex<()>, impl Sync)) -> impl Send + '_ {
    async move {
        let m = Mutex::lock(&value.0);

        m.await;
    }
}

This is currently a limitation in the type checking of async blocks. What you’re doing is not wrong, for some reason rustc currently considers the type of *value [which is a place-expression that kind-of apprears as a “temporary” in the desugaring of &value.0 into &(*value).0 however, place-expressions like this one don’t have to actually produce temporaries, and in this case I’m suspecting that this is the kind of detail that the current heuristic doesn’t consider] to be part of the types of values that are held over the .await point. This hopefully gets fixed eventually, in the meantime it’s possible to work around it, e.g. like you did yourself.

1 Like

Is there a corresponding issue that I can follow?

I strongly suspect there is one, but I have never checked. I just remember having seen similar problems in this forum before, so it’s definitely nothing entirely unknown. Maybe you can find it yourself or someone else knows some issue(s).

See also:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.