Pre-RFC: Improved pattern matching (non-discrete types, bit-limited inputs)


#1

I get the impression the prototypical example of a match statement is something like this.

match an_enum {
    Foo => println!("got a foo"),
    Bar(x) => println!("got a bar with value {}", x),
    // etc.
}

This works excellently. However, it doesn’t work quite so well for continuous categories like matching on u32. The switch-like case is covered…

match an_integer {
    1 => { /* do something */ }
    2 => { /* do something (/ }
    // etc.
    _ => { /* the default case */ }
}

…but I’m writing a Game Boy Advance emulator, and have a lot of code where I’m working with a u32 which I got by pulling only a few bytes from a 32-bit instruction.

let register = (instruction >> 11) & 0b1111;
match register {
    0b0000 => { /* something */ }
    0b0001 => { /* something */ }
    0b0010 => { /* something */ }
    // etc.
    0b1111 => { /* something */ }
    _ => unreachable!(),
}

The unreachable match arm exists here solely because the compiler can’t distinguish between a full 32-bit integer and a 32-bit integer constrained to a four-bit value. Is it possible to make the compiler smarter to cover this case?

Similarly, I’ve seen comments about something like this…

match a_number {
    x where x < 0 => { /* something */ }
    0 => { /* something */ }
    x where x > 0 => { /* something */ }
    _ => unreachable!(),
}

This too requires an unreachable match arm, in this case because the compiler can’t tell that there is no value not covered by the three clauses. (I’m assuming a_number here is something like i32—floats can of course be not-a-number.)


#2

This is a basic and important improvement for the Rust match (at first I was a bit surprised that something so basic is not already done by an otherwise well designed language as Rust).

While this is a sufficiently easy case, in general it’s hard to assure exhaustiveness of if conditions, so this situation is different from the precedent one.