Rust one type (function pointer) is more general than the other

I reached this error in this example and I'm trying to understand what's happening.

use futures::future::{BoxFuture, FutureExt};
use std::sync::Arc;
use futures::lock::Mutex;

struct Message {}
struct Client {}

enum Error {
    ConnectionClosed,
}

#[derive(Default)]
struct MyType{}

impl Client {
    fn send_and_expect<'a, R: 'a + Default + Send>(
        client: Arc<Mutex<Self>>,
        message: &'a Message,
    ) -> BoxFuture<'a, Result<R, Error>> {
        async move { Ok(R::default()) }.boxed()
    }

    pub fn connection_retrier<'a, R: 'a + Default + Send>(
        client: Arc<Mutex<Self>>,
        f: for<'b> fn(Arc<Mutex<Self>>, &'b Message) -> BoxFuture<'b, Result<R, Error>>,
        f_m: &'a Message,
    ) -> BoxFuture<'a, Result<R, Error>>
    {
        async move {Ok(R::default())}.boxed()
    }

    async fn send_with_retry<'a>(
        client: Arc<Mutex<Self>>,
        message: &'a Message,
    ) -> Result<MyType, Error> {
        let client = Arc::new(Mutex::new(Client{}));
        Self::connection_retrier::<MyType>(client, Self::send_and_expect, message)
            .await
    }
}

Error:

error[E0308]: mismatched types
  --> src/lib.rs:36:52
   |
36 |         Self::connection_retrier::<MyType>(client, Self::send_and_expect, message)
   |                                                    ^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected fn pointer `for<'b> fn(Arc<_>, &'b Message) -> Pin<Box<(dyn futures::Future<Output = std::result::Result<MyType, Error>> + std::marker::Send + 'b)>>`
              found fn pointer `fn(Arc<_>, &Message) -> Pin<Box<dyn futures::Future<Output = std::result::Result<MyType, Error>> + std::marker::Send>>`

Playground

Well, connection_retrier requres a function f: for<'b> fn(Arc<Mutex<Self>>, &'b Message) -> BoxFuture<'b, Result<R, Error>>,. The one I passed seems to fit the signature.

The way I view for<'b> fn... is: I accept a function f for any lifetime 'b presented. So, for the particular lifetime 'a, send_and_expect seems to fit everything.

The only suspicion I have is for the lifetime of R being fixed at 'a in connection_retrier so the f with its for<'b> is not free to give any lifetime for its R. I think the lifetime of the R in f should be 'b. Is it possible to force f to have R with lifetime 'b?

Something like this:

    f: for<'b> fn<RR: 'b>(Arc<Mutex<Self>>, &'b Message) -> BoxFuture<'b, Result<RR, Error>>,

Indeed, that's the issue in question.

There is no clean way to achieve this; the trick is to "induce" the bound through a type that requires it, inside the function signature.

For instance, with

struct MyBoxedFuture<'lt, Ret : 'lt> /* = */ (
    BoxedFuture<'lt, Ret>,
);

function signatures involving MyBoxedFuture<'a, R> will "induce" an implicit R : 'a bound, so that you can skip mentioning it.

1 Like