Description
I tried this code to create a mutable variable binding to tuple.0
while also dereferencing it in the same pattern. Of course this code is not correct. I think the intention can be guessed because of the order in which &
and mut
appear, especially in the parenthesized variant.
#![allow(unused_variables)]
fn main() {
let tuple: (&u8, &[u8]) = (&0, &[0, 0]);
let (mut &last, rest) = tuple;
let (mut (&last), rest) = tuple;
// `last` should be type of `u8`
// EDIT: This can be minimized to:
let mut &x = &0;
}
This is the correct code, where the tokens &
and mut
are separated by parentheses to avoid parsing as &mut
. This is also perfectly logical since patterns are read from the outside inwards destructuring the given value. My fault was to interpret &
and mut
like operators which got me stuck at the code I've written above.
#![allow(unused_variables)]
fn main() {
let tuple: (&u8, &[u8]) = (&0, &[0, 0]);
let (&(mut last), rest) = tuple;
// EDIT: This can be minimized to:
let &(mut x) = &0;
}
The issue is that the help output by the compiler isn't actually helping much because it changes semantics of the code. The compiler suggests to use &mut
which would dereference a mutable reference when used in a pattern. That is very different from dereferencing a shared reference and mutably binding a variable.
Since &mut
consists of two tokens &
and mut
the compiler tries to show you that the two token are in the wrong order I guess. In my opinion this is less probable than trying to express the pattern &(mut variable)
wrongly as mut &variable
. For the variant mut (&variable)
the help is not correct anyway since the compiler ignores the parentheses.
I propose to change the help text to suggest &(mut last)
instead. I'm not sure whether there are cases where this help would be wrong also.
Current error and help:
error: `mut` must be attached to each individual binding
--> src/main.rs:5:10
|
4 | let (mut &last, rest) = tuple;
| ^^^^^^^^^ help: add `mut` to each binding: `&mut last`
|
= note: `mut` may be followed by `variable` and `variable @ pattern`
error: `mut` must be attached to each individual binding
--> src/main.rs:6:10
|
5 | let (mut (&last), rest) = tuple;
| ^^^^^^^^^^^ help: add `mut` to each binding: `(&mut last)`
|
= note: `mut` may be followed by `variable` and `variable @ pattern`
warning: unnecessary parentheses around pattern
--> src/main.rs:6:10
|
5 | let (mut (&last), rest) = tuple;
| ^^^^^^^^^^^ help: remove these parentheses
|
= note: `#[warn(unused_parens)]` on by default
Meta
All the compiler channels produce the same output.
rustc --version --verbose
:
Stable:
rustc 1.48.0 (7eac88abb 2020-11-16)
binary: rustc
commit-hash: 7eac88abb2e57e752f3302f02be5f3ce3d7adfb4
commit-date: 2020-11-16
host: x86_64-unknown-linux-gnu
release: 1.48.0
LLVM version: 11.0
Beta:
rustc 1.49.0-beta.4 (877c7cbe1 2020-12-10)
binary: rustc
commit-hash: 877c7cbe142a373f93d38a23741dcc3a0a17a2af
commit-date: 2020-12-10
host: x86_64-unknown-linux-gnu
release: 1.49.0-beta.4
Nightly:
rustc 1.50.0-nightly (f74583445 2020-12-18)
binary: rustc
commit-hash: f74583445702e2e27ec4415376f2c540a83d7ded
commit-date: 2020-12-18
host: x86_64-unknown-linux-gnu
release: 1.50.0-nightly