Type parameters with generic lifetime parameters

For this specific case, since you're doing manual type erasure which is wildly unsafe already, I think it's fine if you have to transmute away some lifetimes to make it work. You only need a single transmute to make the pointer type more general:

pub trait MyObject<'a>: 'a {
    fn add(&self, other: Cell<&'a u8>) -> &'a [u8];
}

pub fn make_vtable_entry_concrete<'a, T: MyObject<'a>>(
) -> for<'b> fn(&'b T, Cell<&'a u8>) -> &'a [u8] {
    |x, y| x.add(y)
}

pub fn make_vtable_entry_erased<'a, T: MyObject<'a>>(
) -> for<'b> unsafe fn(*const (), Cell<&'b u8>) -> &'b [u8] {
    unsafe { mem::transmute(make_vtable_entry_concrete::<T>()) }
}

IIUC this makes no more assumptions than already introduced by using manual vtables.

Given that "lifetimes don't exist," though, I do think lifetime-specific HKT could be reasonable, the same way that we already allow for<'a> in other positions. That could look like

pub fn make_vtable_entry<for<'a> T<'a>: MyObject<'a>>(
) -> for<'a, 'b> fn(&'b T<'a>, Cell<&'a u8>) -> &'a [u8] {
    |x, y| x.add(y)
}

This would have to be called with an explicit turbofish, e.g.

make_vtable_entry::<for<'a> &'a u8>()

Your HKT signature cannot work for Foo as written, though, @stepancheg, as in the body of make_vtable_entry you can name T<'static> which may not be valid Foo<'v, V> for non-'static V. There needs to be an extra 'bound lifetime, which is where all of the additional complexity is coming from, e.g.

pub fn make_vtable_entry<'bound, for<'a where 'bound: 'a> T<'a>: MyObject<'a>(
) -> for<'a, 'b where 'bound: 'a> fn(&'b T<'a>, Cell<&'a u8>) -> &'a [u8] {
    |x, y| x.add(y)
}
make_vtable_entry::<'v, for<'a where 'v: 'a> Foo<'a, V>>()

or perhaps use '_ for single-lifetime sugar. The for<where> syntax is from Extending `for<'a>` construct.

I tried to explicitly reify this with GAT, but ran into a cryptic lifetime bound not satisfied error that doesn't even provide the source of the bound.

pub trait TMyObject<'bound> {
    type Apply<'a>: MyObject<'a>
    where
        'bound: 'a;
}

pub fn make_vtable_entry<'bound, Kind: TMyObject<'bound>>(
) -> for<'a, 'b> fn(&'b Kind::Apply<'a>, Cell<&'a u8>) -> &'a [u8] {
    |x, y| x.add(y)
}

pub struct Foo<'v, V: 'v> {
    // invariance for maximum pessimism; I tried covariance as well
    _phantom: PhantomData<fn(&'v V) -> &'v V>,
}

impl<'v, V: 'v> TMyObject<'v> for Foo<'v, V> {
    type Apply<'a> = Foo<'a, V>
    where
        'v: 'a;
}

impl<'v, V: 'v> MyObject<'v> for Foo<'v, V> {
    fn add(&self, _other: Cell<&'v u8>) -> &'v [u8] { unimplemented!() }
}

pub fn make_foo_vtable_entry<'v, V: 'v>(
) -> for<'a> fn(&'a Foo<'v, V>, Cell<&'v u8>) -> &'v [u8] {
    make_vtable_entry::<'v, Foo<'v, V>>()
}