Generate code which only compiles if type is invariant

I decided to make a library providing a macro to enforce a compile time requirement that a type's generic parameters conform to a certain variance. My plan for doing this was to have the macro generate code which only compiles if the type follows that variance, but I cannot figure out how to do that for invariance. Is making a function which only compiles if a type is invariant with respect to a specific generic parameter even possible? If not, would the best path forward be to insert fields to ensure invariance but continue with the compile-time checking strategy for enforcing covariance and contravariance?

I can point you to PhantomData paterns. Not clued up to figure out what your trying to achieve so will be hard to give something definitive.

Here's an attempt to clarify what I'm trying to do. The idea is to create a macro (which I'll be calling enforce_variance for which the macro call enforce_variance!{ struct Example<#[covariant] 'a>(&'a u8) } expands to something like

const _: () = {
    fn ensure_covariance<'short, 'long: 'short>(val: Example<'long>) -> Example<'short> { val }
};

That code will only compile if Example is covariant with respect to 'a. The actual code would need to be quite a bit more complicated in scenarios with more parameters and interactions between those parameters, but the general idea still applies. The problem is, I'm not aware of any code that would only compile if a type is invariant with respect to a particular one of its generic parameters. Based on the fact that it doesn't seem to be possible to do that, I'll probably use the PhantomData patterns to make sure that the parameter isn't unconstrained (and has the correct variance if nothing contradicts it) and then generate code only in the covariant and contravariant cases to make sure that the type has the correct variance, since it is impossible to override invariance.

1 Like

I'm not really sure what the idea behind this response is, since the code doesn't compile as-is, and it is very much possible to implement that trait for non-invariant types.

yoke - Rust has a special trait to ensure covariant lifetimes.

I think type gaining covariance (or contravariance) only increases the possible accepted code blocks, due to more coercions being available... that's a catch...

maybe you can introduce multiple impls which would overlap on contra-/covariant types?

Implementations and bounds don't "care" about variance. E.g. an implementation for fn(&'static str) is not an implementation for for<'a> fn(&'a str) even though the latter can coerce to the former, etc.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.