Skip to content

Commit f7b0d87

Browse files
Merge pull request #709 from PLeVasseur/if-let-guards-1-95
Document if let guards
2 parents 3c73fb2 + f25e095 commit f7b0d87

7 files changed

Lines changed: 414 additions & 34 deletions

src/changelog.rst

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,109 @@ Language changes in Rust 1.95.0
2323
-------------------------------
2424

2525
- `Stabilize if let guards on match arms <https://github.com/rust-lang/rust/pull/141295>`_
26+
27+
Changed syntax: :s:`MatchArmGuard`
28+
29+
The FLS models the Rust 2021 syntax accepted by stable :t:`rustc` 1.95.0.
30+
It does not add the Rust Reference's attribute position before a guard
31+
``let`` pattern because attributes remain unstable in that position.
32+
33+
New syntax:
34+
35+
- :s:`MatchArmGuardChain`
36+
- :s:`MatchArmGuardCondition`
37+
- :s:`MatchArmGuardConditionOperand`
38+
- :s:`MatchArmGuardConditions`
39+
- :s:`MatchArmGuardLetPattern`
40+
- :s:`MatchArmGuardOperand`
41+
- :s:`MatchArmGuardScrutinee`
42+
43+
New glossary entries:
44+
45+
- :t:`match arm guard chain`
46+
- :t:`match arm guard condition`
47+
- :t:`match arm guard condition operand`
48+
- :t:`match arm guard let pattern`
49+
- :t:`match arm guard operand`
50+
- :t:`match arm guard scrutinee`
51+
52+
Updated glossary entries:
53+
54+
- :t:`let binding`
55+
56+
Changed existing paragraphs:
57+
58+
- :p:`fls_72JHo343O7jp`
59+
- :p:`fls_6bwTtGKb7ba7`
60+
- :p:`fls_bzhz5wjd90ii`
61+
- :p:`fls_st9onPgDrc8y`
62+
- :p:`fls_4dv7x9nh2h4e`
63+
- :p:`fls_sbtx1l6n2tp2`
64+
- :p:`fls_e02um1gb89d0`
65+
- :p:`fls_lbsfhg42yiqy`
66+
- :p:`fls_fnvr5w2wzxns`
67+
- :p:`fls_ptk6yibqyfzi`
68+
- :p:`fls_a5tmilqxdb6f`
69+
70+
New paragraphs:
71+
72+
- :p:`fls_3TGpt9OGydQi`
73+
- :p:`fls_7OkU5RVrAyev`
74+
- :p:`fls_Uv7QsP2nKcDx`
75+
- :p:`fls_DT4N2rr6wpvZ`
76+
- :p:`fls_gNQBzI92IAir`
77+
- :p:`fls_Er5TmL9bXwVq`
78+
- :p:`fls_AAuyKfxLgJ43`
79+
- :p:`fls_Yq4NhC8sRpJm`
80+
- :p:`fls_kM6dZv3PaNqT`
81+
- :p:`fls_Lc8EwS5rYpBn`
82+
- :p:`fls_Nc6JvS9rFaLm`
83+
- :p:`fls_Qr3TcH8vNpKs`
84+
- :p:`fls_Lm5WqZ2dJvYp`
85+
- :p:`fls_Bx8KsV4nQdRt`
86+
- :p:`fls_Mv2YpG7sLcHw`
87+
- :p:`fls_Xd4LqN9vTrPm`
88+
- :p:`fls_Hw6CkR3mVzQn`
89+
- :p:`fls_gfD9XwVj5hab`
90+
- :p:`fls_Zm9VxF5pQwLd`
91+
- :p:`fls_Dp8aJr2LqYwS`
92+
- :p:`fls_Wm4QvN7xTcRb`
93+
- :p:`fls_Ks9FdL3pVxQa`
94+
- :p:`fls_Rt5XcG8nMbPw`
95+
- :p:`fls_Yh2NqT6vLsCk`
96+
- :p:`fls_Cw2RsH7pVnQx`
97+
- :p:`fls_Pb7MzD4wQkXe`
98+
- :p:`fls_Fj8QpM3dLsVt`
99+
- :p:`fls_Qf4VnH8sMxRa`
100+
- :p:`fls_Kz7NvR2xYpWm`
101+
- :p:`fls_Zc6TbK2wLpNd`
102+
- :p:`fls_Bd9TmL4qVcNs`
103+
- :p:`fls_Rp5HxK8wJqYd`
104+
- :p:`fls_Vr9MqJ5xNsYd`
105+
- :p:`fls_Nt6QmC3sLpXz`
106+
- :p:`fls_Av4JyT9nMkRp`
107+
- :p:`fls_Gc5RpT8nYvQm`
108+
- :p:`fls_Nw2KxL7qVmRs`
109+
- :p:`fls_Rh9TsD4vQpLm`
110+
- :p:`fls_8Vrz9SNfjSh7`
111+
- :p:`fls_X4y3QltM208J`
112+
- :p:`fls_vQ3tHg9XmDkF`
113+
- :p:`fls_Td7McP9rQxVn`
114+
- :p:`fls_Jp4NsK8vYqRc`
115+
- :p:`fls_Vq8LdN2xWmTs`
116+
- :p:`fls_Et6PqW9nRcVm`
117+
- :p:`fls_7yybrl2J37Et`
118+
119+
Removed paragraphs:
120+
121+
- :p:`fls_k7kliy101m0f`
122+
- :p:`fls_k68zkb6jv0vz`
123+
- :p:`fls_gbb6wbmher5z`
124+
- :p:`fls_jl4av757yx8j`
125+
- :p:`fls_wkh5wztauwhu`
126+
- :p:`fls_f5f0x8jstp1g`
127+
- :p:`fls_yk8l9zjh7i0d`
128+
26129
- `irrefutable_let_patterns lint no longer lints on let chains <https://github.com/rust-lang/rust/pull/146832>`_
27130

28131
- Lints are outside the scope of the FLS.

src/entities-and-resolution.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,11 @@ related :t:`let statement` appears.
496496
The :t:`binding` of a :t:`match arm` is :t:`in scope` within its related
497497
:t:`[expression]s` and related :t:`match arm guard`.
498498

499+
:dp:`fls_Td7McP9rQxVn`
500+
Each :t:`let binding` introduced by a :t:`match arm guard let pattern` is
501+
:t:`in scope` within the following :t:`[match arm guard condition]s` of the
502+
same :t:`match arm guard` and within the related :t:`match arm body`.
503+
499504
:dp:`fls_eBacCVlDaKYK`
500505
A :t:`binding` declared outside of a :t:`const block expression` is not :t:`in
501506
scope` within such a :t:`const block expression`.

src/expressions.rst

Lines changed: 200 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4645,7 +4645,38 @@ Match Expressions
46454645
OuterAttributeOrDoc* Pattern MatchArmGuard?
46464646

46474647
MatchArmGuard ::=
4648-
$$if$$ Operand
4648+
$$if$$ MatchArmGuardConditions
4649+
4650+
MatchArmGuardConditions ::=
4651+
MatchArmGuardChain
4652+
| MatchArmGuardOperand
4653+
4654+
MatchArmGuardChain ::=
4655+
MatchArmGuardCondition ($$&&$$ MatchArmGuardCondition)*
4656+
4657+
MatchArmGuardCondition ::=
4658+
MatchArmGuardConditionOperand
4659+
| MatchArmGuardLetPattern
4660+
4661+
MatchArmGuardLetPattern ::=
4662+
$$let$$ Pattern $$=$$ MatchArmGuardScrutinee
4663+
4664+
MatchArmGuardOperand ::=
4665+
Operand
4666+
4667+
:dp:`fls_3TGpt9OGydQi`
4668+
A :ds:`MatchArmGuardConditionOperand` is any expression in category
4669+
:s:`Expression`, except expressions in categories :s:`AssignmentExpression`,
4670+
:s:`CompoundAssignmentExpression`, :s:`LazyBooleanExpression`,
4671+
:s:`RangeFromExpression`, :s:`RangeFromToExpression`, and
4672+
:s:`RangeInclusiveExpression`.
4673+
4674+
:dp:`fls_7OkU5RVrAyev`
4675+
A :ds:`MatchArmGuardScrutinee` is any expression in category
4676+
:s:`Expression`, except expressions in categories :s:`AssignmentExpression`,
4677+
:s:`CompoundAssignmentExpression`, :s:`LazyBooleanExpression`,
4678+
:s:`RangeFromExpression`, :s:`RangeFromToExpression`, and
4679+
:s:`RangeInclusiveExpression`.
46494680

46504681
.. rubric:: Legality Rules
46514682

@@ -4679,6 +4710,31 @@ A :t:`match arm body` is the :t:`operand` of a :t:`match arm`.
46794710
A :t:`match arm guard` is a :t:`construct` that provides additional filtering to
46804711
a :t:`match arm matcher`.
46814712

4713+
:dp:`fls_Uv7QsP2nKcDx`
4714+
A :t:`match arm guard operand` is the :t:`operand` of a :t:`match arm guard`
4715+
that does not have a :t:`match arm guard chain`.
4716+
4717+
:dp:`fls_DT4N2rr6wpvZ`
4718+
A :t:`match arm guard chain` is a sequence of one or more
4719+
:t:`[match arm guard condition]s`, separated by ``&&``.
4720+
4721+
:dp:`fls_gNQBzI92IAir`
4722+
A :t:`match arm guard` that contains a :t:`match arm guard let pattern` has a
4723+
:t:`match arm guard chain`; otherwise it has a :t:`match arm guard operand`.
4724+
4725+
:dp:`fls_Er5TmL9bXwVq`
4726+
A :t:`match arm guard condition operand` is a :t:`match arm guard condition`
4727+
that consists of an :t:`expression`.
4728+
4729+
:dp:`fls_AAuyKfxLgJ43`
4730+
A :t:`match arm guard let pattern` is a :t:`match arm guard condition` that
4731+
consists of a :t:`pattern` and a :t:`match arm guard scrutinee`.
4732+
4733+
:dp:`fls_Yq4NhC8sRpJm`
4734+
A :t:`match arm guard scrutinee` is the :t:`expression` of a
4735+
:t:`match arm guard let pattern` whose :t:`value` is matched against the
4736+
:t:`pattern` of that :t:`match arm guard let pattern`.
4737+
46824738
:dp:`fls_RPMOAaZ6lflI`
46834739
:t:`[Binding]s` introduced in the :t:`pattern` of a :t:`match arm matcher` are
46844740
:t:`immutable` in the :t:`match arm guard`.
@@ -4688,9 +4744,17 @@ The :t:`type` of the :t:`subject expression` and the :t:`[type]s` of all
46884744
:t:`[pattern]s` of all :t:`[match arm matcher]s` shall be :t:`unifiable`.
46894745

46904746
:dp:`fls_bzhz5wjd90ii`
4691-
The :t:`type` of the :t:`operand` of a :t:`match arm guard` shall be :t:`type`
4747+
The :t:`type` of a :t:`match arm guard operand` shall be :t:`type` :c:`bool`.
4748+
4749+
:dp:`fls_kM6dZv3PaNqT`
4750+
The :t:`type` of a :t:`match arm guard condition operand` shall be :t:`type`
46924751
:c:`bool`.
46934752

4753+
:dp:`fls_Lc8EwS5rYpBn`
4754+
The :t:`expected type` of the :t:`pattern` of a
4755+
:t:`match arm guard let pattern` is the :t:`type` of its
4756+
:t:`match arm guard scrutinee`.
4757+
46944758
:dp:`fls_17ag0wzdbxv6`
46954759
The :t:`[type]s` of all :t:`match arm bodies <match arm body>` shall be
46964760
:t:`unifiable`.
@@ -4708,8 +4772,9 @@ A :t:`match arm` is selected when its :t:`pattern` matches the
47084772
:t:`Match arm` selection happens in declarative order.
47094773

47104774
:dp:`fls_e02um1gb89d0`
4711-
The :t:`[pattern]s` of all :t:`[match arm]s` taken together shall exhaustively
4712-
match the :t:`[subject expression]'s` :t:`type`.
4775+
The :t:`[pattern]s` of all :t:`[match arm]s` without a
4776+
:t:`match arm guard` taken together shall exhaustively match the
4777+
:t:`[subject expression]'s` :t:`type`.
47134778

47144779
:dp:`fls_4sh2yrslszvb`
47154780
The :t:`value` of a :t:`match expression` is the :t:`value` of the :t:`operand`
@@ -4742,35 +4807,133 @@ The :t:`evaluation` of a :t:`match expression` proceeds as follows:
47424807
Otherwise control proceeds with the :t:`evaluation` of the next
47434808
:t:`match arm`.
47444809

4810+
:dp:`fls_Nc6JvS9rFaLm`
4811+
When the :t:`pattern` of a :t:`match arm matcher` is an :t:`or-pattern`, each
4812+
:t:`pattern-without-alternation` of the :t:`or-pattern` is considered in source
4813+
order during :t:`evaluation` of the :t:`match arm matcher`. Otherwise, the
4814+
:t:`pattern` itself is considered.
4815+
47454816
:dp:`fls_4dv7x9nh2h4e`
47464817
The :t:`evaluation` of a :t:`match arm matcher` proceeds as follows:
47474818

4748-
#. :dp:`fls_k7kliy101m0f`
4749-
The :t:`pattern` of the :t:`match arm matcher` is evaluated.
4819+
#. :dp:`fls_Qr3TcH8vNpKs`
4820+
Each :t:`pattern` determined by :p:`fls_Nc6JvS9rFaLm` is considered in
4821+
source order as follows:
4822+
4823+
#. :dp:`fls_Lm5WqZ2dJvYp`
4824+
If :t:`pattern matching` with the :t:`pattern` and the :t:`value` of the
4825+
:t:`subject expression` fails, then evaluation continues with the next
4826+
:t:`pattern`, if any.
47504827

4751-
#. :dp:`fls_k68zkb6jv0vz`
4752-
If the :t:`pattern` succeeds, then
4828+
#. :dp:`fls_Bx8KsV4nQdRt`
4829+
If :t:`pattern matching` with the :t:`pattern` succeeds, then:
47534830

4754-
#. :dp:`fls_gbb6wbmher5z`
4755-
If the :t:`match arm matcher` has a :t:`match arm guard`, then
4831+
#. :dp:`fls_Mv2YpG7sLcHw`
4832+
If the :t:`match arm matcher` has no :t:`match arm guard`, then the
4833+
:t:`match arm matcher` succeeds and its :t:`evaluation` is complete.
47564834

4757-
#. :dp:`fls_jl4av757yx8j`
4758-
The :t:`match arm guard` is evaluated.
4835+
#. :dp:`fls_Xd4LqN9vTrPm`
4836+
If the :t:`match arm matcher` has a :t:`match arm guard`, then the
4837+
:t:`match arm guard` is evaluated.
47594838

4760-
#. :dp:`fls_wkh5wztauwhu`
4839+
#. :dp:`fls_Hw6CkR3mVzQn`
47614840
If the :t:`match arm guard` evaluates to ``true``, then the
4762-
:t:`match arm matcher` succeeds.
4841+
:t:`match arm matcher` succeeds and its :t:`evaluation` is complete.
47634842

4764-
#. :dp:`fls_f5f0x8jstp1g`
4765-
Otherwise the :t:`match arm matcher` fails.
4843+
#. :dp:`fls_gfD9XwVj5hab`
4844+
If the :t:`match arm guard` evaluates to ``false``, then the
4845+
:t:`drop scope` of the related :t:`match arm` is left, and evaluation
4846+
continues with the next :t:`pattern`, including subsequent
4847+
:t:`[pattern-without-alternation]s` of the same :t:`or-pattern`.
47664848

4767-
#. :dp:`fls_yk8l9zjh7i0d`
4768-
Otherwise the :t:`match arm matcher` fails.
4849+
#. :dp:`fls_Zm9VxF5pQwLd`
4850+
If no considered :t:`pattern` causes the :t:`match arm matcher` to succeed,
4851+
then the :t:`match arm matcher` fails.
47694852

47704853
:dp:`fls_sbtx1l6n2tp2`
4771-
The :t:`evaluation` of a :t:`match arm guard` evaluates its :t:`operand`. A
4772-
:t:`match arm guard` evaluates to ``true`` when its :t:`operand` evaluates to
4773-
``true``, otherwise it evaluates to ``false``.
4854+
The :t:`evaluation` of a :t:`match arm guard` proceeds as follows:
4855+
4856+
#. :dp:`fls_Dp8aJr2LqYwS`
4857+
If the :t:`match arm guard` has a :t:`match arm guard operand`, then:
4858+
4859+
#. :dp:`fls_Wm4QvN7xTcRb`
4860+
The :t:`match arm guard operand` is evaluated.
4861+
4862+
#. :dp:`fls_Ks9FdL3pVxQa`
4863+
If the :t:`match arm guard operand` evaluates to ``false``, then the
4864+
:t:`match arm guard` evaluates to ``false`` and its :t:`evaluation` is
4865+
complete.
4866+
4867+
#. :dp:`fls_Rt5XcG8nMbPw`
4868+
If the :t:`match arm guard operand` evaluates to ``true``, then the
4869+
:t:`match arm guard` evaluates to ``true`` and its :t:`evaluation` is
4870+
complete.
4871+
4872+
#. :dp:`fls_Yh2NqT6vLsCk`
4873+
Otherwise, the :t:`match arm guard` has a :t:`match arm guard chain`, and:
4874+
4875+
#. :dp:`fls_Cw2RsH7pVnQx`
4876+
Each :t:`match arm guard condition` of the chain is evaluated in source
4877+
order as follows:
4878+
4879+
#. :dp:`fls_Pb7MzD4wQkXe`
4880+
If the :t:`match arm guard condition` is a
4881+
:t:`match arm guard condition operand`, then:
4882+
4883+
#. :dp:`fls_Fj8QpM3dLsVt`
4884+
The :t:`match arm guard condition operand` is evaluated.
4885+
4886+
#. :dp:`fls_Qf4VnH8sMxRa`
4887+
If the :t:`match arm guard condition operand` evaluates to
4888+
``false``, then the :t:`match arm guard` evaluates to ``false`` and
4889+
no subsequent :t:`[match arm guard condition]s` are evaluated.
4890+
4891+
#. :dp:`fls_Kz7NvR2xYpWm`
4892+
If the :t:`match arm guard condition operand` evaluates to
4893+
``true``, then evaluation continues with the next
4894+
:t:`match arm guard condition`, if any.
4895+
4896+
#. :dp:`fls_Zc6TbK2wLpNd`
4897+
If the :t:`match arm guard condition` is a
4898+
:t:`match arm guard let pattern`, then:
4899+
4900+
#. :dp:`fls_Bd9TmL4qVcNs`
4901+
The :t:`match arm guard scrutinee` is evaluated.
4902+
4903+
#. :dp:`fls_Rp5HxK8wJqYd`
4904+
:t:`Pattern matching` is performed with the :t:`pattern` of the
4905+
:t:`match arm guard let pattern` against the resulting :t:`value`.
4906+
4907+
#. :dp:`fls_Vr9MqJ5xNsYd`
4908+
If the :t:`pattern matching` fails, then the
4909+
:t:`match arm guard` evaluates to ``false`` and no subsequent
4910+
:t:`[match arm guard condition]s` are evaluated.
4911+
4912+
#. :dp:`fls_Nt6QmC3sLpXz`
4913+
If the :t:`pattern matching` succeeds, then any :t:`[binding]s`
4914+
introduced by the :t:`pattern` are bound to the matched
4915+
:t:`[value]s` as described in :p:`fls_t34oqarwcusu`, and evaluation
4916+
continues with the next :t:`match arm guard condition`, if any.
4917+
4918+
#. :dp:`fls_Av4JyT9nMkRp`
4919+
If every :t:`match arm guard condition` of the chain has been evaluated
4920+
without the :t:`match arm guard` evaluating to ``false``, then the
4921+
:t:`match arm guard` evaluates to ``true``.
4922+
4923+
:dp:`fls_Gc5RpT8nYvQm`
4924+
During the :t:`evaluation` of a :t:`match arm guard`, each :t:`binding`
4925+
introduced by the :t:`pattern` of the related :t:`match arm matcher` is
4926+
accessed through a :t:`shared reference` to the matched part of the
4927+
:t:`subject expression`'s :t:`value`.
4928+
4929+
:dp:`fls_Nw2KxL7qVmRs`
4930+
If the :t:`binding mode` of such a :t:`binding` is :t:`by value`, then the copy
4931+
or move described by :p:`fls_pxvtqxke1enp` is performed only if the related
4932+
:t:`match arm guard` evaluates to ``true``.
4933+
4934+
:dp:`fls_Rh9TsD4vQpLm`
4935+
If the related :t:`match arm guard` evaluates to ``false``, then no copy or
4936+
move into such a :t:`binding` is performed.
47744937

47754938
.. rubric:: Examples
47764939

@@ -4785,6 +4948,22 @@ The :t:`evaluation` of a :t:`match arm guard` evaluates its :t:`operand`. A
47854948
}
47864949
}
47874950
4951+
:dp:`fls_8Vrz9SNfjSh7`
4952+
A match arm guard chain consisting of a match arm guard let pattern followed by
4953+
a match arm guard condition operand.
4954+
4955+
.. code-block:: rust
4956+
4957+
fn categorize(input: Option<&str>) -> &'static str {
4958+
match input {
4959+
Some(text)
4960+
if let Ok(number) = text.parse::<i32>()
4961+
&& number > 9 => "big number",
4962+
Some(_) => "other text",
4963+
None => "no text"
4964+
}
4965+
}
4966+
47884967
.. _fls_8l74abhlxzdl:
47894968

47904969
Return Expressions

0 commit comments

Comments
 (0)