Rust attribute to disallow enum variant

Is there an attribute to throw a compiler error when a specific enum variant is constructed?

I had this issue where I could not use a generic type parameter on an enum because of the error R: parameter is never used:

enum Msg<R: Route, P: Page<R>> {
    Page(<P as Component>::Msg),
    UrlChanged(subs::UrlChanged),
}

So I added a phantom variant, which should never be used:

enum Msg<R: Route, P: Page<R>> {
    Page(<P as Component>::Msg),
    UrlChanged(subs::UrlChanged),
    _Unreachable(std::marker::PhantomData<R>),
}

How can I tell the compiler to throw an error when this variant is constructed, or maybe even used in a pattern?

One way to kind of achieve this is to throw a void / uninhabited type into the unreachable variant:

enum Unreachable {}

pub
struct PhantomUnreachable<T : ?Sized> (
    Unreachable,
    ::core::marker::PhantomData<T>,
);
impl<T : ?Sized> PhantomUnreachable<T> {
    pub
    fn unreachable_arm (&self) -> !
    {
        match self.0 {}
    }
}

and then use a PhantomUnreachable<R> as the payload of your type:

enum Msg<R: Route, P: Page<R>> {
    Page(<P as Component>::Msg),
    UrlChanged(subs::UrlChanged),
    _Unreachable(PhantomUnreachable<R>),
}

let thing: Msg = …;
match thing {
    …
    _Unreachable(impossible) => impossible.unreachable_arm(),
}

and the variant can obviously not be populated since there is no value of type Unreachable to populate it with.

6 Likes

I wonder how this could be put into an attribute macro..
basically something like

enum Foo<T> {
    #[unreachable]
    _Unreachable(std::marker::PhantomData<T>),
}

would be nice

Alternatively, you could add PhantomData<R> to the Page(...) variant, where P: Page<R> is also used, and avoid the extra variant.

(A more typical pattern is to drop the trait constraints on data structures and specify them on functions and impls, but I understand why putting it on the data structure is sometimes preferred.)

In my case I can't do that, because another type I use requires this type to satisfy these specific trait bounds.

Related discussion about Type parameter not used: Type parameter not used on enums - traits working group - Rust Internals

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.