diff options
| author | bors <bors@rust-lang.org> | 2019-07-28 09:12:04 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-07-28 09:12:04 +0000 |
| commit | 0cfb2f7fbda1d27e12913d21d1c8e56a4133dbe1 (patch) | |
| tree | 5f511147f1c0f419f26fb362c24710e1cd459ec6 /src/libsyntax | |
| parent | 9a239ef4ded03d155c72b68b5a2dd7aff013e141 (diff) | |
| parent | 370aa19f28ea6d42f1aaf6de39a294e5e4e9aab7 (diff) | |
| download | rust-0cfb2f7fbda1d27e12913d21d1c8e56a4133dbe1.tar.gz rust-0cfb2f7fbda1d27e12913d21d1c8e56a4133dbe1.zip | |
Auto merge of #63074 - Centril:rollup-k1a8z0n, r=Centril
Rollup of 8 pull requests Successful merges: - #62550 (Implement RFC 2707 + Parser recovery for range patterns) - #62759 (Actually add rustc-guide to toolstate, don't fail builds for the guide) - #62806 (Fix few Clippy warnings) - #62974 (bump crossbeam-epoch dependency) - #63051 (Avoid ICE when referencing desugared local binding in borrow error) - #63061 (In which we constantly improve the Vec(Deque) array PartialEq impls) - #63067 (Add test for issue-50900) - #63071 (Allow rustbot to add `F-*` + `requires-nightly`.) Failed merges: r? @ghost
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 66 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 22 | ||||
| -rw-r--r-- | src/libsyntax/mut_visit.rs | 14 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 525 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 56 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 16 |
7 files changed, 318 insertions, 385 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index dbfad3ef7f4..a7453f4f9da 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -519,21 +519,28 @@ impl fmt::Debug for Pat { } impl Pat { + /// Attempt reparsing the pattern as a type. + /// This is intended for use by diagnostics. pub(super) fn to_ty(&self) -> Option<P<Ty>> { let node = match &self.node { + // In a type expression `_` is an inference variable. PatKind::Wild => TyKind::Infer, + // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`. PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) => { TyKind::Path(None, Path::from_ident(*ident)) } PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()), PatKind::Mac(mac) => TyKind::Mac(mac.clone()), + // `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type. PatKind::Ref(pat, mutbl) => pat .to_ty() .map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?, - PatKind::Slice(pats, None, _) if pats.len() == 1 => { - pats[0].to_ty().map(TyKind::Slice)? - } - PatKind::Tuple(pats, None) => { + // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array, + // when `P` can be reparsed as a type `T`. + PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?, + // A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)` + // assuming `T0` to `Tn` are all syntactically valid as types. + PatKind::Tuple(pats) => { let mut tys = Vec::with_capacity(pats.len()); // FIXME(#48994) - could just be collected into an Option<Vec> for pat in pats { @@ -559,19 +566,15 @@ impl Pat { return false; } - match self.node { - PatKind::Ident(_, _, Some(ref p)) => p.walk(it), - PatKind::Struct(_, ref fields, _) => fields.iter().all(|field| field.node.pat.walk(it)), - PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => { + match &self.node { + PatKind::Ident(_, _, Some(p)) => p.walk(it), + PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.node.pat.walk(it)), + PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => { s.iter().all(|p| p.walk(it)) } - PatKind::Box(ref s) | PatKind::Ref(ref s, _) | PatKind::Paren(ref s) => s.walk(it), - PatKind::Slice(ref before, ref slice, ref after) => { - before.iter().all(|p| p.walk(it)) - && slice.iter().all(|p| p.walk(it)) - && after.iter().all(|p| p.walk(it)) - } + PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it), PatKind::Wild + | PatKind::Rest | PatKind::Lit(_) | PatKind::Range(..) | PatKind::Ident(..) @@ -579,6 +582,14 @@ impl Pat { | PatKind::Mac(_) => true, } } + + /// Is this a `..` pattern? + pub fn is_rest(&self) -> bool { + match self.node { + PatKind::Rest => true, + _ => false, + } + } } /// A single field in a struct pattern @@ -630,9 +641,7 @@ pub enum PatKind { Struct(Path, Vec<Spanned<FieldPat>>, /* recovered */ bool), /// A tuple struct/variant pattern (`Variant(x, y, .., z)`). - /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position. - /// `0 <= position <= subpats.len()`. - TupleStruct(Path, Vec<P<Pat>>, Option<usize>), + TupleStruct(Path, Vec<P<Pat>>), /// A possibly qualified path pattern. /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants @@ -641,9 +650,7 @@ pub enum PatKind { Path(Option<QSelf>, Path), /// A tuple pattern (`(a, b)`). - /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position. - /// `0 <= position <= subpats.len()`. - Tuple(Vec<P<Pat>>, Option<usize>), + Tuple(Vec<P<Pat>>), /// A `box` pattern. Box(P<Pat>), @@ -657,9 +664,22 @@ pub enum PatKind { /// A range pattern (e.g., `1...2`, `1..=2` or `1..2`). Range(P<Expr>, P<Expr>, Spanned<RangeEnd>), - /// `[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>>), + /// A slice pattern `[a, b, c]`. + Slice(Vec<P<Pat>>), + + /// A rest pattern `..`. + /// + /// Syntactically it is valid anywhere. + /// + /// Semantically however, it only has meaning immediately inside: + /// - a slice pattern: `[a, .., b]`, + /// - a binding pattern immediately inside a slice pattern: `[a, r @ ..]`, + /// - a tuple pattern: `(a, .., b)`, + /// - a tuple struct/variant pattern: `$path(a, .., b)`. + /// + /// In all of these cases, an additional restriction applies, + /// only one rest pattern may occur in the pattern sequences. + Rest, /// Parentheses in patterns used for grouping (i.e., `(PAT)`). Paren(P<Pat>), diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index baf1031de1e..528b27d6153 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -840,14 +840,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn pat_tuple_struct(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> { - self.pat(span, PatKind::TupleStruct(path, subpats, None)) + self.pat(span, PatKind::TupleStruct(path, subpats)) } fn pat_struct(&self, span: Span, path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> { self.pat(span, PatKind::Struct(path, field_pats, false)) } fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> { - self.pat(span, PatKind::Tuple(pats, None)) + self.pat(span, PatKind::Tuple(pats)) } fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 72184b0bd64..384474b08f6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -2151,11 +2151,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_pat(&mut self, pattern: &'a ast::Pat) { - match pattern.node { - PatKind::Slice(_, Some(ref subslice), _) => { - gate_feature_post!(&self, slice_patterns, - subslice.span, - "syntax for subslices in slice patterns is not yet stabilized"); + match &pattern.node { + PatKind::Slice(pats) => { + for pat in &*pats { + let span = pat.span; + let inner_pat = match &pat.node { + PatKind::Ident(.., Some(pat)) => pat, + _ => pat, + }; + if inner_pat.is_rest() { + gate_feature_post!( + &self, + slice_patterns, + span, + "subslice patterns are unstable" + ); + } + } } PatKind::Box(..) => { gate_feature_post!(&self, box_patterns, diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index dc656222fbc..86525406718 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1020,15 +1020,15 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { let Pat { id, node, span } = pat.deref_mut(); vis.visit_id(id); match node { - PatKind::Wild => {} + PatKind::Wild | PatKind::Rest => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); } PatKind::Lit(e) => vis.visit_expr(e), - PatKind::TupleStruct(path, pats, _ddpos) => { + PatKind::TupleStruct(path, elems) => { vis.visit_path(path); - visit_vec(pats, |pat| vis.visit_pat(pat)); + visit_vec(elems, |elem| vis.visit_pat(elem)); } PatKind::Path(qself, path) => { vis.visit_qself(qself); @@ -1043,7 +1043,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { vis.visit_span(span); }; } - PatKind::Tuple(elts, _ddpos) => visit_vec(elts, |elt| vis.visit_pat(elt)), + 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: _ }) => { @@ -1051,11 +1051,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { vis.visit_expr(e2); vis.visit_span(span); } - PatKind::Slice(before, slice, after) => { - visit_vec(before, |pat| vis.visit_pat(pat)); - visit_opt(slice, |slice| vis.visit_pat(slice)); - visit_vec(after, |pat| vis.visit_pat(pat)); - } + PatKind::Slice(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/parser.rs b/src/libsyntax/parse/parser.rs index a5b6f0d6836..8f8ed411180 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -890,14 +890,13 @@ impl<'a> Parser<'a> { /// Parses a sequence, including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - pub fn parse_seq_to_end<T, F>(&mut self, - ket: &TokenKind, - sep: SeqSep, - f: F) - -> PResult<'a, Vec<T>> where - F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - { - let (val, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; + pub fn parse_seq_to_end<T>( + &mut self, + ket: &TokenKind, + sep: SeqSep, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, Vec<T>> { + let (val, _, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; if !recovered { self.bump(); } @@ -907,39 +906,39 @@ impl<'a> Parser<'a> { /// Parses a sequence, not including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - pub fn parse_seq_to_before_end<T, F>( + pub fn parse_seq_to_before_end<T>( &mut self, ket: &TokenKind, sep: SeqSep, - f: F, - ) -> PResult<'a, (Vec<T>, bool)> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> - { + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec<T>, bool, bool)> { self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) } - crate fn parse_seq_to_before_tokens<T, F>( + fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool { + kets.iter().any(|k| { + match expect { + TokenExpectType::Expect => self.check(k), + TokenExpectType::NoExpect => self.token == **k, + } + }) + } + + crate fn parse_seq_to_before_tokens<T>( &mut self, kets: &[&TokenKind], sep: SeqSep, expect: TokenExpectType, - mut f: F, - ) -> PResult<'a, (Vec<T>, bool /* recovered */)> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> - { + mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec<T>, bool /* trailing */, bool /* recovered */)> { let mut first = true; let mut recovered = false; + let mut trailing = false; let mut v = vec![]; - while !kets.iter().any(|k| { - match expect { - TokenExpectType::Expect => self.check(k), - TokenExpectType::NoExpect => self.token == **k, - } - }) { - match self.token.kind { - token::CloseDelim(..) | token::Eof => break, - _ => {} - }; + while !self.expect_any_with_type(kets, expect) { + if let token::CloseDelim(..) | token::Eof = self.token.kind { + break + } if let Some(ref t) = sep.sep { if first { first = false; @@ -973,12 +972,8 @@ impl<'a> Parser<'a> { } } } - if sep.trailing_sep_allowed && kets.iter().any(|k| { - match expect { - TokenExpectType::Expect => self.check(k), - TokenExpectType::NoExpect => self.token == **k, - } - }) { + if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) { + trailing = true; break; } @@ -986,27 +981,45 @@ impl<'a> Parser<'a> { v.push(t); } - Ok((v, recovered)) + Ok((v, trailing, recovered)) } /// Parses a sequence, including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - fn parse_unspanned_seq<T, F>( + fn parse_unspanned_seq<T>( &mut self, bra: &TokenKind, ket: &TokenKind, sep: SeqSep, - f: F, - ) -> PResult<'a, Vec<T>> where - F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - { + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec<T>, bool)> { self.expect(bra)?; - let (result, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; + let (result, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; if !recovered { self.eat(ket); } - Ok(result) + Ok((result, trailing)) + } + + fn parse_delim_comma_seq<T>( + &mut self, + delim: DelimToken, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec<T>, bool)> { + self.parse_unspanned_seq( + &token::OpenDelim(delim), + &token::CloseDelim(delim), + SeqSep::trailing_allowed(token::Comma), + f, + ) + } + + fn parse_paren_comma_seq<T>( + &mut self, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec<T>, bool)> { + self.parse_delim_comma_seq(token::Paren, f) } /// Advance the parser by one token @@ -1804,15 +1817,7 @@ impl<'a> Parser<'a> { AngleBracketedArgs { args, constraints, span }.into() } else { // `(T, U) -> R` - self.bump(); // `(` - let (inputs, recovered) = self.parse_seq_to_before_tokens( - &[&token::CloseDelim(token::Paren)], - SeqSep::trailing_allowed(token::Comma), - TokenExpectType::Expect, - |p| p.parse_ty())?; - if !recovered { - self.bump(); // `)` - } + let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; let span = lo.to(self.prev_span); let output = if self.eat(&token::RArrow) { Some(self.parse_ty_common(false, false, false)?) @@ -2516,12 +2521,7 @@ impl<'a> Parser<'a> { Ok(match self.token.kind { token::OpenDelim(token::Paren) => { // Method call `expr.f()` - let mut args = self.parse_unspanned_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| Ok(p.parse_expr()?) - )?; + let mut args = self.parse_paren_expr_seq()?; args.insert(0, self_arg); let span = lo.to(self.prev_span); @@ -2606,12 +2606,7 @@ impl<'a> Parser<'a> { match self.token.kind { // expr(...) token::OpenDelim(token::Paren) => { - let seq = self.parse_unspanned_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| Ok(p.parse_expr()?) - ).map(|es| { + let seq = self.parse_paren_expr_seq().map(|es| { let nd = self.mk_call(e, es); let hi = self.prev_span; self.mk_expr(lo.to(hi), nd, ThinVec::new()) @@ -2635,6 +2630,10 @@ impl<'a> Parser<'a> { return Ok(e); } + fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec<P<Expr>>> { + self.parse_paren_comma_seq(|p| p.parse_expr()).map(|(r, _)| r) + } + crate fn process_potential_macro_variable(&mut self) { self.token = match self.token.kind { token::Dollar if self.token.span.ctxt() != SyntaxContext::empty() && @@ -3536,122 +3535,6 @@ impl<'a> Parser<'a> { }; } - // 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))?; - let result = match self.parse_pat_list() { - Ok(result) => result, - Err(mut err) => { // recover from parse error in tuple pattern list - err.emit(); - self.consume_block(token::Paren); - return Ok((vec![], Some(0), false)); - } - }; - self.expect(&token::CloseDelim(token::Paren))?; - Ok(result) - } - - fn parse_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> { - let mut fields = Vec::new(); - let mut ddpos = None; - let mut prev_dd_sp = None; - let mut trailing_comma = false; - loop { - if self.eat(&token::DotDot) { - if ddpos.is_none() { - ddpos = Some(fields.len()); - prev_dd_sp = Some(self.prev_span); - } else { - // Emit a friendly error, ignore `..` and continue parsing - let mut err = self.struct_span_err( - self.prev_span, - "`..` can only be used once per tuple or tuple struct pattern", - ); - err.span_label(self.prev_span, "can only be used once per pattern"); - if let Some(sp) = prev_dd_sp { - err.span_label(sp, "previously present here"); - } - err.emit(); - } - } else if !self.check(&token::CloseDelim(token::Paren)) { - fields.push(self.parse_pat(None)?); - } else { - break - } - - trailing_comma = self.eat(&token::Comma); - if !trailing_comma { - break - } - } - - if ddpos == Some(fields.len()) && trailing_comma { - // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed. - let msg = "trailing comma is not permitted after `..`"; - self.struct_span_err(self.prev_span, msg) - .span_label(self.prev_span, msg) - .emit(); - } - - Ok((fields, ddpos, trailing_comma)) - } - - fn parse_pat_vec_elements( - &mut self, - ) -> PResult<'a, (Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>)> { - let mut before = Vec::new(); - let mut slice = None; - let mut after = Vec::new(); - let mut first = true; - let mut before_slice = true; - - while self.token != token::CloseDelim(token::Bracket) { - if first { - first = false; - } else { - self.expect(&token::Comma)?; - - if self.token == token::CloseDelim(token::Bracket) - && (before_slice || !after.is_empty()) { - break - } - } - - if before_slice { - if self.eat(&token::DotDot) { - - if self.check(&token::Comma) || - self.check(&token::CloseDelim(token::Bracket)) { - slice = Some(P(Pat { - id: ast::DUMMY_NODE_ID, - node: PatKind::Wild, - span: self.prev_span, - })); - before_slice = false; - } - continue - } - } - - let subpat = self.parse_pat(None)?; - if before_slice && self.eat(&token::DotDot) { - slice = Some(subpat); - before_slice = false; - } else if before_slice { - before.push(subpat); - } else { - after.push(subpat); - } - } - - Ok((before, slice, after)) - } - fn parse_pat_field( &mut self, lo: Span, @@ -3847,20 +3730,34 @@ impl<'a> Parser<'a> { } } - // helper function to decide whether to parse as ident binding or to try to do - // something more complex like range patterns + /// Is the current token suitable as the start of a range patterns end? + fn is_pat_range_end_start(&self) -> bool { + self.token.is_path_start() // e.g. `MY_CONST`; + || self.token == token::Dot // e.g. `.5` for recovery; + || self.token.can_begin_literal_or_bool() // e.g. `42`. + } + + // Helper function to decide whether to parse as ident binding + // or to try to do something more complex like range patterns. fn parse_as_ident(&mut self) -> bool { self.look_ahead(1, |t| match t.kind { token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | - token::DotDotDot | token::DotDotEq | token::ModSep | token::Not => Some(false), - // ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the - // range pattern branch - token::DotDot => None, - _ => Some(true), - }).unwrap_or_else(|| self.look_ahead(2, |t| match t.kind { - token::Comma | token::CloseDelim(token::Bracket) => true, - _ => false, - })) + token::DotDotDot | token::DotDotEq | token::DotDot | + token::ModSep | token::Not => false, + _ => true, + }) + } + + /// Parse and throw away a parentesized comma separated + /// sequence of patterns until `)` is reached. + fn skip_pat_list(&mut self) -> PResult<'a, ()> { + while !self.check(&token::CloseDelim(token::Paren)) { + self.parse_pat(None)?; + if !self.eat(&token::Comma) { + return Ok(()) + } + } + Ok(()) } /// A wrapper around `parse_pat` with some special error handling for the @@ -3876,7 +3773,7 @@ impl<'a> Parser<'a> { // later. let comma_span = self.token.span; self.bump(); - if let Err(mut err) = self.parse_pat_list() { + if let Err(mut err) = self.skip_pat_list() { // We didn't expect this to work anyway; we just wanted // to advance to the end of the comma-sequence so we know // the span to suggest parenthesizing @@ -3908,6 +3805,53 @@ impl<'a> Parser<'a> { self.parse_pat_with_range_pat(true, expected) } + /// Parse a range-to pattern, e.g. `..X` and `..=X` for recovery. + fn parse_pat_range_to(&mut self, re: RangeEnd, form: &str) -> PResult<'a, PatKind> { + let lo = self.prev_span; + let end = self.parse_pat_range_end()?; + let range_span = lo.to(end.span); + let begin = self.mk_expr(range_span, ExprKind::Err, ThinVec::new()); + + self.diagnostic() + .struct_span_err(range_span, &format!("`{}X` range patterns are not supported", form)) + .span_suggestion( + range_span, + "try using the minimum value for the type", + format!("MIN{}{}", form, pprust::expr_to_string(&end)), + Applicability::HasPlaceholders, + ) + .emit(); + + Ok(PatKind::Range(begin, end, respan(lo, re))) + } + + /// Parse the end of a `X..Y`, `X..=Y`, or `X...Y` range pattern or recover + /// if that end is missing treating it as `X..`, `X..=`, or `X...` respectively. + fn parse_pat_range_end_opt(&mut self, begin: &Expr, form: &str) -> PResult<'a, P<Expr>> { + if self.is_pat_range_end_start() { + // Parsing e.g. `X..=Y`. + self.parse_pat_range_end() + } else { + // Parsing e.g. `X..`. + let range_span = begin.span.to(self.prev_span); + + self.diagnostic() + .struct_span_err( + range_span, + &format!("`X{}` range patterns are not supported", form), + ) + .span_suggestion( + range_span, + "try using the maximum value for the type", + format!("{}{}MAX", pprust::expr_to_string(&begin), form), + Applicability::HasPlaceholders, + ) + .emit(); + + Ok(self.mk_expr(range_span, ExprKind::Err, ThinVec::new())) + } + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -3934,20 +3878,41 @@ impl<'a> Parser<'a> { pat = PatKind::Ref(subpat, mutbl); } token::OpenDelim(token::Paren) => { - // Parse (pat,pat,pat,...) as tuple pattern - let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?; - pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma { + // Parse a tuple or parenthesis pattern. + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; + + // Here, `(pat,)` is a tuple pattern. + // For backward compatibility, `(..)` is a tuple pattern as well. + pat = if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) { PatKind::Paren(fields.into_iter().nth(0).unwrap()) } else { - PatKind::Tuple(fields, ddpos) + PatKind::Tuple(fields) }; } token::OpenDelim(token::Bracket) => { - // Parse [pat,pat,...] as slice pattern + // Parse `[pat, pat,...]` as a slice pattern. + let (slice, _) = self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?; + pat = PatKind::Slice(slice); + } + token::DotDot => { + self.bump(); + pat = if self.is_pat_range_end_start() { + // Parse `..42` for recovery. + self.parse_pat_range_to(RangeEnd::Excluded, "..")? + } else { + // A rest pattern `..`. + PatKind::Rest + }; + } + token::DotDotEq => { + // Parse `..=42` for recovery. self.bump(); - let (before, slice, after) = self.parse_pat_vec_elements()?; - self.expect(&token::CloseDelim(token::Bracket))?; - pat = PatKind::Slice(before, slice, after); + pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")?; + } + token::DotDotDot => { + // Parse `...42` for recovery. + self.bump(); + pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?; } // At this point, token != &, &&, (, [ _ => if self.eat_keyword(kw::Underscore) { @@ -4004,10 +3969,10 @@ impl<'a> Parser<'a> { pat = PatKind::Mac(mac); } token::DotDotDot | token::DotDotEq | token::DotDot => { - let end_kind = match self.token.kind { - token::DotDot => RangeEnd::Excluded, - token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot), - token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq), + let (end_kind, form) = match self.token.kind { + token::DotDot => (RangeEnd::Excluded, ".."), + token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."), + token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="), _ => panic!("can only parse `..`/`...`/`..=` for ranges \ (checked above)"), }; @@ -4016,9 +3981,8 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_span); let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new()); self.bump(); - let end = self.parse_pat_range_end()?; - let op = Spanned { span: op_span, node: end_kind }; - pat = PatKind::Range(begin, end, op); + let end = self.parse_pat_range_end_opt(&begin, form)?; + pat = PatKind::Range(begin, end, respan(op_span, end_kind)); } token::OpenDelim(token::Brace) => { if qself.is_some() { @@ -4045,8 +4009,8 @@ impl<'a> Parser<'a> { return Err(err); } // Parse tuple struct or enum pattern - let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?; - pat = PatKind::TupleStruct(path, fields, ddpos) + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; + pat = PatKind::TupleStruct(path, fields) } _ => pat = PatKind::Path(qself, path), } @@ -4057,19 +4021,18 @@ impl<'a> Parser<'a> { let op_span = self.token.span; if self.check(&token::DotDot) || self.check(&token::DotDotEq) || self.check(&token::DotDotDot) { - let end_kind = if self.eat(&token::DotDotDot) { - RangeEnd::Included(RangeSyntax::DotDotDot) + let (end_kind, form) = if self.eat(&token::DotDotDot) { + (RangeEnd::Included(RangeSyntax::DotDotDot), "...") } else if self.eat(&token::DotDotEq) { - RangeEnd::Included(RangeSyntax::DotDotEq) + (RangeEnd::Included(RangeSyntax::DotDotEq), "..=") } else if self.eat(&token::DotDot) { - RangeEnd::Excluded + (RangeEnd::Excluded, "..") } else { panic!("impossible case: we already matched \ on a range-operator token") }; - let end = self.parse_pat_range_end()?; - let op = Spanned { span: op_span, node: end_kind }; - pat = PatKind::Range(begin, end, op); + let end = self.parse_pat_range_end_opt(&begin, form)?; + pat = PatKind::Range(begin, end, respan(op_span, end_kind)) } else { pat = PatKind::Lit(begin); } @@ -5359,59 +5322,48 @@ impl<'a> Parser<'a> { fn parse_fn_args(&mut self, named_args: bool, allow_c_variadic: bool) -> PResult<'a, (Vec<Arg> , bool)> { - self.expect(&token::OpenDelim(token::Paren))?; - let sp = self.token.span; let mut c_variadic = false; - let (args, recovered): (Vec<Option<Arg>>, bool) = - self.parse_seq_to_before_end( - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| { - let do_not_enforce_named_arguments_for_c_variadic = - |token: &token::Token| -> bool { - if token == &token::DotDotDot { - false - } else { - named_args - } - }; - match p.parse_arg_general( - false, - allow_c_variadic, - do_not_enforce_named_arguments_for_c_variadic - ) { - Ok(arg) => { - if let TyKind::CVarArgs = arg.ty.node { - c_variadic = true; - if p.token != token::CloseDelim(token::Paren) { - let span = p.token.span; - p.span_err(span, - "`...` must be the last argument of a C-variadic function"); - Ok(None) - } else { - Ok(Some(arg)) - } - } else { - Ok(Some(arg)) - } - }, - Err(mut e) => { - e.emit(); - let lo = p.prev_span; - // Skip every token until next possible arg or end. - p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); - // Create a placeholder argument for proper arg count (issue #34264). - let span = lo.to(p.prev_span); - Ok(Some(dummy_arg(Ident::new(kw::Invalid, span)))) + let (args, _): (Vec<Option<Arg>>, _) = self.parse_paren_comma_seq(|p| { + let do_not_enforce_named_arguments_for_c_variadic = + |token: &token::Token| -> bool { + if token == &token::DotDotDot { + false + } else { + named_args + } + }; + match p.parse_arg_general( + false, + allow_c_variadic, + do_not_enforce_named_arguments_for_c_variadic + ) { + Ok(arg) => { + if let TyKind::CVarArgs = arg.ty.node { + c_variadic = true; + if p.token != token::CloseDelim(token::Paren) { + let span = p.token.span; + p.span_err(span, + "`...` must be the last argument of a C-variadic function"); + Ok(None) + } else { + Ok(Some(arg)) } + } else { + Ok(Some(arg)) } + }, + Err(mut e) => { + e.emit(); + let lo = p.prev_span; + // Skip every token until next possible arg or end. + p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); + // Create a placeholder argument for proper arg count (issue #34264). + let span = lo.to(p.prev_span); + Ok(Some(dummy_arg(Ident::new(kw::Invalid, span)))) } - )?; - - if !recovered { - self.eat(&token::CloseDelim(token::Paren)); - } + } + })?; let args: Vec<_> = args.into_iter().filter_map(|x| x).collect(); @@ -5573,7 +5525,7 @@ impl<'a> Parser<'a> { (vec![self_arg], false) } else if self.eat(&token::Comma) { let mut fn_inputs = vec![self_arg]; - let (mut input, recovered) = self.parse_seq_to_before_end( + let (mut input, _, recovered) = self.parse_seq_to_before_end( &token::CloseDelim(token::Paren), sep, parse_arg_fn)?; fn_inputs.append(&mut input); (fn_inputs, recovered) @@ -5584,7 +5536,9 @@ impl<'a> Parser<'a> { } } } else { - self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)? + let (input, _, recovered) = + self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?; + (input, recovered) }; if !recovered { @@ -6185,26 +6139,20 @@ impl<'a> Parser<'a> { fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> { // This is the case where we find `struct Foo<T>(T) where T: Copy;` // Unit like structs are handled in parse_item_struct function - let fields = self.parse_unspanned_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| { - let attrs = p.parse_outer_attributes()?; - let lo = p.token.span; - let vis = p.parse_visibility(true)?; - let ty = p.parse_ty()?; - Ok(StructField { - span: lo.to(ty.span), - vis, - ident: None, - id: ast::DUMMY_NODE_ID, - ty, - attrs, - }) - })?; - - Ok(fields) + self.parse_paren_comma_seq(|p| { + let attrs = p.parse_outer_attributes()?; + let lo = p.token.span; + let vis = p.parse_visibility(true)?; + let ty = p.parse_ty()?; + Ok(StructField { + span: lo.to(ty.span), + vis, + ident: None, + id: ast::DUMMY_NODE_ID, + ty, + attrs, + }) + }).map(|(r, _)| r) } /// Parses a structure field declaration. @@ -7786,11 +7734,8 @@ impl<'a> Parser<'a> { /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`] /// ``` fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> { - self.parse_unspanned_seq(&token::OpenDelim(token::Brace), - &token::CloseDelim(token::Brace), - SeqSep::trailing_allowed(token::Comma), |this| { - Ok((this.parse_use_tree()?, ast::DUMMY_NODE_ID)) - }) + self.parse_delim_comma_seq(token::Brace, |p| Ok((p.parse_use_tree()?, ast::DUMMY_NODE_ID))) + .map(|(r, _)| r) } fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c4623576395..c7be0b12302 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2368,22 +2368,10 @@ impl<'a> State<'a> { self.print_pat(p); } } - PatKind::TupleStruct(ref path, ref elts, ddpos) => { + PatKind::TupleStruct(ref path, ref elts) => { self.print_path(path, true, 0); self.popen(); - if let Some(ddpos) = ddpos { - self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); - if ddpos != 0 { - self.word_space(","); - } - self.s.word(".."); - if ddpos != elts.len() { - self.s.word(","); - self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p)); - } - } else { - self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); - } + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); self.pclose(); } PatKind::Path(None, ref path) => { @@ -2415,23 +2403,11 @@ impl<'a> State<'a> { self.s.space(); self.s.word("}"); } - PatKind::Tuple(ref elts, ddpos) => { + PatKind::Tuple(ref elts) => { self.popen(); - if let Some(ddpos) = ddpos { - self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); - if ddpos != 0 { - self.word_space(","); - } - self.s.word(".."); - if ddpos != elts.len() { - self.s.word(","); - self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p)); - } - } else { - self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); - if elts.len() == 1 { - self.s.word(","); - } + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); + if elts.len() == 1 { + self.s.word(","); } self.pclose(); } @@ -2457,26 +2433,12 @@ impl<'a> State<'a> { } self.print_expr(end); } - PatKind::Slice(ref before, ref slice, ref after) => { + PatKind::Slice(ref elts) => { self.s.word("["); - self.commasep(Inconsistent, - &before[..], - |s, p| s.print_pat(p)); - if let Some(ref p) = *slice { - if !before.is_empty() { self.word_space(","); } - if let PatKind::Wild = p.node { - // Print nothing - } else { - self.print_pat(p); - } - self.s.word(".."); - if !after.is_empty() { self.word_space(","); } - } - self.commasep(Inconsistent, - &after[..], - |s, p| s.print_pat(p)); + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); self.s.word("]"); } + PatKind::Rest => self.s.word(".."), PatKind::Paren(ref inner) => { self.popen(); self.print_pat(inner); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9ec9550f93a..ff6440fb9dc 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -428,9 +428,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(visitor: &mut V, pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { match pattern.node { - PatKind::TupleStruct(ref path, ref children, _) => { + PatKind::TupleStruct(ref path, ref elems) => { visitor.visit_path(path, pattern.id); - walk_list!(visitor, visit_pat, children); + walk_list!(visitor, visit_pat, elems); } PatKind::Path(ref opt_qself, ref path) => { if let Some(ref qself) = *opt_qself { @@ -446,8 +446,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { visitor.visit_pat(&field.node.pat) } } - PatKind::Tuple(ref tuple_elements, _) => { - walk_list!(visitor, visit_pat, tuple_elements); + PatKind::Tuple(ref elems) => { + walk_list!(visitor, visit_pat, elems); } PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) | @@ -463,11 +463,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { visitor.visit_expr(lower_bound); visitor.visit_expr(upper_bound); } - PatKind::Wild => (), - PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => { - walk_list!(visitor, visit_pat, prepatterns); - walk_list!(visitor, visit_pat, slice_pattern); - walk_list!(visitor, visit_pat, postpatterns); + PatKind::Wild | PatKind::Rest => {}, + PatKind::Slice(ref elems) => { + walk_list!(visitor, visit_pat, elems); } PatKind::Mac(ref mac) => visitor.visit_mac(mac), } |
