document Closure capture precision#698
Conversation
e3ed8e9 to
7be2ad5
Compare
|
all addressed but #698 (comment) |
There was a problem hiding this comment.
I will probably need to read Capture precision to ensure that no rules have been omitted.
| A :t:`closure expression` :t:`[borrow]s` or :t:`moves <by move>` the :t:`capture path`, which may be truncated based on these rules: | ||
|
|
||
| - :dp:`fls_4TESOxGpEY2h` | ||
| When a :t:`capture path` and an ancestor :t:`capture path` are both :t:`captured <capturing>`, the ancestor :t:`capture path` is captured with the highest :t:`capture mode` among the two :t:`[capture path]s`. |
There was a problem hiding this comment.
| When a :t:`capture path` and an ancestor :t:`capture path` are both :t:`captured <capturing>`, the ancestor :t:`capture path` is captured with the highest :t:`capture mode` among the two :t:`[capture path]s`. | |
| - When a :t:`capture path` and an ancestor :t:`capture path` are both :t:`captured <capturing>`, the ancestor :t:`capture path` is :t:`captured` with the highest :t:`capture mode` among the two :t:`[capture path]s`. |
This and the following rules should be list items.
There was a problem hiding this comment.
The shared-prefix rule also seems to need the Reference's recursive-propagation note.
A deeper descendant can strengthen an intermediate ancestor, and that stronger mode may then need to propagate again to a more distant ancestor.
Could a short note be added here saying this rule may need to be applied recursively?
Support:
- Reference
type.closure.capture.precision.shared-prefix
There was a problem hiding this comment.
was thinking an ancestor should cover that, since ancestor can mean parent, grand parent, great grand parent, and so on... unless you don't think that is strong enough
There was a problem hiding this comment.
This and the following rules should be list items.
it already is... see the line prior
There was a problem hiding this comment.
I am OK with Tshepang's latest change. Pete however should also chime in with respect to his comment.
There was a problem hiding this comment.
How about something along the lines of
When a :t:capture path and an ancestor :t:capture path are both :t:captured <capturing>, the ancestor :t:capture path is :t:captured with the highest :t:capture mode among the two :t:[capture path]s, recursively, for all such pairs of :t:[capture path]s.
The Reference's "recursive" note is not 100% clear because one also has to take into account pairs of paths.
| :dp:`fls_v8IFXHJnXhez` | ||
| A :t:`place` is not captured when an :t:`underscore expression` is used to bind it. | ||
|
|
||
| :dp:`fls_gujpU7p5n9Zx` | ||
| A :t:`place` is not captured by destructuring tuples, structs, and single-variant enums. | ||
|
|
||
| :dp:`fls_t8tFLUg8O83Q` | ||
| A :t:`place` is not captured by being matched against a :t:`rest pattern`. | ||
|
|
||
| :dp:`fls_RaONmCLH2KGM` | ||
| The entire :t:`slice` or :t:`array` is always captured even if used with :t:`underscore expression`, :t:`indexing <index expression>`, or :t:`slicing <slice>`. | ||
|
|
||
| :dp:`fls_Vt9C9mKxHOwo` | ||
| A :t:`place` is captured by :t:`immutable borrow` if its :t:`discriminant` is read by :t:`pattern matching`. | ||
|
|
||
| :dp:`fls_Fs12dmznjsMf` | ||
| Matching against a variant of an enum that has more than one variant captures the :t:`place` by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_7EXHdE2eOVek` | ||
| Matching against a variant of an enum that has one variant does not capture the place, unless it is marked with :t:`attribute` ``non_exhaustive``, in which case the place is captured by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_iLH8X2U4ADHb` | ||
| Matching against a :t:`range pattern` captures the place by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_HMJUXHrvOmPl` | ||
| Matching a :t:`slice` against a slice :t:`pattern`, other than one with only a single rest pattern ``[..]``, captures the slice by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_Gj1znNpthHY6` | ||
| Matching an array against a slice pattern does not capture the :t:`place`. | ||
|
|
||
| :dp:`fls_IFyJvb6mlFU4` | ||
| Move closures can only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`reference`. | ||
|
|
||
| :dp:`fls_7NEEJgKSpQQ8` | ||
| Closures will only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`raw pointer`. | ||
|
|
||
| :dp:`fls_kYFd3p06pWWV` | ||
| Closures will only capture the prefix of a :t:`capture path` of a :t:`union` that runs up to the union itself. | ||
|
|
||
| :dp:`fls_fATMTNUOHsfb` | ||
| Closures will only capture the prefix of the :t:`capture path` that runs up to, but not including, the first :t:`field access expression` into a structure that uses the :t:`attribute` ``packed`` representation, in unaligned :t:`[field]s` in a struct. | ||
|
|
||
| :dp:`fls_fITor3jpmgrl` | ||
| Taking the address of an unaligned :t:`field` captures the entire struct. |
There was a problem hiding this comment.
I made significant reorderings and rewording of some of the paragraphs.
| :dp:`fls_v8IFXHJnXhez` | |
| A :t:`place` is not captured when an :t:`underscore expression` is used to bind it. | |
| :dp:`fls_gujpU7p5n9Zx` | |
| A :t:`place` is not captured by destructuring tuples, structs, and single-variant enums. | |
| :dp:`fls_t8tFLUg8O83Q` | |
| A :t:`place` is not captured by being matched against a :t:`rest pattern`. | |
| :dp:`fls_RaONmCLH2KGM` | |
| The entire :t:`slice` or :t:`array` is always captured even if used with :t:`underscore expression`, :t:`indexing <index expression>`, or :t:`slicing <slice>`. | |
| :dp:`fls_Vt9C9mKxHOwo` | |
| A :t:`place` is captured by :t:`immutable borrow` if its :t:`discriminant` is read by :t:`pattern matching`. | |
| :dp:`fls_Fs12dmznjsMf` | |
| Matching against a variant of an enum that has more than one variant captures the :t:`place` by :t:`immutable borrow`. | |
| :dp:`fls_7EXHdE2eOVek` | |
| Matching against a variant of an enum that has one variant does not capture the place, unless it is marked with :t:`attribute` ``non_exhaustive``, in which case the place is captured by :t:`immutable borrow`. | |
| :dp:`fls_iLH8X2U4ADHb` | |
| Matching against a :t:`range pattern` captures the place by :t:`immutable borrow`. | |
| :dp:`fls_HMJUXHrvOmPl` | |
| Matching a :t:`slice` against a slice :t:`pattern`, other than one with only a single rest pattern ``[..]``, captures the slice by :t:`immutable borrow`. | |
| :dp:`fls_Gj1znNpthHY6` | |
| Matching an array against a slice pattern does not capture the :t:`place`. | |
| :dp:`fls_IFyJvb6mlFU4` | |
| Move closures can only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`reference`. | |
| :dp:`fls_7NEEJgKSpQQ8` | |
| Closures will only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`raw pointer`. | |
| :dp:`fls_kYFd3p06pWWV` | |
| Closures will only capture the prefix of a :t:`capture path` of a :t:`union` that runs up to the union itself. | |
| :dp:`fls_fATMTNUOHsfb` | |
| Closures will only capture the prefix of the :t:`capture path` that runs up to, but not including, the first :t:`field access expression` into a structure that uses the :t:`attribute` ``packed`` representation, in unaligned :t:`[field]s` in a struct. | |
| :dp:`fls_fITor3jpmgrl` | |
| Taking the address of an unaligned :t:`field` captures the entire struct. | |
| :dp:`fls_Vt9C9mKxHOwo` | |
| A :t:`place` is :t:`captured` by :t:`immutable borrow` if its :t:`discriminant` is read by :t:`pattern matching`. | |
| :dp:`fls_v8IFXHJnXhez` | |
| A :t:`place` is not :t:`captured` when an :t:`underscore expression` is used to bind it. | |
| :dp:`fls_gujpU7p5n9Zx` | |
| A :t:`place` is not :t:`captured` by destructuring :t:`[struct]s`, :t:`[tuple]s`, and :t:`[enum]s` with a single :t:`enum variant`. | |
| :dp:`fls_t8tFLUg8O83Q` | |
| A :t:`place` is not :t:`captured` by being matched against a :t:`rest pattern`. | |
| :dp:`fls_RaONmCLH2KGM` | |
| An :t:`array` or :t:`slice` is :t:`captured` whole. | |
| :dp:`fls_Fs12dmznjsMf` | |
| Matching against an :t:`enum variant` of an :t:`enum` with more than one :t:`[enum variant]s` :t:`captures` the :t:`place` by :t:`immutable borrow`. | |
| :dp:`fls_7EXHdE2eOVek` | |
| Matching against an :t:`enum variant` of an :t:`enum` with one :t:`enum variant` does not :t:`capture` the :t:`place`, unless it is subject to :t:`attribute` ``non_exhaustive``, in which case the :t:`place` is captured by :t:`immutable borrow`. | |
| :dp:`fls_iLH8X2U4ADHb` | |
| Matching against a :t:`range pattern` :t:`captures` the :t:`place` by :t:`immutable borrow`. | |
| :dp:`fls_HMJUXHrvOmPl` | |
| Matching a :t:`slice` against a :t:`slice pattern`, other than one with only a single :t:`rest pattern`, :t:`captures` the :t:`slice` by :t:`immutable borrow`. | |
| :dp:`fls_Gj1znNpthHY6` | |
| Matching an :t:`array` against a :t:`slice pattern` does not :t:`capture` the :t:`place`. | |
| :dp:`fls_IFyJvb6mlFU4` | |
| A :t:`closure expression` subject to keyword ``move`` :t:`captures` the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`reference`. | |
| :dp:`fls_7NEEJgKSpQQ8` | |
| A :t:`closure expression` :t:`captures` the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`raw pointer`. | |
| :dp:`fls_kYFd3p06pWWV` | |
| A :t:`closure expression` :t:`captures` the prefix of a :t:`capture path` of a :t:`union` that runs up to the :t:`union` itself. | |
| :dp:`fls_fATMTNUOHsfb` | |
| A :t:`closure expression` :t:`captures` the prefix of the :t:`capture path` that runs up to, but not including, the first :t:`field access expression` into a :t:`struct` that uses the :t:`attribute` :c:`repr` with modifier ``packed``, in unaligned :t:`[field]s` in a :t:`struct`. | |
| :dp:`fls_fITor3jpmgrl` | |
| Taking the address of an unaligned :t:`field` captures the entire struct. |
There was a problem hiding this comment.
Several rules in this block still seem too strong relative to the Reference.
_here should use the FLS termunderscore pattern, notunderscore expression, and_does not introduce a binding.- The destructuring /
../ array-vs-slice rules should saydoes not by itself read or capture. That qualifier matters because subpatterns can still capture subplaces; e.g.let (x0, ..) = x;still capturesx.0.
Could this subsection be adjusted along those lines?
Support:
- FLS glossary
underscore expression/underscore patterninsrc/glossary.rst:4799-4811 - Reference
type.closure.capture.precision.wildcard.reads - Reference
type.closure.capture.precision.wildcard.destructuring - Reference
type.closure.capture.precision.wildcard.fields - Reference
type.closure.capture.precision.slice-patterns.arrays - Make closure capturing have consistent and correct behaviour around patterns rust#138961
There was a problem hiding this comment.
Separate point on the Matching a slice against a slice pattern... rule in this block: the current summary seems to compress away an important Reference detail.
Upstream treats this as a read of the slice length, but the captured place is the slice pointee rather than the wide-pointer place.
That distinction matters for cases like &mut [T] and &mut &'l [u8], where the effective capture is *x / **x, not x / *x.
Could that pointee-vs-wide-pointer behavior be made explicit here, or backed with a brief note/example mirroring the Reference?
Support:
- Reference
type.closure.capture.precision.slice-patterns.slices - Make closure capturing have consistent and correct behaviour around patterns rust#138961
- Document how closure capturing interacts with discriminant reads reference#1837
There was a problem hiding this comment.
Separate point on the repr(packed) rule in this block: this still seems narrower than the Reference.
Upstream truncates at the first field access into any repr(packed) struct, and explicitly says this includes fields that are currently aligned as well, for future-compatibility reasons.
Could this sentence be widened accordingly instead of limiting it to unaligned fields?
Support:
- Reference
type.closure.capture.precision.unaligned
There was a problem hiding this comment.
array-vs-slice rules
what does this mean, a typo perhaps... the paragraph is about enums, structs, and tuples
There was a problem hiding this comment.
should say
does not by itself read or capture
dcd9707 adds clarity, and fls_Vt9C9mKxHOwo covers (maybe) this part of your concern
would that be enough
There was a problem hiding this comment.
Could this sentence be widened accordingly instead of limiting it to
unalignedfields?
I see that as additional explanation, and does not change the primary rule at all... "this is nutritious (even if you don't enjoy the taste)"
There was a problem hiding this comment.
I propose that rule 6.22:4 is changed as follows:
Capturing is the process of saving the capture targets of a capturing expression's capturing environment, only when the capture targets need to be read.
Given the above, we have the following changes:
:dp:fls_v8IFXHJnXhez
A :t:place is not :t:captured when an :t:underscore pattern is used to bind it as the :t:value is not read.
:dp:fls_gujpU7p5n9Zx
A :t:place is not :t:captured by using a :t:rest pattern when :t:destructuring <pattern destructuring> :t:[struct]s, :t:[tuple]s, and :t:[enum]s with a single :t:enum variant as the :t:value is not read.
:dp:fls_t8tFLUg8O83Q
A :t:field is not :t:captured by being matched against a :t:rest pattern as the :t:field is not read.
:dp:fls_HMJUXHrvOmPl
Matching a :t:slice against a :t:slice pattern, other than one with only a single :t:rest pattern, :t:captures <capturing> the :t:slice by :t:immutable borrow as the length of the :t:slice is read.
:dp:fls_Gj1znNpthHY6
Matching an :t:array against a :t:slice pattern does not :t:capture <capturing> the :t:place as the length of the :t:array is fixed by its :t:type.
:dp:fls_fATMTNUOHsfb
A :t:closure expression :t:captures <capturing> the prefix of the :t:capture path that runs up to, but not including, the first :t:field access expression into a :t:struct that uses the :t:attribute :c:repr with modifier packed.
(I removed some redundancy and relaxed the rule a bit)
| A :dt:`place projection` is a :t:`field access expression`, :t:`dereference`, :t:`array` or :t:`slice` :t:`index expression`, or :t:`pattern` destructuring applied to a :t:`variable`. | ||
|
|
||
| :dp:`fls_rdDT7jsaOMbs` |
There was a problem hiding this comment.
Two semantic gaps still seem unresolved here.
place projectionstill seems narrower than the Reference because it omits automatic dereferences. Upstream saysdereference (and automatic dereferences), and that matters because these rules operate on the projected place, not only explicit*syntax.- This subsection should also say how
capture pathrelates to the existingcapture target/capturing environmentmodel above. Earlier in 6.22, a capture target is only a variable or a field of a variable; here, capture paths now include dereferences, indexing, raw-pointer truncation, union truncation, and packed-struct truncation, so it is hard to tell whethercapture pathrefines that model or replaces it for this subsection.
Could this subsection tighten both definitions together, perhaps by widening place projection and adding a short bridge sentence about how capture path fits the model above?
Support:
- Reference
type.closure.capture.precision.place-projection - Reference
type.closure.capture.precision src/expressions.rst:5103-5184src/glossary.rst:768-785
There was a problem hiding this comment.
hm, I don't really know how to address this review... I need to get a better understanding of these things
There was a problem hiding this comment.
also, there are overlaps with #698 (comment)... maybe a topic for a meet
There was a problem hiding this comment.
Here are my suggestions:
:dp:fls_j9WyKVyOLFon
A :dt:place projection is an :t:array :t:index expression, an automatic :t:dereference, an explicit :t:dereference, a :t:field access expression, a :t:pattern destructuring applied to a :t:variable, or a :t:slice :t:index expression.
(alphabetized, included automatic dereference)
I think that to fit "capture path" into the existing 6.22 Capturing model, we should change the rule about capture paths as follows:
:dp:fls_rdDT7jsaOMbs
A :dt:capture path is a sequence starting with a :t:capture target from the :t:capturing environment followed by zero or more :t:[place projection]s from that :t:capture target.
| - `Const blocks are no longer evaluated to determine if expressions involving fallible operations can implicitly be constant-promoted <https://github.com/rust-lang/rust/pull/150557>`_ | ||
| - `Make operational semantics of pattern matching independent of crate and module <https://github.com/rust-lang/rust/pull/150681>`_ | ||
|
|
||
| Changed paragraphs: |
There was a problem hiding this comment.
The paragraph-ID list itself looks fine, but this changelog attribution still seems too broad.
The changed capture-mode paragraphs fit rust-lang/rust#150681, but the new capture-precision block spans multiple sources: some items align with the later pattern/discriminant work in rust-lang/rust#138961 and rust-lang/reference#1837, while others are pre-existing Reference behavior now being documented here.
Could this entry be split, or reworded so #150681 is not presented as introducing the whole block? The note that these paragraphs mostly document behavior that existed before this release already points in that direction.
Support:
There was a problem hiding this comment.
I can go find where each behavior was added, but am not sure it's worth the time
maybe a good compromise is having a different heading, like "Pre-existing behavior before 1.95", or just "FLS maintenance"
| A :t:`closure expression` :t:`[borrow]s` or :t:`moves <by move>` the :t:`capture path`, which may be truncated based on these rules: | ||
|
|
||
| - :dp:`fls_4TESOxGpEY2h` | ||
| When a :t:`capture path` and an ancestor :t:`capture path` are both :t:`captured <capturing>`, the ancestor :t:`capture path` is captured with the highest :t:`capture mode` among the two :t:`[capture path]s`. |
There was a problem hiding this comment.
The shared-prefix rule also seems to need the Reference's recursive-propagation note.
A deeper descendant can strengthen an intermediate ancestor, and that stronger mode may then need to propagate again to a more distant ancestor.
Could a short note be added here saying this rule may need to be applied recursively?
Support:
- Reference
type.closure.capture.precision.shared-prefix
| :dp:`fls_v8IFXHJnXhez` | ||
| A :t:`place` is not captured when an :t:`underscore expression` is used to bind it. | ||
|
|
||
| :dp:`fls_gujpU7p5n9Zx` | ||
| A :t:`place` is not captured by destructuring tuples, structs, and single-variant enums. | ||
|
|
||
| :dp:`fls_t8tFLUg8O83Q` | ||
| A :t:`place` is not captured by being matched against a :t:`rest pattern`. | ||
|
|
||
| :dp:`fls_RaONmCLH2KGM` | ||
| The entire :t:`slice` or :t:`array` is always captured even if used with :t:`underscore expression`, :t:`indexing <index expression>`, or :t:`slicing <slice>`. | ||
|
|
||
| :dp:`fls_Vt9C9mKxHOwo` | ||
| A :t:`place` is captured by :t:`immutable borrow` if its :t:`discriminant` is read by :t:`pattern matching`. | ||
|
|
||
| :dp:`fls_Fs12dmznjsMf` | ||
| Matching against a variant of an enum that has more than one variant captures the :t:`place` by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_7EXHdE2eOVek` | ||
| Matching against a variant of an enum that has one variant does not capture the place, unless it is marked with :t:`attribute` ``non_exhaustive``, in which case the place is captured by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_iLH8X2U4ADHb` | ||
| Matching against a :t:`range pattern` captures the place by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_HMJUXHrvOmPl` | ||
| Matching a :t:`slice` against a slice :t:`pattern`, other than one with only a single rest pattern ``[..]``, captures the slice by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_Gj1znNpthHY6` | ||
| Matching an array against a slice pattern does not capture the :t:`place`. | ||
|
|
||
| :dp:`fls_IFyJvb6mlFU4` | ||
| Move closures can only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`reference`. | ||
|
|
||
| :dp:`fls_7NEEJgKSpQQ8` | ||
| Closures will only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`raw pointer`. | ||
|
|
||
| :dp:`fls_kYFd3p06pWWV` | ||
| Closures will only capture the prefix of a :t:`capture path` of a :t:`union` that runs up to the union itself. | ||
|
|
||
| :dp:`fls_fATMTNUOHsfb` | ||
| Closures will only capture the prefix of the :t:`capture path` that runs up to, but not including, the first :t:`field access expression` into a structure that uses the :t:`attribute` ``packed`` representation, in unaligned :t:`[field]s` in a struct. | ||
|
|
||
| :dp:`fls_fITor3jpmgrl` | ||
| Taking the address of an unaligned :t:`field` captures the entire struct. |
There was a problem hiding this comment.
Several rules in this block still seem too strong relative to the Reference.
_here should use the FLS termunderscore pattern, notunderscore expression, and_does not introduce a binding.- The destructuring /
../ array-vs-slice rules should saydoes not by itself read or capture. That qualifier matters because subpatterns can still capture subplaces; e.g.let (x0, ..) = x;still capturesx.0.
Could this subsection be adjusted along those lines?
Support:
- FLS glossary
underscore expression/underscore patterninsrc/glossary.rst:4799-4811 - Reference
type.closure.capture.precision.wildcard.reads - Reference
type.closure.capture.precision.wildcard.destructuring - Reference
type.closure.capture.precision.wildcard.fields - Reference
type.closure.capture.precision.slice-patterns.arrays - Make closure capturing have consistent and correct behaviour around patterns rust#138961
| :dp:`fls_v8IFXHJnXhez` | ||
| A :t:`place` is not captured when an :t:`underscore expression` is used to bind it. | ||
|
|
||
| :dp:`fls_gujpU7p5n9Zx` | ||
| A :t:`place` is not captured by destructuring tuples, structs, and single-variant enums. | ||
|
|
||
| :dp:`fls_t8tFLUg8O83Q` | ||
| A :t:`place` is not captured by being matched against a :t:`rest pattern`. | ||
|
|
||
| :dp:`fls_RaONmCLH2KGM` | ||
| The entire :t:`slice` or :t:`array` is always captured even if used with :t:`underscore expression`, :t:`indexing <index expression>`, or :t:`slicing <slice>`. | ||
|
|
||
| :dp:`fls_Vt9C9mKxHOwo` | ||
| A :t:`place` is captured by :t:`immutable borrow` if its :t:`discriminant` is read by :t:`pattern matching`. | ||
|
|
||
| :dp:`fls_Fs12dmznjsMf` | ||
| Matching against a variant of an enum that has more than one variant captures the :t:`place` by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_7EXHdE2eOVek` | ||
| Matching against a variant of an enum that has one variant does not capture the place, unless it is marked with :t:`attribute` ``non_exhaustive``, in which case the place is captured by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_iLH8X2U4ADHb` | ||
| Matching against a :t:`range pattern` captures the place by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_HMJUXHrvOmPl` | ||
| Matching a :t:`slice` against a slice :t:`pattern`, other than one with only a single rest pattern ``[..]``, captures the slice by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_Gj1znNpthHY6` | ||
| Matching an array against a slice pattern does not capture the :t:`place`. | ||
|
|
||
| :dp:`fls_IFyJvb6mlFU4` | ||
| Move closures can only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`reference`. | ||
|
|
||
| :dp:`fls_7NEEJgKSpQQ8` | ||
| Closures will only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`raw pointer`. | ||
|
|
||
| :dp:`fls_kYFd3p06pWWV` | ||
| Closures will only capture the prefix of a :t:`capture path` of a :t:`union` that runs up to the union itself. | ||
|
|
||
| :dp:`fls_fATMTNUOHsfb` | ||
| Closures will only capture the prefix of the :t:`capture path` that runs up to, but not including, the first :t:`field access expression` into a structure that uses the :t:`attribute` ``packed`` representation, in unaligned :t:`[field]s` in a struct. | ||
|
|
||
| :dp:`fls_fITor3jpmgrl` | ||
| Taking the address of an unaligned :t:`field` captures the entire struct. |
There was a problem hiding this comment.
Separate point on the Matching a slice against a slice pattern... rule in this block: the current summary seems to compress away an important Reference detail.
Upstream treats this as a read of the slice length, but the captured place is the slice pointee rather than the wide-pointer place.
That distinction matters for cases like &mut [T] and &mut &'l [u8], where the effective capture is *x / **x, not x / *x.
Could that pointee-vs-wide-pointer behavior be made explicit here, or backed with a brief note/example mirroring the Reference?
Support:
- Reference
type.closure.capture.precision.slice-patterns.slices - Make closure capturing have consistent and correct behaviour around patterns rust#138961
- Document how closure capturing interacts with discriminant reads reference#1837
| :dp:`fls_v8IFXHJnXhez` | ||
| A :t:`place` is not captured when an :t:`underscore expression` is used to bind it. | ||
|
|
||
| :dp:`fls_gujpU7p5n9Zx` | ||
| A :t:`place` is not captured by destructuring tuples, structs, and single-variant enums. | ||
|
|
||
| :dp:`fls_t8tFLUg8O83Q` | ||
| A :t:`place` is not captured by being matched against a :t:`rest pattern`. | ||
|
|
||
| :dp:`fls_RaONmCLH2KGM` | ||
| The entire :t:`slice` or :t:`array` is always captured even if used with :t:`underscore expression`, :t:`indexing <index expression>`, or :t:`slicing <slice>`. | ||
|
|
||
| :dp:`fls_Vt9C9mKxHOwo` | ||
| A :t:`place` is captured by :t:`immutable borrow` if its :t:`discriminant` is read by :t:`pattern matching`. | ||
|
|
||
| :dp:`fls_Fs12dmznjsMf` | ||
| Matching against a variant of an enum that has more than one variant captures the :t:`place` by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_7EXHdE2eOVek` | ||
| Matching against a variant of an enum that has one variant does not capture the place, unless it is marked with :t:`attribute` ``non_exhaustive``, in which case the place is captured by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_iLH8X2U4ADHb` | ||
| Matching against a :t:`range pattern` captures the place by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_HMJUXHrvOmPl` | ||
| Matching a :t:`slice` against a slice :t:`pattern`, other than one with only a single rest pattern ``[..]``, captures the slice by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_Gj1znNpthHY6` | ||
| Matching an array against a slice pattern does not capture the :t:`place`. | ||
|
|
||
| :dp:`fls_IFyJvb6mlFU4` | ||
| Move closures can only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`reference`. | ||
|
|
||
| :dp:`fls_7NEEJgKSpQQ8` | ||
| Closures will only capture the prefix of a :t:`capture path` that runs up to, but not including, the first :t:`dereference` of a :t:`raw pointer`. | ||
|
|
||
| :dp:`fls_kYFd3p06pWWV` | ||
| Closures will only capture the prefix of a :t:`capture path` of a :t:`union` that runs up to the union itself. | ||
|
|
||
| :dp:`fls_fATMTNUOHsfb` | ||
| Closures will only capture the prefix of the :t:`capture path` that runs up to, but not including, the first :t:`field access expression` into a structure that uses the :t:`attribute` ``packed`` representation, in unaligned :t:`[field]s` in a struct. | ||
|
|
||
| :dp:`fls_fITor3jpmgrl` | ||
| Taking the address of an unaligned :t:`field` captures the entire struct. |
There was a problem hiding this comment.
Separate point on the repr(packed) rule in this block: this still seems narrower than the Reference.
Upstream truncates at the first field access into any repr(packed) struct, and explicitly says this includes fields that are currently aligned as well, for future-compatibility reasons.
Could this sentence be widened accordingly instead of limiting it to unaligned fields?
Support:
- Reference
type.closure.capture.precision.unaligned
| The :t:`capture path` is truncated at the rightmost :t:`dereference` in the :t:`capture path` if the :t:`dereference` is applied to a :t:`shared reference`. | ||
|
|
||
| :dp:`fls_v8IFXHJnXhez` | ||
| A :t:`place` is not captured when an :t:`underscore expression` is used to bind it. |
There was a problem hiding this comment.
Optional completeness point: upstream also states that values matched with wildcards must still be initialized.
If you want closer Reference parity in this subsection, consider adding a short note or rule for that as well.
Support:
- Reference
type.closure.capture.precision.wildcard.initialized
There was a problem hiding this comment.
I skipped that deliberately as I thought it was redundant (pedantic)... the value won't be used anyways, and if this restriction gets removed in future, it does not affect the content of the FLS.
There was a problem hiding this comment.
We have the following blanket rule:
15.2:4 A variable shall be initialized before it is accessed.
where we conveniently do not explain what "accessed" means. 😆
| Matching against a variant of an enum that has more than one variant captures the :t:`place` by :t:`immutable borrow`. | ||
|
|
||
| :dp:`fls_7EXHdE2eOVek` | ||
| Matching against a variant of an enum that has one variant does not capture the place, unless it is marked with :t:`attribute` ``non_exhaustive``, in which case the place is captured by :t:`immutable borrow`. |
There was a problem hiding this comment.
Separate completeness point on the discriminant-read rules: this block still seems to omit the Reference rule for uninhabited variants.
Even if all variants but the one being matched against are uninhabited, the discriminant is still read if it otherwise would be.
Could this subsection add that explicitly?
Support:
- Reference
type.closure.capture.precision.discriminants.uninhabited-variants - Make operational semantics of pattern matching independent of crate and module rust#150681
There was a problem hiding this comment.
The FLS does not define what an "uninhabited type" is, and it should. I propose we insert the following rules between 4.1:1 and 4.1:2:
An :t:inhabited type is a :t:type with :t:[constructor]s and :t:[value]s.
An :t:uninhabited type is a :t:type without :t:[constructor]s and :t:[value]s.
The FLS also does not define what a "constructor" is, and it should. I propose we insert a new 6.1.3 Constructor Expressions subsection, with the following singular legality rule:
A :t:constructor is an :t:array expression, a :t:struct expression, or a :t:tuple expression.
(I probably missed an expression here...)
Needless to say, all these rules will need corresponding entries in the Glossary.
Give the above, I propose the following changes:
:dp:fls_Fs12dmznjsMf
Matching against an :t:enum variant of an :t:enum with more than one :t:[enum variant]s :t:captures <capturing> the :t:place by :t:immutable borrow as the :t:discriminant is read.
:dp:fls_7EXHdE2eOVek
Matching against an :t:enum variant of an :t:enum with one :t:enum variant does not :t:capture <capturing> the :t:place as the :t:discriminant is not read, unless the :t:enum is subject to :t:attribute non_exhaustive, in which case the :t:place is captured by :t:immutable borrow.
I do not understand what the type.closure.capture.precision.discriminants.uninhabited-variants Reference rule is trying to say. Is it something along the lines of "if an enum type has at least one inhabited variant, and possibly multiple uninhabited variants, then the discriminant is still read, thus capturing takes place"?
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Hristian Kirtchev <60669983+kirtchev-adacore@users.noreply.github.com>
Co-authored-by: Hristian Kirtchev <60669983+kirtchev-adacore@users.noreply.github.com>
…erload the term) Co-authored-by: Hristian Kirtchev <60669983+kirtchev-adacore@users.noreply.github.com>
Co-authored-by: Hristian Kirtchev <60669983+kirtchev-adacore@users.noreply.github.com>
dcd9707 to
550f10d
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
Co-authored-by: Hristian Kirtchev <60669983+kirtchev-adacore@users.noreply.github.com>
Just to clarify, after reading the Reference's Capture precision, I think "place" is indeed the proper term. |
This captures some gaps FLS has compared to Reference, and the content is adjusted from Closure capture precision section.