diff options
| author | bors <bors@rust-lang.org> | 2019-08-18 01:02:20 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-08-18 01:02:20 +0000 |
| commit | fc8765d6d8623b2b5b4ca1d526ed1d7beb3fce18 (patch) | |
| tree | 8401657213f0b7a7805fb2915902396d424e02bf /src/libsyntax | |
| parent | bd1da18b04afba5dfc09ad1b56df3285f1d039c3 (diff) | |
| parent | 1870537f2701e5aa47080a879b63a4d6b391553b (diff) | |
| download | rust-fc8765d6d8623b2b5b4ca1d526ed1d7beb3fce18.tar.gz rust-fc8765d6d8623b2b5b4ca1d526ed1d7beb3fce18.zip | |
Auto merge of #61708 - dlrobertson:or-patterns-0, r=centril
Initial implementation of or-patterns An incomplete implementation of or-patterns (e.g. `Some(0 | 1)` as a pattern). This patch set aims to implement initial parsing of `or-patterns`. Related to: #54883 CC @alexreg @varkor r? @Centril
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 11 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/mut_visit.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser/pat.rs | 41 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 36 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 7 |
7 files changed, 80 insertions, 28 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9091607629e..50e428ea0cc 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -572,9 +572,10 @@ impl Pat { match &self.node { PatKind::Ident(_, _, Some(p)) => p.walk(it), PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk(it)), - PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => { - s.iter().all(|p| p.walk(it)) - } + PatKind::TupleStruct(_, s) + | PatKind::Tuple(s) + | PatKind::Slice(s) + | PatKind::Or(s) => s.iter().all(|p| p.walk(it)), PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it), PatKind::Wild | PatKind::Rest @@ -648,6 +649,10 @@ pub enum PatKind { /// A tuple struct/variant pattern (`Variant(x, y, .., z)`). TupleStruct(Path, Vec<P<Pat>>), + /// An or-pattern `A | B | C`. + /// Invariant: `pats.len() >= 2`. + Or(Vec<P<Pat>>), + /// A possibly qualified path pattern. /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants /// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1a87a903156..bbc3ae28225 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -559,6 +559,9 @@ declare_features! ( // Allows `impl Trait` to be used inside type aliases (RFC 2515). (active, type_alias_impl_trait, "1.38.0", Some(63063), None), + // Allows the use of or-patterns, e.g. `0 | 1`. + (active, or_patterns, "1.38.0", Some(54883), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -571,6 +574,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::impl_trait_in_bindings, sym::generic_associated_types, sym::const_generics, + sym::or_patterns, sym::let_chains, ]; @@ -2443,6 +2447,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental"); gate_all!(async_closure_spans, async_closure, "async closures are unstable"); gate_all!(yield_spans, generators, "yield syntax is experimental"); + gate_all!(or_pattern_spans, or_patterns, "or-patterns syntax is experimental"); let visitor = &mut PostExpansionVisitor { context: &ctx, diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 18d4a646355..9785f8e2de0 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1050,7 +1050,6 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { vis.visit_span(span); }; } - PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)), PatKind::Box(inner) => vis.visit_pat(inner), PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => { @@ -1058,7 +1057,9 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { vis.visit_expr(e2); vis.visit_span(span); } - PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)), + PatKind::Tuple(elems) + | PatKind::Slice(elems) + | PatKind::Or(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)), PatKind::Paren(inner) => vis.visit_pat(inner), PatKind::Mac(mac) => vis.visit_mac(mac), } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 9088f929372..b1f3612a839 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -66,6 +66,8 @@ pub struct ParseSess { // Places where `yield e?` exprs were used and should be feature gated. pub yield_spans: Lock<Vec<Span>>, pub injected_crate_name: Once<Symbol>, + // Places where or-patterns e.g. `Some(Foo | Bar)` were used and should be feature gated. + pub or_pattern_spans: Lock<Vec<Span>>, } impl ParseSess { @@ -96,6 +98,7 @@ impl ParseSess { async_closure_spans: Lock::new(Vec::new()), yield_spans: Lock::new(Vec::new()), injected_crate_name: Once::new(), + or_pattern_spans: Lock::new(Vec::new()), } } diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index c3079d2da0c..fd458aec743 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -14,7 +14,10 @@ use errors::{Applicability, DiagnosticBuilder}; impl<'a> Parser<'a> { /// Parses a pattern. - pub fn parse_pat(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> { + pub fn parse_pat( + &mut self, + expected: Option<&'static str> + ) -> PResult<'a, P<Pat>> { self.parse_pat_with_range_pat(true, expected) } @@ -97,6 +100,34 @@ impl<'a> Parser<'a> { Ok(()) } + /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). + fn parse_pat_with_or(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> { + // Parse the first pattern. + let first_pat = self.parse_pat(expected)?; + + // If the next token is not a `|`, this is not an or-pattern and + // we should exit here. + if !self.check(&token::BinOp(token::Or)) { + return Ok(first_pat) + } + + let lo = first_pat.span; + + let mut pats = vec![first_pat]; + + while self.eat(&token::BinOp(token::Or)) { + pats.push(self.parse_pat_with_range_pat( + true, expected + )?); + } + + let or_pattern_span = lo.to(self.prev_span); + + self.sess.or_pattern_spans.borrow_mut().push(or_pattern_span); + + Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -240,7 +271,9 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { - let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { + p.parse_pat_with_or(None) + })?; // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. @@ -483,7 +516,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None))?; Ok(PatKind::TupleStruct(path, fields)) } @@ -627,7 +660,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat(None)?; + let pat = self.parse_pat_with_or(None)?; hi = pat.span; (pat, fieldname, false) } else { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8a7009828bc..4dc00af4860 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -436,18 +436,30 @@ pub trait PrintState<'a>: std::ops::Deref<Target=pp::Printer> + std::ops::DerefM fn print_ident(&mut self, ident: ast::Ident); fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool); - fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F) + fn strsep<T, F>(&mut self, sep: &'static str, space_before: bool, + b: Breaks, elts: &[T], mut op: F) where F: FnMut(&mut Self, &T), { self.rbox(0, b); - let mut first = true; - for elt in elts { - if first { first = false; } else { self.word_space(","); } - op(self, elt); + if let Some((first, rest)) = elts.split_first() { + op(self, first); + for elt in rest { + if space_before { + self.space(); + } + self.word_space(sep); + op(self, elt); + } } self.end(); } + fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F) + where F: FnMut(&mut Self, &T), + { + self.strsep(",", false, b, elts, op) + } + fn maybe_print_comment(&mut self, pos: BytePos) { while let Some(ref cmnt) = self.next_comment() { if cmnt.pos < pos { @@ -2353,6 +2365,9 @@ impl<'a> State<'a> { self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); self.pclose(); } + PatKind::Or(ref pats) => { + self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p)); + } PatKind::Path(None, ref path) => { self.print_path(path, true, 0); } @@ -2429,16 +2444,7 @@ impl<'a> State<'a> { } fn print_pats(&mut self, pats: &[P<ast::Pat>]) { - let mut first = true; - for p in pats { - if first { - first = false; - } else { - self.s.space(); - self.word_space("|"); - } - self.print_pat(p); - } + self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p)); } fn print_arm(&mut self, arm: &ast::Arm) { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 6648347d4ae..91b92d84a81 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -447,9 +447,6 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { visitor.visit_pat(&field.pat) } } - PatKind::Tuple(ref elems) => { - walk_list!(visitor, visit_pat, elems); - } PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) | PatKind::Paren(ref subpattern) => { @@ -465,7 +462,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { visitor.visit_expr(upper_bound); } PatKind::Wild | PatKind::Rest => {}, - PatKind::Slice(ref elems) => { + PatKind::Tuple(ref elems) + | PatKind::Slice(ref elems) + | PatKind::Or(ref elems) => { walk_list!(visitor, visit_pat, elems); } PatKind::Mac(ref mac) => visitor.visit_mac(mac), |
