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