How to Create `Fn` Bound That Includes Arguments With Higher-ranked Lifetime Bound

So, let's say you have a F: for<'f> Fn(&'f str). What happens when you pass it to this?

fn a<G: Fn(In), In>(_: G) {}

The answer is that the compiler has to choose a single type to resolve the In type parameter. So it chooses a single lifetime, 'static say, and you can pass in your F: Fn(&'static str). It's no longer higher-ranked, because generic type parameters must resolve to a single type (and types that differ by lifetime only are still distinct types).


There is a way partially around this with custom traits, but it's a pain and wrecks a lot of inference. The key trick is to avoid "naming" higher-ranked things with type parameters. (More details.)

But I don't think it helps with this type-erased form, because you basically want to end up with something like

trait BorrowingFn {
    type In<'a>;
    type Out<'a>;
    fn call<'a>(&self, input: Self::In<'a>) -> Self::Out<'a>;
}

let _ = &dyn BorrowingFn< ... ? ... >

and we don't have a way to support or even specify GATs/higher-ranked things in trait objects yet.

// Imaginary syntax for some future Rust
dyn BorrowingFn<for<'x, 'y> In<'x> = &'x String, Out<'y> = &'y str>>

As for the 'static bounds, a fn(&'a str): 'static bound fails for example; the lifetime relationship is syntactical in nature. It's probably the same thing going on with Fn, but I also think it's not your actual problem and just a symptom, so I won't dig any further.

(fn(&str): 'static is a bound that can be met.)