What is feature "bind_by_move_pattern_guards"?

First of all, you need to know what a match actually does, see this post of mine: How to understand the match pattern? - #4 by Yandros

Now, Rust being Rust, ownership comes into question. Imagine the following counter-example:

fn main ()
{
    let opt_v = Some(vec![42]);
    match opt_v {
        | Some(v)
            if v.into_iter().next().is_none() // <-- pattern guard
        => {
            // use v?
            drop(v)
        },
        | Some(v) => {
            // use v?
            drop(v)
        },
        | None => {},
    }
}

So the issue lies mainly at the pattern guard line: if such code were to compile, then the guard would have taken and consumed ownership of v, meaning that it would be impossible to use v within its body.

Worse, if the check failed (but having already taken ownership of v), then the following match branches would be using a moved value.

That's why

A pattern guard is not allowed to move out of a variable bound by the pattern it guards.

This means that the v within the pattern guard is more like *(&v)1; so when v : impl !Copy, unless you go and use & v ~ & *(&v) ~ &v, you get a compiler error.

The fact that v behaves as *(&v) is described as: "v has been bound by reference" (rather than by move).


Now, up until Rust version 1.39.0, for technical reasons / due to a compiler limitation, this behavior of "v is bound by reference" / v behaves as *(&v) was not supported. Instead, you were forced to make such "by ref" binding explicit by annotating the binding with ref, which resulted in a bind-by-ref, even within the arm body, resulting in an unneeded and unjustified coding constraint.

So what currently can be written as:

match Some(vec![42]) {
    | Some(v) if v.is_empty() => {
        // owns v: Vec<i32>
        drop::<Vec<_>>(v);
    },
    | _ => {},
}

had to be written as:

match Some(vec![42]) {
    | Some(ref v) if v.is_empty() => {
        // because of `ref`, `v` is a borrow: `v: &Vec<_>`.
    },
    | _ => {},
}

which means that code like the following one would fail to compile:

match vec![42] {
    | v if true => drop(v),
    | _ => {},
}

Conclusion

Since 1.39.0, we can bind-by-move a pattern variable in the body of a match arm guarded by a condition.
As @alice TL,DR-ed: now

it just works™


1 Rust seems to have made the sensible but opinionated choice of not using *(&mut v): Playground