Unsatisfied trait bounds on Fn that implements a trait

This has probably been asked before, but I can't figure out how to search for it. Feel free to link an answer if you find one.

Why does the following not compile?

The playground is currently not working for me, so here is the compiler error:

22 |     fun.say_hello("fr");
   |         ^^^^^^^^^ method cannot be called on `fn(&str) -> Option<&str> {fun}` due to unsatisfied trait bounds

The error goes away once I change the fun function to return Option<String> , which leads me to believe this is related to the lifetime of the associated type. But that's as far as i understand.

Thank you

The desugared version of fun is

fn fun<'s>(lang: &'s str) -> Option<&'s str>

Where the input and output have the same lifetime.

The desugared version of your Greeter implementation is

impl<F, Out> Greeter for F
where
    F: for<'any> Fn(&'any str) -> Option<Out>,

Type parameters like Out must resolve to a single type, but types that differ by lifetime (even if they only differ by lifetime) are distinct types. So there's no way Out could be capturing the lifetime 'any; the output type has to be the same for every lifetime input lifetime 'any.

Thus the implementation does not apply to fun, which has a different output type for every input lifetime.

For a direct solution, you would need something like a generic type constructor or a way to put a bound on the output type without unifying it with a generic type parameter. That's not possible in Rust today, but there are sometimes workarounds like shadowing the Fn traits in a way that doesn't require naming the output type with a generic type parameter.

1 Like

Here's one such workaround.

(I also tweaked the lifetimes on say_hello so that the return borrows lang and not self (as an educated guess on what you wanted). See also, the method signatures elision rules.)

Thank you! The workaround you suggested is a bit to gnarly for me :smile:

but this:

helped me understand the compiler error, which is what I was after.