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

Stabilize "RangeFrom" patterns in 1.55 #83918

Merged
merged 6 commits into from
Jul 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,9 @@ pub enum BindingMode {

#[derive(Clone, Encodable, Decodable, Debug)]
pub enum RangeEnd {
/// `..=` or `...`
Included(RangeSyntax),
/// `..`
Excluded,
}

Expand All @@ -687,6 +689,7 @@ pub enum RangeSyntax {
DotDotEq,
}

/// All the different flavors of pattern that Rust recognizes.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum PatKind {
/// Represents a wildcard pattern (`_`).
Expand Down Expand Up @@ -727,7 +730,7 @@ pub enum PatKind {
/// A literal.
Lit(P<Expr>),

/// A range pattern (e.g., `1...2`, `1..=2` or `1..2`).
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>),

/// A slice pattern `[a, b, c]`.
Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,22 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {

fn visit_pat(&mut self, pattern: &'a ast::Pat) {
match &pattern.kind {
PatKind::Slice(pats) => {
for pat in pats {
let inner_pat = match &pat.kind {
PatKind::Ident(.., Some(pat)) => pat,
_ => pat,
};
if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind {
gate_feature_post!(
&self,
half_open_range_patterns,
pat.span,
"`X..` patterns in slices are experimental"
);
}
}
}
PatKind::Box(..) => {
gate_feature_post!(
&self,
Expand All @@ -548,7 +564,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
"box pattern syntax is experimental"
);
}
PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => {
PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
gate_feature_post!(
&self,
exclusive_range_pattern,
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,6 @@ impl<'a> Parser<'a> {
} else if self.eat(&token::DotDotEq) {
RangeEnd::Included(RangeSyntax::DotDotEq)
} else if self.eat(&token::DotDot) {
self.sess.gated_spans.gate(sym::exclusive_range_pattern, self.prev_token.span);
RangeEnd::Excluded
} else {
return None;
Expand All @@ -735,7 +734,6 @@ impl<'a> Parser<'a> {
Some(self.parse_pat_range_end()?)
} else {
// Parsing e.g. `X..`.
self.sess.gated_spans.gate(sym::half_open_range_patterns, begin.span.to(re.span));
if let RangeEnd::Included(_) = re.node {
// FIXME(Centril): Consider semantic errors instead in `ast_validation`.
// Possibly also do this for `X..=` in *expression* contexts.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# `exclusive_range_pattern`

The tracking issue for this feature is: [#37854].


[#67264]: https://github.com/rust-lang/rust/issues/67264
[#37854]: https://github.com/rust-lang/rust/issues/37854
-----

The `exclusive_range_pattern` feature allows non-inclusive range
patterns (`0..10`) to be used in appropriate pattern matching
contexts. It also can be combined with `#![feature(half_open_range_patterns]`
to be able to use RangeTo patterns (`..10`).

It also enabled RangeFrom patterns but that has since been
stabilized.

```rust
#![feature(exclusive_range_pattern)]
let x = 5;
match x {
0..10 => println!("single digit"),
10 => println!("ten isn't part of the above range"),
_ => println!("nor is everything else.")
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# `half_open_range_patterns`

The tracking issue for this feature is: [#67264]
It is part of the `#![exclusive_range_pattern]` feature,
tracked at [#37854].

[#67264]: https://github.com/rust-lang/rust/issues/67264
[#37854]: https://github.com/rust-lang/rust/issues/37854
-----

The `half_open_range_patterns` feature allows RangeTo patterns
(`..10`) to be used in appropriate pattern matching contexts.
This requires also enabling the `exclusive_range_pattern` feature.

It also enabled RangeFrom patterns but that has since been
stabilized.

```rust
#![feature(half_open_range_patterns)]
#![feature(exclusive_range_pattern)]
let x = 5;
match x {
..0 => println!("negative!"), // "RangeTo" pattern. Unstable.
0 => println!("zero!"),
1.. => println!("positive!"), // "RangeFrom" pattern. Stable.
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,8 @@ fn foo() {
//~| ERROR range-to patterns with `...` are not allowed
if let ..5 = 0 {}
//~^ ERROR half-open range patterns are unstable
if let 5.. = 0 {}
//~^ ERROR half-open range patterns are unstable
if let 5..= = 0 {}
//~^ ERROR half-open range patterns are unstable
//~| ERROR inclusive range with no end
//~^ ERROR inclusive range with no end
if let 5... = 0 {}
//~^ ERROR half-open range patterns are unstable
//~| ERROR inclusive range with no end
//~^ ERROR inclusive range with no end
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ LL | if let ...5 = 0 {}
| ^^^ help: use `..=` instead

error[E0586]: inclusive range with no end
--> $DIR/feature-gate-half-open-range-patterns.rs:16:13
--> $DIR/feature-gate-half-open-range-patterns.rs:14:13
|
LL | if let 5..= = 0 {}
| ^^^ help: use `..` instead
|
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)

error[E0586]: inclusive range with no end
--> $DIR/feature-gate-half-open-range-patterns.rs:19:13
--> $DIR/feature-gate-half-open-range-patterns.rs:16:13
|
LL | if let 5... = 0 {}
| ^^^ help: use `..` instead
Expand Down Expand Up @@ -47,34 +47,7 @@ LL | if let ..5 = 0 {}
= note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
= help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable

error[E0658]: half-open range patterns are unstable
--> $DIR/feature-gate-half-open-range-patterns.rs:14:12
|
LL | if let 5.. = 0 {}
| ^^^
|
= note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
= help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable

error[E0658]: half-open range patterns are unstable
--> $DIR/feature-gate-half-open-range-patterns.rs:16:12
|
LL | if let 5..= = 0 {}
| ^^^^
|
= note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
= help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable

error[E0658]: half-open range patterns are unstable
--> $DIR/feature-gate-half-open-range-patterns.rs:19:12
|
LL | if let 5... = 0 {}
| ^^^^
|
= note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
= help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable

error: aborting due to 9 previous errors
error: aborting due to 6 previous errors

Some errors have detailed explanations: E0586, E0658.
For more information about an error, try `rustc --explain E0586`.
32 changes: 32 additions & 0 deletions src/test/ui/half-open-range-patterns/range_pat_interactions0.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// run-pass
#![allow(incomplete_features)]
#![feature(exclusive_range_pattern)]
#![feature(half_open_range_patterns)]
#![feature(inline_const)]

fn main() {
let mut if_lettable = vec![];
let mut first_or = vec![];
let mut or_two = vec![];
let mut range_from = vec![];
let mut bottom = vec![];

for x in -9 + 1..=(9 - 2) {
if let -1..=0 | 2..3 | 4 = x {
if_lettable.push(x)
}
match x {
1 | -3..0 => first_or.push(x),
y @ (0..5 | 6) => or_two.push(y),
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
y @ -5.. => range_from.push(y),
y @ ..-7 => assert_eq!(y, -8),
y => bottom.push(y),
}
}
assert_eq!(if_lettable, [-1, 0, 2, 4]);
assert_eq!(first_or, [-3, -2, -1, 1]);
assert_eq!(or_two, [0, 2, 3, 4, 6]);
assert_eq!(range_from, [-5, -4, 7]);
assert_eq!(bottom, [-7, -6]);
}
29 changes: 29 additions & 0 deletions src/test/ui/half-open-range-patterns/range_pat_interactions1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
fn main() {
let mut if_lettable = Vec::<i32>::new();
let mut first_or = Vec::<i32>::new();
let mut or_two = Vec::<i32>::new();
let mut range_from = Vec::<i32>::new();
let mut bottom = Vec::<i32>::new();
let mut errors_only = Vec::<i32>::new();

for x in -9 + 1..=(9 - 2) {
if let n @ 2..3|4 = x {
//~^ error: variable `n` is not bound in all patterns
//~| exclusive range pattern syntax is experimental
errors_only.push(x);
} else if let 2..3 | 4 = x {
//~^ exclusive range pattern syntax is experimental
if_lettable.push(x);
}
match x as i32 {
0..5+1 => errors_only.push(x),
//~^ error: expected one of `=>`, `if`, or `|`, found `+`
1 | -3..0 => first_or.push(x),
y @ (0..5 | 6) => or_two.push(y),
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
y @ -5.. => range_from.push(y),
y @ ..-7 => assert_eq!(y, -8),
y => bottom.push(y),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
error: expected one of `=>`, `if`, or `|`, found `+`
--> $DIR/range_pat_interactions1.rs:19:17
|
LL | 0..5+1 => errors_only.push(x),
| ^ expected one of `=>`, `if`, or `|`

error[E0408]: variable `n` is not bound in all patterns
--> $DIR/range_pat_interactions1.rs:10:25
|
LL | if let n @ 2..3|4 = x {
| - ^ pattern doesn't bind `n`
| |
| variable not in all patterns

error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/range_pat_interactions1.rs:10:20
|
LL | if let n @ 2..3|4 = x {
| ^^^^
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable

error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/range_pat_interactions1.rs:14:23
|
LL | } else if let 2..3 | 4 = x {
| ^^^^
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0408, E0658.
For more information about an error, try `rustc --explain E0408`.
21 changes: 21 additions & 0 deletions src/test/ui/half-open-range-patterns/range_pat_interactions2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
fn main() {
let mut first_or = Vec::<i32>::new();
let mut or_two = Vec::<i32>::new();
let mut range_from = Vec::<i32>::new();
let mut bottom = Vec::<i32>::new();
let mut errors_only = Vec::<i32>::new();

for x in -9 + 1..=(9 - 2) {
match x as i32 {
0..=(5+1) => errors_only.push(x),
//~^ error: inclusive range with no end
//~| error: expected one of `=>`, `if`, or `|`, found `(`
1 | -3..0 => first_or.push(x),
y @ (0..5 | 6) => or_two.push(y),
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
y @ -5.. => range_from.push(y),
y @ ..-7 => assert_eq!(y, -8),
y => bottom.push(y),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0586]: inclusive range with no end
--> $DIR/range_pat_interactions2.rs:10:14
|
LL | 0..=(5+1) => errors_only.push(x),
| ^^^ help: use `..` instead
|
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)

error: expected one of `=>`, `if`, or `|`, found `(`
--> $DIR/range_pat_interactions2.rs:10:17
|
LL | 0..=(5+1) => errors_only.push(x),
| ^ expected one of `=>`, `if`, or `|`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0586`.
24 changes: 24 additions & 0 deletions src/test/ui/half-open-range-patterns/range_pat_interactions3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
fn main() {
let mut first_or = Vec::<i32>::new();
let mut or_two = Vec::<i32>::new();
let mut range_from = Vec::<i32>::new();
let mut bottom = Vec::<i32>::new();

for x in -9 + 1..=(9 - 2) {
match x as i32 {
8.. => bottom.push(x),
1 | -3..0 => first_or.push(x),
//~^ exclusive range pattern syntax is experimental
y @ (0..5 | 6) => or_two.push(y),
//~^ exclusive range pattern syntax is experimental
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
//~^ inline-const is experimental
//~| exclusive range pattern syntax is experimental
y @ -5.. => range_from.push(y),
y @ ..-7 => assert_eq!(y, -8),
//~^ half-open range patterns are unstable
//~| exclusive range pattern syntax is experimental
y => bottom.push(y),
}
}
}
Loading