This is due to how HRTBs work.

The bound `Fn(&T) -> &S`

stands for `for<'a> Fn(&'a T) -> &'a S`

, which in turn stands for something there isn’t quite syntax for, but let’s assume we can add a where clause, then it stands for something like

```
for<'a> [where T: 'a, S: 'a] Fn(&'a T) -> &'a S
```

i.e. it *requires* `Fn(&'a T) -> &'a S`

precisely for those lifetimes such that `T: 'a`

and `S: 'a`

are true.

The same of course is true for the other two trait bounds.

So `Fn(&T) -> &S`

, `Fn(&S) -> &R`

and `Fn(&T) -> &R`

stand for

```
for<'a> [where T: 'a, S: 'a] Fn(&'a T) -> &'a S
```

```
for<'a> [where S: 'a, R: 'a] Fn(&'a S) -> &'a R
```

```
for<'a> [where T: 'a, R: 'a] Fn(&'a T) -> &'a R
```

notably the `where`

clauses are *different*.

Assume we want to verify for any given lifetime `'a`

matching the where clause `where T: 'a, R: 'a`

, that `Fn(&'a T) -> &'a R`

is truly implemented by our return value. For the closure to work correctly, both `f1`

and `f2`

must thus be able to, one after the other, process `&'a T`

. Buf for `f1`

already, the call faces a problem: The `where`

clause for **it** requires `T: 'a`

which we have assumed, and `S: 'a`

, which is a relation we *don’t* know is true.

The compiler ultimately infers that fabricating the necessary `S: 'a`

bound would only really be possible if the function also requires `S: 'static`

(which does imply `S: 'a`

for all lifetimes `'a`

).

This may seem a bit overly restrictive… more precisely we’d only need to require `S: 'a`

for those lifetimes that fulfill `T: 'a`

and `R: 'a`

, but Rust offers no syntax to write such a relationship either.

Regarding solutions, thus adding `S: 'static`

*is* a reasonable way to address the issue.

Other reasonable ways:

Perhaps you never intended to have higher-ranked types in the first place. You could write a function

```
fn chain<'a, T: 'a, S: 'a, R: 'a>(
f1: impl Fn(&'a T) -> &'a S,
f2: impl Fn(&'a S) -> &'a R,
) -> impl Fn(&'a T) -> &'a R {
move |v| f2(f1(v))
}
```

that only involves non-higher-ranked types, though arguably in that case, you might as well rewrite it into the more general

```
fn chain<T, S, R>(
f1: impl Fn(T) -> S,
f2: impl Fn(S) -> R,
) -> impl Fn(T) -> R {
move |v| f2(f1(v))
}
```

Or perhaps you might desire to add something akin to a modified `where`

bound on the higher-ranked type… really if we could specify that the returned closure still requires `S: 'a`

…

… but we can only somewhat clunkily and indirectly do that: By adding a `PhantomData<&'a S>`

argument that’s otherwise going to be irrelevant/ignored

```
use core::marker::PhantomData;
fn chain<T, S, R>(
f1: impl Fn(&T) -> &S,
f2: impl Fn(&S) -> &R,
) -> impl for<'a> Fn(&'a T, PhantomData<&'a S>) -> &'a R {
move |v, _| f2(f1(v))
}
```

What solution may be best depends strongly on your use-case for this function, and arguably no approach is really perfect