Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exclusive range patterns #35712

Merged
merged 3 commits into from
Jan 25, 2017
Merged

Conversation

oli-obk
Copy link
Contributor

@oli-obk oli-obk commented Aug 16, 2016

adds .. patterns to the language under a feature gate (exclusive_range_pattern).

This allows turning

match i {
    0...9 => {},
    10...19 => {},
    20...29 => {},
    _ => {}
}

into

match i {
    0..10 => {},
    10..20 => {},
    20..30 => {},
    _ => {}
}

@rust-highfive

This comment has been minimized.

@@ -585,6 +586,8 @@ pub enum PatKind {
Lit(P<Expr>),
/// A range pattern, e.g. `1...2`
Range(P<Expr>, P<Expr>),
/// A range pattern excluding the end, e.g. `1..2`
ExclusiveRange(P<Expr>, P<Expr>),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In most cases inclusive and exclusive ranges behave identically, it's probably more convenient to merge them into one variant Range(P<Expr>, P<Expr>, RangeKind).

Copy link
Contributor Author

@oli-obk oli-obk Aug 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this, it's much less code and more readable code now 👍

@bors

This comment has been minimized.

@oli-obk oli-obk force-pushed the exclusive_range_patterns branch 2 times, most recently from 5d9114a to a033745 Compare September 6, 2016 12:57
@bors

This comment has been minimized.

@bors

This comment has been minimized.

@bors

This comment has been minimized.

@brson brson added I-nominated T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Nov 9, 2016
@brson
Copy link
Contributor

brson commented Nov 9, 2016

This PR seems to have gone under the radar for a long time. Can somebody review?

Is this an implementation of an RFC. Is there a tracking issue?

@brson brson added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Nov 9, 2016
@brson
Copy link
Contributor

brson commented Nov 9, 2016

cc @rust-lang/compiler

@oli-obk
Copy link
Contributor Author

oli-obk commented Nov 9, 2016

No rfc or tracking issue, I thought it was just an oversight. But I can write an RFC...

@brson brson added the relnotes Marks issues that should be documented in the release notes of the next release. label Nov 11, 2016
@nikomatsakis
Copy link
Contributor

There was an RFC, iirc, but @aturon has been having second thoughts on the syntax here, and wanting something more general.

@nikomatsakis nikomatsakis added T-lang Relevant to the language team, which will review and decide on the PR/issue. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 17, 2016
@nikomatsakis
Copy link
Contributor

My mistake: I thought this was adding ... expressions, not .. patterns.

@aturon
Copy link
Member

aturon commented Nov 17, 2016

Note: this was not covered by rust-lang/rfcs#1192

@eddyb
Copy link
Member

eddyb commented Nov 17, 2016

Any thoughts on a.. or ..b?

@nikomatsakis
Copy link
Contributor

Discussed in the @rust-lang/lang meeting:

  • This needs a tracking issue and feature-gate.
  • We feel OK landing this for now, as long as it is gated, because it seems that in any possible world this is desirable, but:
    • we would be unlikely to stabilize until the question of how to handle ... is resolved
      • my preference is ..= (which generalizes to <..<, <..= and so forth)

@alexcrichton

This comment has been minimized.

@bors

This comment has been minimized.

@bors

This comment has been minimized.

@alexcrichton

This comment has been minimized.

@bors

This comment has been minimized.

@bors

This comment has been minimized.

@bors

This comment has been minimized.

@bors

This comment has been minimized.

@alexcrichton

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Jan 25, 2017

⌛ Testing commit 98fef41 with merge c0d0e68...

bors added a commit that referenced this pull request Jan 25, 2017
exclusive range patterns

adds `..` patterns to the language under a feature gate (`exclusive_range_pattern`).

This allows turning

``` rust
match i {
    0...9 => {},
    10...19 => {},
    20...29 => {},
    _ => {}
}
```

into

``` rust
match i {
    0..10 => {},
    10..20 => {},
    20..30 => {},
    _ => {}
}
```
@bors
Copy link
Contributor

bors commented Jan 25, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing c0d0e68 to master...

@bors bors merged commit 98fef41 into rust-lang:master Jan 25, 2017
@oli-obk oli-obk deleted the exclusive_range_patterns branch January 25, 2017 12:33
@Centril Centril added the F-exclusive_range_pattern `#![feature(exclusive_range_pattern)]` label Dec 12, 2019
Centril added a commit to Centril/rust that referenced this pull request Jan 9, 2020
Introduce `X..`, `..X`, and `..=X` range patterns

Tracking issue: rust-lang#67264
Feature gate: `#![feature(half_open_range_patterns)]`

---------------------------

In this PR, we introduce range-from (`X..`), range-to (`..X`), and range-to-inclusive (`..=X`) patterns.
These correspond to the `RangeFrom`, `RangeTo`, and `RangeToInclusive` expression forms introduced with the same syntaxes. The correspondence is both syntactic and semantic (in the sense that e.g. a `X..` pattern matching on a scrutinee `s` holds exactly when `(X..).contains(&s)` holds).

---------------------------

Noteworthy:

- The compiler complexity added with this PR is around 10 lines (discounting new tests, which account for the large PR size).

- `...X` is accepted syntactically with the same meaning as `..=X`. This is done primarily to simplify and unify the implementation & spec. If-and-when we decide to make `X...Y` a hard error on a new edition, we can do the same for `...X` patterns as well.

- `X...` and `X..=` is rejected syntactically just like it is for the expression equivalents. We should perhaps make these into semantic restrictions (cc @petrochenkov).

- In HAIR, these half-open ranges are represented by inserting the max/min values for the approprate types. That is, `X..` where `X: u8` would become `X..=u8::MAX` in HAIR (note the `..=` since `RangeFrom` includes the end).

- Exhaustive integer / char matching does not (yet) allow for e.g. exhaustive matching on `0usize..` or `..5usize | 5..` (same idea for `isize`). This would be a substantially more invasive change, and could be added in some other PR.

- The issues with slice pattern syntax has been resolved as we decided to use `..` to mean a "rest-pattern" and `[xs @ ..]` to bind the rest to a name in a slice pattern.

- Like with rust-lang#35712, which provided `X..Y` range patterns, this is not yet backed up by an RFC. I'm providing this experimental implementation now to have something concrete to discuss. I would be happy to provide an RFC for this PR as well as for rust-lang#35712 to finalize and confirm the ideas with the larger community.

Closes rust-lang/rfcs#947.

---------------------------

r? @varkor cc @matthewjasper @oli-obk

I would recommend reviewing this (in particular HAIR-lowering and pattern parsing changes) with whitespace changes ignored.
Centril added a commit to Centril/rust that referenced this pull request Jan 10, 2020
Introduce `X..`, `..X`, and `..=X` range patterns

Tracking issue: rust-lang#67264
Feature gate: `#![feature(half_open_range_patterns)]`

---------------------------

In this PR, we introduce range-from (`X..`), range-to (`..X`), and range-to-inclusive (`..=X`) patterns.
These correspond to the `RangeFrom`, `RangeTo`, and `RangeToInclusive` expression forms introduced with the same syntaxes. The correspondence is both syntactic and semantic (in the sense that e.g. a `X..` pattern matching on a scrutinee `s` holds exactly when `(X..).contains(&s)` holds).

---------------------------

Noteworthy:

- The compiler complexity added with this PR is around 10 lines (discounting new tests, which account for the large PR size).

- `...X` is accepted syntactically with the same meaning as `..=X`. This is done primarily to simplify and unify the implementation & spec. If-and-when we decide to make `X...Y` a hard error on a new edition, we can do the same for `...X` patterns as well.

- `X...` and `X..=` is rejected syntactically just like it is for the expression equivalents. We should perhaps make these into semantic restrictions (cc @petrochenkov).

- In HAIR, these half-open ranges are represented by inserting the max/min values for the approprate types. That is, `X..` where `X: u8` would become `X..=u8::MAX` in HAIR (note the `..=` since `RangeFrom` includes the end).

- Exhaustive integer / char matching does not (yet) allow for e.g. exhaustive matching on `0usize..` or `..5usize | 5..` (same idea for `isize`). This would be a substantially more invasive change, and could be added in some other PR.

- The issues with slice pattern syntax has been resolved as we decided to use `..` to mean a "rest-pattern" and `[xs @ ..]` to bind the rest to a name in a slice pattern.

- Like with rust-lang#35712, which provided `X..Y` range patterns, this is not yet backed up by an RFC. I'm providing this experimental implementation now to have something concrete to discuss. I would be happy to provide an RFC for this PR as well as for rust-lang#35712 to finalize and confirm the ideas with the larger community.

Closes rust-lang/rfcs#947.

---------------------------

r? @varkor cc @matthewjasper @oli-obk

I would recommend reviewing this (in particular HAIR-lowering and pattern parsing changes) with whitespace changes ignored.
Centril added a commit to Centril/rust that referenced this pull request Jan 10, 2020
Introduce `X..`, `..X`, and `..=X` range patterns

Tracking issue: rust-lang#67264
Feature gate: `#![feature(half_open_range_patterns)]`

---------------------------

In this PR, we introduce range-from (`X..`), range-to (`..X`), and range-to-inclusive (`..=X`) patterns.
These correspond to the `RangeFrom`, `RangeTo`, and `RangeToInclusive` expression forms introduced with the same syntaxes. The correspondence is both syntactic and semantic (in the sense that e.g. a `X..` pattern matching on a scrutinee `s` holds exactly when `(X..).contains(&s)` holds).

---------------------------

Noteworthy:

- The compiler complexity added with this PR is around 10 lines (discounting new tests, which account for the large PR size).

- `...X` is accepted syntactically with the same meaning as `..=X`. This is done primarily to simplify and unify the implementation & spec. If-and-when we decide to make `X...Y` a hard error on a new edition, we can do the same for `...X` patterns as well.

- `X...` and `X..=` is rejected syntactically just like it is for the expression equivalents. We should perhaps make these into semantic restrictions (cc @petrochenkov).

- In HAIR, these half-open ranges are represented by inserting the max/min values for the approprate types. That is, `X..` where `X: u8` would become `X..=u8::MAX` in HAIR (note the `..=` since `RangeFrom` includes the end).

- Exhaustive integer / char matching does not (yet) allow for e.g. exhaustive matching on `0usize..` or `..5usize | 5..` (same idea for `isize`). This would be a substantially more invasive change, and could be added in some other PR.

- The issues with slice pattern syntax has been resolved as we decided to use `..` to mean a "rest-pattern" and `[xs @ ..]` to bind the rest to a name in a slice pattern.

- Like with rust-lang#35712, which provided `X..Y` range patterns, this is not yet backed up by an RFC. I'm providing this experimental implementation now to have something concrete to discuss. I would be happy to provide an RFC for this PR as well as for rust-lang#35712 to finalize and confirm the ideas with the larger community.

Closes rust-lang/rfcs#947.

---------------------------

r? @varkor cc @matthewjasper @oli-obk

I would recommend reviewing this (in particular HAIR-lowering and pattern parsing changes) with whitespace changes ignored.
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Jan 10, 2020
Introduce `X..`, `..X`, and `..=X` range patterns

Tracking issue: rust-lang#67264
Feature gate: `#![feature(half_open_range_patterns)]`

---------------------------

In this PR, we introduce range-from (`X..`), range-to (`..X`), and range-to-inclusive (`..=X`) patterns.
These correspond to the `RangeFrom`, `RangeTo`, and `RangeToInclusive` expression forms introduced with the same syntaxes. The correspondence is both syntactic and semantic (in the sense that e.g. a `X..` pattern matching on a scrutinee `s` holds exactly when `(X..).contains(&s)` holds).

---------------------------

Noteworthy:

- The compiler complexity added with this PR is around 10 lines (discounting new tests, which account for the large PR size).

- `...X` is accepted syntactically with the same meaning as `..=X`. This is done primarily to simplify and unify the implementation & spec. If-and-when we decide to make `X...Y` a hard error on a new edition, we can do the same for `...X` patterns as well.

- `X...` and `X..=` is rejected syntactically just like it is for the expression equivalents. We should perhaps make these into semantic restrictions (cc @petrochenkov).

- In HAIR, these half-open ranges are represented by inserting the max/min values for the approprate types. That is, `X..` where `X: u8` would become `X..=u8::MAX` in HAIR (note the `..=` since `RangeFrom` includes the end).

- Exhaustive integer / char matching does not (yet) allow for e.g. exhaustive matching on `0usize..` or `..5usize | 5..` (same idea for `isize`). This would be a substantially more invasive change, and could be added in some other PR.

- The issues with slice pattern syntax has been resolved as we decided to use `..` to mean a "rest-pattern" and `[xs @ ..]` to bind the rest to a name in a slice pattern.

- Like with rust-lang#35712, which provided `X..Y` range patterns, this is not yet backed up by an RFC. I'm providing this experimental implementation now to have something concrete to discuss. I would be happy to provide an RFC for this PR as well as for rust-lang#35712 to finalize and confirm the ideas with the larger community.

Closes rust-lang/rfcs#947.

---------------------------

r? @varkor cc @matthewjasper @oli-obk

I would recommend reviewing this (in particular HAIR-lowering and pattern parsing changes) with whitespace changes ignored.
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Jan 10, 2020
Introduce `X..`, `..X`, and `..=X` range patterns

Tracking issue: rust-lang#67264
Feature gate: `#![feature(half_open_range_patterns)]`

---------------------------

In this PR, we introduce range-from (`X..`), range-to (`..X`), and range-to-inclusive (`..=X`) patterns.
These correspond to the `RangeFrom`, `RangeTo`, and `RangeToInclusive` expression forms introduced with the same syntaxes. The correspondence is both syntactic and semantic (in the sense that e.g. a `X..` pattern matching on a scrutinee `s` holds exactly when `(X..).contains(&s)` holds).

---------------------------

Noteworthy:

- The compiler complexity added with this PR is around 10 lines (discounting new tests, which account for the large PR size).

- `...X` is accepted syntactically with the same meaning as `..=X`. This is done primarily to simplify and unify the implementation & spec. If-and-when we decide to make `X...Y` a hard error on a new edition, we can do the same for `...X` patterns as well.

- `X...` and `X..=` is rejected syntactically just like it is for the expression equivalents. We should perhaps make these into semantic restrictions (cc @petrochenkov).

- In HAIR, these half-open ranges are represented by inserting the max/min values for the approprate types. That is, `X..` where `X: u8` would become `X..=u8::MAX` in HAIR (note the `..=` since `RangeFrom` includes the end).

- Exhaustive integer / char matching does not (yet) allow for e.g. exhaustive matching on `0usize..` or `..5usize | 5..` (same idea for `isize`). This would be a substantially more invasive change, and could be added in some other PR.

- The issues with slice pattern syntax has been resolved as we decided to use `..` to mean a "rest-pattern" and `[xs @ ..]` to bind the rest to a name in a slice pattern.

- Like with rust-lang#35712, which provided `X..Y` range patterns, this is not yet backed up by an RFC. I'm providing this experimental implementation now to have something concrete to discuss. I would be happy to provide an RFC for this PR as well as for rust-lang#35712 to finalize and confirm the ideas with the larger community.

Closes rust-lang/rfcs#947.

---------------------------

r? @varkor cc @matthewjasper @oli-obk

I would recommend reviewing this (in particular HAIR-lowering and pattern parsing changes) with whitespace changes ignored.
bors added a commit to rust-lang-ci/rust that referenced this pull request Jul 11, 2021
…r=joshtriplett

Stabilize "RangeFrom" patterns in 1.55

Implements a partial stabilization of rust-lang#67264 and rust-lang#37854.
Reference PR: rust-lang/reference#900

# Stabilization Report

This stabilizes the `X..` pattern, shown as such, offering an exhaustive match for unsigned integers:
```rust
match x as u32 {
      0 => println!("zero!"),
      1.. => println!("positive number!"),
}
```

Currently if a Rust author wants to write such a match on an integer, they must use `1..={integer}::MAX` . By allowing a "RangeFrom" style pattern, this simplifies the match to not require the MAX path and thus not require specifically repeating the type inside the match, allowing for easier refactoring. This is particularly useful for instances like the above case, where different behavior on "0" vs. "1 or any positive number" is desired, and the actual MAX is unimportant.

Notably, this excepts slice patterns which include half-open ranges from stabilization, as the wisdom of those is still subject to some debate.

## Practical Applications

Instances of this specific usage have appeared in the compiler:
https://github.com/rust-lang/rust/blob/16143d10679537d3fde4247e15334e78ad9d55b9/compiler/rustc_middle/src/ty/inhabitedness/mod.rs#L219
https://github.com/rust-lang/rust/blob/673d0db5e393e9c64897005b470bfeb6d5aec61b/compiler/rustc_ty_utils/src/ty.rs#L524

And I have noticed there are also a handful of "in the wild" users who have deployed it to similar effect, especially in the case of rejecting any value of a certain number or greater. It simply makes it much more ergonomic to write an irrefutable match, as done in Katholieke Universiteit Leuven's [SCALE and MAMBA project](https://github.com/KULeuven-COSIC/SCALE-MAMBA/blob/05e5db00d553573534258585651c525d0da5f83f/WebAssembly/scale_std/src/fixed_point.rs#L685-L695).

## Tests
There were already many tests in [src/test/ui/half-open-range/patterns](https://github.com/rust-lang/rust/tree/90a2e5e3fe59a254d4d707aa291517b3791ea5a6/src/test/ui/half-open-range-patterns), as well as [generic pattern tests that test the `exclusive_range_pattern` feature](https://github.com/rust-lang/rust/blob/673d0db5e393e9c64897005b470bfeb6d5aec61b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs), many dating back to the feature's introduction and remaining standing to this day. However, this stabilization comes with some additional tests to explore the... sometimes interesting behavior of interactions with other patterns. e.g. There is, at least, a mild diagnostic improvement in some edge cases, because before now, the pattern `0..=(5+1)` encounters the `half_open_range_patterns` feature gate and can thus emit the request to enable the feature flag, while also emitting the "inclusive range with no end" diagnostic. There is no intent to allow an `X..=` pattern that I am aware of, so removing the flag request is a strict improvement. The arrival of the `J | K` "or" pattern also enables some odd formations.

Some of the behavior tested for here is derived from experiments in this [Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=58777b3c715c85165ac4a70d93efeefc) example, linked at rust-lang#67264 (comment), which may be useful to reference to observe the current behavior more closely.

In addition tests constituting an explanation of the "slicing range patterns" syntax issue are included in this PR.

## Desiderata

The exclusive range patterns and half-open range patterns are fairly strongly requested by many authors, as they make some patterns much more natural to write, but there is disagreement regarding the "closed" exclusive range pattern or the "RangeTo" pattern, especially where it creates "off by one" gaps in the presence of a "catch-all" wildcard case. Also, there are obviously no range analyses in place that will force diagnostics for e.g. highly overlapping matches. I believe these should be warned on, ideally, and I think it would be reasonable to consider such a blocker to stabilizing this feature, but there is no technical issue with the feature as-is from the purely syntactic perspective as such overlapping or missed matches can already be generated today with such a catch-all case. And part of the "point" of the feature, at least from my view, is to make it easier to omit wildcard matches: a pattern with such an "open" match produces an irrefutable match and does not need the wild card case, making it easier to benefit from exhaustiveness checking.

## History

- Implemented:
  - Partially via exclusive ranges: rust-lang#35712
  - Fully with half-open ranges: rust-lang#67258
- Unresolved Questions:
  - The precedence concerns of rust-lang#48501 were considered as likely requiring adjustment but probably wanting a uniform consistent change across all pattern styles, given rust-lang#67264 (comment), but it is still unknown what changes might be desired
  - How we want to handle slice patterns in ranges seems to be an open question still, as witnessed in the discussion of this PR!

I checked but I couldn't actually find an RFC for this, and given "approved provisionally by lang team without an RFC", I believe this might require an RFC before it can land? Unsure of procedure here, on account of this being stabilizing a subset of a feature of syntax.

r? `@scottmcm`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-exclusive_range_pattern `#![feature(exclusive_range_pattern)]` relnotes Marks issues that should be documented in the release notes of the next release. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.