Multiple Matchers via | (i.e. OR) with value bound to a Name with @ causes error


#1

Why does the following error occur if you’re matching multiple things and binding the value to a name with @ via using a | (the OR symbol, i.e. 1000 | 2000, which means matches values 1000 or 2000)?

The Patterns chapter of the Rust language book suggests this should compile.

Error message:

error: variable `f` from pattern #1 is not bound in pattern #2
f @ 1000 | 2000 => println!("century detected: {}", f),

Code used (note that the third match using 1000 | 2000 is the one that causes the error):

use std::old_io;

fn main() {
    try_patterns();
}

fn try_patterns() {

    let my_input = 1;

    // WORKING - Match Range of Values (Bound to a Name)
    match my_input {
        e @ 1 ... 5 => println!("range element detected: {}", e),
        _ => println!("anything"),
    }

    // WORKING - Match Multiple Values
    match my_input {
        1000 | 2000 => println!("century detected"),
        _ => println!("anything"),
    }

    // NOT WORKING - Match Multiple Values (Bound to a Name)
    match my_input {
        f @ 1000 | 2000 => println!("century detected: {}", f),
        _ => println!("anything"),
    }

}

#2

It works with

f @ 1000 | f @ 2000 => println!("century detected: {}", f),

| takes two entirely independent patterns, i.e. f @ 1000 | 2000 is parsed as (f @ 1000) | 2000. This means it requires explicit bindings in all alternations. This allows, for example,

match foo {
    f @ Bar | Baz(&f) => { ... }
    ...
}

where the binding is introduced in entirely different parts of the matched value.

Whereas e @ 1 ... 5 is parsed as a @ (1 ... 5). (Parsing it as (a @ 1) ... 5 wouldn’t be very useful: one would essentially always have to write (a @ 1) ... (a @ 5) to do anything useful with a, and there’s no sensible way to bind a subpart of a ranged pattern.)

A possible extension to pattern matching I could imagine would be allowing () for grouping and | nested in other patterns (at the moment, the | is part of the match construct, not patterns themselves), then f @ (1000 | 2000) would work.