diff --git a/src/expressions/closure-expr.md b/src/expressions/closure-expr.md index 217a6a19c..6fbbd4c4c 100644 --- a/src/expressions/closure-expr.md +++ b/src/expressions/closure-expr.md @@ -10,7 +10,7 @@ >    _ClosureParam_ (`,` _ClosureParam_)\* `,`? > > _ClosureParam_ :\ ->    [_OuterAttribute_]\* [_Pattern_] ( `:` [_Type_] )? +>    [_OuterAttribute_]\* [_PatternNoTopAlt_] ( `:` [_Type_] )? A _closure expression_, also know as a lambda expression or a lambda, defines a closure and denotes it as a value, in a single expression. A closure expression @@ -80,7 +80,7 @@ Attributes on closure parameters follow the same rules and restrictions as [_Expression_]: ../expressions.md [_BlockExpression_]: block-expr.md [_TypeNoBounds_]: ../types.md#type-expressions -[_Pattern_]: ../patterns.md +[_PatternNoTopAlt_]: ../patterns.md [_Type_]: ../types.md#type-expressions [`let` binding]: ../statements.md#let-statements [_OuterAttribute_]: ../attributes.md diff --git a/src/expressions/if-expr.md b/src/expressions/if-expr.md index 5d04bb5c7..a00c823a8 100644 --- a/src/expressions/if-expr.md +++ b/src/expressions/if-expr.md @@ -44,7 +44,7 @@ assert_eq!(y, "Bigger"); > **Syntax**\ > _IfLetExpression_ :\ ->    `if` `let` [_MatchArmPatterns_] `=` [_Expression_]_except struct or lazy boolean operator expression_ +>    `if` `let` [_Pattern_] `=` [_Expression_]_except struct or lazy boolean operator expression_ > [_BlockExpression_]\ >    (`else` ( > [_BlockExpression_] @@ -155,7 +155,7 @@ if let PAT = ( EXPR || EXPR ) { .. } [_BlockExpression_]: block-expr.md [_Expression_]: ../expressions.md [_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators -[_MatchArmPatterns_]: match-expr.md +[_Pattern_]: ../patterns.md [_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018 [`match` expression]: match-expr.md [scrutinee]: ../glossary.md#scrutinee diff --git a/src/expressions/loop-expr.md b/src/expressions/loop-expr.md index 9ddefa12f..40cb90a9d 100644 --- a/src/expressions/loop-expr.md +++ b/src/expressions/loop-expr.md @@ -67,7 +67,7 @@ while i < 10 { > **Syntax**\ > [_PredicatePatternLoopExpression_] :\ ->    `while` `let` [_MatchArmPatterns_] `=` [_Expression_]_except struct or lazy boolean operator expression_ +>    `while` `let` [_Pattern_] `=` [_Expression_]_except struct or lazy boolean operator expression_ > [_BlockExpression_] A `while let` loop is semantically similar to a `while` loop but in place of a @@ -291,7 +291,6 @@ expression `()`. [LIFETIME_OR_LABEL]: ../tokens.md#lifetimes-and-loop-labels [_BlockExpression_]: block-expr.md [_Expression_]: ../expressions.md -[_MatchArmPatterns_]: match-expr.md [_Pattern_]: ../patterns.md [`match` expression]: match-expr.md [scrutinee]: ../glossary.md#scrutinee diff --git a/src/expressions/match-expr.md b/src/expressions/match-expr.md index 6d9f3f2af..9716d8bda 100644 --- a/src/expressions/match-expr.md +++ b/src/expressions/match-expr.md @@ -15,10 +15,7 @@ >    _MatchArm_ `=>` [_Expression_] `,`? > > _MatchArm_ :\ ->    [_OuterAttribute_]\* _MatchArmPatterns_ _MatchArmGuard_? -> -> _MatchArmPatterns_ :\ ->    `|`? [_Pattern_] ( `|` [_Pattern_] )\* +>    [_OuterAttribute_]\* [_Pattern_] _MatchArmGuard_? > > _MatchArmGuard_ :\ >    `if` [_Expression_] diff --git a/src/items/functions.md b/src/items/functions.md index b6bd15904..9d6ebcde3 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -32,7 +32,7 @@ > ) > > _FunctionParamPattern_ :\ ->    [_Pattern_] `:` ( [_Type_] | `...` ) +>    [_PatternNoTopAlt_] `:` ( [_Type_] | `...` ) > > _FunctionReturnType_ :\ >    `->` [_Type_] @@ -378,7 +378,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [_BlockExpression_]: ../expressions/block-expr.md [_GenericParams_]: generics.md [_Lifetime_]: ../trait-bounds.md -[_Pattern_]: ../patterns.md +[_PatternNoTopAlt_]: ../patterns.md [_Type_]: ../types.md#type-expressions [_WhereClause_]: generics.md#where-clauses [_OuterAttribute_]: ../attributes.md diff --git a/src/macros-by-example.md b/src/macros-by-example.md index e97455d0b..172b9863e 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -122,7 +122,7 @@ fragment specifiers are: * `block`: a [_BlockExpression_] * `stmt`: a [_Statement_] without the trailing semicolon (except for item statements that require semicolons) - * `pat`: a [_Pattern_] + * `pat`: a [_PatternNoTopAlt_] * `expr`: an [_Expression_] * `ty`: a [_Type_] * `ident`: an [IDENTIFIER_OR_KEYWORD] @@ -488,7 +488,7 @@ For more detail, see the [formal specification]. [_Item_]: items.md [_LiteralExpression_]: expressions/literal-expr.md [_MetaListIdents_]: attributes.md#meta-item-attribute-syntax -[_Pattern_]: patterns.md +[_PatternNoTopAlt_]: patterns.md [_Statement_]: statements.md [_TokenTree_]: macros.md#macro-invocation [_Token_]: tokens.md diff --git a/src/patterns.md b/src/patterns.md index 121b825d1..7676d5255 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -2,6 +2,9 @@ > **Syntax**\ > _Pattern_ :\ +>       `|`? _PatternNoTopAlt_ ( `|` _PatternNoTopAlt_ )\* +> +> _PatternNoTopAlt_ :\ >       _PatternWithoutRange_\ >    | [_RangePattern_] > @@ -756,6 +759,63 @@ Path patterns are irrefutable when they refer to structs or an enum variant when has only one variant or a constant whose type is irrefutable. They are refutable when they refer to refutable constants or enum variants for enums with multiple variants. +## Or-patterns + +_Or-patterns_ are patterns that match on one of two or more sub-patterns (e.g. +`A | B | C`). They can nest arbitrarily. Syntactically, or-patterns are allowed +in any of the places where other patterns are allowed (represented by the +_Pattern_ production), with the exceptions of `let`-bindings and function and +closure arguments (represented by the _PatternNoTopAlt_ production). + +### Static semantics + +1. Given a pattern `p | q` at some depth for some arbitrary patterns `p` and `q`, + the pattern is considered ill-formed if: + + + the type inferred for `p` does not unify with the type inferred for `q`, or + + the same set of bindings are not introduced in `p` and `q`, or + + the type of any two bindings with the same name in `p` and `q` do not unify + with respect to types or binding modes. + + Unification of types is in all instances aforementioned exact and + implicit [type coercions] do not apply. + +2. When type checking an expression `match e_s { a_1 => e_1, ... a_n => e_n }`, + for each match arm `a_i` which contains a pattern of form `p_i | q_i`, + the pattern `p_i | q_i` is considered ill formed if, + at the depth `d` where it exists the fragment of `e_s` at depth `d`, + the type of the expression fragment does not unify with `p_i | q_i`. + +3. With respect to exhaustiveness checking, a pattern `p | q` is + considered to cover `p` as well as `q`. For some constructor `c(x, ..)` + the distributive law applies such that `c(p | q, ..rest)` covers the same + set of value as `c(p, ..rest) | c(q, ..rest)` does. This can be applied + recursively until there are no more nested patterns of form `p | q` other + than those that exist at the top level. + + Note that by *"constructor"* we do not refer to tuple struct patterns, + but rather we refer to a pattern for any product type. + This includes enum variants, tuple structs, structs with named fields, + arrays, tuples, and slices. + +### Dynamic semantics + +1. The dynamic semantics of pattern matching a scrutinee expression `e_s` + against a pattern `c(p | q, ..rest)` at depth `d` where `c` is some constructor, + `p` and `q` are arbitrary patterns, and `rest` is optionally any remaining + potential factors in `c`, is defined as being the same as that of + `c(p, ..rest) | c(q, ..rest)`. + +### Precedence with other undelimited patterns + +As shown elsewhere in this chapter, there are several types of patterns that +are syntactically undelimited, including identifier patterns, reference +patterns, and or-patterns. Or-patterns always have the lowest-precedence. This +allows us to reserve syntactic space for a possible future type ascription +feature and also to reduce ambiguity. For example, `x @ A(..) | B(..)` will +result in an error that `x` is not bound in all patterns, `&A(x) | B(x)` will +result in a type mismatch between `x` in the different subpatterns. + [_GroupedPattern_]: #grouped-patterns [_IdentifierPattern_]: #identifier-patterns [_LiteralPattern_]: #literal-patterns @@ -782,3 +842,4 @@ refer to refutable constants or enum variants for enums with multiple variants. [structs]: items/structs.md [tuples]: types/tuple.md [scrutinee]: glossary.md#scrutinee +[type coercions]: type-coercions.md diff --git a/src/statements.md b/src/statements.md index 5d8e0e95d..06cd9513e 100644 --- a/src/statements.md +++ b/src/statements.md @@ -53,7 +53,7 @@ fn outer() { > **Syntax**\ > _LetStatement_ :\ ->    [_OuterAttribute_]\* `let` [_Pattern_] +>    [_OuterAttribute_]\* `let` [_PatternNoTopAlt_] > ( `:` [_Type_] )? (`=` [_Expression_] )? `;` A *`let` statement* introduces a new set of [variables], given by an @@ -133,5 +133,5 @@ statement are [`cfg`], and [the lint check attributes]. [_LetStatement_]: #let-statements [_MacroInvocationSemi_]: macros.md#macro-invocation [_OuterAttribute_]: attributes.md -[_Pattern_]: patterns.md +[_PatternNoTopAlt_]: patterns.md [_Type_]: types.md