Bernard
Bernard

Reputation: 5666

Expected bound lifetime parameter, found concrete lifetime when trying to pass an Option<FnOnce>

In the code below, I'm trying to pass an Option<FnOnce(&mut Thing)> to the higher order function invoke_me_maybe(). The function being passed will be invoked if it is present, and not invoked otherwise.

The Option<FnOnce(&mut Thing)> are constructed using as_some() from additional trait methods on booleans, copied the boolinator crate.

struct Thing{}

fn invoke_me_maybe<F: FnOnce(&mut Thing)>(t: &mut Thing, opt_f: Option<F>) {
    if let Some(f) = opt_f {
        f(t);
    }
}

trait BoolOption {
    fn as_some<T>(self, some: T) -> Option<T>;
}

impl BoolOption for bool {
    fn as_some<T>(self, some: T) -> Option<T> {
        if self { Some(some) } else { None }
    }
}

pub fn main() {
    let mut thing = Thing{};
    invoke_me_maybe(&mut thing, true.as_some(|t| {}));
}

The invoke_me_maybe() function does not keep opt_f beyond the end of the function, so we should not need to wrap the function in a Box or anything like that.

The error produced is as follows:

error[E0631]: type mismatch in closure arguments
  --> src/main.rs:21:33
   |
3  | fn invoke_me_maybe<F: FnOnce(&mut Thing)>(t: &mut Thing, opt_f: Option<F>) {
   |    ---------------    ------------------ required by this bound in `invoke_me_maybe`
...
21 |     invoke_me_maybe(&mut thing, true.as_some(|t| {}));
   |                                 ^^^^^^^^^^^^^---^^^^
   |                                 |            |
   |                                 |            found signature of `fn(_) -> _`
   |                                 expected signature of `for<'r> fn(&'r mut Thing) -> _`

error[E0271]: type mismatch resolving `for<'r> <[closure@src/main.rs:21:46: 21:52] as std::ops::FnOnce<(&'r mut Thing,)>>::Output == ()`
  --> src/main.rs:21:5
   |
3  | fn invoke_me_maybe<F: FnOnce(&mut Thing)>(t: &mut Thing, opt_f: Option<F>) {
   |    ---------------    ------------------ required by this bound in `invoke_me_maybe`
...
21 |     invoke_me_maybe(&mut thing, true.as_some(|t| {}));
   |     ^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0271, E0631.
For more information about an error, try `rustc --explain E0271`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

I'm probably missing some explicit lifetime parameters or something like that, but I can't figure it out. Doesn't fn(_) -> _ already match with for<'r> fn(&'r mut Thing) -> _?

Upvotes: 0

Views: 67

Answers (1)

rodrigo
rodrigo

Reputation: 98398

Using closures as higher order functions is tricky. I've noticed that explicitly writing the type of the arguments usually helps. In your case it does the trick:

    invoke_me_maybe(&mut thing, true.as_some(|t: &mut Thing| {}));

The problem seems to be that invoke_me_maybe takes a generic argument with a lot of possibilities, while |t| {} may mean anything, and the compiler is not able to match both. Adding the type annotation helps in this case.

Personally I consider this a compiler bug, but I've been wrong before...

Upvotes: 1

Related Questions