` for<'a> &'a T ` seems to require ` T: 'static `

Hi,

On my project, I'm facing some weird error, with a type required to outlive 'static somehow.

Here's a reduced version of my code:

// RUN THIS CODE WITH THE `-Znext-solver` RUST FLAG

use std::ops::Deref;

trait GenerateName {
    fn generate_name(self) -> String;
}

// This allows to implement GenerateName for `&&&&T` (and so on) where `&T: GenerateName`
impl<'a, T, S> GenerateName for &'a T
where
    S: 'a,
    &'a S: GenerateName,
    T: Deref<Target = S>,
{
    fn generate_name(self) -> String {
        (**self).generate_name()
    }
}

struct NameGenerator<'a> {
    example_field: &'a (),
}

impl GenerateName for &NameGenerator<'_> {
    fn generate_name(self) -> String {
        "Rick Astley".into()
    }
}

fn func<Generator>(generator: Generator)
where
    for<'a> &'a Generator: GenerateName, // I use this to be able to call `generate_name` multiple times
{
    generator.generate_name();
    generator.generate_name();
}

fn main() {
    let counter = ();

    let context = NameGenerator {
        example_field: &counter,
    };

    func(&context);
}

This code only produces my error with the new trait solver, for some reason (with the current trait solver, it gives an overflow error). I've tried it on nightly (rustc 1.94.0-nightly (2ca7bcd03 2025-12-23)), but maybe it "works" on stable/beta.

When I run this code, it says that counter must be borrowed for 'static, because func requires for<'a> &'a Generator: GenerateName. As a hint, it says due to a current limitation of the type system, this implies a `'static` lifetime.

~~~ a current limitation of the type system ~~~

Also, when I call func(context) without the reference, it works, so maybe it has to do with my generic implementation on Derefs.

Can someone explain why there is this error, and what it means?

Any &'a T comes with a hidden requirement that T: 'a since that is necessary for the validity of the reference type itself. So when you have for<'a> … &'a T you'll also implicit require for<'a> T: 'a and that can be instantiated with 'a = 'static to see it in particular requires T: 'static.

Ok, but then why does it work when calling func(context) instaid of func(&context)? context isn't 'static.

func(context) works with the current code, but if I add Generator: 'static, it doesn't.

I'm not sure exactly why func(context) works, but it's very likely to have something to do with "implied bounds". The existence of the type &'a &'b () implies that 'b: 'a. The for<'a> T: Trait bound doesn't actually mean "for all 'a ...", it means "for all 'a where some well-formedness constraints hold...". In particular, you can try sneaking well-formedness constraints into the trait itself. (I'm not sure exactly when well-formedness constraints of the generic T are implied or required, but I think the well-formedness of the trait should be implied there.) That's what the lender crate does to get for<'a> to work better; maybe you can find inspiration from its docs (or source code).

1 Like

Really, &'a T come with an “implied bound” of T: 'a. In a normal where bound or the like, this would mean extra requirement… but if the lifetime is introduced in higher-order bounds, i.e. some for<'a> …-style HRTBs[1], the intended meaning is instead that the for<'a> … quantifier is meant to only range over all such lifetimes that fulfill T: 'a.

The “current limitation of the type system” that this compiler error mentions is that the type system doesn’t actually properly support such restricted ranges for for<'a> … trait bounds, but kind-of rather just behaves as-if these were to truly range over all possible lifetimes, just that whenever you’re going to use that same bound, you’ll have to sort-of mention the very same &'a T type again and now if that’ll be in a context about some concrete (not higher-rank) lifetime parameter, that gives rise to the same implied bound once-again and now you gotta actually fulfill it.

So all is fine.

Except when it isn’t. :collision:

Yeah, anyway, in most practical cases this works as intended though, but as linked above there is some unsoundness on one hand, and as noted in this thread / by that compilation error, there are some remaining restrictions on the other hand.

“Proper support” would mean that something like for<'a> &'a Generator: GenerateName would more literally desugar to something like

for <'a> ( if <Generator: 'a> /* then */ ( &'a Generator: GenerateName ) )

(there is no actual official syntax for this … yet … I believe … so take it as pseudo-code)

One difficulty of proper support, as far as I remember, is that it would imply the type system needs to handle bounds like

impl<'a, 'b, 'i> …
where
    'a: 'i,
    'b: 'i,
    for<'l> ( if<'a: 'l, 'b: 'l> ( 'i: 'l )),
{ … }

and

impl<'a, 'b, 'u> …
where
    'u: 'a,
    'u: 'b,
    for<'l> ( if<'l: 'a, 'l: 'b> ( 'l: 'u )),
{ … }

which can be used to nail down 'i or 'u, effectively to be equal, to the “intersection”, or the “union” of two lifetimes 'a and 'b, respectively;[2] and I think may have read somewhere that at least one of the two [not sure off the top of my head which one it was, “intersection” or “union”] is somehow more fundamentally beyond the capabilities of what the current type system could handle.


  1. "higher-rank trait bounds" ↩︎

  2. equivalently you can think of thes as something like of binary supremum and infimum if you consider the : an order relation ↩︎

2 Likes

By the way, avoiding all explicit mentions of …: 'a in this trait impl appears to be possible in a way the compiler tolerates: by not introducing S as a separate variable, you can fix your code like this:

impl<'a, T> GenerateName for &'a T
where
    &'a T::Target: GenerateName,
    T: Deref,
{
    fn generate_name(self) -> String {
        (**self).generate_name()
    }
}
2 Likes

Ok, thank you very much for this answer, it was very interesting. (now I think I'm gonna need some Doliprane lol)
So for now, I guess I have to use the solution you mentioned in your last message. (still marking the first one as the solution, because I think the second one is a bit too specific)