Stabilizing `non_exhaustive_omitted_patterns` or a better alternative

As other's have mentioned: It's not about making this an error that prevents compilation, but like #[deprecated] a built-in way to inform dependencies that they may want to look into the new variant, even if it just to find out that there is a new feature they may want to use.

I disagree. There are use-cases for both in the same crate on the same type and different needs/desires in terms of stability vs correctness. Let me give you two examples why:

Example 1: Consumer

As a project depending on library X, which uses #[non_exhaustive] I WANT to be notified when there is a new variant. If I'm working on a security/safety critical application I may even WANT my build to fail with an error if a new variant is added (e.g. when using locked versions from cargo.lock). At the moment there is no way for me to opt-into those breaking change (also see this topic). Personally I haven't had this situation, but I really don't like the idea of NEEDING a catch-all branch without even getting notified when compiling that I'm missing something, with the only way to find it being a runtime panic. In my opinion this goes against one of Rusts core concepts, but I do see the need/desire for #[non_exhaustive] and the advantages this can bring. In fact that's exactly the issue I have in my second example:

Example 2: Producer and Consumer

For context: I have a types crate defining common types used across a HTTP API boundry on both client and server side. I am the one that wrote the server side using this (same workspace), but I'm not the (only) one that uses the types crate on the client-side.

Today I wanted to add #[non_exhaustive] to the enums in that crate, to allow adding more variants to them without breaking backwards compatibility to clients using an older version of types (no actual breaking change => no need to do a major version bump, at the moment the project is still in development, so not having #[non_exhaustive] yet is okay). Backwards compatibility on the API is not an issue, since the encoding (JSON in this case) does allow adding new variants to enums.

But on the server side, where I'm consuming these enums I do not want the catch-all. I do not want missing variants to go unnoticed until the server crashes in staging/production. At the very least I WANT warnings when new variants are added, too (granted, I'm usually the one adding them, but looking through all match statements to find them is still error prone). I'd actually PREFER this to be an error in this case and WANT to opt-in to these as errors caused by my own changes (or others working on the project).

Currently (on stable at least) this is like if you'd have to use a catch-all in every match statement in your own crate, which defined the enum (just that it's the same workspace and/or organisation in my case). This makes deciding whether or not I want to use #[non_exhaustive] or not a difficult decision (for which I'm currently tending towards no).

This specific example could be solved by having workspaces behave like crates in regards to requiring the catch-all (another option I've seen proposed while looking into this), but that would not help in example 1 and might not be what everyone with a workspace wants (e.g. in examples meant to show how to use the crate).

An alternative (hacky) workaround

The only ways I can think of to solve this (as of now) is to:

  • use nightly (don't want that for production unless absolutely necessary) or
  • use conditional compilation and a separate nightly run just to check exhaustiveness (which is still only semi-complete)
  • use conditional compilation (e.g. via env variable) to disable/remove the #[non_exhaustive] attribute while working on the project.

None of these is ideal.

2 Likes