Skip to content

Commit 00fe720

Browse files
committed
Revise ...discriminants.slice-patterns-* rules
The section here stated: > Matching against a slice pattern that needs to inspect the length of > the scrutinee performs a read of the pointer value in order to fetch > the length. The read will cause the closure to borrow the relevant > place by `ImmBorrow`. It then goes on to state exceptions for arrays matched against slice patterns and slice patterns containing only a rest pattern. In saying that the pointer value is read, this might suggest that the pointer is captured. Actually, though, it's the slice (the pointee) that is captured. Let's fix this. Beyond that, as we saw in an earlier commit, it's better to not lean on the reader to infer the "relevant place" or when the length needs to be inspected. Let's elaborate those details and state the full rule in one go, upfront, and then state a separate guarantee that matching an array against a slice pattern does not do a read. We'll also fix a typo, add rule identifiers, and tighten up the examples.
1 parent 78de4d7 commit 00fe720

File tree

1 file changed

+25
-21
lines changed

1 file changed

+25
-21
lines changed

src/types/closure.md

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -365,38 +365,42 @@ let _ = &mut x; // ERROR: Cannot borrow `x` as mutable.
365365
c();
366366
```
367367

368-
r[type.closure.capture.precision.discriminants.slice-patterns]
369-
Matching against a [slice pattern][patterns.slice] that needs to inspect the length of the scrutinee performs a read of the pointer value in order to fetch the length. The read will cause the closure to borrow the relevant place by `ImmBorrow`.
368+
r[type.closure.capture.precision.discriminants.slice-patterns-slices]
369+
Matching a slice against a [slice pattern][patterns.slice] other than one with only a single [rest pattern][patterns.rest] (i.e. `[..]`) is treated as a read of the length from the slice and captures the slice by `ImmBorrow`.
370370

371-
```rust,compile_fail,E0506
372-
let x: &mut [i32] = &mut [1, 2, 3];
373-
let c = || match x { // captures `*x` by ImmBorrow
374-
[_, _, _] => println!("three elements"),
375-
_ => println!("something else"),
371+
```rust,compile_fail,E0502
372+
let x: &mut [u8] = &mut [];
373+
let c = || match x { // Captures `*x` by `ImmBorrow`.
374+
&mut [] => (),
375+
// ^^
376+
// This matches a slice of exactly zero elements. To know whether the
377+
// scrutinee matches, the length must be read, causing the slice to
378+
// be captured.
379+
_ => (),
376380
};
377-
x[0] += 1; // ERROR: cannot assign to `x[_]` because it is borrowed
381+
let _ = &mut *x; // ERROR: Cannot borrow `*x` as mutable.
378382
c();
379383
```
380384

381-
As such, matching against an array doesn't itself cause any borrows, as the lengthh is fixed and the pattern doesn't need to inspect it.
382-
383-
```rust
384-
let mut x: [i32; 3] = [1, 2, 3];
385-
let c = || match x { // does not capture `x`
386-
[_, _, _] => println!("three elements, obviously"),
385+
```rust,no_run
386+
let x: &mut [u8] = &mut [];
387+
let c = || match x { // Does not capture `*x`.
388+
[..] => (),
389+
// ^^ Rest pattern.
387390
};
388-
x[0] += 1; // `x` can be modified while the closure is live
391+
let _ = &mut *x; // OK: `*x` can be borrow here.
389392
c();
390393
```
391394

392-
Likewise, a slice pattern that matches slices of all possible lengths does not constitute a read.
395+
r[type.closure.capture.precision.discriminants.slice-patterns-arrays]
396+
As the length of an array is fixed by its type, matching an array against a slice pattern does not by itself capture the place.
393397

394-
```rust
395-
let x: &mut [i32] = &mut [1, 2, 3];
396-
let c = || match x { // does not capture `x`
397-
[..] => println!("always matches"),
398+
```rust,no_run
399+
let x: [u8; 1] = [0];
400+
let c = || match x { // Does not capture `x`.
401+
[_] => (), // Length is fixed.
398402
};
399-
x[0] += 1; // `x` can be modified while the closure is live
403+
x; // OK: `x` can be moved here.
400404
c();
401405
```
402406

0 commit comments

Comments
 (0)