Skip to content

Commit d23f9da

Browse files
authored
Merge pull request rust-lang#957 from mark-i-m/or-patterns
Document or-patterns
2 parents 095b2d0 + 629e7df commit d23f9da

File tree

8 files changed

+73
-16
lines changed

8 files changed

+73
-16
lines changed

src/expressions/closure-expr.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
> &nbsp;&nbsp; _ClosureParam_ (`,` _ClosureParam_)<sup>\*</sup> `,`<sup>?</sup>
1111
>
1212
> _ClosureParam_ :\
13-
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> [_Pattern_]&nbsp;( `:` [_Type_] )<sup>?</sup>
13+
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> [_PatternNoTopAlt_]&nbsp;( `:` [_Type_] )<sup>?</sup>
1414
1515
A *closure expression*, also know as a lambda expression or a lambda, defines a [closure type] and evaluates to a value of that type.
1616
The syntax for a closure expression is an optional `move` keyword, then a pipe-symbol-delimited (`|`) comma-separated list of [patterns], called the *closure parameters* each optionally followed by a `:` and a type, then an optional `->` and type, called the *return type*, and then an expression, called the *closure body operand*.
@@ -59,7 +59,7 @@ Attributes on closure parameters follow the same rules and restrictions as [regu
5959
[_Expression_]: ../expressions.md
6060
[_BlockExpression_]: block-expr.md
6161
[_TypeNoBounds_]: ../types.md#type-expressions
62-
[_Pattern_]: ../patterns.md
62+
[_PatternNoTopAlt_]: ../patterns.md
6363
[_Type_]: ../types.md#type-expressions
6464
[`let` binding]: ../statements.md#let-statements
6565
[`Send`]: ../special-types-and-traits.md#send

src/expressions/if-expr.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ assert_eq!(y, "Bigger");
4141

4242
> **<sup>Syntax</sup>**\
4343
> _IfLetExpression_ :\
44-
> &nbsp;&nbsp; `if` `let` [_MatchArmPatterns_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
44+
> &nbsp;&nbsp; `if` `let` [_Pattern_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
4545
> [_BlockExpression_]\
4646
> &nbsp;&nbsp; (`else` (
4747
> [_BlockExpression_]
@@ -147,7 +147,7 @@ if let PAT = ( EXPR || EXPR ) { .. }
147147
[_BlockExpression_]: block-expr.md
148148
[_Expression_]: ../expressions.md
149149
[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
150-
[_MatchArmPatterns_]: match-expr.md
150+
[_Pattern_]: ../patterns.md
151151
[_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018
152152
[`match` expression]: match-expr.md
153153
[boolean type]: ../types/boolean.md

src/expressions/loop-expr.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ while i < 10 {
6262

6363
> **<sup>Syntax</sup>**\
6464
> [_PredicatePatternLoopExpression_] :\
65-
> &nbsp;&nbsp; `while` `let` [_MatchArmPatterns_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
65+
> &nbsp;&nbsp; `while` `let` [_Pattern_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
6666
> [_BlockExpression_]
6767
6868
A `while let` loop is semantically similar to a `while` loop but in place of a condition expression it expects the keyword `let` followed by a pattern, an `=`, a [scrutinee] expression and a block expression.
@@ -263,7 +263,6 @@ In the case a `loop` has an associated `break`, it is not considered diverging,
263263
[LIFETIME_OR_LABEL]: ../tokens.md#lifetimes-and-loop-labels
264264
[_BlockExpression_]: block-expr.md
265265
[_Expression_]: ../expressions.md
266-
[_MatchArmPatterns_]: match-expr.md
267266
[_Pattern_]: ../patterns.md
268267
[`match` expression]: match-expr.md
269268
[boolean]: ../types/boolean.md

src/expressions/match-expr.md

+1-4
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@
1515
> &nbsp;&nbsp; _MatchArm_ `=>` [_Expression_] `,`<sup>?</sup>
1616
>
1717
> _MatchArm_ :\
18-
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> _MatchArmPatterns_ _MatchArmGuard_<sup>?</sup>
19-
>
20-
> _MatchArmPatterns_ :\
21-
> &nbsp;&nbsp; `|`<sup>?</sup> [_Pattern_] ( `|` [_Pattern_] )<sup>\*</sup>
18+
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> [_Pattern_] _MatchArmGuard_<sup>?</sup>
2219
>
2320
> _MatchArmGuard_ :\
2421
> &nbsp;&nbsp; `if` [_Expression_]

src/items/functions.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
> )
3333
>
3434
> _FunctionParamPattern_ :\
35-
> &nbsp;&nbsp; [_Pattern_] `:` ( [_Type_] | `...` )
35+
> &nbsp;&nbsp; [_PatternNoTopAlt_] `:` ( [_Type_] | `...` )
3636
>
3737
> _FunctionReturnType_ :\
3838
> &nbsp;&nbsp; `->` [_Type_]
@@ -378,7 +378,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) {
378378
[_BlockExpression_]: ../expressions/block-expr.md
379379
[_GenericParams_]: generics.md
380380
[_Lifetime_]: ../trait-bounds.md
381-
[_Pattern_]: ../patterns.md
381+
[_PatternNoTopAlt_]: ../patterns.md
382382
[_Type_]: ../types.md#type-expressions
383383
[_WhereClause_]: generics.md#where-clauses
384384
[_OuterAttribute_]: ../attributes.md

src/macros-by-example.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ fragment specifiers are:
122122
* `block`: a [_BlockExpression_]
123123
* `stmt`: a [_Statement_] without the trailing semicolon (except for item
124124
statements that require semicolons)
125-
* `pat`: a [_Pattern_]
125+
* `pat`: a [_PatternNoTopAlt_]
126126
* `expr`: an [_Expression_]
127127
* `ty`: a [_Type_]
128128
* `ident`: an [IDENTIFIER_OR_KEYWORD]
@@ -488,7 +488,7 @@ For more detail, see the [formal specification].
488488
[_Item_]: items.md
489489
[_LiteralExpression_]: expressions/literal-expr.md
490490
[_MetaListIdents_]: attributes.md#meta-item-attribute-syntax
491-
[_Pattern_]: patterns.md
491+
[_PatternNoTopAlt_]: patterns.md
492492
[_Statement_]: statements.md
493493
[_TokenTree_]: macros.md#macro-invocation
494494
[_Token_]: tokens.md

src/patterns.md

+61
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
> **<sup>Syntax</sup>**\
44
> _Pattern_ :\
5+
> &nbsp;&nbsp; &nbsp;&nbsp; `|`<sup>?</sup> _PatternNoTopAlt_ ( `|` _PatternNoTopAlt_ )<sup>\*</sup>
6+
>
7+
> _PatternNoTopAlt_ :\
58
> &nbsp;&nbsp; &nbsp;&nbsp; _PatternWithoutRange_\
69
> &nbsp;&nbsp; | [_RangePattern_]
710
>
@@ -756,6 +759,63 @@ Path patterns are irrefutable when they refer to structs or an enum variant when
756759
has only one variant or a constant whose type is irrefutable. They are refutable when they
757760
refer to refutable constants or enum variants for enums with multiple variants.
758761

762+
## Or-patterns
763+
764+
_Or-patterns_ are patterns that match on one of two or more sub-patterns (e.g.
765+
`A | B | C`). They can nest arbitrarily. Syntactically, or-patterns are allowed
766+
in any of the places where other patterns are allowed (represented by the
767+
_Pattern_ production), with the exceptions of `let`-bindings and function and
768+
closure arguments (represented by the _PatternNoTopAlt_ production).
769+
770+
### Static semantics
771+
772+
1. Given a pattern `p | q` at some depth for some arbitrary patterns `p` and `q`,
773+
the pattern is considered ill-formed if:
774+
775+
+ the type inferred for `p` does not unify with the type inferred for `q`, or
776+
+ the same set of bindings are not introduced in `p` and `q`, or
777+
+ the type of any two bindings with the same name in `p` and `q` do not unify
778+
with respect to types or binding modes.
779+
780+
Unification of types is in all instances aforementioned exact and
781+
implicit [type coercions] do not apply.
782+
783+
2. When type checking an expression `match e_s { a_1 => e_1, ... a_n => e_n }`,
784+
for each match arm `a_i` which contains a pattern of form `p_i | q_i`,
785+
the pattern `p_i | q_i` is considered ill formed if,
786+
at the depth `d` where it exists the fragment of `e_s` at depth `d`,
787+
the type of the expression fragment does not unify with `p_i | q_i`.
788+
789+
3. With respect to exhaustiveness checking, a pattern `p | q` is
790+
considered to cover `p` as well as `q`. For some constructor `c(x, ..)`
791+
the distributive law applies such that `c(p | q, ..rest)` covers the same
792+
set of value as `c(p, ..rest) | c(q, ..rest)` does. This can be applied
793+
recursively until there are no more nested patterns of form `p | q` other
794+
than those that exist at the top level.
795+
796+
Note that by *"constructor"* we do not refer to tuple struct patterns,
797+
but rather we refer to a pattern for any product type.
798+
This includes enum variants, tuple structs, structs with named fields,
799+
arrays, tuples, and slices.
800+
801+
### Dynamic semantics
802+
803+
1. The dynamic semantics of pattern matching a scrutinee expression `e_s`
804+
against a pattern `c(p | q, ..rest)` at depth `d` where `c` is some constructor,
805+
`p` and `q` are arbitrary patterns, and `rest` is optionally any remaining
806+
potential factors in `c`, is defined as being the same as that of
807+
`c(p, ..rest) | c(q, ..rest)`.
808+
809+
### Precedence with other undelimited patterns
810+
811+
As shown elsewhere in this chapter, there are several types of patterns that
812+
are syntactically undelimited, including identifier patterns, reference
813+
patterns, and or-patterns. Or-patterns always have the lowest-precedence. This
814+
allows us to reserve syntactic space for a possible future type ascription
815+
feature and also to reduce ambiguity. For example, `x @ A(..) | B(..)` will
816+
result in an error that `x` is not bound in all patterns, `&A(x) | B(x)` will
817+
result in a type mismatch between `x` in the different subpatterns.
818+
759819
[_GroupedPattern_]: #grouped-patterns
760820
[_IdentifierPattern_]: #identifier-patterns
761821
[_LiteralPattern_]: #literal-patterns
@@ -782,3 +842,4 @@ refer to refutable constants or enum variants for enums with multiple variants.
782842
[structs]: items/structs.md
783843
[tuples]: types/tuple.md
784844
[scrutinee]: glossary.md#scrutinee
845+
[type coercions]: type-coercions.md

src/statements.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fn outer() {
5353

5454
> **<sup>Syntax</sup>**\
5555
> _LetStatement_ :\
56-
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> `let` [_Pattern_]
56+
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> `let` [_PatternNoTopAlt_]
5757
> ( `:` [_Type_] )<sup>?</sup> (`=` [_Expression_] )<sup>?</sup> `;`
5858
5959
A *`let` statement* introduces a new set of [variables], given by an
@@ -133,5 +133,5 @@ statement are [`cfg`], and [the lint check attributes].
133133
[_LetStatement_]: #let-statements
134134
[_MacroInvocationSemi_]: macros.md#macro-invocation
135135
[_OuterAttribute_]: attributes.md
136-
[_Pattern_]: patterns.md
136+
[_PatternNoTopAlt_]: patterns.md
137137
[_Type_]: types.md

0 commit comments

Comments
 (0)