diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c721624323923..cb7b93d2ef24b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -40,8 +40,8 @@ use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces}; use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource}; use ast::{MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; -use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; -use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; +use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion}; +use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle}; use ast::{PolyTraitRef, QSelf}; use ast::{Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; @@ -86,12 +86,10 @@ bitflags! { flags Restrictions: u8 { const UNRESTRICTED = 0b0000, const RESTRICTION_STMT_EXPR = 0b0001, - const RESTRICTION_NO_BAR_OP = 0b0010, - const RESTRICTION_NO_STRUCT_LITERAL = 0b0100, + const RESTRICTION_NO_STRUCT_LITERAL = 0b0010, } } - type ItemInfo = (Ident, Item_, Option >); /// How to parse a path. There are four different kinds of paths, all of which @@ -2603,13 +2601,6 @@ impl<'a> Parser<'a> { pub fn parse_more_binops(&mut self, lhs: P, min_prec: usize) -> P { if self.expr_is_complete(&*lhs) { return lhs; } - // Prevent dynamic borrow errors later on by limiting the - // scope of the borrows. - if self.token == token::BinOp(token::Or) && - self.restrictions.contains(RESTRICTION_NO_BAR_OP) { - return lhs; - } - self.expected_tokens.push(TokenType::Operator); let cur_op_span = self.span; @@ -2956,6 +2947,22 @@ impl<'a> Parser<'a> { }; } + fn parse_pat_tuple_elements(&mut self) -> Vec> { + let mut fields = vec![]; + if !self.check(&token::CloseDelim(token::Paren)) { + fields.push(self.parse_pat()); + if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) { + while self.eat(&token::Comma) && !self.check(&token::CloseDelim(token::Paren)) { + fields.push(self.parse_pat()); + } + } + if fields.len() == 1 { + self.expect(&token::Comma); + } + } + fields + } + fn parse_pat_vec_elements( &mut self, ) -> (Vec>, Option>, Vec>) { @@ -3087,250 +3094,145 @@ impl<'a> Parser<'a> { return (fields, etc); } + fn parse_pat_range_end(&mut self) -> P { + if self.is_path_start() { + let lo = self.span.lo; + let path = self.parse_path(LifetimeAndTypesWithColons); + let hi = self.last_span.hi; + self.mk_expr(lo, hi, ExprPath(None, path)) + } else { + self.parse_literal_maybe_minus() + } + } + + fn is_path_start(&self) -> bool { + (self.token == token::ModSep || self.token.is_ident() || self.token.is_path()) + && !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False) + } + /// Parse a pattern. pub fn parse_pat(&mut self) -> P { maybe_whole!(self, NtPat); let lo = self.span.lo; - let mut hi; let pat; match self.token { - // parse _ token::Underscore => { + // Parse _ self.bump(); pat = PatWild(PatWildSingle); - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) } token::BinOp(token::And) | token::AndAnd => { - // parse &pat and &mut pat - let lo = self.span.lo; + // Parse &pat / &mut pat self.expect_and(); - let mutability = if self.eat_keyword(keywords::Mut) { - ast::MutMutable - } else { - ast::MutImmutable - }; - let sub = self.parse_pat(); - pat = PatRegion(sub, mutability); - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) + let mutbl = self.parse_mutability(); + let subpat = self.parse_pat(); + pat = PatRegion(subpat, mutbl); } token::OpenDelim(token::Paren) => { - // parse (pat,pat,pat,...) as tuple + // Parse (pat,pat,pat,...) as tuple pattern self.bump(); - if self.check(&token::CloseDelim(token::Paren)) { - self.bump(); - pat = PatTup(vec![]); - } else { - let mut fields = vec!(self.parse_pat()); - if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) { - while self.check(&token::Comma) { - self.bump(); - if self.check(&token::CloseDelim(token::Paren)) { break; } - fields.push(self.parse_pat()); - } - } - if fields.len() == 1 { self.expect(&token::Comma); } - self.expect(&token::CloseDelim(token::Paren)); - pat = PatTup(fields); - } - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) + let fields = self.parse_pat_tuple_elements(); + self.expect(&token::CloseDelim(token::Paren)); + pat = PatTup(fields); } token::OpenDelim(token::Bracket) => { - // parse [pat,pat,...] as vector pattern + // Parse [pat,pat,...] as vector pattern self.bump(); - let (before, slice, after) = - self.parse_pat_vec_elements(); - + let (before, slice, after) = self.parse_pat_vec_elements(); self.expect(&token::CloseDelim(token::Bracket)); - pat = ast::PatVec(before, slice, after); - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) + pat = PatVec(before, slice, after); } - _ => {} - } - // at this point, token != _, ~, &, &&, (, [ - - if (!(self.token.is_ident() || self.token.is_path()) - && self.token != token::ModSep) - || self.token.is_keyword(keywords::True) - || self.token.is_keyword(keywords::False) { - // Parse an expression pattern or exp ... exp. - // - // These expressions are limited to literals (possibly - // preceded by unary-minus) or identifiers. - let val = self.parse_literal_maybe_minus(); - if (self.check(&token::DotDotDot)) && - self.look_ahead(1, |t| { - *t != token::Comma && *t != token::CloseDelim(token::Bracket) - }) { - self.bump(); - let end = if self.token.is_ident() || self.token.is_path() { - let path = self.parse_path(LifetimeAndTypesWithColons); - let hi = self.span.hi; - self.mk_expr(lo, hi, ExprPath(None, path)) - } else { - self.parse_literal_maybe_minus() - }; - pat = PatRange(val, end); - } else { - pat = PatLit(val); - } - } else if self.eat_keyword(keywords::Mut) { - pat = self.parse_pat_ident(BindByValue(MutMutable)); - } else if self.eat_keyword(keywords::Ref) { - // parse ref pat - let mutbl = self.parse_mutability(); - pat = self.parse_pat_ident(BindByRef(mutbl)); - } else if self.eat_keyword(keywords::Box) { - // `box PAT` - // - // FIXME(#13910): Rename to `PatBox` and extend to full DST - // support. - let sub = self.parse_pat(); - pat = PatBox(sub); - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) - } else { - let can_be_enum_or_struct = self.look_ahead(1, |t| { - match *t { - token::OpenDelim(_) | token::Lt | token::ModSep => true, - _ => false, - } - }); - - if self.look_ahead(1, |t| *t == token::DotDotDot) && - self.look_ahead(2, |t| { - *t != token::Comma && *t != token::CloseDelim(token::Bracket) - }) { - let start = self.parse_expr_res(RESTRICTION_NO_BAR_OP); - self.eat(&token::DotDotDot); - let end = self.parse_expr_res(RESTRICTION_NO_BAR_OP); - pat = PatRange(start, end); - } else if self.token.is_plain_ident() && !can_be_enum_or_struct { - let id = self.parse_ident(); - let id_span = self.last_span; - let pth1 = codemap::Spanned{span:id_span, node: id}; - if self.eat(&token::Not) { - // macro invocation - let delim = self.expect_open_delim(); - let tts = self.parse_seq_to_end(&token::CloseDelim(delim), - seq_sep_none(), - |p| p.parse_token_tree()); - - let mac = MacInvocTT(ident_to_path(id_span,id), tts, EMPTY_CTXT); - pat = ast::PatMac(codemap::Spanned {node: mac, span: self.span}); - } else { - let sub = if self.eat(&token::At) { - // parse foo @ pat - Some(self.parse_pat()) - } else { - // or just foo - None - }; - pat = PatIdent(BindByValue(MutImmutable), pth1, sub); - } - } else if self.look_ahead(1, |t| *t == token::Lt) { - self.bump(); - self.unexpected() - } else { - // parse an enum pat - let enum_path = self.parse_path(LifetimeAndTypesWithColons); - match self.token { - token::OpenDelim(token::Brace) => { - self.bump(); - let (fields, etc) = - self.parse_pat_fields(); + _ => { + // At this point, token != _, &, &&, (, [ + if self.eat_keyword(keywords::Mut) { + // Parse mut ident @ pat + pat = self.parse_pat_ident(BindByValue(MutMutable)); + } else if self.eat_keyword(keywords::Ref) { + // Parse ref ident @ pat / ref mut ident @ pat + let mutbl = self.parse_mutability(); + pat = self.parse_pat_ident(BindByRef(mutbl)); + } else if self.eat_keyword(keywords::Box) { + // Parse box pat + let subpat = self.parse_pat(); + pat = PatBox(subpat); + } else if self.is_path_start() { + // Parse pattern starting with a path + if self.token.is_plain_ident() && self.look_ahead(1, |t| *t != token::DotDotDot && + *t != token::OpenDelim(token::Brace) && + *t != token::OpenDelim(token::Paren)) { + // Plain idents have some extra abilities here compared to general paths + if self.look_ahead(1, |t| *t == token::Not) { + // Parse macro invocation + let ident = self.parse_ident(); + let ident_span = self.last_span; + let path = ident_to_path(ident_span, ident); self.bump(); - pat = PatStruct(enum_path, fields, etc); + let delim = self.expect_open_delim(); + let tts = self.parse_seq_to_end(&token::CloseDelim(delim), + seq_sep_none(), |p| p.parse_token_tree()); + let mac = MacInvocTT(path, tts, EMPTY_CTXT); + pat = PatMac(codemap::Spanned {node: mac, span: self.span}); + } else { + // Parse ident @ pat + // This can give false positives and parse nullary enums, + // they are dealt with later in resolve + pat = self.parse_pat_ident(BindByValue(MutImmutable)); } - token::DotDotDot => { + } else { + // Parse as a general path + let path = self.parse_path(LifetimeAndTypesWithColons); + match self.token { + token::DotDotDot => { + // Parse range let hi = self.last_span.hi; - let start = self.mk_expr(lo, hi, ExprPath(None, enum_path)); - self.eat(&token::DotDotDot); - let end = if self.token.is_ident() || self.token.is_path() { - let path = self.parse_path(LifetimeAndTypesWithColons); - let hi = self.span.hi; - self.mk_expr(lo, hi, ExprPath(None, path)) + let begin = self.mk_expr(lo, hi, ExprPath(None, path)); + self.bump(); + let end = self.parse_pat_range_end(); + pat = PatRange(begin, end); + } + token::OpenDelim(token::Brace) => { + // Parse struct pattern + self.bump(); + let (fields, etc) = self.parse_pat_fields(); + self.bump(); + pat = PatStruct(path, fields, etc); + } + token::OpenDelim(token::Paren) => { + // Parse tuple struct or enum pattern + if self.look_ahead(1, |t| *t == token::DotDot) { + // This is a "top constructor only" pat + self.bump(); + self.bump(); + self.expect(&token::CloseDelim(token::Paren)); + pat = PatEnum(path, None); } else { - self.parse_literal_maybe_minus() - }; - pat = PatRange(start, end); - } - _ => { - let mut args: Vec> = Vec::new(); - match self.token { - token::OpenDelim(token::Paren) => { - let is_dotdot = self.look_ahead(1, |t| { - match *t { - token::DotDot => true, - _ => false, - } - }); - if is_dotdot { - // This is a "top constructor only" pat - self.bump(); - self.bump(); - self.expect(&token::CloseDelim(token::Paren)); - pat = PatEnum(enum_path, None); - } else { - args = self.parse_enum_variant_seq( - &token::OpenDelim(token::Paren), + let args = self.parse_enum_variant_seq(&token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), - seq_sep_trailing_allowed(token::Comma), - |p| p.parse_pat() - ); - pat = PatEnum(enum_path, Some(args)); - } - }, - _ => { - if !enum_path.global && - enum_path.segments.len() == 1 && - enum_path.segments[0].parameters.is_empty() - { - // NB: If enum_path is a single identifier, - // this should not be reachable due to special - // handling further above. - // - // However, previously a PatIdent got emitted - // here, so we preserve the branch just in case. - // - // A rewrite of the logic in this function - // would probably make this obvious. - self.span_bug(enum_path.span, - "ident only path should have been covered already"); - } else { - pat = PatEnum(enum_path, Some(args)); - } - } + seq_sep_trailing_allowed(token::Comma), |p| p.parse_pat()); + pat = PatEnum(path, Some(args)); } + } + _ => { + // Parse nullary enum + pat = PatEnum(path, Some(vec![])); + } } } + } else { + // Try to parse everything else as literal with optional minus + let begin = self.parse_literal_maybe_minus(); + if self.eat(&token::DotDotDot) { + let end = self.parse_pat_range_end(); + pat = PatRange(begin, end); + } else { + pat = PatLit(begin); + } } + } } - hi = self.last_span.hi; + + let hi = self.last_span.hi; P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, diff --git a/src/test/compile-fail/issue-22426-1.rs b/src/test/compile-fail/issue-22426-1.rs index f026a5db551e4..6d3d120778830 100644 --- a/src/test/compile-fail/issue-22426-1.rs +++ b/src/test/compile-fail/issue-22426-1.rs @@ -11,7 +11,7 @@ fn main() { match 42 { x < 7 => (), - //~^ error: unexpected token: `<` + //~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<` _ => () } } diff --git a/src/test/compile-fail/issue-22426-2.rs b/src/test/compile-fail/issue-22426-2.rs index ea5180e3eec61..6a0653041d45b 100644 --- a/src/test/compile-fail/issue-22426-2.rs +++ b/src/test/compile-fail/issue-22426-2.rs @@ -9,4 +9,4 @@ // except according to those terms. fn a(B<) {} - //~^ error: unexpected token: `<` + //~^ error: expected one of `:` or `@`, found `<` diff --git a/src/test/compile-fail/issue-22426-3.rs b/src/test/compile-fail/issue-22426-3.rs index 2e0b5d6b80fa7..8ea2bcf900c97 100644 --- a/src/test/compile-fail/issue-22426-3.rs +++ b/src/test/compile-fail/issue-22426-3.rs @@ -14,7 +14,7 @@ impl Foo { fn foo(&self) { match *self { Foo(x, y) => { - //~^ error: unexpected token: `<` + //~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<` println!("Goodbye, World!") } } diff --git a/src/test/parse-fail/issue-22647.rs b/src/test/parse-fail/issue-22647.rs index 5de8627001087..1ace57edba3d8 100644 --- a/src/test/parse-fail/issue-22647.rs +++ b/src/test/parse-fail/issue-22647.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let caller = |f: F| //~ ERROR unexpected token: `<` + let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` where F: Fn() -> i32 { let x = f(); diff --git a/src/test/parse-fail/issue-22712.rs b/src/test/parse-fail/issue-22712.rs index abc9e599467e9..ed936cdd9a934 100644 --- a/src/test/parse-fail/issue-22712.rs +++ b/src/test/parse-fail/issue-22712.rs @@ -13,7 +13,7 @@ struct Foo { } fn bar() { - let Foo> //~ ERROR unexpected token: `<` + let Foo> //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` } fn main() {} diff --git a/src/test/parse-fail/match-vec-invalid.rs b/src/test/parse-fail/match-vec-invalid.rs index 3e073d34f3261..0fc00c350748a 100644 --- a/src/test/parse-fail/match-vec-invalid.rs +++ b/src/test/parse-fail/match-vec-invalid.rs @@ -11,7 +11,7 @@ fn main() { let a = Vec::new(); match a { - [1, tail.., tail..] => {}, //~ ERROR: expected one of `!`, `,`, or `@`, found `..` + [1, tail.., tail..] => {}, //~ ERROR: expected one of `,` or `@`, found `..` _ => () } } diff --git a/src/test/parse-fail/omitted-arg-in-item-fn.rs b/src/test/parse-fail/omitted-arg-in-item-fn.rs index 729b45df8b430..2826d3b4af942 100644 --- a/src/test/parse-fail/omitted-arg-in-item-fn.rs +++ b/src/test/parse-fail/omitted-arg-in-item-fn.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(x) { //~ ERROR expected one of `!`, `:`, or `@`, found `)` +fn foo(x) { //~ ERROR expected one of `:` or `@`, found `)` } diff --git a/src/test/parse-fail/removed-syntax-larrow-init.rs b/src/test/parse-fail/removed-syntax-larrow-init.rs index 1474cc9dd396d..116848c42c28e 100644 --- a/src/test/parse-fail/removed-syntax-larrow-init.rs +++ b/src/test/parse-fail/removed-syntax-larrow-init.rs @@ -11,5 +11,5 @@ fn removed_moves() { let mut x = 0; let y <- x; - //~^ ERROR expected one of `!`, `:`, `;`, `=`, or `@`, found `<-` + //~^ ERROR expected one of `:`, `;`, `=`, or `@`, found `<-` } diff --git a/src/test/parse-fail/struct-literal-in-match-discriminant.rs b/src/test/parse-fail/struct-literal-in-match-discriminant.rs index cdcf98a42f94b..85addc822939d 100644 --- a/src/test/parse-fail/struct-literal-in-match-discriminant.rs +++ b/src/test/parse-fail/struct-literal-in-match-discriminant.rs @@ -14,7 +14,7 @@ struct Foo { fn main() { match Foo { - x: 3 //~ ERROR expected one of `!`, `=>`, `@`, `if`, or `|`, found `:` + x: 3 //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `:` } { Foo { x: x