Skip to content

Commit 9e1bb8e

Browse files
Expand motivation and examples
1 parent 6081324 commit 9e1bb8e

File tree

1 file changed

+93
-50
lines changed

1 file changed

+93
-50
lines changed

text/3627-match-ergonomics-2024.md

Lines changed: 93 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -22,34 +22,71 @@ Various changes to the match ergonomics rules:
2222
Match ergonomics have been a great success overall, but there are some surprising
2323
interactions that regularly confuse users.
2424

25-
- `mut` resets the binding mode to by-value, which users do not expect; the
26-
mutability of the binding seems like a separate concern from its type
27-
(<https://github.com/rust-lang/rust/issues/105647>,
28-
<https://github.com/rust-lang/rust/issues/112545>)
29-
- `&` and `&mut` patterns must correspond with a reference in the same position
30-
in the scrutinee, even if there is an inherited reference present. Therefore,
31-
users have no general mechanism to "cancel out" an inherited reference
32-
(<https://users.rust-lang.org/t/reference-of-tuple-and-tuple-of-reference/91713/6>,
33-
<https://users.rust-lang.org/t/cannot-deconstruct-reference-inside-match-on-reference-why/92147>,
34-
<https://github.com/rust-lang/rust/issues/50008>,
35-
<https://github.com/rust-lang/rust/issues/64586>)
36-
- When an `&` or `&mut` pattern is used in a location where there is also an
37-
inherited reference present, both are stripped; adding a single `&` to the
38-
pattern can remove two `&`s from the type of the binding.
25+
## `mut` resets the binding mode
26+
27+
`mut` resets the binding mode to by-value, which users do not expect; the
28+
mutability of the binding would seem to be separate concern from its type
29+
(<https://github.com/rust-lang/rust/issues/105647>,
30+
<https://github.com/rust-lang/rust/issues/112545>).
31+
32+
```rust
33+
let (x, mut y) = &(true, false);
34+
let _: (&bool, bool) = (x, y);
35+
```
36+
37+
## Can't cancel out an inherited reference
38+
39+
`&` and `&mut` patterns must correspond with a reference in the same position in
40+
the scrutinee, even if there is an inherited reference present. Therefore, users
41+
have no general mechanism to "cancel out" an inherited reference
42+
(<https://users.rust-lang.org/t/reference-of-tuple-and-tuple-of-reference/91713/6>,
43+
<https://users.rust-lang.org/t/cannot-deconstruct-reference-inside-match-on-reference-why/92147>,
44+
<https://github.com/rust-lang/rust/issues/50008>,
45+
<https://github.com/rust-lang/rust/issues/64586>).
46+
47+
48+
```rust
49+
fn foo(arg: &(String, Vec<i32>, u8)) {
50+
// We want to extract `&String`, `&Vec`, and `u8` from the tuple.
51+
let (s, v, u) = arg; // u is &u8, not what we wanted
52+
let &(ref s, ref v, u) = arg; // we have to abandon match ergonomics entirely
53+
}
54+
```
55+
56+
## A single `&` can strip two references
57+
58+
When an `&` or `&mut` pattern is used in a location where there is also an
59+
inherited reference present, both are stripped; adding a single `&` to the
60+
pattern can remove two `&`s from the type of the binding.
61+
62+
```rust
63+
let [a] = &[&42]; // a = &&42
64+
let [&a] = &[&42]; // a = 42
65+
```
3966

4067
# Guide-level explanation
4168
[guide-level-explanation]: #guide-level-explanation
4269

4370
Match ergonomics works a little differently in edition 2024 and above.
4471

72+
## `mut` no longer strips the inherited reference
73+
74+
`mut` on a binding does not reset the binding mode on edition ≥ 2024.
75+
76+
```rust
77+
//! Edition ≥ 2024
78+
let (x, mut y) = &(true, false);
79+
let _: (&bool, &bool) = (x, y); // instead of `(&bool, bool)`
80+
```
81+
4582
## Matching against inherited references
4683

4784
In all editions, when you match against an `&` or `&mut` reference with the type
4885
of its referent, you get an "inherited reference": the binding mode of
4986
"downstream" bindings is set to `ref` or `ref mut`.
5087

5188
```rust
52-
// Unchanged from old editions:
89+
//! All editions
5390
// `x` "inherits" the `&` from the scrutinee type.
5491
let [x] = &[42];
5592
let _: &u8 = x;
@@ -59,10 +96,21 @@ In edition 2024 and above, an `&` or `&mut` pattern can match against this
5996
inherited reference, consuming it. A pattern that does this has no other effect.
6097

6198
```rust
62-
// New in edition 2024:
99+
//! Edition ≥ 2024
100+
63101
// `&` pattern consumes inherited `&` reference.
64102
let [&x] = &[42];
65103
let _: u8 = x;
104+
105+
// Examples from motivation section
106+
107+
fn foo(arg: &(String, Vec<i32>, u8)) {
108+
let (s, v, &u) = arg;
109+
let _: (&String, &Vec<i32>, u8) = (s, v, u);
110+
}
111+
112+
let [&x] = &[&42];
113+
let _: &u8 = x;
66114
```
67115

68116
## `&` matches against `&mut`
@@ -71,49 +119,45 @@ In edition 2024 and above, `&` patterns can match against `&mut` references
71119
(including "inherited" references).
72120

73121
```rust
122+
//! Edition ≥ 2024
74123
let &foo = &mut 42;
75124
let _: u8 = foo;
76125
```
77126

78-
## `mut` no longer strips the inherited reference
79-
80-
In older editions, `mut` on a binding "stripped" the inherited reference:
127+
# Reference-level explanation
128+
[reference-level-explanation]: #reference-level-explanation
81129

82-
```rust
83-
// Old editions
84-
let (x, mut y) = &(true, false);
85-
let _: (&bool, bool) = (x, y);
86-
```
130+
This explanation assumes familiarity with the current match ergonomics rules,
131+
including the "default binding mode" terminology. Refer to [RFC 2005](./2005-match-ergonomics.md#detailed-design).
87132

88-
This no longer happens on edition ≥ 2024.
133+
## Edition 2024: `mut` does not reset binding mode to by-value
89134

135+
In the new edition, `mut` no longer resets the binding mode to by-value.
136+
Therefore, it is possible to have a mutable by-reference binding. (An explicit
137+
syntax for this is left to a future RFC.)
90138

91139
```rust
92-
// Edition ≥ 2024
93-
let (x, mut y) = &(true, false);
94-
let _: (&bool, &bool) = (x, y);
140+
//! Edition ≥ 2024
141+
let &[mut a] = &[42];
142+
a = &47;
95143
```
96144

97-
# Reference-level explanation
98-
[reference-level-explanation]: #reference-level-explanation
99-
100-
This explanation assumes familiarity with the current match ergonomics rules,
101-
including the "default binding mode" terminology. Refer to [RFC 2005](./2005-match-ergonomics.md#detailed-design).
102-
103145
## Edition 2024: `&` patterns can match against `&mut` references
104146

105147
`&` patterns can match against `&mut` references.
106148

107149
```rust
150+
//! Edition ≥ 2024
108151
let &foo = &mut 42;
109152
let _: u8 = foo;
110153
```
111154

112155
However, the `ref mut` binding mode cannot be used behind such patterns.
113156

114157
```rust
158+
//! All editions
115159
let &ref mut foo = &mut 42;
116-
// ^~ERROR: replace `&` with `&mut`
160+
// ^~ERROR: replace `&` with `&mut `
117161
let _: &mut u8 = foo;
118162
```
119163

@@ -125,6 +169,8 @@ by-value, while `&mut` can only reset `ref mut`. An `&` or `&mut` pattern that
125169
resets the binding mode in this way has no other effect.
126170

127171
```rust
172+
//! Edition ≥ 2024
173+
128174
let [&x] = &[3u8];
129175
let _: u8 = x;
130176

@@ -133,13 +179,18 @@ let _: u8 = x;
133179

134180
let [&x] = &mut [3u8];
135181
let _: u8 = x;
182+
```
136183

184+
```rust
185+
//! All editions
137186
//let [&mut x] = &[3u8]; // ERROR
138187
```
139188

140189
`&` patterns are otherwise unchanged from older editions.
141190

142191
```rust
192+
//! All editions
193+
143194
let &a = &3;
144195
let _: u8 = a;
145196

@@ -150,9 +201,12 @@ If the default binding mode is `ref`, then `&mut` patterns are forbidden. If it
150201
is by-value, then they have the same effect as on older editions.
151202

152203
```rust
204+
//! Edition ≥ 2024
153205
//let [&mut x] = &[&mut 42]; // ERROR
206+
```
154207

155-
// Unchanged from old editions
208+
```rust
209+
//! All editions
156210

157211
let &mut x = &mut 3;
158212
let _: u8 = x;
@@ -166,24 +220,13 @@ let _: &&mut u8 = x;
166220
//let &mut x = &&mut 3; // ERROR
167221
```
168222

169-
## Edition 2024: `mut` does not reset binding mode to by-value
170-
171-
In the new edition, `mut` no longer resets the binding mode to by-value.
172-
Therefore, it is possible to have a mutable by-reference binding. (An explicit
173-
syntax for this is left to a future RFC.)
174-
175-
```rust
176-
let &[mut a] = &[42];
177-
a = &47;
178-
```
179-
180223
## All editions: the default binding mode is never set to `ref mut` behind an `&` pattern or reference
181224

182225
The binding mode is set to `ref` instead in such cases. (On older editions, this
183226
allows strictly more code to compile.)
184227

185228
```rust
186-
// All editions
229+
//! All editions (new)
187230

188231
let &[[a]]; = &[&mut [42]];
189232
let _: &u8 = a;
@@ -193,7 +236,7 @@ let _: &u8 = a;
193236
```
194237

195238
```rust
196-
// Edition ≥ 2024
239+
//! Edition ≥ 2024
197240

198241
let &[[&a]]; = &[&mut [42]];
199242
let _: u8 = a;
@@ -319,7 +362,7 @@ explicit `ref` is required. Notably, this can occur where `&mut` is nested
319362
behind `&`:
320363

321364
```rust
322-
// No way to avoid the `ref` here currently
365+
// No way to avoid the `ref`, even with this RFC
323366
let &[&mut ref x] = &[&mut 42];
324367
```
325368

0 commit comments

Comments
 (0)