-
Notifications
You must be signed in to change notification settings - Fork 41
document if let guards #693
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a9d2416
79c2910
695990c
9045712
d44f6c2
f2bef9f
eba5309
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4645,7 +4645,35 @@ Match Expressions | |
| OuterAttributeOrDoc* Pattern MatchArmGuard? | ||
|
|
||
| MatchArmGuard ::= | ||
| $$if$$ Operand | ||
| $$if$$ (Operand | MatchArmGuardChain) | ||
|
|
||
| MatchArmGuardChain ::= | ||
| MatchArmGuardCondition ($$&&$$ MatchArmGuardCondition)* | ||
|
|
||
| MatchArmGuardCondition ::= | ||
| (MatchArmGuardExpression | OuterAttributeOrDoc* MatchArmGuardLetPattern) | ||
|
|
||
| MatchArmGuardLetPattern ::= | ||
| $$let$$ Pattern $$=$$ MatchArmGuardExpression | ||
|
|
||
| MatchArmGuardExpression ::= | ||
| Expression | ||
|
kirtchev-adacore marked this conversation as resolved.
|
||
|
|
||
| :dp:`fls_UlxLrpyPlVmv` | ||
| A :dt:`match arm guard expression` is any :t:`expression` in category :s:`Expression`, except: | ||
|
|
||
| - :dp:`fls_XADcpJBUxSfv` | ||
| :s:`AssignmentExpression` | ||
| - :dp:`fls_gfHe2Cy6WXsK` | ||
| :s:`CompoundAssignmentExpression` | ||
| - :dp:`fls_QQep7FKA1EQX` | ||
| :s:`LazyBooleanExpression` | ||
| - :dp:`fls_Wepy5R7FZQPU` | ||
| :s:`RangeFromExpression` | ||
| - :dp:`fls_imEIc7PUUO1x` | ||
| :s:`RangeFromToExpression` | ||
| - :dp:`fls_fs4ZpXjt0Wqt` | ||
| :s:`RangeInclusiveExpression` | ||
|
|
||
| .. rubric:: Legality Rules | ||
|
|
||
|
|
@@ -4679,6 +4707,9 @@ A :t:`match arm body` is the :t:`operand` of a :t:`match arm`. | |
| A :t:`match arm guard` is a :t:`construct` that provides additional filtering to | ||
| a :t:`match arm matcher`. | ||
|
|
||
| :dp:`fls_DT4N2rr6wpvZ` | ||
| A :dt:`match arm guard chain` is a set of conditions that must each evaluate to ``true`` in the case of :t:`[match arm guard expression]s`, or must each produce a positive match in the case of a :t:`[match arm guard let pattern]s` for the :t:`match arm` to be selected. | ||
|
|
||
| :dp:`fls_RPMOAaZ6lflI` | ||
| :t:`[Binding]s` introduced in the :t:`pattern` of a :t:`match arm matcher` are | ||
| :t:`immutable` in the :t:`match arm guard`. | ||
|
|
@@ -4715,6 +4746,12 @@ match the :t:`[subject expression]'s` :t:`type`. | |
| The :t:`value` of a :t:`match expression` is the :t:`value` of the :t:`operand` | ||
| of the selected :t:`match arm`. | ||
|
|
||
| :dp:`fls_AAuyKfxLgJ43` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think FLS still needs an explicit guard-specific rule for when arm-pattern bindings become values. Today the shared pattern rules say by-value bindings move or copy during pattern matching ( Could we add the guard-specific rule from the Reference here (or in the shared pattern / guard text), and tie it back to the existing immutability rule for match-arm-guard bindings? That would also explain why mutation through those bindings is rejected while the guard runs. Support:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still seems to miss the Reference's guard-borrow rule for bindings introduced by the match arm pattern. Before a match guard is evaluated, arm-pattern bindings are accessed through shared references to the matched parts of the scrutinee. Only if the guard succeeds are values moved or copied into by-value arm-pattern bindings. If the guard fails, those moves/copies do not happen. Without that guard-specific rule, the generic by-value pattern rule in Support:
Add this guard-specific rule in :dp:`fls_Gc5RpT8nYvQm`
Before a :t:`match arm guard` is evaluated, each :t:`binding` introduced by the
:t:`pattern` of the related :t:`match arm matcher` is accessed in the
:t:`match arm guard` through a shared reference to the matched part of the
:t:`subject expression`'s :t:`value`.
:dp:`fls_Nw2KxL7qVmRs`
If the :t:`binding mode` of such a :t:`binding` is :t:`by value`, then the copy
or move described by :p:`fls_pxvtqxke1enp` is performed only if the related
:t:`match arm guard` evaluates to ``true``.
:dp:`fls_Rh9TsD4vQpLm`
If the related :t:`match arm guard` evaluates to ``false``, then no copy or
move into such a :t:`binding` is performed.As an alternative to changing the generic rule's base wording, the qualification can also live next to the generic pattern rule. In that case, add this note to :dp:`fls_<new-id>`
For a :t:`binding` introduced by the :t:`pattern` of a
:t:`match arm matcher` with a related :t:`match arm guard`, the timing of a
copy or move into a :t:`by value` binding is specified by the
:t:`match arm guard` dynamic semantics.The consolidated changelog entry for this release note should include the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pete's suggestions LGTM! |
||
| A :dt:`match arm guard let pattern` is evaluated when its :t:`match arm guard expression` matches the specified :t:`pattern`. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Evaluation" is a dynamic semantic, so it has no business in the Legality Rules section.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sentence is describing evaluation, so I think it belongs in Dynamic Semantics rather than Legality Rules. It also calls the right-hand side a Target: :dp:`fls_AAuyKfxLgJ43`
A :t:`match arm guard let pattern` is a :t:`match arm guard condition` that
consists of a :t:`pattern` and a :t:`match arm guard scrutinee`.The evaluation steps belong in Dynamic Semantics, not in this legality-rule paragraph. |
||
|
|
||
| :dp:`fls_uCDQMkWx5OMS` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this stabilization is still incomplete outside The new local rule says bindings introduced by a guard Upstream needed matching updates in Support:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the scope/destructor pieces need to be updated in the shared chapters, not only locally in The Reference update for this feature added more than match-expression grammar. It also added FLS still has the old single-guard-operand model in these shared rules:
The PR-added local scope paragraph Target: :dp:`fls_6bwTtGKb7ba7`
A :dt:`let binding` is a :t:`binding` introduced by the :t:`pattern` of a
:t:`let statement`, an :t:`if let expression`, a
:t:`while let loop expression`, or a :t:`match arm guard let pattern`.Target: let binding
^^^^^^^^^^^
A :dt:`let binding` is a :t:`binding` introduced by the :t:`pattern` of a
:t:`let statement`, an :t:`if let expression`, a
:t:`while let loop expression`, or a :t:`match arm guard let pattern`.Target: :dp:`fls_72JHo343O7jp`
An :t:`or-pattern` shall not be used as the top-level :t:`pattern` of a
:t:`closure parameter`, a :t:`function parameter`, or a :t:`let statement`.Target: :dp:`fls_uCDQMkWx5OMS`
Each :t:`let binding` introduced in a :t:`match arm guard let pattern` is :t:`in scope` for the rest of the :t:`match arm guard` as well as the :t:`match arm body`.Target: :dp:`fls_Td7McP9rQxVn`
Each :t:`let binding` introduced by a :t:`match arm guard let pattern` is
:t:`in scope` within the following :t:`[match arm guard condition]s` of the
same :t:`match arm guard` and within the related :t:`match arm body`.Target: * :dp:`fls_lbsfhg42yiqy`
The parent :t:`drop scope` of a :t:`match arm guard operand` or a
:t:`match arm guard condition operand` is the :t:`drop scope` of the
:t:`match arm` that contains the :t:`match arm guard`.
* :dp:`fls_Jp4NsK8vYqRc`
The parent :t:`drop scope` of the :t:`match arm guard scrutinee` of a
:t:`match arm guard let pattern` is the :t:`drop scope` of the
:t:`match arm` that contains the :t:`match arm guard`.Target: :dp:`fls_fnvr5w2wzxns`
A :t:`binding` introduced by the :t:`pattern` of a
:t:`match arm matcher`, or a :t:`let binding` introduced by a
:t:`match arm guard let pattern`, is associated with the :t:`drop scope` of the
related :t:`match arm`.Target: * :dp:`fls_ptk6yibqyfzi`
The :t:`drop scope` of a :t:`match arm guard operand` or a
:t:`match arm guard condition operand`.
* :dp:`fls_Vq8LdN2xWmTs`
The :t:`drop scope` of the :t:`match arm` that contains the
:t:`match arm guard`, when the :t:`temporary` is created while evaluating a
:t:`match arm guard scrutinee` of a :t:`match arm guard let pattern`.Target: This is needed because the current generic FLS order would otherwise read as “temporaries before bindings” for the whole match-arm drop scope. That does not model pattern-matching match guards, where evaluated guard-let conditions are processed in reverse source order and each condition's bindings are dropped before temporaries created for that condition. * :dp:`fls_Et6PqW9nRcVm`
Evaluated :t:`[match arm guard let pattern]s` that have
:t:`[let binding]s` or :t:`[temporary]s` associated with the
:t:`drop scope` of a :t:`match arm` are processed in reverse source order.
For each such pattern, its :t:`[let binding]s`, if any, are dropped in reverse
declaration order before the :t:`[temporary]s` created while evaluating its
:t:`match arm guard scrutinee` are dropped in reverse creation order.
* :dp:`fls_7yybrl2J37Et`
When a :t:`match arm guard` evaluates to ``false``, the
:t:`[let binding]s` and :t:`[temporary]s` associated with the related
:t:`match arm` are :t:`dropped` before the next :t:`pattern` or
:t:`match arm` is considered.
* :dp:`fls_a5tmilqxdb6f`
All other :t:`[temporary]s` are :t:`dropped` in reverse creation order.The consolidated changelog entry for this release note should account for these pattern, glossary, scope, temporary-scope, and drop-order updates, including the changed generic temporary drop-order paragraph
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pete's suggestions LGTM! |
||
| Each :t:`let binding` introduced in a :t:`match arm guard let pattern` is :t:`in scope` for the rest of the :t:`match arm guard` as well as the :t:`match arm body`. | ||
|
|
||
| .. rubric:: Dynamic Semantics | ||
|
|
||
| :dp:`fls_g551l8r8yh6d` | ||
|
|
@@ -4767,11 +4804,6 @@ The :t:`evaluation` of a :t:`match arm matcher` proceeds as follows: | |
| #. :dp:`fls_yk8l9zjh7i0d` | ||
| Otherwise the :t:`match arm matcher` fails. | ||
|
|
||
| :dp:`fls_sbtx1l6n2tp2` | ||
| The :t:`evaluation` of a :t:`match arm guard` evaluates its :t:`operand`. A | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, this paragraph is actually useful. In fact, there Dynamic Semantics section should be updated to account for match guard let patterns.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thought it was redundant since
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree the Dynamic Semantics section needs an explicit update here, not just a revised success criterion. As written, Could we make those parts explicit in Dynamic Semantics, perhaps by replacing the removed Support:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The :t:
This suggestion is no longer relevant.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the Dynamic Semantics section needs a chain-aware guard evaluation rule, a bit more than what @kirtchev-adacore might've been suggesting. The Reference specifies this operationally:
Current FLS Target: The example below assumes a grammar that separates ordinary guard operands from guard-let chains. If the final grammar uses different category names, we can still adjust the terms while preserving the same evaluation rules. :dp:`fls_sbtx1l6n2tp2`
The :t:`evaluation` of a :t:`match arm guard` proceeds as follows:
#. :dp:`fls_Dp8aJr2LqYwS`
If the :t:`match arm guard` has a :t:`match arm guard operand`, then:
#. :dp:`fls_Wm4QvN7xTcRb`
The :t:`match arm guard operand` is evaluated.
#. :dp:`fls_Ks9FdL3pVxQa`
If the :t:`match arm guard operand` evaluates to ``false``, then the
:t:`match arm guard` evaluates to ``false`` and its :t:`evaluation` is
complete.
#. :dp:`fls_Rt5XcG8nMbPw`
If the :t:`match arm guard operand` evaluates to ``true``, then the
:t:`match arm guard` evaluates to ``true`` and its :t:`evaluation` is
complete.
#. :dp:`fls_Yh2NqT6vLsCk`
If the :t:`match arm guard` has a :t:`match arm guard chain`, then:
#. :dp:`fls_Cw2RsH7pVnQx`
Each :t:`match arm guard condition` of the chain is evaluated in source
order as follows:
#. :dp:`fls_Pb7MzD4wQkXe`
If the :t:`match arm guard condition` is a
:t:`match arm guard condition operand`, then:
#. :dp:`fls_Fj8QpM3dLsVt`
The :t:`match arm guard condition operand` is evaluated.
#. :dp:`fls_Qf4VnH8sMxRa`
If the :t:`match arm guard condition operand` evaluates to
``false``, then the :t:`match arm guard` evaluates to ``false`` and
no later :t:`[match arm guard condition]s` are evaluated.
#. :dp:`fls_Kz7NvR2xYpWm`
If the :t:`match arm guard condition operand` evaluates to
``true``, then evaluation continues with the next
:t:`match arm guard condition`.
#. :dp:`fls_Zc6TbK2wLpNd`
If the :t:`match arm guard condition` is a
:t:`match arm guard let pattern`, then:
#. :dp:`fls_Bd9TmL4qVcNs`
The :t:`match arm guard scrutinee` is evaluated.
#. :dp:`fls_Rp5HxK8wJqYd`
:t:`Pattern matching` is performed with the :t:`pattern` of the
:t:`match arm guard let pattern` against the resulting :t:`value`.
#. :dp:`fls_Vr9MqJ5xNsYd`
If the :t:`pattern matching` fails, then the
:t:`match arm guard` evaluates to ``false`` and no later
:t:`[match arm guard condition]s` are evaluated.
#. :dp:`fls_Nt6QmC3sLpXz`
If the :t:`pattern matching` succeeds, then any :t:`[binding]s`
introduced by the :t:`pattern` are bound according to the
:t:`binding pattern` semantics, and evaluation continues with the
next :t:`match arm guard condition`.
#. :dp:`fls_Av4JyT9nMkRp`
If every :t:`match arm guard condition` of the chain has been evaluated
without the :t:`match arm guard` evaluating to ``false``, then the
:t:`match arm guard` evaluates to ``true``.Target: :dp:`fls_Nc6JvS9rFaLm`
When the :t:`pattern` of a :t:`match arm matcher` is an :t:`or-pattern`, each
:t:`pattern-without-alternation` of the :t:`or-pattern` is considered in source
order during :t:`evaluation` of the :t:`match arm matcher`. Otherwise, the
:t:`pattern` itself is considered.
:dp:`fls_4dv7x9nh2h4e`
The :t:`evaluation` of a :t:`match arm matcher` proceeds as follows:
#. :dp:`fls_Qr3TcH8vNpKs`
Each :t:`pattern` determined by :p:`fls_Nc6JvS9rFaLm` is considered in
source order as follows:
#. :dp:`fls_Lm5WqZ2dJvYp`
If :t:`pattern matching` with the :t:`pattern` and the :t:`value` of the
:t:`subject expression` fails, then evaluation continues with the next
:t:`pattern`.
#. :dp:`fls_Bx8KsV4nQdRt`
If :t:`pattern matching` with the :t:`pattern` succeeds, then:
#. :dp:`fls_Mv2YpG7sLcHw`
If the :t:`match arm matcher` has no :t:`match arm guard`, then the
:t:`match arm matcher` succeeds and its :t:`evaluation` is complete.
#. :dp:`fls_Xd4LqN9vTrPm`
If the :t:`match arm matcher` has a :t:`match arm guard`, then the
:t:`match arm guard` is evaluated.
#. :dp:`fls_Hw6CkR3mVzQn`
If the :t:`match arm guard` evaluates to ``true``, then the
:t:`match arm matcher` succeeds and its :t:`evaluation` is complete.
#. :dp:`fls_gfD9XwVj5hab`
If the :t:`match arm guard` evaluates to ``false``, then evaluation
leaves the :t:`drop scope` of the related :t:`match arm` and continues
with the next :t:`pattern`, including later
:t:`[pattern-without-alternation]s` of the same :t:`or-pattern`.
#. :dp:`fls_Zm9VxF5pQwLd`
If no considered :t:`pattern` causes the :t:`match arm matcher` to succeed,
then the :t:`match arm matcher` fails.Target: A useful accounting shape would be: - Changed syntax: :s:`MatchArmGuard`
- New syntax:
- :s:`MatchArmGuardConditions`
- :s:`MatchArmGuardChain`
- :s:`MatchArmGuardCondition`
- :s:`MatchArmGuardConditionAfterLet`
- :s:`MatchArmGuardConditionOperand`
- :s:`MatchArmGuardConditionOperandBeforeLet`
- :s:`MatchArmGuardLetPattern`
- :s:`MatchArmGuardOperand`
- :s:`MatchArmGuardScrutinee`
- New glossary entries:
- :t:`match arm guard chain`
- :t:`match arm guard condition`
- :t:`match arm guard condition operand`
- :t:`match arm guard let pattern`
- :t:`match arm guard operand`
- :t:`match arm guard scrutinee`
- Updated glossary entries:
- :t:`let binding`
- Changed existing paragraphs, verifying the final list against the source:
- :p:`fls_72JHo343O7jp`
- :p:`fls_6bwTtGKb7ba7`
- :p:`fls_bzhz5wjd90ii`
- :p:`fls_st9onPgDrc8y`
- :p:`fls_4dv7x9nh2h4e`
- :p:`fls_sbtx1l6n2tp2`
- :p:`fls_e02um1gb89d0`
- :p:`fls_lbsfhg42yiqy`
- :p:`fls_fnvr5w2wzxns`
- :p:`fls_ptk6yibqyfzi`
- :p:`fls_a5tmilqxdb6f`
- Removed paragraphs, if the matcher algorithm is rewritten as above:
- :p:`fls_k7kliy101m0f`
- :p:`fls_k68zkb6jv0vz`
- :p:`fls_gbb6wbmher5z`
- :p:`fls_jl4av757yx8j`
- :p:`fls_wkh5wztauwhu`
- :p:`fls_f5f0x8jstp1g`
- :p:`fls_yk8l9zjh7i0d`
- New paragraphs for the landed definitions and rules, including:
- the match-arm-guard-chain, operand, condition operand, and scrutinee definitions;
- the syntax-subset definitions and exclusion-list items;
- the bool-typing and guard-let expected-type rules;
- the guard-let scrutinee inference rule;
- the match-guard dynamic-semantics substeps;
- the candidate-pattern/or-pattern retry rule;
- the shared source-scope, drop-scope, temporary-scope, and drop-order updates;
- the delayed copy/move rule for arm-pattern bindings with guards.We should not keep the |
||
| :t:`match arm guard` evaluates to ``true`` when its :t:`operand` evaluates to | ||
| ``true``, otherwise it evaluates to ``false``. | ||
|
|
||
| .. rubric:: Examples | ||
|
|
||
| .. code-block:: rust | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new grammar now admits two different kinds of guard condition, but the old single-
boolrules are still in place.For
if let PAT = EXPR,EXPRis a scrutinee matched againstPAT;EXPRitself is not required to have typebool. Only expression-valued guard conditions arebool-typed. As written, that seems to conflict with both the existing legality rule insrc/expressions.rst(fls_bzhz5wjd90ii) and the stale inference rule insrc/types-and-traits.rst(fls_st9onPgDrc8y), which still infer all match-arm-guard operands with expected typebool.Could this be split the same way the Reference and the existing FLS already distinguish ordinary boolean conditions from
if let/while letscrutinees? One possible shape would be a distinct guard-scrutinee rule with the pattern's type as its expected type.Support:
MatchGuardConditionMatchGuardScrutineeexpr.match.guard.conditionsrc/expressions.rstfls_bzhz5wjd90iisrc/types-and-traits.rstfls_st9onPgDrc8ytests/ui/rfcs/rfc-2294-if-let-guard/type-inference.rstests/ui/rfcs/rfc-2294-if-let-guard/typeck.rsView changes since the review
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think
MatchArmGuardConditionneeds to be changed as follows:This way a leading expression which starts a guard chain still needs to evaluate to
boolas perfls_bzhz5wjd90ii.I think
fls_bzhz5wjd90iiitsled should also be changed toThe :t:
typeof an :t:operandof a :t:match arm guardshall be :t:type:c:
bool.(I used "an" instead of "the" since a guard chain can now introduce multiple operands)
This suggestion is no longer relevant.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually
MatchArmGuardneeds to be changed too, and one of the productions thrown out:This way "pure" expressions (operands) must evaluate to
bool, and the grammar now handles a starting operand or a starting let pattern.This suggestion is no longer relevant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs a source-level split between ordinary match-arm guard operands, expression-valued guard-chain condition operands, and guard-let scrutinees.
The reason is semantic. The Reference distinguishes these roles:
MatchConditions -> MatchGuardChain | ExpressionMatchGuardCondition -> Expression except ExcludedMatchConditions | let Pattern = MatchGuardScrutineeMatchGuardScrutinee -> Expression except ExcludedMatchConditionsOnly expression-valued guard operands/conditions are required to have type
bool. A guard-let scrutinee is matched against the related pattern and is not itself required to have typebool.As written,
MatchArmGuardExpressionappears to cover ordinary guard expressions, chain condition expressions, and guard-let scrutinees. That leaves the existing FLS rules stale or ambiguous:src/expressions.rstfls_bzhz5wjd90iistill speaks about theoperandof a match arm guard beingbool, andsrc/types-and-traits.rstfls_st9onPgDrc8ystill infers all match-arm-guard operands with expected typebool.One concrete FLS shape would be this disjoint split. I do not care about the exact category names, but I think the roles need to remain distinct. This shape intentionally omits the Reference's guard-let attribute position for Rust 2021 FLS because stable
rustc +1.95.0 --edition=2021rejects attributes before guard-let patterns withE0658:MatchArmGuard ::= $$if$$ MatchArmGuardConditions MatchArmGuardConditions ::= MatchArmGuardChain | MatchArmGuardOperand MatchArmGuardOperand ::= Operand MatchArmGuardChain ::= MatchArmGuardConditionOperandBeforeLet* MatchArmGuardLetPattern MatchArmGuardConditionAfterLet* MatchArmGuardConditionOperandBeforeLet ::= MatchArmGuardConditionOperand $$&&$$ MatchArmGuardConditionAfterLet ::= $$&&$$ MatchArmGuardCondition MatchArmGuardCondition ::= MatchArmGuardConditionOperand | MatchArmGuardLetPattern MatchArmGuardConditionOperand ::= Expression MatchArmGuardLetPattern ::= $$let$$ Pattern $$=$$ MatchArmGuardScrutinee MatchArmGuardScrutinee ::= ExpressionWith this shape, expression-only guards such as
if a && bremain ordinaryMatchArmGuardOperands, while chain-specific rules apply only when a guard-let pattern is present. A more Reference-shaped grammar can also work, provided the final text still separates ordinary guard operands, chain condition operands, and guard-let scrutinees for typing, inference, scope, drop-scope, temporary-scope, and dynamic-semantics purposes. For FLS Rust 2021, I do not think the grammar should require the Reference's guard-let attribute position unless stable rustc accepts it or the divergence is explicitly documented.A bare
Operandfor every chain condition is too broad in the FLS becauseOperand ::= Expressionand would admit categories the Reference excludes inside guard chains.Target:
src/expressions.rst, immediately after the syntax block. Replace the currentfls_UlxLrpyPlVmvparagraph and its six list-item paragraphs (fls_XADcpJBUxSfv,fls_gfHe2Cy6WXsK,fls_QQep7FKA1EQX,fls_Wepy5R7FZQPU,fls_imEIc7PUUO1x,fls_fs4ZpXjt0Wqt) with syntax-subset definitions. The exclusions belong on chain operands and guard-let scrutinees, not on ordinary guards. Since the syntax categories are defined by the surrounding.. syntax::block, these subset paragraphs should use:s:links rather than introducing duplicate syntax definitions with:ds::The three excluded range categories above intentionally mirror the Reference's excluded range forms for match-guard chains: FLS
RangeFromToExpressionmaps to the ReferenceRangeExpr, whileRangeFromExpressionandRangeInclusiveExpressionmap directly. I do not thinkRangeFullExpression,RangeToExpression, orRangeToInclusiveExpressionshould be added unless the Reference'sExcludedMatchConditionschanges.Target:
src/expressions.rst, Legality Rules. With a split along these lines, insert the new bucket paragraphs immediately afterfls_hs1rr54hu18w, then replacefls_bzhz5wjd90iiwith rules for the two bool-typed cases and the guard-let pattern/scrutinee relationship. Because the corresponding terms should be defined insrc/glossary.rst, these main-text paragraphs use:t:rather than:dt::Target:
src/types-and-traits.rst,fls_st9onPgDrc8y. Replace the old inference step with context-specific inference:Target:
src/glossary.rst, near the existingmatch arm guardentry. Add entries formatch arm guard chain,match arm guard condition,match arm guard condition operand,match arm guard let pattern,match arm guard operand, andmatch arm guard scrutinee, preserving glossary alphabetical order.Target:
src/changelog.rst, Rust 1.95.0 entry forStabilize if let guards on match arms. We can use the final source shape to replace the current accounting with one consolidated changelog block. We should not listMatchArmGuardExpressionorfls_UlxLrpyPlVmv/its list-item IDs if the final update uses separate categories for these roles. We should not listfls_uCDQMkWx5OMS; that PR-local scope paragraph should be deleted before merge, and the shared scope/drop updates are accounted for by thesrc/entities-and-resolution.rstandsrc/ownership-and-deconstruction.rstIDs in the consolidated block. We should list the changed pattern paragraphsfls_72JHo343O7jpandfls_6bwTtGKb7ba7, and listlet bindingas an updated glossary entry. The new glossary entries are on an informational page, but the changelog still records them asNew glossary entrieswith:t:references.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Vis-a-vis the grammar, how about the more compact
plus the syntactic clarifications about
MatchArmGuardConditionOperandandMatchArmGuardScrutinee(there is no need to add productions for those).I could not comprehend the roles of
MatchArmGuardConditionOperandBeforeLetandMatchArmGuardConditionAfterLet, so I left them out.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure where you got the "contains at least one match arm guard let pattern". I do not see such a requirement in the Reference.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure what the purpose of the following rules is
This is like saying "foo bar is a FooBar". If you want to give a term to a construct, then you should phrase the rules similar to