Why is PhantomData still necessary when a lifetime is used in trait bounds?

Consider this struct:

trait InnerHasLifetime<'a> {}
struct NeedsLifetime<'a, I: InnerHasLifetime<'a>>(I);

It's invalid without adding a PhantomData using 'a, because otherwise the compiler complains that 'a is never used. But why? Clearly I must be tied to 'a because of the trait bound.

Is this something that the compiler could accept in principle but doesn't? Or is there a fundamental reason why

In this thread, it's recommended to simply not add trait bounds to the struct definition, but in the case of a struct that can only ever be used with types that satisfy the trait bounds, I don't see why that information couldn't be used to avoid the "unused lifetime" error and the need for PhantomData.

it's not about I, it's about the 'a before I. since your struct has 'a as a generic parameter, you must use 'a in the struct definition.

I don't know what your real use case is, but if your type definition doesn't need 'a, you probably don't want the trait bounds in the type definition itself. instead, you can put it in impl blocks:

struct<I> Foo(I);

impl<'a, I: Bar<'a>> Foo<I> {
}

Rust wants the parameter to be used or constrained so that it can infer the variance of the lifetime. The only way a bound can constrain another parameter is via associated type equality.

Theoretically the language could fallback to invariance, or maybe support bivariant lifetime parameters (I'm not totally sure what the challenges there would be). Or have some annotation-driven variance... but that could be pretty complicated (e.g. maybe the variance of the lifetime parameter depends on I's implementation of the trait).

2 Likes