Skip to content

Commit c3a4690

Browse files
committed
Add rule identifiers
1 parent 934b8c4 commit c3a4690

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

src/types/closure.md

+24-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
r[type.closure]
44

5+
r[type.closure.intro]
56
A [closure expression] produces a closure value with a unique, anonymous type that cannot be written out.
67
A closure type is approximately equivalent to a struct which contains the captured values.
78
For instance, the following closure:
@@ -83,6 +84,7 @@ The mode is not affected by the code surrounding the closure, such as the lifeti
8384

8485
### `Copy` values
8586

87+
r[type.closure.capture.copy]
8688
Values that implement [`Copy`] that are moved into the closure are captured with the `ImmBorrow` mode.
8789

8890
```rust
@@ -94,10 +96,13 @@ let c = || {
9496

9597
## Capture Precision
9698

99+
r[type.closure.capture.precision.capture-path]
97100
A *capture path* is a sequence starting with a variable from the environment followed by zero or more place projections that were applied to that variable.
98101

102+
r[type.closure.capture.precision.place-projection]
99103
A *place projection* is a [field access], [tuple index], [dereference] (and automatic dereferences), or [array or slice index] expression applied to a variable.
100104

105+
r[type.closure.capture.precision.intro]
101106
The closure borrows or moves the capture path, which may be truncated based on the rules described below.
102107

103108
For example:
@@ -124,6 +129,7 @@ This closure captures an immutable borrow of `s.f1.1`.
124129

125130
### Shared prefix
126131

132+
r[type.closure.capture.precision.shared-prefix]
127133
In the case where a capture path and one of the ancestor’s of that path are both captured by a closure, the ancestor path is captured with the highest capture mode among the two captures, `CaptureMode = max(AncestorCaptureMode, DescendantCaptureMode)`, using the strict weak ordering:
128134

129135
`ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue`
@@ -149,6 +155,7 @@ Overall this closure will capture `u` by `ByValue`.
149155

150156
### Rightmost shared reference truncation
151157

158+
r[type.closure.capture.precision.dereference-shared]
152159
The capture path is truncated at the rightmost dereference in the capture path if the dereference is applied to a shared reference.
153160

154161
This truncation is allowed because fields that are read through a shared reference will always be read via a shared reference or a copy.
@@ -176,6 +183,7 @@ If this were to capture `m`, then the closure would no longer outlive `'static`,
176183

177184
### Wildcard pattern bindings
178185

186+
r[type.closure.capture.precision.wildcard]
179187
Closures only capture data that needs to be read.
180188
Binding a value with a [wildcard pattern] does not count as a read, and thus won't be captured.
181189
For example, the following closures will not capture `x`:
@@ -227,6 +235,7 @@ println!("{:?}", e.f1);
227235
c();
228236
```
229237

238+
r[type.closure.capture.precision.wildcard.array-slice]
230239
Partial captures of arrays and slices are not supported; the entire slice or array is always captured even if used with wildcard pattern matching, indexing, or sub-slicing.
231240
For example:
232241

@@ -242,6 +251,7 @@ c();
242251
println!("{:?}", x[1]); // ERROR: borrow of moved value: `x`
243252
```
244253

254+
r[type.closure.capture.precision.wildcard.initialized]
245255
Values that are matched with wildcards must still be initialized.
246256

247257
```rust,compile_fail,E0381
@@ -257,6 +267,7 @@ let c = || {
257267

258268
### Capturing references in move contexts
259269

270+
r[type.closure.capture.precision.move-dereference]
260271
Because it is not allowed to move fields out of a reference, `move` closures will only capture the prefix of a capture path that runs up to, but not including, the first dereference of a reference.
261272
The reference itself will be moved into the closure.
262273

@@ -273,6 +284,7 @@ c();
273284

274285
### Raw pointer dereference
275286

287+
r[type.closure.capture.precision.raw-pointer-dereference]
276288
Because it is `unsafe` to dereference a raw pointer, closures will only capture the prefix of a capture path that runs up to, but not including, the first dereference of a raw pointer.
277289

278290
```rust
@@ -289,6 +301,7 @@ c();
289301

290302
### Union fields
291303

304+
r[type.closure.capture.precision.union]
292305
Because it is `unsafe` to access a union field, closures will only capture the prefix of a capture path that runs up to the union itself.
293306

294307
```rust
@@ -314,6 +327,7 @@ c();
314327

315328
### Reference into unaligned `struct`s
316329

330+
r[type.closure.capture.precision.unaligned]
317331
Because it is [undefined behavior] to create references to unaligned fields in a structure,
318332
closures will only capture the prefix of the capture path that runs up to, but not including, the first field access into a structure that uses [the `packed` representation].
319333
This includes all fields, even those that are aligned, to protect against compatibility concerns should any of the fields in the structure change in the future.
@@ -364,6 +378,7 @@ c();
364378

365379
### `Box` vs other `Deref` implementations
366380

381+
r[type.closure.capture.precision.box-deref]
367382
The implementation of the [`Deref`] trait for [`Box`] is treated differently from other `Deref` implementations, as it is considered a special entity.
368383

369384
For example, let us look at examples involving `Rc` and `Box`. The `*rc` is desugared to a call to the trait method `deref` defined on `Rc`, but since `*box` is treated differently, it is possible to do a precise capture of the contents of the `Box`.
@@ -373,6 +388,7 @@ For example, let us look at examples involving `Rc` and `Box`. The `*rc` is desu
373388

374389
#### `Box` with non-`move` closure
375390

391+
r[type.closure.capture.precision.box-non-move.not-moved]
376392
In a non-`move` closure, if the contents of the `Box` are not moved into the closure body, the contents of the `Box` are precisely captured.
377393

378394
```rust
@@ -392,6 +408,7 @@ let c_rc = || {
392408
c_rc();
393409
```
394410

411+
r[type.closure.capture.precision.box-non-move.moved]
395412
However, if the contents of the `Box` are moved into the closure, then the box is entirely captured. This is done so the amount of data that needs to be moved into the closure is minimized.
396413

397414
```rust
@@ -409,6 +426,7 @@ c_box();
409426

410427
#### `Box` with move closure
411428

429+
r[type.closure.capture.precision.box-move.read]
412430
Similarly to moving contents of a `Box` in a non-`move` closure, reading the contents of a `Box` in a `move` closure will capture the `Box` entirely.
413431

414432
```rust
@@ -525,6 +543,7 @@ Because captures are often by reference, the following general rules arise:
525543

526544
## Drop Order
527545

546+
r[type.closure.drop-order]
528547
If a closure captures a field of a composite types such as structs, tuples, and enums by value, the field's lifetime would now be tied to the closure. As a result, it is possible for disjoint fields of a composite types to be dropped at different times.
529548

530549
```rust
@@ -544,6 +563,7 @@ If a closure captures a field of a composite types such as structs, tuples, and
544563

545564
### Closure types difference
546565

566+
r[type.closure.capture.precision.edition2018.entirety]
547567
In Edition 2018 and before, closures always capture a variable in its entirety, without its precise capture path. This means that for the example used in the [Closure types](#closure-types) section, the generated closure type would instead look something like this:
548568

549569
<!-- ignore: simplified -->
@@ -571,7 +591,7 @@ f(Closure { rect: rect });
571591

572592
### Capture precision difference
573593

574-
r[type.closure.capture.composite]
594+
r[type.closure.capture.precision.edition2018.composite]
575595
Composite types such as structs, tuples, and enums are always captured in its entirety,
576596
not by individual fields. As a result, it may be necessary to borrow into a local variable in order to capture a single field:
577597

@@ -595,13 +615,15 @@ impl SetVec {
595615

596616
If, instead, the closure were to use `self.vec` directly, then it would attempt to capture `self` by mutable reference. But since `self.set` is already borrowed to iterate over, the code would not compile.
597617

598-
r[type.closure.capture.move]
618+
r[type.closure.capture.precision.edition2018.move]
599619
If the `move` keyword is used, then all captures are by move or, for `Copy` types, by copy, regardless of whether a borrow would work. The `move` keyword is usually used to allow the closure to outlive the captured values, such as if the closure is being returned or used to spawn a new thread.
600620

621+
r[type.closure.capture.precision.edition2018.wildcard]
601622
Regardless of if the data will be read by the closure, i.e. in case of wild card patterns, if a variable defined outside the closure is mentioned within the closure the variable will be captured in its entirety.
602623

603624
### Drop order difference
604625

626+
r[type.closure.capture.precision.edition2018.drop-order]
605627
As composite types are captured in their entirety, a closure which captures one of those composite types by value would drop the entire captured variable at the same time as the closure gets dropped.
606628

607629
```rust

0 commit comments

Comments
 (0)