How to match `T` and `&T` in the same arm?

I'm trying to understand why this code shouldn't compile:

enum Foo<'a, T> {
    C(&'a T),

fn main() {
    let foo = Foo::<'static, ()>::A;
    match foo {
        Foo::A => {},
        Foo::B(ref t) | Foo::C(t) => todo!(),

isn't t bound to an &T in both cases? This more verbose version works just fine:

fn main() {
    let foo = Foo::<'static, ()>::A;
    let t = match foo {
        Foo::A => return,
        Foo::B(ref t) => t,
        Foo::C(t) => t,

Link to a playground.


t has to be bound the same way in all alternatives joined with |. I'm not sure if there is a "real" reason for this or if it's a consequence of how pattern ergonomics works, or something else, but you can work around it (at least in this case) by matching

Foo::B(ref t) | Foo::C(&ref t) => ...
//                     ^^^^^

It could use a better error message, but the reason is because they have different lifetimes. When you match it separately, that gives it a chance for variance to coerce the lifetime shorter. You can force C to reborrow with &(ref t).


I filed a diagnostic issue:


This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.