Open
Description
Background: apart from paths, another way to make use of the precise capture of variables by closures is with irrefutable patterns:
fn main() {
let mut a = (21, 37);
// only captures a.0, example compiles fine
let mut f = || {
let (ref mut x, _) = a;
*x = 42;
};
a.1 = 69;
f();
}
One would expect this to be equivalent to an if let
or match
that happens to be irrefutable. However, this isn't the case:
fn main() {
let mut a = (21, 37);
// captures the entirety of a, example doesn't pass borrow check
let mut f = || {
match a {
(ref mut x, _) => *x = 42,
}
};
a.1 = 69;
f();
}
However, one can get the code to compile again by introducing a no-op @
-pattern:
fn main() {
let mut a = (21, 37);
// captures only a.0 again, and against all odds, the example compiles
let mut f = || {
match a {
(ref mut x @ _, _) => *x = 42,
}
};
a.1 = 69;
f();
}
This suggests that the inconsistency is definitely a bug.
I have discovered this while investigating #137467, and I am working on resolving both issues. I am creating this issue to make it easy to keep track of the bug.
@rustbot claim
Meta
rustc --version --verbose
:
rustc 1.87.0-nightly (f280acf4c 2025-02-19)
binary: rustc
commit-hash: f280acf4c743806abbbbcfe65050ac52ec4bdec0
commit-date: 2025-02-19
host: x86_64-unknown-linux-gnu
release: 1.87.0-nightly
LLVM version: 20.1.0
(git blame suggests that this behavior got introduced 3 years ago or so)