diff options
| author | Yuki Okushi <huyuumi.dev@gmail.com> | 2020-01-11 04:50:46 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-01-11 04:50:46 +0900 |
| commit | 793b1be6df51a259477880a45a78fb5b42f1c9b4 (patch) | |
| tree | d29b8a4b57c383e12742c71fa115759e47595e4e /src/libsyntax | |
| parent | 2dbcf0841a81fbada9a2b3af253b62b30a8318cc (diff) | |
| parent | d5598aa7a07b324789576585f4f035c93993fea4 (diff) | |
| download | rust-793b1be6df51a259477880a45a78fb5b42f1c9b4.tar.gz rust-793b1be6df51a259477880a45a78fb5b42f1c9b4.zip | |
Rollup merge of #67258 - Centril:open-ended-ranges, r=oli-obk
Introduce `X..`, `..X`, and `..=X` range patterns Tracking issue: https://github.com/rust-lang/rust/issues/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 https://github.com/rust-lang/rust/pull/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 #35712 to finalize and confirm the ideas with the larger community. Closes https://github.com/rust-lang/rfcs/issues/947. --------------------------- r? @varkor cc @matthewjasper @oli-obk I would recommend reviewing this (in particular HAIR-lowering and pattern parsing changes) with whitespace changes ignored.
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate/check.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/mut_visit.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 10 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 4 |
5 files changed, 13 insertions, 8 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1d3bb7d8768..33acba8eba0 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -649,7 +649,7 @@ pub enum PatKind { Lit(P<Expr>), /// A range pattern (e.g., `1...2`, `1..=2` or `1..2`). - Range(P<Expr>, P<Expr>, Spanned<RangeEnd>), + Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>), /// A slice pattern `[a, b, c]`. Slice(Vec<P<Pat>>), diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 52eb20d320f..5e431905172 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -911,6 +911,7 @@ pub fn check_crate( gate_all!(raw_ref_op, "raw address of syntax is experimental"); gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental"); gate_all!(const_trait_impl, "const trait impls are experimental"); + gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 264ba25cede..58d4e46111b 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1075,8 +1075,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { PatKind::Box(inner) => vis.visit_pat(inner), PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => { - vis.visit_expr(e1); - vis.visit_expr(e2); + visit_opt(e1, |e| vis.visit_expr(e)); + visit_opt(e2, |e| vis.visit_expr(e)); vis.visit_span(span); } PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index dd9976510dc..11c8cb8ef75 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2329,14 +2329,18 @@ impl<'a> State<'a> { } PatKind::Lit(ref e) => self.print_expr(&**e), PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => { - self.print_expr(begin); - self.s.space(); + if let Some(e) = begin { + self.print_expr(e); + self.s.space(); + } match *end_kind { RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("..."), RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..="), RangeEnd::Excluded => self.s.word(".."), } - self.print_expr(end); + if let Some(e) = end { + self.print_expr(e); + } } PatKind::Slice(ref elts) => { self.s.word("["); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ebb49abebb0..3c2ebacbc4e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -492,8 +492,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { } PatKind::Lit(ref expression) => visitor.visit_expr(expression), PatKind::Range(ref lower_bound, ref upper_bound, _) => { - visitor.visit_expr(lower_bound); - visitor.visit_expr(upper_bound); + walk_list!(visitor, visit_expr, lower_bound); + walk_list!(visitor, visit_expr, upper_bound); } PatKind::Wild | PatKind::Rest => {} PatKind::Tuple(ref elems) | PatKind::Slice(ref elems) | PatKind::Or(ref elems) => { |
