Implementation of trait is not general enough, or conflicting trait implementations

I have this function which is having some lifetime trouble:

fn provide_importable_func<Params, Returns, F>(&mut self, name : &str, f : F) -> Result<&mut Self, VxConfigError>
where
    Params       : WasmToVxList,
    Params::Wasm : 'static,
    Returns      : VxToWasmList,
    for<'l, 'k> F
        : Clone + Send + Sync + 'static
        + AsyncFn<PrependTuple<&'k SharedState, Params::Vx<'l>>, Output = Returns::Vx<'static>>,
    for<'l, 'k>  (&'k SharedState, Params::Vx<'l>,) :  TuplePrepend<&'k SharedState, Params::Vx<'l>>,
    for<'l, 'k> <(&'k SharedState, Params::Vx<'l>,) as TuplePrepend<&'k SharedState, Params::Vx<'l>>>::Type : Tuple,

This won't compile beacuse

future cannot be sent between threads safely
the trait `Send` is not implemented for `<F as AsyncFnMut<<(&SharedState, Params::Vx<'_>) as TuplePrepend<&SharedState, Params::Vx<'_>>>::Type>>::CallRefFuture<'_>`

which makes perfect sense. Calling f returns a Future that isn't send, so the async block around it isn't Send because it awaits said Future.


So I added this where clause to the function:

where for<'a, 'b, 'e> <F as AsyncFnMut<<(&'a SharedState, Params::Vx<'b>) as TuplePrepend<&'a SharedState, Params::Vx<'b>>>::Type>>::CallRefFuture<'e> : Send

...but the Box::new(async move { /* ... */ }) inside the function errors saying

implementation of `Send` is not general enough
`Send` would have to be implemented for the type `<F as AsyncFnMut<<(&SharedState, Params::Vx<'_>) as TuplePrepend<&SharedState, Params::Vx<'_>>>::Type>>::CallRefFuture<'_>`
...but `Send` is actually implemented for the type `<F as AsyncFnMut<<(&'0 SharedState, Params::Vx<'_>) as TuplePrepend<&'0 SharedState, Params::Vx<'_>>>::Type>>::CallRefFuture<'_>`, for some specific lifetime `'0`

Adding a few more lifetimes to the where clause fixes that:

where for<'a, 'b, 'c, 'd, 'e> <F as AsyncFnMut<<(&'a SharedState, Params::Vx<'b>) as TuplePrepend<&'c SharedState, Params::Vx<'d>>>::Type>>::CallRefFuture<'e> : Send

...but causes calls of this function to error with

implementation of `TuplePrepend` is not general enough
`(&'a (), (&'b str,))` must implement `TuplePrepend<&'c (), (&'d str,)>`
...but it actually implements `TuplePrepend<&'a (), (&'b str,)>`

So it seems like both clauses are needed:

where
    for<'a, 'b, 'e>         <F as AsyncFnMut<<(&'a SharedState, Params::Vx<'b>) as TuplePrepend<&'a SharedState, Params::Vx<'b>>>::Type>>::CallRefFuture<'e> : Send,
    for<'a, 'b, 'c, 'd, 'e> <F as AsyncFnMut<<(&'a SharedState, Params::Vx<'b>) as TuplePrepend<&'c SharedState, Params::Vx<'d>>>::Type>>::CallRefFuture<'e> : Send

Now the Box in Box::new(async move { /* ... */ }) errors with

type annotations needed: cannot satisfy `<F as AsyncFnMut<<(&SharedState, Params::Vx<'b>) as TuplePrepend<&SharedState, ...>>::CallRefFuture<'e> : Send`
...multiple `impl`s or `where` clauses satisfying`for<'a, 'b, 'e> <F as AsyncFnMut<<(&'a SharedState, Params::Vx<'b>) as TuplePrepend<&'a SharedState, Params::Vx<'b>>>::Type>>::CallRefFuture<'e> : Send` found

I'm not sure how to get around this, or if I am overthinking it.
Any help would be appreciated. Thank you.

Given that you’re trying to write clauses explicitly involving e.g. reference to the CallRefFuture type, it sounds like you are looking for options involving unstable feature on nightly Rust. If this isn’t actually the case, note that the new AsyncFn traits do actually offer very little support for Send bounds on the futures unfortunately, in stable Rust; they’re sort of a MVP / not quite as powerful as they should hopefully become eventually, in this regard.

For answering your question with usage of unstable nightly-only access to the AsyncFn trait, this is actually something I haven’t fully explored yet myself, but I’d love to!

I can imagine this might be solvable, perhaps under usage of some helper traits… but it’s hard to predict what the compiler is capable of here, especially given that AsyncFn is one of those traits that are magically implemented compiler-internally, and thus it might interact subtly differently with the trait solver than any assumed-to-be-equivalent handwritten impl, and then auto traits too are magically implemented compiler-internally; normal trait-system arithmetic might no longer fully apply, and even the normal stuff is quite subtle and a bit broken[1] around higher-ranked lifetimes already anyway

It would be really helpful as a starting point (or perhaps rather end goal?)[2] if you could provide a way to reproduce your exact scenario. Either refer to the real code if it’s open source, or try to mock the relevant types (please make sure that it’s sufficiently complete so that it can compile successfully without the line of code that requires the Send-ness added; feel free to share both this, and a non-compiling variant of the code that has the set of …: Send bounds added that you already tried).


  1. usually “broken” in the sense of some things conservatively don’t compile even though they would appear fine, not so much bad code not being rejected ↩︎

  2. so I could know I’d be working on actually solving your problem, and not some superficially similar, but fundamentally different variation of it – and on a more basic level, to spare me the rather large effort of trying to mock this myself, from much more limited information ↩︎