From c0343a7cb835599e937ae815bcfde8b6feb96215 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 14 Aug 2020 18:54:49 -0700 Subject: [PATCH 1/3] Add rest patterns. --- src/patterns.md | 75 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/src/patterns.md b/src/patterns.md index 88940641c..bdfbd9716 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -5,6 +5,7 @@ >       [_LiteralPattern_]\ >    | [_IdentifierPattern_]\ >    | [_WildcardPattern_]\ +>    | [_RestPattern_]\ >    | [_RangePattern_]\ >    | [_ReferencePattern_]\ >    | [_StructPattern_]\ @@ -317,6 +318,59 @@ if let Some(_) = x {} The wildcard pattern is always irrefutable. +## Rest patterns + +> **Syntax**\ +> _RestPattern_ :\ +>    `..` + +The _rest pattern_ (the `..` token) acts as a variable-length pattern which +matches zero or more elements that haven't been matched already before and +after. It may only be used in [tuple](#tuple-patterns), [tuple +struct](#tuple-struct-patterns), and [slice](#slice-patterns) patterns, and +may only appear once as one of the elements in those patterns. It is also +allowed in an [identifier pattern](#identifier-patterns) for [slice +patterns](#slice-patterns) only. + +The rest pattern is always irrefutable. + +Examples: + +```rust +# let words = vec!["a", "b", "c"]; +# let slice = &words[..]; +match slice { + [] => println!("slice is empty"), + [one] => println!("single element {}", one), + [head, tail @ ..] => println!("head={} tail={:?}", head, tail), +} + +match slice { + // Ignore everything but the last element, which must be "!". + [.., "!"] => println!("!!!"), + + // `start` is a slice of everything except the last element, which must be "z". + [start @ .., "z"] => println!("starts with: {:?}", start), + + // `end` is a slice of everything but the first element, which must be "a". + ["a", end @ ..] => println!("ends with: {:?}", end), + + rest => println!("{:?}", rest), +} + +if let [.., penultimate, _] = slice { + println!("next to last is {}", penultimate); +} + +# let tuple = (1, 2, 3, 4, 5); +// Rest patterns may also be used in tuple and tuple struct patterns. +match tuple { + (1, .., y, z) => println!("y={} z={}", y, z), + (.., 5) => println!("tail must be 5"), + (..) => println!("matches everything else"), +} +``` + ## Range patterns > **Syntax**\ @@ -559,8 +613,7 @@ A struct pattern is refutable when one of its subpatterns is refutable. >    [_PathInExpression_] `(` _TupleStructItems_? `)` > > _TupleStructItems_ :\ ->       [_Pattern_] ( `,` [_Pattern_] )\* `,`?\ ->    | ([_Pattern_] `,`)\* `..` (`,` [_Pattern_])* `,`? +>    [_Pattern_] ( `,` [_Pattern_] )\* `,`? Tuple struct patterns match tuple struct and enum values that match all criteria defined by its subpatterns. They are also used to [destructure](#destructuring) a tuple struct or @@ -576,12 +629,15 @@ A tuple struct pattern is refutable when one of its subpatterns is refutable. > > _TuplePatternItems_ :\ >       [_Pattern_] `,`\ ->    | [_Pattern_] (`,` [_Pattern_])+ `,`?\ ->    | ([_Pattern_] `,`)\* `..` (`,` [_Pattern_])* `,`? +>    | [_RestPattern_]\ +>    | [_Pattern_] (`,` [_Pattern_])+ `,`? Tuple patterns match tuple values that match all criteria defined by its subpatterns. They are also used to [destructure](#destructuring) a tuple. +The form `(..)` with a single [_RestPattern_] is a special form that does not +require a comma, and matches a tuple of any size. + This pattern is refutable when one of its subpatterns is refutable. ## Grouped patterns @@ -607,7 +663,10 @@ match int_reference { > **Syntax**\ > _SlicePattern_ :\ ->    `[` [_Pattern_] \(`,` [_Pattern_])\* `,`? `]` +>    `[` _SlicePatternItems_? `]` +> +> _SlicePatternItems_ :\ +>    [_Pattern_] \(`,` [_Pattern_])\* `,`? Slice patterns can match both arrays of fixed size and slices of dynamic size. ```rust @@ -628,6 +687,11 @@ match v[..] { }; ``` +Slice patterns are irrefutable when matching an array as long as each element +is irrefutable. When matching a slice, it is irrefutable only in the form with +a single `..` [rest pattern](#rest-patterns) or [identifier +pattern](#identifier-patterns) with the `..` rest pattern as a subpattern. + ## Path patterns > **Syntax**\ @@ -664,6 +728,7 @@ refer to refutable constants or enum variants for enums with multiple variants. [_QualifiedPathInExpression_]: paths.md#qualified-paths [_RangePattern_]: #range-patterns [_ReferencePattern_]: #reference-patterns +[_RestPattern_]: #rest-patterns [_SlicePattern_]: #slice-patterns [_StructPattern_]: #struct-patterns [_TuplePattern_]: #tuple-patterns From 4033b6075f333bca95893ee20897be53a1a8b213 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 14 Aug 2020 18:56:38 -0700 Subject: [PATCH 2/3] Add identifier refutability. --- src/patterns.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/patterns.md b/src/patterns.md index bdfbd9716..1dfac0855 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -249,6 +249,9 @@ copying or moving what was matched. [Path patterns](#path-patterns) take precedence over identifier patterns. It is an error if `ref` or `ref mut` is specified and the identifier shadows a constant. +Identifier patterns are irrefutable if the `@` subpattern is irrefutable or +the subpattern is not specified. + ### Binding modes To service better ergonomics, patterns operate in different *binding modes* in @@ -638,7 +641,7 @@ They are also used to [destructure](#destructuring) a tuple. The form `(..)` with a single [_RestPattern_] is a special form that does not require a comma, and matches a tuple of any size. -This pattern is refutable when one of its subpatterns is refutable. +The tuple pattern is refutable when one of its subpatterns is refutable. ## Grouped patterns From 589c2163d018b408da173325e02c7b59c139c3d1 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 14 Aug 2020 19:12:17 -0700 Subject: [PATCH 3/3] Fix grammar for range pattern not allowed in reference pattern. --- src/patterns.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/patterns.md b/src/patterns.md index 1dfac0855..b9c1b9690 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -2,11 +2,15 @@ > **Syntax**\ > _Pattern_ :\ +>       _PatternWithoutRange_\ +>    | [_RangePattern_] +> +> _PatternWithoutRange_ :\ >       [_LiteralPattern_]\ >    | [_IdentifierPattern_]\ >    | [_WildcardPattern_]\ >    | [_RestPattern_]\ ->    | [_RangePattern_]\ +>    | [_ObsoleteRangePattern_]\ >    | [_ReferencePattern_]\ >    | [_StructPattern_]\ >    | [_TupleStructPattern_]\ @@ -378,8 +382,10 @@ match tuple { > **Syntax**\ > _RangePattern_ :\ ->      _RangePatternBound_ `..=` _RangePatternBound_\ ->    | _RangePatternBound_ `...` _RangePatternBound_ +>    _RangePatternBound_ `..=` _RangePatternBound_ +> +> _ObsoleteRangePattern_ :\ +>    _RangePatternBound_ `...` _RangePatternBound_ > > _RangePatternBound_ :\ >       [CHAR_LITERAL]\ @@ -486,7 +492,7 @@ ranges containing all Unicode Scalar Values: `'\u{0000}'..='\u{D7FF}'` and > **Syntax**\ > _ReferencePattern_ :\ ->    (`&`|`&&`) `mut`? _Pattern_ +>    (`&`|`&&`) `mut`? [_PatternWithoutRange_] Reference patterns dereference the pointers that are being matched and, thus, borrow them. @@ -725,9 +731,11 @@ refer to refutable constants or enum variants for enums with multiple variants. [_IdentifierPattern_]: #identifier-patterns [_LiteralPattern_]: #literal-patterns [_MacroInvocation_]: macros.md#macro-invocation +[_ObsoleteRangePattern_]: #range-patterns [_PathInExpression_]: paths.md#paths-in-expressions [_PathPattern_]: #path-patterns [_Pattern_]: #patterns +[_PatternWithoutRange_]: #patterns [_QualifiedPathInExpression_]: paths.md#qualified-paths [_RangePattern_]: #range-patterns [_ReferencePattern_]: #reference-patterns