Skip to content

document if let guards#693

Open
tshepang wants to merge 7 commits intomainfrom
tshepang/document-if-let-guards
Open

document if let guards#693
tshepang wants to merge 7 commits intomainfrom
tshepang/document-if-let-guards

Conversation

@tshepang
Copy link
Copy Markdown
Member

No description provided.

Copy link
Copy Markdown
Member

@jyn514 jyn514 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/expressions.rst Outdated
@kirtchev-adacore kirtchev-adacore self-requested a review April 21, 2026 11:10
Comment thread src/expressions.rst Outdated
Comment thread src/expressions.rst Outdated
The :t:`value` of a :t:`match expression` is the :t:`value` of the :t:`operand`
of the selected :t:`match arm`.

:dp:`fls_DT4N2rr6wpvZ`
Copy link
Copy Markdown
Contributor

@kirtchev-adacore kirtchev-adacore Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This paragraph should follow "6.18:8 A match arm guard ...".

View changes since the review

Comment thread src/expressions.rst Outdated

MatchArmGuard ::=
$$if$$ Operand
$$if$$ (Operand | MatchGuardChain)
Copy link
Copy Markdown
Contributor

@kirtchev-adacore kirtchev-adacore Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether these new non-terminal should have "MatchArm" in their names, as opposed to just "Match".

View changes since the review

Comment thread src/expressions.rst Outdated
of the selected :t:`match arm`.

:dp:`fls_DT4N2rr6wpvZ`
A :dt:`match guard chain` is a set of conditions that should each evaluate to ``true`` in the case of :t:`[match guard expression]s` or have a positive match in the case of a :t:`[match guard let pattern]s` for the :t:`match arm` to be selected.
Copy link
Copy Markdown
Contributor

@kirtchev-adacore kirtchev-adacore Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the way this rule is worded, it appears that a single positive match is sufficient to evaluate the guard to true. How about

Suggested change
A :dt:`match guard chain` is a set of conditions that should each evaluate to ``true`` in the case of :t:`[match guard expression]s` or have a positive match in the case of a :t:`[match guard let pattern]s` for the :t:`match arm` to be selected.
A :dt:`match guard chain` is a set of conditions that must each evaluate to ``true`` in the case of :t:`[match guard expression]s`, or must each produce a positive match in the case of a :t:`[match guard let pattern]s` for the :t:`match arm` to be selected.

View changes since the review

Comment thread src/expressions.rst Outdated
A :dt:`match guard chain` is a set of conditions that should each evaluate to ``true`` in the case of :t:`[match guard expression]s` or have a positive match in the case of a :t:`[match guard let pattern]s` for the :t:`match arm` to be selected.

:dp:`fls_AAuyKfxLgJ43`
A :dt:`match guard let pattern` is a construct that evaluates if a :t:`match guard expression` matches the specified :t:`pattern`.
Copy link
Copy Markdown
Contributor

@kirtchev-adacore kirtchev-adacore Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A :dt:`match guard let pattern` is a construct that evaluates if a :t:`match guard expression` matches the specified :t:`pattern`.
A :dt:`match guard let pattern` is evaluated when its :t:`match guard expression` matches the specified :t:`pattern`.

View changes since the review

Comment thread src/expressions.rst Outdated
A :dt:`match guard let pattern` is a construct that evaluates if a :t:`match guard expression` matches the specified :t:`pattern`.

:dp:`fls_uCDQMkWx5OMS`
Each :t:`let binding` in a :t:`match guard let pattern` is in scope for the rest of the :t:`match arm guard` as well as the :t:`match arm body`.
Copy link
Copy Markdown
Contributor

@kirtchev-adacore kirtchev-adacore Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Each :t:`let binding` in a :t:`match guard let pattern` is in scope for the rest of the :t:`match arm guard` as well as the :t:`match arm body`.
Each :t:`let binding` introduced in a :t:`match guard let pattern` is :t:`in scope` for the rest of the :t:`match arm guard` as well as the :t:`match arm body`.

View changes since the review

Comment thread src/expressions.rst
Otherwise the :t:`match arm matcher` fails.

:dp:`fls_sbtx1l6n2tp2`
The :t:`evaluation` of a :t:`match arm guard` evaluates its :t:`operand`. A
Copy link
Copy Markdown
Contributor

@kirtchev-adacore kirtchev-adacore Apr 21, 2026

Choose a reason for hiding this comment

The 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.

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought it was redundant since fls_wkh5wztauwhu says the same thing

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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, fls_DT4N2rr6wpvZ still reads more like an unordered condition for when a guard succeeds. The Reference specifies this operationally: once the arm pattern matches, guard conditions are evaluated left-to-right; evaluation stops at the first false or failed let match; later conditions are not evaluated; and if the guard fails, matching resumes, including later | alternatives in the same arm.

Could we make those parts explicit in Dynamic Semantics, perhaps by replacing the removed fls_sbtx1l6n2tp2 with a chain-aware evaluation rule?

Support:

  • Reference expr.match.guard.behavior
  • Reference expr.match.guard.next
  • Reference expr.match.guard.chains.order
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs

tshepang and others added 2 commits April 21, 2026 16:35
Co-authored-by: Hristian Kirtchev <60669983+kirtchev-adacore@users.noreply.github.com>
@tshepang tshepang force-pushed the tshepang/document-if-let-guards branch from 7931d63 to 38075b5 Compare April 21, 2026 15:15
@tshepang tshepang force-pushed the tshepang/document-if-let-guards branch from 38075b5 to eba5309 Compare April 21, 2026 15:20
Comment thread src/expressions.rst
MatchArmGuardChain ::=
MatchArmGuardCondition ($$&&$$ MatchArmGuardCondition)*

MatchArmGuardCondition ::=
Copy link
Copy Markdown
Contributor

@PLeVasseur PLeVasseur Apr 22, 2026

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-bool rules are still in place.

For if let PAT = EXPR, EXPR is a scrutinee matched against PAT; EXPR itself is not required to have type bool. Only expression-valued guard conditions are bool-typed. As written, that seems to conflict with both the existing legality rule in src/expressions.rst (fls_bzhz5wjd90ii) and the stale inference rule in src/types-and-traits.rst (fls_st9onPgDrc8y), which still infer all match-arm-guard operands with expected type bool.

Could this be split the same way the Reference and the existing FLS already distinguish ordinary boolean conditions from if let / while let scrutinees? One possible shape would be a distinct guard-scrutinee rule with the pattern's type as its expected type.

Support:

  • Reference grammar MatchGuardCondition
  • Reference grammar MatchGuardScrutinee
  • Reference expr.match.guard.condition
  • FLS src/expressions.rst fls_bzhz5wjd90ii
  • FLS src/types-and-traits.rst fls_st9onPgDrc8y
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/type-inference.rs
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs

View changes since the review

Comment thread src/expressions.rst
:dp:`fls_AAuyKfxLgJ43`
A :dt:`match arm guard let pattern` is evaluated when its :t:`match arm guard expression` matches the specified :t:`pattern`.

:dp:`fls_uCDQMkWx5OMS`
Copy link
Copy Markdown
Contributor

@PLeVasseur PLeVasseur Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this stabilization is still incomplete outside src/expressions.rst.

The new local rule says bindings introduced by a guard let are in scope for the rest of the guard and the arm body, but the shared scope / destructor chapters still describe the older model: src/entities-and-resolution.rst fls_xbnki64un70v only covers arm-pattern bindings, and src/ownership-and-deconstruction.rst fls_lbsfhg42yiqy, fls_fnvr5w2wzxns, and fls_ptk6yibqyfzi still talk about a single guard operand rather than pattern-matching guard conditions with arm-scope bindings and temporaries.

Upstream needed matching updates in names/scopes and destructors for the same feature (rust-lang/reference#1957). Could this PR update those shared chapters too? Otherwise the new local rule here will not match the shared scope / drop-scope text.

Support:

  • Reference PR rust-lang/reference#1957
  • Reference names.scopes.pattern-bindings.match-guard-let
  • Reference expr.match.guard.chains.bindings
  • Reference destructors.scope.bindings.match-arm
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency.rs
  • rustc test tests/ui/drop/if-let-guards.rs

View changes since the review

Comment thread src/expressions.rst
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`
Copy link
Copy Markdown
Contributor

@PLeVasseur PLeVasseur Apr 22, 2026

Choose a reason for hiding this comment

The 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 (src/patterns.rst fls_pxvtqxke1enp), but the stabilized guard behavior is different for arm-pattern bindings: during guard evaluation they are observed through shared references, and only after the guard succeeds are values moved or copied from the scrutinee into the arm bindings. Without that exception, the spec still reads as though a by-value arm binding may move before guard evaluation.

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:

  • Reference expr.match.guard.shared-ref
  • Reference expr.match.guard.value
  • Reference expr.match.guard.no-mutation
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.rs
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let.rs
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs

View changes since the review

Comment thread src/expressions.rst
Otherwise the :t:`match arm matcher` fails.

:dp:`fls_sbtx1l6n2tp2`
The :t:`evaluation` of a :t:`match arm guard` evaluates its :t:`operand`. A
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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, fls_DT4N2rr6wpvZ still reads more like an unordered condition for when a guard succeeds. The Reference specifies this operationally: once the arm pattern matches, guard conditions are evaluated left-to-right; evaluation stops at the first false or failed let match; later conditions are not evaluated; and if the guard fails, matching resumes, including later | alternatives in the same arm.

Could we make those parts explicit in Dynamic Semantics, perhaps by replacing the removed fls_sbtx1l6n2tp2 with a chain-aware evaluation rule?

Support:

  • Reference expr.match.guard.behavior
  • Reference expr.match.guard.next
  • Reference expr.match.guard.chains.order
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
  • rustc test tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants