Variables bound with different modes in patterns

a4a9362
Opened by Steven Allen at 2023-11-19 05:52:02

The following doesn't compile:

enum Test<'a> {
    A(&'a u64),
    B(u64),
}
fn foo(test: Test) {
    match test {
        Test::A(r) | Test::B(ref r) => println!("{}", r)
    }
}
fn main() {
    foo(Test::A(&0));
    foo(Test::B(1));
}

failing with the following error:

test.rs:7:30: 7:35 error: variable `r` is bound with different mode in pattern #2 than in pattern #1
test.rs:7         Test::A(r) | Test::B(ref r) => println!("{}", r)
                                       ^~~~~
error: aborting due to previous error

However, the following does work:

enum Test<'a> {
    A(&'a u64),
    B(u64),
}
fn foo(test: Test) {
    match test {
        Test::A(&ref r) | Test::B(ref r) => println!("{}", r)
    }
}
fn main() {
    foo(Test::A(&0));
    foo(Test::B(1));
}

Is there any reason rust can't just perform this reborrow automatically? &ref is a very cryptic pattern.

  1. Is there any reason we put in this restriction in the first place in https://github.com/rust-lang/rust/commit/a6a5c48c6461b67ba84eaab66a38938226bfe739? Seems like the type equality restriction on bindings should be enough.

    cc @nikomatsakis

    Deleted user at 2015-03-24 23:28:46

  2. this error still occur in rustc 1.11.0 (9b21dcd6a 2016-08-15)

    kdeeee at 2016-09-30 14:56:31

  3. @nikomatsakis Is there a chance the &ref pattern is actually bypassing the match checking that is intended to not allow binding both by-move and by-reference in the same arm? It seems to be, so... perhaps this is a problem in a wider sense?

    Mark Rousskov at 2017-05-14 15:03:30

  4. @Mark-Simulacrum

    Is there a chance the &ref pattern is actually bypassing the match checking that is intended to not allow binding both by-move and by-reference in the same arm?

    I don't understand what you mean here -- we have two bindings, both are "by reference", so how is the current code mixing by-move and by-ref in the same pattern?

    Niko Matsakis at 2017-05-25 17:42:11

  5. I think that in principle we do not need to require all bindings to be in the same mode; in that sense I agree with @ghost. However, I'm not sure how hard it would be to keep current code "up and going" without that simplifying restriction. I'd have to dig in in more detail. I think that once we are doing borrowck on MIR, things ought to be simpler, since most of the rules we have to keep borrowck + match sound could go away.

    Niko Matsakis at 2017-05-25 17:43:50

  6. Oh, I think I misread about the two bindings being by-move and by-reference -- never mind.

    I agree that we should probably leave this for after MIR borrowck (which might in its implementation resolve these sorts of issues on its own, I don't know).

    Mark Rousskov at 2017-05-25 19:44:30

  7. Triage: MIR borrowcheck has now landed, but this still gives this error.

    Steve Klabnik at 2018-12-20 19:14:17

  8. Current error:

    error[E0409]: variable `r` is bound inconsistently across alternatives separated by `|`
     --> src/main.rs:7:34
      |
    7 |         Test::A(r) | Test::B(ref r) => println!("{}", r)
      |                 - first binding  ^ bound in different ways
    
    For more information about this error, try `rustc --explain E0409`
    

    Dylan DPC at 2023-11-19 05:52:02