Implementation of `Send` is not general enough, but cannot make it more general

I have a curious issue where I'm trying to make a structure Send, to be able to use it in tokio's async workers.
This struct uses some raw pointers, so I have to manually implement Send for some structures.

However, I'm getting an error which I do not understand how to solve.

I have boiled it down to the essentials here:

pub struct Receiver<T: Send + 'static>(pub Option<T>);

impl<T: Send + 'static> Receiver<T> {
    pub async fn get_shared(&mut self) -> Option<&mut T> {
        None
    }
}

pub struct Event<'a>(&'a FFIEvent);

// Redundant in this test, but assume Receiver<T> has some raw pointer fields too.
// Commenting this out, and making the compiler automatically derive Send makes everything compile.
// But obviously I cannot do that if there are raw pointers in the struct.
unsafe impl<T: Send + 'static> Send for Receiver<T> {}

struct FFIEvent();

#[tokio::main]
async fn main() {
    // implementation of `std::marker::Send` is not general enough
    // = note: `Send` would have to be implemented for the type `&'0 FFIEvent`, for any lifetime `'0`...
    // = note: ...but `Send` is actually implemented for the type `&'1 FFIEvent`, for some specific lifetime `'1`
    tokio::spawn(async move {
        let mut r: Receiver<Event<'static>> = Receiver(None);

        r.get_shared().await.unwrap();
    });
}

Link to rust playground: Rust Playground

This results in the error:

Does anyone know how to interpret this error, and how to solve it?

To me, it sounds like it wants me to use higher kinded types for implementing Send in some way. But I don't think that's possible.

I can reproduce this both on stable and nightly.

I think you've hit this issue. Generalizing your Send implementation for Receiver to T living arbitrarily long (not only for 'static) makes your playground compile.

2 Likes

Interesting. Thanks for the workaround.

I think it's particularly weird because Receiver requires T to be 'static already. So

unsafe impl<'a, T: Send + 'a> Send for Receiver<T> {}

seems like it shouldn't be stronger than using Send + 'static.

You can mostly chalk up this behavior to the way rustc currently works; As the spiritual successor to Salsa is fully integrated, and the compiler's code paths (in this case everything to do with the type and borrow systems) are all migrated to use that, I'd expect such corner cases to gradually disappear over time.
The time frame for that may well me measured in terms of years though.

1 Like

Thanks!
So I guess this is a compiler bug then. But a known one, that will hopefully get smoothed out with time.

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.