Skip to content

#[feature(exhaustive_patterns)] thinks irrefutable pattern is refutable when enum contains struct with private fields. #104034

Closed
@BGR360

Description

@BGR360

The following code compiles on nightly (playground):

#![feature(exhaustive_patterns, never_type)]

enum Either<A, B> {
    A(A),
    B(Wrapper<B>),
}

struct Wrapper<T>(T);

fn foo() -> Either<(), !> {
    Either::A(())
}

fn main() {
    let Either::A(()) = foo();
}

But if the wrapper type is moved into a module to make the field private, then it does not: (playground):

#![feature(exhaustive_patterns, never_type)]

mod inner {
    pub struct Wrapper<T>(T);
}

enum Either<A, B> {
    A(A),
    B(inner::Wrapper<B>),
}

fn foo() -> Either<(), !> {
    Either::A(())
}

fn main() {
    let Either::A(()) = foo();
}
error[E0005]: refutable pattern in local binding: `Either::B(_)` not covered
  --> src/main.rs:17:9
   |
17 |     let Either::A(()) = foo();
   |         ^^^^^^^^^^^^^ pattern `Either::B(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Either<(), !>` defined here
  --> src/main.rs:9:5
   |
7  | enum Either<A, B> {
   |      ------
8  |     A(A),
9  |     B(inner::Wrapper<B>),
   |     ^ not covered
   = note: the matched value is of type `Either<(), !>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
17 |     if let Either::A(()) = foo() { todo!() }
   |     ++                           ~~~~~~~~~~~

Making the field pub makes it compile again.

Is this expected? I suppose I could understand if it is; the private fields could change to make Wrapper<!> actually be constructable and therefore make the pattern refutable. But if that's the case, then I think the compiler should point this out, like note: the pattern is currently irrefutable, but the type contains private fields which may change in the future to make the pattern refutable.

If indeed this is expected, is there any way for me as a library author to somehow convince the compiler that I will never change the fields to make the type constructable? I want users of my library to be able to elide match arms when I give them an Either<A, !>.

@rustbot label +T-compiler +F-never_type +D-confusing +requires-nightly +S-bug-has-mcve

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-exhaustiveness-checkingRelating to exhaustiveness / usefulness checking of patternsC-bugCategory: This is a bug.D-confusingDiagnostics: Confusing error or lint that should be reworked.F-exhaustive_patterns`#![feature(exhaustive_patterns)]`F-never_type`#![feature(never_type)]`S-bug-has-testStatus: This bug is tracked inside the repo by a `known-bug` test.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions