diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-02-24 15:27:06 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-03-01 01:47:56 +0300 |
| commit | c9aff92e6dc3ea43228d3d4e24ee7f5485943569 (patch) | |
| tree | 84fe8eb3d8ea997a2fecd31c818ce040a3f741af /src/libsyntax | |
| parent | 0ff9872b2280009f094af0df3dcdc542cc46a5fd (diff) | |
| download | rust-c9aff92e6dc3ea43228d3d4e24ee7f5485943569.tar.gz rust-c9aff92e6dc3ea43228d3d4e24ee7f5485943569.zip | |
Support parentheses in patterns under feature gate
Improve recovery for trailing comma after `..`
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 66 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 3 |
6 files changed, 58 insertions, 28 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6609b77b132..40000bc378e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -562,7 +562,7 @@ impl Pat { PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => { s.iter().all(|p| p.walk(it)) } - PatKind::Box(ref s) | PatKind::Ref(ref s, _) => { + PatKind::Box(ref s) | PatKind::Ref(ref s, _) | PatKind::Paren(ref s) => { s.walk(it) } PatKind::Slice(ref before, ref slice, ref after) => { @@ -656,6 +656,8 @@ pub enum PatKind { /// `[a, b, ..i, y, z]` is represented as: /// `PatKind::Slice(box [a, b], Some(i), box [y, z])` Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), + /// Parentheses in patters used for grouping, i.e. `(PAT)`. + Paren(P<Pat>), /// A macro pattern; pre-expansion Mac(Mac), } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1ebf52e9fe8..c9ac34aa917 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -449,6 +449,9 @@ declare_features! ( // Multiple patterns with `|` in `if let` and `while let` (active, if_while_or_patterns, "1.26.0", Some(48215)), + + // Parentheses in patterns + (active, pattern_parentheses, "1.26.0", None), ); declare_features! ( @@ -1663,6 +1666,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span, "`..=` syntax in patterns is experimental"); } + PatKind::Paren(..) => { + gate_feature_post!(&self, pattern_parentheses, pattern.span, + "parentheses in patterns are unstable"); + } _ => {} } visit::walk_pat(self, pattern) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index e8eb75f5e60..1963ab45f1a 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1148,6 +1148,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> { slice.map(|x| folder.fold_pat(x)), after.move_map(|x| folder.fold_pat(x))) } + PatKind::Paren(inner) => PatKind::Paren(folder.fold_pat(inner)), PatKind::Mac(mac) => PatKind::Mac(folder.fold_mac(mac)) }, span: folder.new_span(span) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 09dd00fa5fa..881e3e412d4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3484,33 +3484,47 @@ impl<'a> Parser<'a> { }; } - fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool) - -> PResult<'a, (Vec<P<Pat>>, Option<usize>)> { - let mut fields = vec![]; - let mut ddpos = None; + // Parses a parenthesized list of patterns like + // `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns: + // - a vector of the patterns that were parsed + // - an option indicating the index of the `..` element + // - a boolean indicating whether a trailing comma was present. + // Trailing commas are significant because (p) and (p,) are different patterns. + fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> { + self.expect(&token::OpenDelim(token::Paren))?; - while !self.check(&token::CloseDelim(token::Paren)) { - if ddpos.is_none() && self.eat(&token::DotDot) { - ddpos = Some(fields.len()); - if self.eat(&token::Comma) { - // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed. - fields.push(self.parse_pat()?); + let mut fields = Vec::new(); + let mut ddpos = None; + let mut trailing_comma = false; + loop { + if self.eat(&token::DotDot) { + if ddpos.is_none() { + ddpos = Some(fields.len()); + } else { + // Emit a friendly error, ignore `..` and continue parsing + self.span_err(self.prev_span, + "`..` can only be used once per tuple or tuple struct pattern"); } - } else if ddpos.is_some() && self.eat(&token::DotDot) { - // Emit a friendly error, ignore `..` and continue parsing - self.span_err(self.prev_span, "`..` can only be used once per \ - tuple or tuple struct pattern"); - } else { + } else if !self.check(&token::CloseDelim(token::Paren)) { fields.push(self.parse_pat()?); + } else { + break } - if !self.check(&token::CloseDelim(token::Paren)) || - (unary_needs_comma && fields.len() == 1 && ddpos.is_none()) { - self.expect(&token::Comma)?; + trailing_comma = self.eat(&token::Comma); + if !trailing_comma { + break } } - Ok((fields, ddpos)) + if ddpos == Some(fields.len()) && trailing_comma { + // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed. + self.span_err(self.prev_span, "trailing comma is not permitted after `..`"); + } + + self.expect(&token::CloseDelim(token::Paren))?; + + Ok((fields, ddpos, trailing_comma)) } fn parse_pat_vec_elements( @@ -3714,10 +3728,12 @@ impl<'a> Parser<'a> { } token::OpenDelim(token::Paren) => { // Parse (pat,pat,pat,...) as tuple pattern - self.bump(); - let (fields, ddpos) = self.parse_pat_tuple_elements(true)?; - self.expect(&token::CloseDelim(token::Paren))?; - pat = PatKind::Tuple(fields, ddpos); + let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?; + pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma { + PatKind::Paren(fields.into_iter().nth(0).unwrap()) + } else { + PatKind::Tuple(fields, ddpos) + }; } token::OpenDelim(token::Bracket) => { // Parse [pat,pat,...] as slice pattern @@ -3807,9 +3823,7 @@ impl<'a> Parser<'a> { return Err(self.fatal("unexpected `(` after qualified path")); } // Parse tuple struct or enum pattern - self.bump(); - let (fields, ddpos) = self.parse_pat_tuple_elements(false)?; - self.expect(&token::CloseDelim(token::Paren))?; + let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?; pat = PatKind::TupleStruct(path, fields, ddpos) } _ => pat = PatKind::Path(qself, path), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 9cad9f46e98..77afafbb4e0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2659,6 +2659,11 @@ impl<'a> State<'a> { |s, p| s.print_pat(p))?; self.s.word("]")?; } + PatKind::Paren(ref inner) => { + self.popen()?; + self.print_pat(inner)?; + self.pclose()?; + } PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?, } self.ann.post(self, NodePat(pat)) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 640f90ecb4a..5a24c61cb5a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -425,7 +425,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { walk_list!(visitor, visit_pat, tuple_elements); } PatKind::Box(ref subpattern) | - PatKind::Ref(ref subpattern, _) => { + PatKind::Ref(ref subpattern, _) | + PatKind::Paren(ref subpattern) => { visitor.visit_pat(subpattern) } PatKind::Ident(_, ref pth1, ref optional_subpattern) => { |
