Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistency in pattern matching over the never type ! as an associated trait type #112997

Closed
radrow opened this issue Jun 24, 2023 · 1 comment · Fixed by #113103
Closed

Inconsistency in pattern matching over the never type ! as an associated trait type #112997

radrow opened this issue Jun 24, 2023 · 1 comment · Fixed by #113103
Labels
C-bug Category: This is a bug. F-exhaustive_patterns `#![feature(exhaustive_patterns)]`

Comments

@radrow
Copy link

radrow commented Jun 24, 2023

I have found a weird inconsistency when ! is behind a trait and wrapped as a constructor field:

#![feature(never_type, exhaustive_patterns)]

trait Tag {
    type TagType;
}

enum Keep {}
enum Erase {}

impl Tag for Keep {
    type TagType = ();
}

impl Tag for Erase {
    type TagType = !;
}

enum TagInt<T: Tag> {
    Untagged(i32),
    Tagged(T::TagType, i32)
}

fn test(keep: TagInt<Keep>, erase: TagInt<Erase>) {
    // This is fine
    match keep {
        TagInt::Untagged(_) => (),
        TagInt::Tagged(_, _) => ()
    };

    match erase {
        TagInt::Untagged(_) => (),
        TagInt::Tagged(_, _) => ()  // unreachable pattern
    };

    match erase { // non-exhaustive patterns: `TagInt::Tagged(_, _)` not covered
        TagInt::Untagged(_) => ()
    };
}

Note the errors in the comments. I hoped for the typechecker to notice that Tagged could not be a value of TagInt<Erase>, and thus not demand covering that case. On the other hand, when I follow the advice and consider it, the typechecker suddenly realizes this is dead code and suggests removing it. Regardless whether Tagged should be covered or not , it feels incorrect that the typechecker contradicts itself.

The Tagged case for TagInt<Erase> is indeed unreachable, and the compiler manages to detect it. I would therefore expect the last match to be correct, and the previous one to be marked as it is. This bug breaks my way towards emulating GADTs in Rust's type system. At least I don't see any other hack for conditional constructors.

Meta

rustc --version --verbose:

rustc 1.72.0-nightly (22e9fe644 2023-06-23)
binary: rustc
commit-hash: 22e9fe644ea710eec50cb0aabcae7fa8dd9fd675
commit-date: 2023-06-23
host: x86_64-unknown-linux-gnu
release: 1.72.0-nightly
LLVM version: 16.0.5
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
Build output

    Checking rust-playground v0.1.0 (/home/radek/Programming/rust-playground)
warning: unreachable pattern
  --> src/main.rs:32:9
   |
32 |         TagInt::Tagged(_, _) => ()  // unreachable pattern
   |         ^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(unreachable_patterns)]` on by default

error[E0004]: non-exhaustive patterns: `TagInt::Tagged(_, _)` not covered
  --> src/main.rs:35:11
   |
35 |     match erase { // non-exhaustive patterns: `TagInt::Tagged(_, _)` not covered
   |           ^^^^^ pattern `TagInt::Tagged(_, _)` not covered
   |
note: `TagInt<Erase>` defined here
  --> src/main.rs:20:5
   |
18 | enum TagInt<T: Tag> {
   |      ------
19 |     Untagged(i32),
20 |     Tagged(T::TagType, i32)
   |     ^^^^^^ not covered
   = note: the matched value is of type `TagInt<Erase>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
36 ~         TagInt::Untagged(_) => (),
37 +         TagInt::Tagged(_, _) => todo!()
   |

For more information about this error, try `rustc --explain E0004`.
warning: `rust-playground` (bin "rust-playground") generated 1 warning
error: could not compile `rust-playground` (bin "rust-playground") due to previous error; 1 warning emitted

@radrow radrow added the C-bug Category: This is a bug. label Jun 24, 2023
@Jules-Bertholet
Copy link
Contributor

Jules-Bertholet commented Jun 26, 2023

@rustbot label F-exhaustive_patterns

@rustbot rustbot added the F-exhaustive_patterns `#![feature(exhaustive_patterns)]` label Jun 26, 2023
@bors bors closed this as completed in 4b1d068 Jun 28, 2023
oli-obk pushed a commit to oli-obk/miri that referenced this issue Jun 28, 2023
…rors

Normalize types when applying uninhabited predicate.

Fixes rust-lang/rust#112997
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. F-exhaustive_patterns `#![feature(exhaustive_patterns)]`
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants