Re: [PATCH v3 16/27] rust: types: add `ForLt` trait for higher-ranked lifetime support

From: Gary Guo

Date: Tue May 19 2026 - 07:40:05 EST


On Tue May 19, 2026 at 12:07 PM BST, Alexandre Courbot wrote:
> On Sun May 17, 2026 at 9:01 AM JST, Danilo Krummrich wrote:
> <snip>
>> +/// This is intended to be an "unsafe-to-refer-to" type.
>> +///
>> +/// Must only be used by the `ForLt!` macro.
>> +///
>> +/// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated by macro.
>> +///
>> +/// `WF` is a type that the macro can use to assert some specific type is well-formed.
>> +///
>> +/// `N` is to provide the macro a place to emit arbitrary items, in case it needs to prove
>> +/// additional properties.
>> +#[doc(hidden)]
>> +pub struct UnsafeForLtImpl<T: ?Sized, WF, const N: usize>(PhantomData<(WF, T)>);
>
> Although the documentation makes it clear this should never be
> referenced directly, doing so is still possible, which creates a
> loophole for breaking covariance using only safe code.

I'm aware. That's why it has `Unsafe` in the name. But there's no way to create
unsafe-to-name types, and without adt_const_params only integers can be used as
const generic parameters and thus I cannot use a unsafe-to-create const
parameter for this.

>
> For instance (untested, and based on my limited understanding of the
> patch):
>
> type Bad = UnsafeForLtImpl<
> dyn for<'a> WithLt<'a, Of = Cell<&'a u8>>,
> (),
> 0,
> >;
>
> The blanket `ForLt` implementation applies, and now we can store a
> shorter-lived reference into the `Cell` and potentially observe it after
> its lifetime.
>
> This could be worked around by defining the type implementing `ForLt`
> locally, at the cost of ergonomics since the `ForLt` type would be
> declared separately:
>
> // Defines `DataLt` and implements `ForLt` on it after emitting
> // covariance proof.
> define_for_lt!(DataLt = for<'a> Data<'a>);

An earlier version of this series have `ForLt!()` being quite ubiquitous, so I
want to avoid this approach as this'll be need everywhere. But now we switch to
use GAT for driver data, so perhaps this isn't too terrible anymore (only
driver-core and aux device registration would need this).

This could even be extended to support generic types, such as

define_for_lt!(DataLt<T> = for<'a> Data<'a, T>);

This does also have th benefit of not having the `type_complexity` issue.

Danilo, what do you think?

---

I suppose If we're going down the new type approach, I also have some idea about
generalizing this further to a generic utility that annotate GAT about variance.

#[variance_check]
trait MyTrait {
type MyGat<#[covariant] 'a>;
}

#[variance_check]
impl MyTrait for MyFoo {
type MyGat<#[covariant] 'a> = Bar;
}

Then the expansion of `define_for_lt!` would just be

struct DataLt<T>(PhantomData<T>);

#[variance_check]
impl<T> ForLt for DataLt<T> {
type Of<#[covariant] 'a> = Data<'a, T>;
}

Best,
Gary