Skip to content

Commit 105b647

Browse files
committed
Address most of comments
1 parent fe215c0 commit 105b647

File tree

1 file changed

+66
-31
lines changed

1 file changed

+66
-31
lines changed

text/0000-subslice-pattern-syntax.md

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,33 +41,67 @@ Sub-slices and sub-arrays can be matched using `..` and `<IDENT> @ ..` can be us
4141
these sub-slices and sub-arrays to an identifier.
4242

4343
```rust
44-
// Matching slices using `ref` patterns:
45-
let v = vec![1, 2, 3];
44+
// Matching slices using `ref` and `ref mut`patterns:
45+
let mut v = vec![1, 2, 3];
4646
match v[..] {
47-
[1, ref subslice @ .., 4] => assert_eq!(subslice.len(), 1),
48-
[5, ref subslice @ ..] => assert_eq!(subslice.len(), 2),
49-
[ref subslice @ .., 6] => assert_eq!(subslice.len(), 2),
47+
[1, ref subslice @ .., 4] => assert_eq!(subslice.len(), 1), // typeof(subslice) == &[i32]
48+
[5, ref subslice @ ..] => assert_eq!(subslice.len(), 2), // typeof(subslice) == &[i32]
49+
[ref subslice @ .., 6] => assert_eq!(subslice.len(), 2), // typeof(subslice) == &[i32]
50+
[x, .., y] => assert!(v.len() >= 2),
51+
[..] => {} // Always matches
52+
}
53+
match v[..] {
54+
[1, ref mut subslice @ .., 4] => assert_eq!(subslice.len(), 1), // typeof(subslice) == &mut [i32]
55+
[5, ref mut subslice @ ..] => assert_eq!(subslice.len(), 2), // typeof(subslice) == &mut [i32]
56+
[ref mut subslice @ .., 6] => assert_eq!(subslice.len(), 2), // typeof(subslice) == &mut [i32]
5057
[x, .., y] => assert!(v.len() >= 2),
5158
[..] => {} // Always matches
5259
}
5360

5461
// Matching slices using default-binding-modes:
55-
let v = vec![1, 2, 3];
62+
let mut v = vec![1, 2, 3];
5663
match &v[..] {
57-
[1, subslice @ .., 4] => assert_eq!(subslice.len(), 1),
58-
[5, subslice @ ..] => assert_eq!(subslice.len(), 2),
59-
[subslice @ .., 6] => assert_eq!(subslice.len(), 2),
64+
[1, subslice @ .., 4] => assert_eq!(subslice.len(), 1), // typeof(subslice) == &[i32]
65+
[5, subslice @ ..] => assert_eq!(subslice.len(), 2), // typeof(subslice) == &[i32]
66+
[subslice @ .., 6] => assert_eq!(subslice.len(), 2), // typeof(subslice) == &[i32]
67+
[x, .., y] => assert!(v.len() >= 2),
68+
[..] => {} // Always matches
69+
}
70+
match &mut v[..] {
71+
[1, subslice @ .., 4] => assert_eq!(subslice.len(), 1), // typeof(subslice) == &mut [i32]
72+
[5, subslice @ ..] => assert_eq!(subslice.len(), 2), // typeof(subslice) == &mut [i32]
73+
[subslice @ .., 6] => assert_eq!(subslice.len(), 2), // typeof(subslice) == &mut [i32]
6074
[x, .., y] => assert!(v.len() >= 2),
6175
[..] => {} // Always matches
6276
}
6377

64-
// Matching arrays by-value:
65-
let v = [1, 2, 3];
78+
// Matching slices by value (error):
79+
let mut v = vec![1, 2, 3];
80+
match v[..] {
81+
[x @ ..] => {} // ERROR cannot move out of type `[i32]`, a non-copy slice
82+
}
83+
84+
// Matching arrays by-value and by reference (explicitly or using default-binding-modes):
85+
let mut v = [1, 2, 3];
6686
match v {
67-
[1, subarray @ .., 3] => assert_eq!(subarray, [2]),
68-
[5, subarray @ ..] => has_type::<[i32; 2]>(subarray),
69-
[subarray @ .., 6] => has_type::<[i32, 2]>(subarray),
70-
[x, .., y] => has_type::<[i32, 1]>(x),
87+
[1, subarray @ .., 3] => assert_eq!(subarray, [2]), // typeof(subarray) == [i32; 1]
88+
[5, subarray @ ..] => has_type::<[i32; 2]>(subarray), // typeof(subarray) == [i32; 2]
89+
[subarray @ .., 6] => has_type::<[i32, 2]>(subarray), // typeof(subarray) == [i32; 2]
90+
[x, .., y] => has_type::<[i32, 1]>(x), // typeof(subarray) == [i32; 1]
91+
[..] => {},
92+
}
93+
match v {
94+
[1, ref subarray @ .., 3] => assert_eq!(subarray, [2]), // typeof(subarray) == &[i32; 1]
95+
[5, ref subarray @ ..] => has_type::<&[i32; 2]>(subarray), // typeof(subarray) == &[i32; 2]
96+
[ref subarray @ .., 6] => has_type::<&[i32, 2]>(subarray), // typeof(subarray) == &[i32; 2]
97+
[x, .., y] => has_type::<&[i32, 1]>(x), // typeof(subarray) == &[i32; 1]
98+
[..] => {},
99+
}
100+
match &mut v {
101+
[1, subarray @ .., 3] => assert_eq!(subarray, [2]), // typeof(subarray) == &mut [i32; 1]
102+
[5, subarray @ ..] => has_type::<&mut [i32; 2]>(subarray), // typeof(subarray) == &mut [i32; 2]
103+
[subarray @ .., 6] => has_type::<&mut [i32, 2]>(subarray), // typeof(subarray) == &mut [i32; 2]
104+
[x, .., y] => has_type::<&mut [i32, 1]>(x), // typeof(subarray) == &mut [i32; 1]
71105
[..] => {},
72106
}
73107
```
@@ -82,9 +116,8 @@ reference or mutable reference to a slice or array.
82116

83117
`@` can be used to bind the result of `..` to an identifier.
84118

85-
When used to match against a non-reference slice (`[u8]`), `x @ ..` would attempt to bind
86-
by-value, which would fail in the case that users haven't enabled `feature(unsized_locals)`
87-
(since otherwise it's not possible to bind `[u8]` to a variable directly).
119+
When used to match against a non-reference slice (`[u8]`), `x @ ..` would attempt to bind
120+
by-value, which would fail due a move from a non-copy type `[u8]`.
88121

89122
`..`/`IDENT @ ..` is not a full pattern syntax, but rather a part of slice, tuple and tuple
90123
struct pattern syntaxes. In particular, `..` is not accepted by the `pat` macro matcher.
@@ -103,10 +136,10 @@ ambiguity with ranges, for example
103136
[`.. @ PAT`](https://github.com/rust-lang/rust/issues/23121#issuecomment-280920062) or
104137
[`PAT @ ..`](https://github.com/rust-lang/rust/issues/23121#issuecomment-280906823), or other
105138
similar alternatives.
106-
We reject these syntaxes because they only bring benefits in incredibly contrived cases using a
139+
We reject these syntaxes because they only bring benefits in contrived cases using a
107140
feature that doesn't even exist yet, but normally they only add symbolic noise.
108141

109-
More radical syntax changes not keeping consistency with `..`, for example
142+
More radical syntax changes do not keep consistency with `..`, for example
110143
[`[1, 2, 3, 4] ++ ref v`](https://github.com/rust-lang/rust/issues/23121#issuecomment-289220169).
111144

112145
### `..PAT` or `PAT..`
@@ -118,30 +151,32 @@ The two simplest variations are `..PAT` and `PAT..`.
118151

119152
#### Ambiguity
120153

121-
The issue is that these syntaxes are ambiguous with half-bounded ranges `..END` and `BEGIN..`.
154+
The issue is that these syntaxes are ambiguous with half-bounded ranges `..END` and `BEGIN..`,
155+
and the full range `..`.
122156
To be precise, such ranges are not currently supported in patterns, but they may be supported in
123157
the future.
124158

125159
Syntactic ambiguity is not inherently bad. We see it every day in expressions like
126160
`a + b * c`. What is important is to disambiguate it reasonably by default and have a way to
127161
group operands in the alternative way when default disambiguation turns out to be incorrect.
128-
In case of slice patterns the subslice interpretation seems overwhelmingly more likely, so we
162+
In case of slice patterns the subslice interpretation seems more likely, so we
129163
can take it as a default.
130-
There was no visible demand for implementing half-bounded ranges in patterns so far, but if they
164+
There was very little demand for implementing half-bounded ranges in patterns so far
165+
(see https://github.com/rust-lang/rfcs/issues/947), but if they
131166
are implemented in the future they will be able to be used in slice patterns as well, but they
132-
will require explicit grouping with recently implemented
167+
could require explicit grouping with recently implemented
133168
[parentheses in patterns](https://github.com/rust-lang/rust/pull/48500) (`[a, (..end)]`) or an
134169
explicitly written start boundary (`[a, 0 .. end]`).
135170
We can also make *some* disambiguation effort and, for example, interpret `..LITERAL` as a
136171
range because `LITERAL` can never match a subslice. Time will show if such an effort is necessary
137172
or not.
138173

139-
If/when half-bounded ranges are supported in patterns, for better future compatibility we'll need
140-
to reserve `..PAT` as "rest of the list" in tuples and tuple structs as well, and avoid interpreting
141-
it as a range pattern in those positions.
174+
If/when half-bounded ranges are supported in patterns, for better future compatibility we could
175+
decide to reserve `..PAT` as "rest of the list" in tuples and tuple structs as well, and avoid
176+
interpreting it as a range pattern in those positions.
142177

143178
Note that ambiguity with unbounded ranges as they are used in expressions (`..`) already exists in
144-
variant `Variant(..)` and tuple `(a, b, ..)` patterns, but it's very unlikely that the `..` syntax
179+
variant `Variant(..)` and tuple `(a, b, ..)` patterns, but it's unlikely that the `..` syntax
145180
will ever be used in patterns in the range meaning because it duplicates functionality of the
146181
wildcard pattern `_`.
147182

@@ -153,15 +188,15 @@ That RFC received almost no discussion before it got merged and its motivation i
153188
relevant because arrays now use syntax `[T; N]` instead of `[T, ..N]` used in old Rust.
154189

155190
This RFC originally proposed to switch back to `..PAT`.
156-
Some reasons to switch:
191+
Some reasons to switch were:
157192
- Symmetry with expressions.
158193
One of the general ideas behind patterns is that destructuring with
159194
patterns has the same syntax as construction with expressions, if possible.
160195
In expressions we already have something with the meaning "rest of the list" - functional record
161196
update in struct expressions `S { field1, field2, ..remaining_fields }`.
162197
Right now we can use `S { field1, field1, .. }` in a pattern, but can't bind the remaining fields
163198
as a whole (by creating a new struct type on the fly, for example). It's not inconceivable that
164-
in Rust 2525 we have such ability and it's reasonable to expect it using syntax `..remaining_fields`
199+
in Rust 2030 we have such ability and it's reasonable to expect it using syntax `..remaining_fields`
165200
symmetric to expressions. It would be good for slice patterns to be consistent with it.
166201
Without speculations, even if `..remaining_fields` in struct expressions and `..subslice` in slice
167202
patterns are not entirely the same thing, they are similar enough to keep them symmetric already.
@@ -176,7 +211,7 @@ avoid if possible.
176211

177212
This RFC no longer includes the addition of `..PAT` or `PAT..`, but merely `..` as it results in
178213
a smaller starting surface-area for the feature which can be expanded in the future if necessary.
179-
The currently-proposed change is an extremely minimal addition to patterns (`..` for slices) which
214+
The currently-proposed change is a minimal addition to patterns (`..` for slices) which
180215
already exists in other forms (e.g. tuples) and generalizes well to pattern-matching out sub-tuples,
181216
e.g. `let (a, b @ .., c) = (1, 2, 3, 4);`.
182217

0 commit comments

Comments
 (0)