Unbreakable covariance check

A few crates like yoke and Lender perform covariance check on lifetimes using techniques using pointer assignment like

 fn __check_covariance<'__long: '__short, '__short>(
      p: *const T<'__long>,
  ) -> *const T<'__short>;

Implementing this method with { p } works only if T is covariant in its lifetime. If for some reason (e.g., manually-proven covariance) you want to bypass the check, you would like that the bypass requires an unsafe, and in this case unsafe { transmute { p } } will work.

The problem is that also core::ptr::null() will work, and there's no unsafe.

You can try to improve with

 fn __check_covariance<'__long: '__short, '__short>(
      p: &*const T<'__long>,
  ) -> &*const T<'__short>;

but you can get around with Box::leak(Box::new(null())).

Is there any way to write this type coercion so that the only alternatives to { p } for implementation are unsafe? Clearly Box::leak(Box::new(null())) denotes a strong user intent—can't be a footgun like null()—but, still, it would be nice if unsafe was necessary.

The problem is that there are many ways to wrap T in something whose argument is covariant (e.g., *const, Option, Vec, ...) but in all cases I can think you can conjure one of these out of thin air (core::ptr::null(), None, vec![], ...).

This is of course related to [Compiler support for statically asserting variance?].

I might actually have come up with a solution: a ZST with a private field pub struct CovariantProof<T>(PhantomData<fn() -> T>);. That will not be constructible out of thin air because the field is not public.

You can still implement the method with todo!() or loop {} tho.

1 Like