From a84ea2783fcee84b70c3aa57e28e9a3c9b9d1f1b Mon Sep 17 00:00:00 2001 From: may Date: Mon, 3 Mar 2025 00:18:46 +0100 Subject: [PATCH 1/7] add RangeToExclusivePattern to the reference --- src/patterns.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/patterns.md b/src/patterns.md index dcb8f33fe..5c2eaf355 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -492,6 +492,9 @@ r[patterns.range.syntax] > _RangeFromPattern_ :\ >       _RangePatternBound_ `..` > +> _RangeToExclusivePattern_ :\ +>       `..` _RangePatternBound_ +> > _RangeToInclusivePattern_ :\ >       `..=` _RangePatternBound_ > @@ -537,8 +540,9 @@ For example, `1..` will match 1, 9, or 9001, or 9007199254740991 (if it is of an r[patterns.range.open-above] A range pattern with only an upper bound matches any value less than or equal to the upper bound. -It is written as `..=` followed by its upper bound, and has the same type as its upper bound. -For example, `..=10` will match 10, 1, 0, and for signed integer types, all negative values. +It is written as `..=` for an end-inclusive or `..` for an end-exclusive pattern, followed by its upper bound, +and has the same type as its upper bound. +For example, `..=10` will match 10, 1, 0, and for signed integer types, all negative values, while `..10` will not match 10. r[patterns.range.constraint-slice] Range patterns with only one bound cannot be used as the top-level pattern for subpatterns in [slice patterns](#slice-patterns). From 18e422e1d9cdf85cd8b6d73cff963f0cb629f332 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 3 Mar 2025 11:04:44 -0800 Subject: [PATCH 2/7] Include all range types in the _RangePattern_ production --- src/patterns.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/patterns.md b/src/patterns.md index 5c2eaf355..e4c11a69a 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -478,8 +478,10 @@ r[patterns.range] r[patterns.range.syntax] > **Syntax**\ > _RangePattern_ :\ ->       _RangeInclusivePattern_\ +>       _RangeExclusivePattern_\ +>    | _RangeInclusivePattern_\ >    | _RangeFromPattern_\ +>    | _RangeToExclusivePattern_\ >    | _RangeToInclusivePattern_\ >    | _ObsoleteRangePattern_ > From 9628f6b90e70746ed013481078eaa3c3ece2df80 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 3 Mar 2025 11:06:18 -0800 Subject: [PATCH 3/7] Add note about _ObsoleteRangePattern_ being edition-specific. --- src/patterns.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/patterns.md b/src/patterns.md index e4c11a69a..12163b146 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -483,7 +483,7 @@ r[patterns.range.syntax] >    | _RangeFromPattern_\ >    | _RangeToExclusivePattern_\ >    | _RangeToInclusivePattern_\ ->    | _ObsoleteRangePattern_ +>    | _ObsoleteRangePattern_[^obsolete-range-edition] > > _RangeExclusivePattern_ :\ >       _RangePatternBound_ `..` _RangePatternBound_ @@ -509,6 +509,8 @@ r[patterns.range.syntax] >    | `-`? [INTEGER_LITERAL]\ >    | `-`? [FLOAT_LITERAL]\ >    | [_PathExpression_] +> +> [^obsolete-range-edition]: The _ObsoleteRangePattern_ syntax has been removed in the 2021 edition. r[patterns.range.intro] *Range patterns* match scalar values within the range defined by their bounds. From 5ac1ad015408b995d0c1a8c47d60fa4d35b4744a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 12 Mar 2025 10:33:29 -0700 Subject: [PATCH 4/7] Drop mention of `...` since it is no longer supported in the latest edition --- src/patterns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patterns.md b/src/patterns.md index 12163b146..a5bc17d5a 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -514,7 +514,7 @@ r[patterns.range.syntax] r[patterns.range.intro] *Range patterns* match scalar values within the range defined by their bounds. -They comprise a *sigil* (one of `..`, `..=`, or `...`) and a bound on one or both sides. +They comprise a *sigil* (`..` or `..=`) and a bound on one or both sides. r[patterns.range.lower-bound] A bound on the left of the sigil is a *lower bound*. From 43c4bacf70b52da00bf2cbecb70c234d59d168d1 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 12 Mar 2025 10:34:34 -0700 Subject: [PATCH 5/7] Move the definition of bounds to the intro These are not specific rules, just foundational terminology definitions. --- src/patterns.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/patterns.md b/src/patterns.md index a5bc17d5a..c2a5504b0 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -516,11 +516,9 @@ r[patterns.range.intro] *Range patterns* match scalar values within the range defined by their bounds. They comprise a *sigil* (`..` or `..=`) and a bound on one or both sides. -r[patterns.range.lower-bound] -A bound on the left of the sigil is a *lower bound*. +A bound on the left of the sigil is called a *lower bound*. +A bound on the right is called an *upper bound*. -r[patterns.range.upper-bound] -A bound on the right is an *upper bound*. r[patterns.range.closed] A range pattern with both a lower and upper bound will match all values between and including both of its bounds. From d42bb622d202f6dbceb3096ad73892533235089e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 12 Mar 2025 10:36:11 -0700 Subject: [PATCH 6/7] Fix patterns.range.constraint-slice The old text was not correct, since `..b` or `..=b` single-bound patterns were stabilized in https://github.com/rust-lang/rust/pull/124749 and https://github.com/rust-lang/rust/pull/102275. --- src/patterns.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/patterns.md b/src/patterns.md index c2a5504b0..a870eeb29 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -546,9 +546,6 @@ It is written as `..=` for an end-inclusive or `..` for an end-exclusive pattern and has the same type as its upper bound. For example, `..=10` will match 10, 1, 0, and for signed integer types, all negative values, while `..10` will not match 10. -r[patterns.range.constraint-slice] -Range patterns with only one bound cannot be used as the top-level pattern for subpatterns in [slice patterns](#slice-patterns). - r[patterns.range.bound] The bounds is written as one of: @@ -659,6 +656,10 @@ The range of values for an integer type is the closed range from its minimum to r[patterns.range.refutable-char] The range of values for a `char` type are precisely those ranges containing all Unicode Scalar Values: `'\u{0000}'..='\u{D7FF}'` and `'\u{E000}'..='\u{10FFFF}'`. +r[patterns.range.constraint-slice] +_RangeFromPattern_ cannot be used as a top-level pattern for subpatterns in [slice patterns](#slice-patterns). +For example, the pattern `[1.., _]` is not a valid pattern. + r[patterns.range.edition2021] > **Edition differences**: Before the 2021 edition, range patterns with both a lower and upper bound may also be written using `...` in place of `..=`, with the same meaning. From daa1992f608d9cfae898606f66be39ea0c022247 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 12 Mar 2025 10:40:44 -0700 Subject: [PATCH 7/7] Rework range pattern rules I was not particularly happy with how these were being presented, as I found it a bit confusing how it was combining some of the ranges, and some of the terminology it was using. I've shifted it so that it describes each of the five range kinds separately, using the same terminology from std (and the grammar). This also just has some slight wording tweaks for clarity. --- src/patterns.md | 62 ++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/patterns.md b/src/patterns.md index a870eeb29..9723de445 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -519,57 +519,65 @@ They comprise a *sigil* (`..` or `..=`) and a bound on one or both sides. A bound on the left of the sigil is called a *lower bound*. A bound on the right is called an *upper bound*. +r[patterns.range.exclusive] +The *exclusive range pattern* matches all values from the lower bound up to, but not including the upper bound. +It is written as its lower bound, followed by `..`, followed by the upper bound. -r[patterns.range.closed] -A range pattern with both a lower and upper bound will match all values between and including both of its bounds. -It is written as its lower bound, followed by `..` for end-exclusive or `..=` for end-inclusive, followed by its upper bound. +For example, a pattern `'m'..'p'` will match only `'m'`, `'n'` and `'o'`, specifically **not** including `'p'`. -r[patterns.range.type] -The type of the range pattern is the type unification of its upper and lower bounds. +r[patterns.range.inclusive] +The *inclusive range pattern* matches all values from the lower bound up to and including the upper bound. +It is written as its lower bound, followed by `..=`, followed by the upper bound. For example, a pattern `'m'..='p'` will match only the values `'m'`, `'n'`, `'o'`, and `'p'`. -Similarly, `'m'..'p'` will match only `'m'`, `'n'` and `'o'`, specifically **not** including `'p'`. + +r[patterns.range.from] +The *from range pattern* matches all values greater than or equal to the lower bound. +It is written as its lower bound followed by `..`. + +For example, `1..` will match any integer greater than or equal to 1, such as 1, 9, or 9001, or 9007199254740991 (if it is of an appropriate size), but not 0, and not negative numbers for signed integers. + +r[patterns.range.to-exclusive] +The *to exclusive range pattern* matches all values less than the upper bound. +It is written as `..` followed by the upper bound. + +For example, `..10` will match any integer less than 10, such as 9, 1, 0, and for signed integer types, all negative values. + +r[patterns.range.to-inclusive] +The *to inclusive range pattern* matches all values less than or equal to the upper bound. +It is written as `..=` followed by the upper bound. + +For example, `..=10` will match any integer less than or equal to 10, such as 10, 1, 0, and for signed integer types, all negative values. r[patterns.range.constraint-less-than] The lower bound cannot be greater than the upper bound. That is, in `a..=b`, a ≤ b must be the case. For example, it is an error to have a range pattern `10..=0`. -r[patterns.range.open-below] -A range pattern with only a lower bound will match any value greater than or equal to the lower bound. -It is written as its lower bound followed by `..`, and has the same type as its lower bound. -For example, `1..` will match 1, 9, or 9001, or 9007199254740991 (if it is of an appropriate size), but not 0, and not negative numbers for signed integers. - -r[patterns.range.open-above] -A range pattern with only an upper bound matches any value less than or equal to the upper bound. -It is written as `..=` for an end-inclusive or `..` for an end-exclusive pattern, followed by its upper bound, -and has the same type as its upper bound. -For example, `..=10` will match 10, 1, 0, and for signed integer types, all negative values, while `..10` will not match 10. - r[patterns.range.bound] -The bounds is written as one of: +A bound is written as one of: * A character, byte, integer, or float literal. * A `-` followed by an integer or float literal. * A [path] r[patterns.range.constraint-bound-path] -If the bounds is written as a path, after macro resolution, the path must resolve to a constant item of the type `char`, an integer type, or a float type. +If a bound is written as a path, after macro resolution, the path must resolve to a constant item of the type `char`, an integer type, or a float type. -r[patterns.range.value] -The type and value of the bounds is dependent upon how it is written out. +r[patterns.range.type] +The range pattern matches the type of its upper and lower bounds, which must be the same type. r[patterns.range.path-value] -If the bounds is a [path], the pattern has the type and value of the [constant] the path resolves to. - -r[patterns.range.float-restriction] -For float range patterns, the constant may not be a `NaN`. +If a bound is a [path], the bound matches the type and has the value of the [constant] the path resolves to. r[patterns.range.literal-value] -If it is a literal, it has the type and value of the corresponding [literal expression]. +If a bound is a literal, the bound matches the type and has the value of the corresponding [literal expression]. r[patterns.range.negation] -If is a literal preceded by a `-`, it has the same type as the corresponding [literal expression] and the value of [negating] the value of the corresponding literal expression. +If a bound is a literal preceded by a `-`, the bound matches the same type as the corresponding [literal expression] and has the value of [negating] the value of the corresponding literal expression. + +r[patterns.range.float-restriction] +For float range patterns, the constant may not be a `NaN`. Examples: