Description
For example
fn main() {
struct L;
impl Drop for L {
fn drop(&mut self) {
println!("dropped L")
}
}
struct M;
impl Drop for M {
fn drop(&mut self) {
println!("dropped M")
}
}
let x;
(x = (drop(&L), ()), M);
println!("---"); // -------------
let (x1, x2);
((x1, x2) = (drop(&L), ()), M);
}
Output:
dropped M
dropped L
---
dropped L
dropped M
I came across this by reading the reference:
Assignee expressions are then desugared to pattern matches followed by sequential assignment.
The desugaring method is straightforward, and is illustrated best by example.
(a, b) = (3, 4); [a, b] = [3, 4]; Struct { x: a, y: b } = Struct { x: 3, y: 4}; // desugars to: { let (_a, _b) = (3, 4); a = _a; b = _b; } { let [_a, _b] = [3, 4]; a = _a; b = _b; } { let Struct { x: _a, y: _b } = Struct { x: 3, y: 4}; a = _a; b = _b; }
The difference between
STATEMENT CONTAINING … x = EXPR …
and
STATEMENT CONTAINING … { let _x = EXPR; x = _x } …
is that in the former case, temporaries in EXPR
are dropped after the surrounding statement is evaluated, while the latter case has them dropped right after the let _x = EXPR
.
It seems to me that a better desugaring would have been to use something like
(a, b) = (3, 4);
[a, b] = [3, 4];
Struct { x: a, y: b } = Struct { x: 3, y: 4};
// desugars to:
match (3, 4) {
(_a, _b) => {
a = _a;
b = _b;
}
}
match [3, 4] {
[_a, _b] =>
a = _a;
b = _b;
}
}
match Struct { x: 3, y: 4} {
Struct { x: _a, y: _b } => {
a = _a;
b = _b;
}
}
Or applied to the example above:
fn main() {
………
let (x1, x2);
// current desugaring
(
{
let (_x1, _x2) = (drop(&L), ());
x1 = _x1;
x2 = _x2;
},
M,
);
println!("---"); // -------------
let (x1, x2);
// better desugaring
(
match (drop(&L), ()) {
(_x1, _x2) => {
x1 = _x1;
x2 = _x2;
}
},
M,
);
}
dropped L
dropped M
---
dropped M
dropped L
Full example in the playground.
As a point of comparison, e.g. desugaring of for
loops, and similarly many macros, use match
in a similar way to ensure proper temporary scopes.
Changing it now might technically be a breaking change, OTOH, the feature of destructuring assignment is still very young, and the change is small. I’m not 100% certain about the "bug" label, but I’ll add it for now, next to "enhancement", to let the reader choose whichever they feel more appropriate: @rustbot label C-bug, C-enhancement, F-destructuring_assignment, T-compiler