diff options
| author | Djzin <djzin@users.noreply.github.com> | 2017-05-27 14:31:47 +0100 |
|---|---|---|
| committer | Djzin <djzin@users.noreply.github.com> | 2017-05-27 14:31:47 +0100 |
| commit | 74751358e625878306aa193fed788e79aa53d4fa (patch) | |
| tree | 1ba9b336d1ddb45d9f688d69f5bd4ede028db622 /src/libsyntax/parse | |
| parent | c6307a2fa55c3d62c06b85b349257a8194093442 (diff) | |
| parent | 3e7908f616745573a11ad7dfad245f12be0069da (diff) | |
| download | rust-74751358e625878306aa193fed788e79aa53d4fa.tar.gz rust-74751358e625878306aa193fed788e79aa53d4fa.zip | |
Merge remote-tracking branch 'upstream/master' into fast-swap
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/attr.rs | 71 | ||||
| -rw-r--r-- | src/libsyntax/parse/classify.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/parse/common.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/parse/lexer/comments.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/parse/lexer/mod.rs | 206 | ||||
| -rw-r--r-- | src/libsyntax/parse/lexer/unicode_chars.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 349 | ||||
| -rw-r--r-- | src/libsyntax/parse/obsolete.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 1871 | ||||
| -rw-r--r-- | src/libsyntax/parse/token.rs | 123 |
10 files changed, 1454 insertions, 1189 deletions
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index ded676da3c6..082930777e5 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -10,12 +10,12 @@ use attr; use ast; -use syntax_pos::{mk_sp, Span}; -use codemap::spanned; +use codemap::respan; use parse::common::SeqSep; use parse::PResult; -use parse::token; -use parse::parser::{Parser, TokenType}; +use parse::token::{self, Nonterminal}; +use parse::parser::{Parser, TokenType, PathStyle}; +use tokenstream::TokenStream; #[derive(PartialEq, Eq, Debug)] enum InnerAttributeParsePolicy<'a> { @@ -48,8 +48,7 @@ impl<'a> Parser<'a> { just_parsed_doc_comment = false; } token::DocComment(s) => { - let Span { lo, hi, .. } = self.span; - let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi); + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span); if attr.style != ast::AttrStyle::Outer { let mut err = self.fatal("expected outer doc comment"); err.note("inner doc comments like this (starting with \ @@ -63,7 +62,7 @@ impl<'a> Parser<'a> { _ => break, } } - return Ok(attrs); + Ok(attrs) } /// Matches `attribute = # ! [ meta_item ]` @@ -91,9 +90,9 @@ impl<'a> Parser<'a> { debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token); - let (span, value, mut style) = match self.token { + let (span, path, tokens, mut style) = match self.token { token::Pound => { - let lo = self.span.lo; + let lo = self.span; self.bump(); if inner_parse_policy == InnerAttributeParsePolicy::Permitted { @@ -119,11 +118,11 @@ impl<'a> Parser<'a> { }; self.expect(&token::OpenDelim(token::Bracket))?; - let meta_item = self.parse_meta_item()?; + let (path, tokens) = self.parse_path_and_tokens()?; self.expect(&token::CloseDelim(token::Bracket))?; - let hi = self.prev_span.hi; + let hi = self.prev_span; - (mk_sp(lo, hi), meta_item, style) + (lo.to(hi), path, tokens, style) } _ => { let token_str = self.this_token_to_string(); @@ -143,12 +142,30 @@ impl<'a> Parser<'a> { Ok(ast::Attribute { id: attr::mk_attr_id(), style: style, - value: value, + path: path, + tokens: tokens, is_sugared_doc: false, span: span, }) } + pub fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { + let meta = match self.token { + token::Interpolated(ref nt) => match **nt { + Nonterminal::NtMeta(ref meta) => Some(meta.clone()), + _ => None, + }, + _ => None, + }; + Ok(if let Some(meta) = meta { + self.bump(); + (ast::Path::from_ident(meta.span, ast::Ident::with_empty_ctxt(meta.name)), + meta.node.tokens(meta.span)) + } else { + (self.parse_path(PathStyle::Mod)?, self.parse_tokens()) + }) + } + /// Parse attributes that appear after the opening of an item. These should /// be preceded by an exclamation mark, but we accept and warn about one /// terminated by a semicolon. @@ -165,13 +182,12 @@ impl<'a> Parser<'a> { } let attr = self.parse_attribute(true)?; - assert!(attr.style == ast::AttrStyle::Inner); + assert_eq!(attr.style, ast::AttrStyle::Inner); attrs.push(attr); } token::DocComment(s) => { // we need to get the position of this token before we bump. - let Span { lo, hi, .. } = self.span; - let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi); + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span); if attr.style == ast::AttrStyle::Inner { attrs.push(attr); self.bump(); @@ -219,41 +235,44 @@ impl<'a> Parser<'a> { return Ok(meta); } - let lo = self.span.lo; + let lo = self.span; let ident = self.parse_ident()?; - let node = if self.eat(&token::Eq) { + let node = self.parse_meta_item_kind()?; + Ok(ast::MetaItem { name: ident.name, node: node, span: lo.to(self.prev_span) }) + } + + pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { + Ok(if self.eat(&token::Eq) { ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?) } else if self.token == token::OpenDelim(token::Paren) { ast::MetaItemKind::List(self.parse_meta_seq()?) } else { + self.eat(&token::OpenDelim(token::Paren)); ast::MetaItemKind::Word - }; - let hi = self.prev_span.hi; - Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) }) + }) } /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ; fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { - let sp = self.span; - let lo = self.span.lo; + let lo = self.span; match self.parse_unsuffixed_lit() { Ok(lit) => { - return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::Literal(lit))) + return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::Literal(lit))) } Err(ref mut err) => self.diagnostic().cancel(err) } match self.parse_meta_item() { Ok(mi) => { - return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::MetaItem(mi))) + return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::MetaItem(mi))) } Err(ref mut err) => self.diagnostic().cancel(err) } let found = self.this_token_to_string(); let msg = format!("expected unsuffixed literal or identifier, found {}", found); - Err(self.diagnostic().struct_span_err(sp, &msg)) + Err(self.diagnostic().struct_span_err(lo, &msg)) } /// matches meta_seq = ( COMMASEP(meta_item_inner) ) diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs index 4fe4ec7e4c0..0c6f09ba766 100644 --- a/src/libsyntax/parse/classify.rs +++ b/src/libsyntax/parse/classify.rs @@ -43,14 +43,14 @@ pub fn expr_is_simple_block(e: &ast::Expr) -> bool { } /// this statement requires a semicolon after it. -/// note that in one case (stmt_semi), we've already +/// note that in one case (`stmt_semi`), we've already /// seen the semicolon, and thus don't need another. pub fn stmt_ends_with_semi(stmt: &ast::StmtKind) -> bool { match *stmt { ast::StmtKind::Local(_) => true, - ast::StmtKind::Item(_) => false, ast::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(e), - ast::StmtKind::Semi(..) => false, + ast::StmtKind::Item(_) | + ast::StmtKind::Semi(..) | ast::StmtKind::Mac(..) => false, } } diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index b57708f9193..fe931f7cf6a 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -12,7 +12,7 @@ use parse::token; -/// SeqSep : a sequence separator (token) +/// `SeqSep` : a sequence separator (token) /// and whether a trailing separator is allowed. pub struct SeqSep { pub sep: Option<token::Token>, diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index c97b8ddf919..8b545d3b909 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -77,7 +77,7 @@ pub fn strip_doc_comment_decoration(comment: &str) -> String { while j > i && lines[j - 1].trim().is_empty() { j -= 1; } - lines[i..j].iter().cloned().collect() + lines[i..j].to_vec() } /// remove a "[ \t]*\*" block from each line, if possible @@ -348,8 +348,8 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: String, srdr: &mut R let mut src = Vec::new(); srdr.read_to_end(&mut src).unwrap(); let src = String::from_utf8(src).unwrap(); - let cm = CodeMap::new(); - let filemap = cm.new_filemap(path, None, src); + let cm = CodeMap::new(sess.codemap().path_mapping().clone()); + let filemap = cm.new_filemap(path, src); let mut rdr = lexer::StringReader::new_raw(sess, filemap); let mut comments: Vec<Comment> = Vec::new(); diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index de8a87e3a2b..0bcd4578518 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -9,8 +9,8 @@ // except according to those terms. use ast::{self, Ident}; -use syntax_pos::{self, BytePos, CharPos, Pos, Span}; -use codemap::CodeMap; +use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION}; +use codemap::{CodeMap, FilePathMapping}; use errors::{FatalError, DiagnosticBuilder}; use parse::{token, ParseSess}; use str::char_at; @@ -68,8 +68,12 @@ pub struct StringReader<'a> { open_braces: Vec<(token::DelimToken, Span)>, } +fn mk_sp(lo: BytePos, hi: BytePos) -> Span { + Span { lo: lo, hi: hi, ctxt: NO_EXPANSION } +} + impl<'a> StringReader<'a> { - fn next_token(&mut self) -> TokenAndSpan where Self: Sized { + fn next_token(&mut self) -> TokenAndSpan { let res = self.try_next_token(); self.unwrap_or_abort(res) } @@ -140,7 +144,7 @@ impl<'a> StringReader<'a> { impl<'a> StringReader<'a> { /// For comments.rs, which hackily pokes into next_pos and ch - pub fn new_raw<'b>(sess: &'a ParseSess, filemap: Rc<syntax_pos::FileMap>) -> Self { + pub fn new_raw(sess: &'a ParseSess, filemap: Rc<syntax_pos::FileMap>) -> Self { let mut sr = StringReader::new_raw_internal(sess, filemap); sr.bump(); sr @@ -176,7 +180,7 @@ impl<'a> StringReader<'a> { pub fn new(sess: &'a ParseSess, filemap: Rc<syntax_pos::FileMap>) -> Self { let mut sr = StringReader::new_raw(sess, filemap); - if let Err(_) = sr.advance_token() { + if sr.advance_token().is_err() { sr.emit_fatal_errors(); panic!(FatalError); } @@ -201,7 +205,7 @@ impl<'a> StringReader<'a> { sr.bump(); - if let Err(_) = sr.advance_token() { + if sr.advance_token().is_err() { sr.emit_fatal_errors(); panic!(FatalError); } @@ -225,12 +229,12 @@ impl<'a> StringReader<'a> { /// Report a fatal error spanning [`from_pos`, `to_pos`). fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError { - self.fatal_span(syntax_pos::mk_sp(from_pos, to_pos), m) + self.fatal_span(mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`). fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) { - self.err_span(syntax_pos::mk_sp(from_pos, to_pos), m) + self.err_span(mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -254,7 +258,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.sess.span_diagnostic.struct_span_fatal(syntax_pos::mk_sp(from_pos, to_pos), &m[..]) + self.sess.span_diagnostic.struct_span_fatal(mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -278,7 +282,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.sess.span_diagnostic.struct_span_err(syntax_pos::mk_sp(from_pos, to_pos), &m[..]) + self.sess.span_diagnostic.struct_span_err(mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the @@ -302,11 +306,11 @@ impl<'a> StringReader<'a> { None => { if self.is_eof() { self.peek_tok = token::Eof; - self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos); + self.peek_span = mk_sp(self.filemap.end_pos, self.filemap.end_pos); } else { let start_bytepos = self.pos; self.peek_tok = self.next_token_inner()?; - self.peek_span = syntax_pos::mk_sp(start_bytepos, self.pos); + self.peek_span = mk_sp(start_bytepos, self.pos); }; } } @@ -489,7 +493,7 @@ impl<'a> StringReader<'a> { if let Some(c) = self.ch { if c.is_whitespace() { let msg = "called consume_any_line_comment, but there was whitespace"; - self.sess.span_diagnostic.span_err(syntax_pos::mk_sp(self.pos, self.pos), msg); + self.sess.span_diagnostic.span_err(mk_sp(self.pos, self.pos), msg); } } @@ -500,7 +504,7 @@ impl<'a> StringReader<'a> { self.bump(); // line comments starting with "///" or "//!" are doc-comments - let doc_comment = self.ch_is('/') || self.ch_is('!'); + let doc_comment = (self.ch_is('/') && !self.nextch_is('/')) || self.ch_is('!'); let start_bpos = self.pos - BytePos(2); while !self.is_eof() { @@ -521,7 +525,7 @@ impl<'a> StringReader<'a> { self.bump(); } - return if doc_comment { + if doc_comment { self.with_str_from(start_bpos, |string| { // comments with only more "/"s are not doc comments let tok = if is_doc_comment(string) { @@ -532,15 +536,15 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }) }) } else { Some(TokenAndSpan { tok: token::Comment, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }) - }; + } } Some('*') => { self.bump(); @@ -559,7 +563,7 @@ impl<'a> StringReader<'a> { // I guess this is the only way to figure out if // we're at the beginning of the file... - let cmap = CodeMap::new(); + let cmap = CodeMap::new(FilePathMapping::empty()); cmap.files.borrow_mut().push(self.filemap.clone()); let loc = cmap.lookup_char_pos_adj(self.pos); debug!("Skipping a shebang"); @@ -571,7 +575,7 @@ impl<'a> StringReader<'a> { } return Some(TokenAndSpan { tok: token::Shebang(self.name_from(start)), - sp: syntax_pos::mk_sp(start, self.pos), + sp: mk_sp(start, self.pos), }); } } @@ -599,7 +603,7 @@ impl<'a> StringReader<'a> { } let c = Some(TokenAndSpan { tok: token::Whitespace, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }); debug!("scanning whitespace: {:?}", c); c @@ -661,7 +665,7 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }) }) } @@ -725,7 +729,7 @@ impl<'a> StringReader<'a> { base = 16; num_digits = self.scan_digits(16, 16); } - '0'...'9' | '_' | '.' => { + '0'...'9' | '_' | '.' | 'e' | 'E' => { num_digits = self.scan_digits(10, 10) + 1; } _ => { @@ -750,9 +754,7 @@ impl<'a> StringReader<'a> { // integer literal followed by field/method access or a range pattern // (`0..2` and `12.foo()`) if self.ch_is('.') && !self.nextch_is('.') && - !self.nextch() - .unwrap_or('\0') - .is_xid_start() { + !ident_start(self.nextch()) { // might have stuff after the ., and if it does, it needs to start // with a number self.bump(); @@ -762,7 +764,7 @@ impl<'a> StringReader<'a> { } let pos = self.pos; self.check_float_base(start_bpos, pos, base); - return token::Float(self.name_from(start_bpos)); + token::Float(self.name_from(start_bpos)) } else { // it might be a float if it has an exponent if self.ch_is('e') || self.ch_is('E') { @@ -772,7 +774,7 @@ impl<'a> StringReader<'a> { return token::Float(self.name_from(start_bpos)); } // but we certainly have an integer! - return token::Integer(self.name_from(start_bpos)); + token::Integer(self.name_from(start_bpos)) } } @@ -858,7 +860,7 @@ impl<'a> StringReader<'a> { let valid = if self.ch_is('{') { self.scan_unicode_escape(delim) && !ascii_only } else { - let span = syntax_pos::mk_sp(start, self.pos); + let span = mk_sp(start, self.pos); self.sess.span_diagnostic .struct_span_err(span, "incorrect unicode escape sequence") .span_help(span, @@ -896,13 +898,13 @@ impl<'a> StringReader<'a> { }, c); if e == '\r' { - err.span_help(syntax_pos::mk_sp(escaped_pos, pos), + err.span_help(mk_sp(escaped_pos, pos), "this is an isolated carriage return; consider \ checking your editor and version control \ settings"); } if (e == '{' || e == '}') && !ascii_only { - err.span_help(syntax_pos::mk_sp(escaped_pos, pos), + err.span_help(mk_sp(escaped_pos, pos), "if used in a formatting string, curly braces \ are escaped with `{{` and `}}`"); } @@ -1049,9 +1051,9 @@ impl<'a> StringReader<'a> { self.bump(); if self.ch_is('=') { self.bump(); - return token::BinOpEq(op); + token::BinOpEq(op) } else { - return token::BinOp(op); + token::BinOp(op) } } @@ -1098,15 +1100,15 @@ impl<'a> StringReader<'a> { // One-byte tokens. ';' => { self.bump(); - return Ok(token::Semi); + Ok(token::Semi) } ',' => { self.bump(); - return Ok(token::Comma); + Ok(token::Comma) } '.' => { self.bump(); - return if self.ch_is('.') { + if self.ch_is('.') { self.bump(); if self.ch_is('.') { self.bump(); @@ -1116,61 +1118,61 @@ impl<'a> StringReader<'a> { } } else { Ok(token::Dot) - }; + } } '(' => { self.bump(); - return Ok(token::OpenDelim(token::Paren)); + Ok(token::OpenDelim(token::Paren)) } ')' => { self.bump(); - return Ok(token::CloseDelim(token::Paren)); + Ok(token::CloseDelim(token::Paren)) } '{' => { self.bump(); - return Ok(token::OpenDelim(token::Brace)); + Ok(token::OpenDelim(token::Brace)) } '}' => { self.bump(); - return Ok(token::CloseDelim(token::Brace)); + Ok(token::CloseDelim(token::Brace)) } '[' => { self.bump(); - return Ok(token::OpenDelim(token::Bracket)); + Ok(token::OpenDelim(token::Bracket)) } ']' => { self.bump(); - return Ok(token::CloseDelim(token::Bracket)); + Ok(token::CloseDelim(token::Bracket)) } '@' => { self.bump(); - return Ok(token::At); + Ok(token::At) } '#' => { self.bump(); - return Ok(token::Pound); + Ok(token::Pound) } '~' => { self.bump(); - return Ok(token::Tilde); + Ok(token::Tilde) } '?' => { self.bump(); - return Ok(token::Question); + Ok(token::Question) } ':' => { self.bump(); if self.ch_is(':') { self.bump(); - return Ok(token::ModSep); + Ok(token::ModSep) } else { - return Ok(token::Colon); + Ok(token::Colon) } } '$' => { self.bump(); - return Ok(token::Dollar); + Ok(token::Dollar) } // Multi-byte tokens. @@ -1178,21 +1180,21 @@ impl<'a> StringReader<'a> { self.bump(); if self.ch_is('=') { self.bump(); - return Ok(token::EqEq); + Ok(token::EqEq) } else if self.ch_is('>') { self.bump(); - return Ok(token::FatArrow); + Ok(token::FatArrow) } else { - return Ok(token::Eq); + Ok(token::Eq) } } '!' => { self.bump(); if self.ch_is('=') { self.bump(); - return Ok(token::Ne); + Ok(token::Ne) } else { - return Ok(token::Not); + Ok(token::Not) } } '<' => { @@ -1200,21 +1202,21 @@ impl<'a> StringReader<'a> { match self.ch.unwrap_or('\x00') { '=' => { self.bump(); - return Ok(token::Le); + Ok(token::Le) } '<' => { - return Ok(self.binop(token::Shl)); + Ok(self.binop(token::Shl)) } '-' => { self.bump(); match self.ch.unwrap_or('\x00') { _ => { - return Ok(token::LArrow); + Ok(token::LArrow) } } } _ => { - return Ok(token::Lt); + Ok(token::Lt) } } } @@ -1223,13 +1225,13 @@ impl<'a> StringReader<'a> { match self.ch.unwrap_or('\x00') { '=' => { self.bump(); - return Ok(token::Ge); + Ok(token::Ge) } '>' => { - return Ok(self.binop(token::Shr)); + Ok(self.binop(token::Shr)) } _ => { - return Ok(token::Gt); + Ok(token::Gt) } } } @@ -1299,7 +1301,7 @@ impl<'a> StringReader<'a> { }; self.bump(); // advance ch past token let suffix = self.scan_optional_raw_name(); - return Ok(token::Literal(token::Char(id), suffix)); + Ok(token::Literal(token::Char(id), suffix)) } 'b' => { self.bump(); @@ -1310,7 +1312,7 @@ impl<'a> StringReader<'a> { _ => unreachable!(), // Should have been a token::Ident above. }; let suffix = self.scan_optional_raw_name(); - return Ok(token::Literal(lit, suffix)); + Ok(token::Literal(lit, suffix)) } '"' => { let start_bpos = self.pos; @@ -1341,7 +1343,7 @@ impl<'a> StringReader<'a> { }; self.bump(); let suffix = self.scan_optional_raw_name(); - return Ok(token::Literal(token::Str_(id), suffix)); + Ok(token::Literal(token::Str_(id), suffix)) } 'r' => { let start_bpos = self.pos; @@ -1412,24 +1414,24 @@ impl<'a> StringReader<'a> { Symbol::intern("??") }; let suffix = self.scan_optional_raw_name(); - return Ok(token::Literal(token::StrRaw(id, hash_count), suffix)); + Ok(token::Literal(token::StrRaw(id, hash_count), suffix)) } '-' => { if self.nextch_is('>') { self.bump(); self.bump(); - return Ok(token::RArrow); + Ok(token::RArrow) } else { - return Ok(self.binop(token::Minus)); + Ok(self.binop(token::Minus)) } } '&' => { if self.nextch_is('&') { self.bump(); self.bump(); - return Ok(token::AndAnd); + Ok(token::AndAnd) } else { - return Ok(self.binop(token::And)); + Ok(self.binop(token::And)) } } '|' => { @@ -1437,27 +1439,27 @@ impl<'a> StringReader<'a> { Some('|') => { self.bump(); self.bump(); - return Ok(token::OrOr); + Ok(token::OrOr) } _ => { - return Ok(self.binop(token::Or)); + Ok(self.binop(token::Or)) } } } '+' => { - return Ok(self.binop(token::Plus)); + Ok(self.binop(token::Plus)) } '*' => { - return Ok(self.binop(token::Star)); + Ok(self.binop(token::Star)) } '/' => { - return Ok(self.binop(token::Slash)); + Ok(self.binop(token::Slash)) } '^' => { - return Ok(self.binop(token::Caret)); + Ok(self.binop(token::Caret)) } '%' => { - return Ok(self.binop(token::Percent)); + Ok(self.binop(token::Percent)) } c => { let last_bpos = self.pos; @@ -1466,7 +1468,7 @@ impl<'a> StringReader<'a> { bpos, "unknown start of token", c); - unicode_chars::check_for_substitution(&self, c, &mut err); + unicode_chars::check_for_substitution(self, c, &mut err); self.fatal_errs.push(err); Err(()) } @@ -1488,14 +1490,14 @@ impl<'a> StringReader<'a> { if self.ch_is('\n') { self.bump(); } - return val; + val } fn read_one_line_comment(&mut self) -> String { let val = self.read_to_eol(); assert!((val.as_bytes()[0] == b'/' && val.as_bytes()[1] == b'/') || (val.as_bytes()[0] == b'#' && val.as_bytes()[1] == b'!')); - return val; + val } fn consume_non_eol_whitespace(&mut self) { @@ -1539,7 +1541,7 @@ impl<'a> StringReader<'a> { Symbol::intern("?") }; self.bump(); // advance ch past token - return token::Byte(id); + token::Byte(id) } fn scan_byte_escape(&mut self, delim: char, below_0x7f_only: bool) -> bool { @@ -1572,7 +1574,7 @@ impl<'a> StringReader<'a> { Symbol::intern("??") }; self.bump(); - return token::ByteStr(id); + token::ByteStr(id) } fn scan_raw_byte_string(&mut self) -> token::Lit { @@ -1625,8 +1627,8 @@ impl<'a> StringReader<'a> { self.bump(); } self.bump(); - return token::ByteStrRaw(self.name_from_to(content_start_bpos, content_end_bpos), - hash_count); + token::ByteStrRaw(self.name_from_to(content_start_bpos, content_end_bpos), + hash_count) } } @@ -1644,7 +1646,7 @@ fn in_range(c: Option<char>, lo: char, hi: char) -> bool { } fn is_dec_digit(c: Option<char>) -> bool { - return in_range(c, '0', '9'); + in_range(c, '0', '9') } pub fn is_doc_comment(s: &str) -> bool { @@ -1714,13 +1716,13 @@ mod tests { sess: &'a ParseSess, teststr: String) -> StringReader<'a> { - let fm = cm.new_filemap("zebra.rs".to_string(), None, teststr); + let fm = cm.new_filemap("zebra.rs".to_string(), teststr); StringReader::new(sess, fm) } #[test] fn t1() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); let mut string_reader = setup(&cm, &sh, @@ -1735,7 +1737,7 @@ mod tests { sp: Span { lo: BytePos(21), hi: BytePos(23), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }, }; assert_eq!(tok1, tok2); @@ -1749,7 +1751,7 @@ mod tests { sp: Span { lo: BytePos(24), hi: BytePos(28), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }, }; assert_eq!(tok3, tok4); @@ -1772,7 +1774,7 @@ mod tests { #[test] fn doublecolonparsing() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); check_tokenization(setup(&cm, &sh, "a b".to_string()), vec![mk_ident("a"), token::Whitespace, mk_ident("b")]); @@ -1780,7 +1782,7 @@ mod tests { #[test] fn dcparsing_2() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); check_tokenization(setup(&cm, &sh, "a::b".to_string()), vec![mk_ident("a"), token::ModSep, mk_ident("b")]); @@ -1788,7 +1790,7 @@ mod tests { #[test] fn dcparsing_3() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); check_tokenization(setup(&cm, &sh, "a ::b".to_string()), vec![mk_ident("a"), token::Whitespace, token::ModSep, mk_ident("b")]); @@ -1796,7 +1798,7 @@ mod tests { #[test] fn dcparsing_4() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); check_tokenization(setup(&cm, &sh, "a:: b".to_string()), vec![mk_ident("a"), token::ModSep, token::Whitespace, mk_ident("b")]); @@ -1804,7 +1806,7 @@ mod tests { #[test] fn character_a() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); assert_eq!(setup(&cm, &sh, "'a'".to_string()).next_token().tok, token::Literal(token::Char(Symbol::intern("a")), None)); @@ -1812,7 +1814,7 @@ mod tests { #[test] fn character_space() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); assert_eq!(setup(&cm, &sh, "' '".to_string()).next_token().tok, token::Literal(token::Char(Symbol::intern(" ")), None)); @@ -1820,7 +1822,7 @@ mod tests { #[test] fn character_escaped() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); assert_eq!(setup(&cm, &sh, "'\\n'".to_string()).next_token().tok, token::Literal(token::Char(Symbol::intern("\\n")), None)); @@ -1828,7 +1830,7 @@ mod tests { #[test] fn lifetime_name() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); assert_eq!(setup(&cm, &sh, "'abc".to_string()).next_token().tok, token::Lifetime(Ident::from_str("'abc"))); @@ -1836,7 +1838,7 @@ mod tests { #[test] fn raw_string() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); assert_eq!(setup(&cm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()) .next_token() @@ -1846,7 +1848,7 @@ mod tests { #[test] fn literal_suffixes() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); macro_rules! test { ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ @@ -1890,7 +1892,7 @@ mod tests { #[test] fn nested_block_comments() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); let mut lexer = setup(&cm, &sh, "/* /* */ */'a'".to_string()); match lexer.next_token().tok { @@ -1903,12 +1905,12 @@ mod tests { #[test] fn crlf_comments() { - let cm = Rc::new(CodeMap::new()); + let cm = Rc::new(CodeMap::new(FilePathMapping::empty())); let sh = mk_sess(cm.clone()); let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string()); let comment = lexer.next_token(); assert_eq!(comment.tok, token::Comment); - assert_eq!(comment.sp, ::syntax_pos::mk_sp(BytePos(0), BytePos(7))); + assert_eq!((comment.sp.lo, comment.sp.hi), (BytePos(0), BytePos(7))); assert_eq!(lexer.next_token().tok, token::Whitespace); assert_eq!(lexer.next_token().tok, token::DocComment(Symbol::intern("/// test"))); diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index 6da3e5de75c..83a164bdb96 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -11,7 +11,7 @@ // Characters and their corresponding confusables were collected from // http://www.unicode.org/Public/security/revision-06/confusables.txt -use syntax_pos::mk_sp as make_span; +use syntax_pos::{Span, NO_EXPANSION}; use errors::DiagnosticBuilder; use super::StringReader; @@ -234,11 +234,11 @@ pub fn check_for_substitution<'a>(reader: &StringReader<'a>, .iter() .find(|&&(c, _, _)| c == ch) .map(|&(_, u_name, ascii_char)| { - let span = make_span(reader.pos, reader.next_pos); + let span = Span { lo: reader.pos, hi: reader.next_pos, ctxt: NO_EXPANSION }; match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) { Some(&(ascii_char, ascii_name)) => { let msg = - format!("unicode character '{}' ({}) looks much like '{}' ({}), but it's not", + format!("unicode character '{}' ({}) looks like '{}' ({}), but it's not", ch, u_name, ascii_char, ascii_name); err.span_help(span, &msg); }, diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c00d2952b3b..3a68a6ba764 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -11,8 +11,8 @@ //! The main parser interface use ast::{self, CrateConfig}; -use codemap::CodeMap; -use syntax_pos::{self, Span, FileMap}; +use codemap::{CodeMap, FilePathMapping}; +use syntax_pos::{self, Span, FileMap, NO_EXPANSION}; use errors::{Handler, ColorConfig, DiagnosticBuilder}; use feature_gate::UnstableFeatures; use parse::parser::Parser; @@ -53,8 +53,8 @@ pub struct ParseSess { } impl ParseSess { - pub fn new() -> Self { - let cm = Rc::new(CodeMap::new()); + pub fn new(file_path_mapping: FilePathMapping) -> Self { + let cm = Rc::new(CodeMap::new(file_path_mapping)); let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, @@ -107,18 +107,18 @@ pub fn parse_crate_attrs_from_file<'a>(input: &Path, sess: &'a ParseSess) parser.parse_inner_attributes() } -pub fn parse_crate_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) - -> PResult<'a, ast::Crate> { +pub fn parse_crate_from_source_str(name: String, source: String, sess: &ParseSess) + -> PResult<ast::Crate> { new_parser_from_source_str(sess, name, source).parse_crate_mod() } -pub fn parse_crate_attrs_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) - -> PResult<'a, Vec<ast::Attribute>> { +pub fn parse_crate_attrs_from_source_str(name: String, source: String, sess: &ParseSess) + -> PResult<Vec<ast::Attribute>> { new_parser_from_source_str(sess, name, source).parse_inner_attributes() } -pub fn parse_expr_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) - -> PResult<'a, P<ast::Expr>> { +pub fn parse_expr_from_source_str(name: String, source: String, sess: &ParseSess) + -> PResult<P<ast::Expr>> { new_parser_from_source_str(sess, name, source).parse_expr() } @@ -126,30 +126,32 @@ pub fn parse_expr_from_source_str<'a>(name: String, source: String, sess: &'a Pa /// /// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and`Err` /// when a syntax error occurred. -pub fn parse_item_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) - -> PResult<'a, Option<P<ast::Item>>> { +pub fn parse_item_from_source_str(name: String, source: String, sess: &ParseSess) + -> PResult<Option<P<ast::Item>>> { new_parser_from_source_str(sess, name, source).parse_item() } -pub fn parse_meta_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) - -> PResult<'a, ast::MetaItem> { +pub fn parse_meta_from_source_str(name: String, source: String, sess: &ParseSess) + -> PResult<ast::MetaItem> { new_parser_from_source_str(sess, name, source).parse_meta_item() } -pub fn parse_stmt_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) - -> PResult<'a, Option<ast::Stmt>> { +pub fn parse_stmt_from_source_str(name: String, source: String, sess: &ParseSess) + -> PResult<Option<ast::Stmt>> { new_parser_from_source_str(sess, name, source).parse_stmt() } -pub fn parse_stream_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) +pub fn parse_stream_from_source_str(name: String, source: String, sess: &ParseSess) -> TokenStream { - filemap_to_stream(sess, sess.codemap().new_filemap(name, None, source)) + filemap_to_stream(sess, sess.codemap().new_filemap(name, source)) } // Create a new parser from a source string -pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess, name: String, source: String) - -> Parser<'a> { - filemap_to_parser(sess, sess.codemap().new_filemap(name, None, source)) +pub fn new_parser_from_source_str(sess: &ParseSess, name: String, source: String) + -> Parser { + let mut parser = filemap_to_parser(sess, sess.codemap().new_filemap(name, source)); + parser.recurse_into_file_modules = false; + parser } /// Create a new parser, handling errors as appropriate @@ -173,12 +175,12 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, } /// Given a filemap and config, return a parser -pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc<FileMap>, ) -> Parser<'a> { +pub fn filemap_to_parser(sess: & ParseSess, filemap: Rc<FileMap>, ) -> Parser { let end_pos = filemap.end_pos; let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap)); if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP { - parser.span = syntax_pos::mk_sp(end_pos, end_pos); + parser.span = Span { lo: end_pos, hi: end_pos, ctxt: NO_EXPANSION }; } parser @@ -186,7 +188,7 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc<FileMap>, ) -> Par // must preserve old name for now, because quote! from the *existing* // compiler expands into it -pub fn new_parser_from_tts<'a>(sess: &'a ParseSess, tts: Vec<TokenTree>) -> Parser<'a> { +pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec<TokenTree>) -> Parser { stream_to_parser(sess, tts.into_iter().collect()) } @@ -216,11 +218,9 @@ pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc<FileMap>) -> TokenStream panictry!(srdr.parse_all_token_trees()) } -/// Given stream and the ParseSess, produce a parser -pub fn stream_to_parser<'a>(sess: &'a ParseSess, stream: TokenStream) -> Parser<'a> { - let mut p = Parser::new(sess, stream, None, false); - p.check_unknown_macro_variable(); - p +/// Given stream and the `ParseSess`, produce a parser +pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser { + Parser::new(sess, stream, None, true, false) } /// Parse a string representing a character literal into its final form. @@ -253,7 +253,7 @@ pub fn char_lit(lit: &str) -> (char, isize) { (c, 4) } 'u' => { - assert!(lit.as_bytes()[2] == b'{'); + assert_eq!(lit.as_bytes()[2], b'{'); let idx = lit.find('}').unwrap(); let v = u32::from_str_radix(&lit[3..idx], 16).unwrap(); let c = char::from_u32(v).unwrap(); @@ -263,10 +263,14 @@ pub fn char_lit(lit: &str) -> (char, isize) { } } +pub fn escape_default(s: &str) -> String { + s.chars().map(char::escape_default).flat_map(|x| x).collect() +} + /// Parse a string representing a string literal into its final form. Does /// unescaping. pub fn str_lit(lit: &str) -> String { - debug!("parse_str_lit: given {}", lit.escape_default()); + debug!("parse_str_lit: given {}", escape_default(lit)); let mut res = String::with_capacity(lit.len()); // FIXME #8372: This could be a for-loop if it didn't borrow the iterator @@ -285,51 +289,46 @@ pub fn str_lit(lit: &str) -> String { } let mut chars = lit.char_indices().peekable(); - loop { - match chars.next() { - Some((i, c)) => { - match c { - '\\' => { - let ch = chars.peek().unwrap_or_else(|| { - panic!("{}", error(i)) - }).1; - - if ch == '\n' { - eat(&mut chars); - } else if ch == '\r' { - chars.next(); - let ch = chars.peek().unwrap_or_else(|| { - panic!("{}", error(i)) - }).1; - - if ch != '\n' { - panic!("lexer accepted bare CR"); - } - eat(&mut chars); - } else { - // otherwise, a normal escape - let (c, n) = char_lit(&lit[i..]); - for _ in 0..n - 1 { // we don't need to move past the first \ - chars.next(); - } - res.push(c); - } - }, - '\r' => { - let ch = chars.peek().unwrap_or_else(|| { - panic!("{}", error(i)) - }).1; + while let Some((i, c)) = chars.next() { + match c { + '\\' => { + let ch = chars.peek().unwrap_or_else(|| { + panic!("{}", error(i)) + }).1; + + if ch == '\n' { + eat(&mut chars); + } else if ch == '\r' { + chars.next(); + let ch = chars.peek().unwrap_or_else(|| { + panic!("{}", error(i)) + }).1; - if ch != '\n' { - panic!("lexer accepted bare CR"); - } + if ch != '\n' { + panic!("lexer accepted bare CR"); + } + eat(&mut chars); + } else { + // otherwise, a normal escape + let (c, n) = char_lit(&lit[i..]); + for _ in 0..n - 1 { // we don't need to move past the first \ chars.next(); - res.push('\n'); } - c => res.push(c), + res.push(c); } }, - None => break + '\r' => { + let ch = chars.peek().unwrap_or_else(|| { + panic!("{}", error(i)) + }).1; + + if ch != '\n' { + panic!("lexer accepted bare CR"); + } + chars.next(); + res.push('\n'); + } + c => res.push(c), } } @@ -341,25 +340,19 @@ pub fn str_lit(lit: &str) -> String { /// Parse a string representing a raw string literal into its final form. The /// only operation this does is convert embedded CRLF into a single LF. pub fn raw_str_lit(lit: &str) -> String { - debug!("raw_str_lit: given {}", lit.escape_default()); + debug!("raw_str_lit: given {}", escape_default(lit)); let mut res = String::with_capacity(lit.len()); - // FIXME #8372: This could be a for-loop if it didn't borrow the iterator let mut chars = lit.chars().peekable(); - loop { - match chars.next() { - Some(c) => { - if c == '\r' { - if *chars.peek().unwrap() != '\n' { - panic!("lexer accepted bare CR"); - } - chars.next(); - res.push('\n'); - } else { - res.push(c); - } - }, - None => break + while let Some(c) = chars.next() { + if c == '\r' { + if *chars.peek().unwrap() != '\n' { + panic!("lexer accepted bare CR"); + } + chars.next(); + res.push('\n'); + } else { + res.push(c); } } @@ -374,38 +367,80 @@ fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { s[1..].chars().all(|c| '0' <= c && c <= '9') } -fn filtered_float_lit(data: Symbol, suffix: Option<Symbol>, sd: &Handler, sp: Span) - -> ast::LitKind { +macro_rules! err { + ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => { + match $opt_diag { + Some(($span, $diag)) => { $($body)* } + None => return None, + } + } +} + +pub fn lit_token(lit: token::Lit, suf: Option<Symbol>, diag: Option<(Span, &Handler)>) + -> (bool /* suffix illegal? */, Option<ast::LitKind>) { + use ast::LitKind; + + match lit { + token::Byte(i) => (true, Some(LitKind::Byte(byte_lit(&i.as_str()).0))), + token::Char(i) => (true, Some(LitKind::Char(char_lit(&i.as_str()).0))), + + // There are some valid suffixes for integer and float literals, + // so all the handling is done internally. + token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)), + token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)), + + token::Str_(s) => { + let s = Symbol::intern(&str_lit(&s.as_str())); + (true, Some(LitKind::Str(s, ast::StrStyle::Cooked))) + } + token::StrRaw(s, n) => { + let s = Symbol::intern(&raw_str_lit(&s.as_str())); + (true, Some(LitKind::Str(s, ast::StrStyle::Raw(n)))) + } + token::ByteStr(i) => { + (true, Some(LitKind::ByteStr(byte_str_lit(&i.as_str())))) + } + token::ByteStrRaw(i, _) => { + (true, Some(LitKind::ByteStr(Rc::new(i.to_string().into_bytes())))) + } + } +} + +fn filtered_float_lit(data: Symbol, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>) + -> Option<ast::LitKind> { debug!("filtered_float_lit: {}, {:?}", data, suffix); let suffix = match suffix { Some(suffix) => suffix, - None => return ast::LitKind::FloatUnsuffixed(data), + None => return Some(ast::LitKind::FloatUnsuffixed(data)), }; - match &*suffix.as_str() { + Some(match &*suffix.as_str() { "f32" => ast::LitKind::Float(data, ast::FloatTy::F32), "f64" => ast::LitKind::Float(data, ast::FloatTy::F64), suf => { - if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { - // if it looks like a width, lets try to be helpful. - sd.struct_span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..])) - .help("valid widths are 32 and 64") - .emit(); - } else { - sd.struct_span_err(sp, &format!("invalid suffix `{}` for float literal", suf)) - .help("valid suffixes are `f32` and `f64`") - .emit(); - } + err!(diag, |span, diag| { + if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { + // if it looks like a width, lets try to be helpful. + let msg = format!("invalid width `{}` for float literal", &suf[1..]); + diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit() + } else { + let msg = format!("invalid suffix `{}` for float literal", suf); + diag.struct_span_err(span, &msg) + .help("valid suffixes are `f32` and `f64`") + .emit(); + } + }); ast::LitKind::FloatUnsuffixed(data) } - } + }) } -pub fn float_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> ast::LitKind { +pub fn float_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>) + -> Option<ast::LitKind> { debug!("float_lit: {:?}, {:?}", s, suffix); // FIXME #2252: bounds checking float literals is deferred until trans let s = s.chars().filter(|&c| c != '_').collect::<String>(); - filtered_float_lit(Symbol::intern(&s), suffix, sd, sp) + filtered_float_lit(Symbol::intern(&s), suffix, diag) } /// Parse a string representing a byte literal into its final form. Similar to `char_lit` @@ -415,7 +450,7 @@ pub fn byte_lit(lit: &str) -> (u8, usize) { if lit.len() == 1 { (lit.as_bytes()[0], 1) } else { - assert!(lit.as_bytes()[0] == b'\\', err(0)); + assert_eq!(lit.as_bytes()[0], b'\\', "{}", err(0)); let b = match lit.as_bytes()[1] { b'"' => b'"', b'n' => b'\n', @@ -436,7 +471,7 @@ pub fn byte_lit(lit: &str) -> (u8, usize) { } } }; - return (b, 2); + (b, 2) } } @@ -447,7 +482,7 @@ pub fn byte_str_lit(lit: &str) -> Rc<Vec<u8>> { let error = |i| format!("lexer should have rejected {} at {}", lit, i); /// Eat everything up to a non-whitespace - fn eat<'a, I: Iterator<Item=(usize, u8)>>(it: &mut iter::Peekable<I>) { + fn eat<I: Iterator<Item=(usize, u8)>>(it: &mut iter::Peekable<I>) { loop { match it.peek().map(|x| x.1) { Some(b' ') | Some(b'\n') | Some(b'\r') | Some(b'\t') => { @@ -500,7 +535,8 @@ pub fn byte_str_lit(lit: &str) -> Rc<Vec<u8>> { Rc::new(res) } -pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> ast::LitKind { +pub fn integer_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>) + -> Option<ast::LitKind> { // s can only be ascii, byte indexing is fine let s2 = s.chars().filter(|&c| c != '_').collect::<String>(); @@ -524,13 +560,16 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a // 1f64 and 2f32 etc. are valid float literals. if let Some(suf) = suffix { if looks_like_width_suffix(&['f'], &suf.as_str()) { - match base { - 16 => sd.span_err(sp, "hexadecimal float literal is not supported"), - 8 => sd.span_err(sp, "octal float literal is not supported"), - 2 => sd.span_err(sp, "binary float literal is not supported"), - _ => () + let err = match base { + 16 => Some("hexadecimal float literal is not supported"), + 8 => Some("octal float literal is not supported"), + 2 => Some("binary float literal is not supported"), + _ => None, + }; + if let Some(err) = err { + err!(diag, |span, diag| diag.span_err(span, err)); } - return filtered_float_lit(Symbol::intern(&s), Some(suf), sd, sp) + return filtered_float_lit(Symbol::intern(s), Some(suf), diag) } } @@ -539,7 +578,9 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a } if let Some(suf) = suffix { - if suf.as_str().is_empty() { sd.span_bug(sp, "found empty literal suffix in Some")} + if suf.as_str().is_empty() { + err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some")); + } ty = match &*suf.as_str() { "isize" => ast::LitIntType::Signed(ast::IntTy::Is), "i8" => ast::LitIntType::Signed(ast::IntTy::I8), @@ -556,17 +597,20 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a suf => { // i<digits> and u<digits> look like widths, so lets // give an error message along those lines - if looks_like_width_suffix(&['i', 'u'], suf) { - sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal", - &suf[1..])) - .help("valid widths are 8, 16, 32, 64 and 128") - .emit(); - } else { - sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)) - .help("the suffix must be one of the integral types \ - (`u32`, `isize`, etc)") - .emit(); - } + err!(diag, |span, diag| { + if looks_like_width_suffix(&['i', 'u'], suf) { + let msg = format!("invalid width `{}` for integer literal", &suf[1..]); + diag.struct_span_err(span, &msg) + .help("valid widths are 8, 16, 32, 64 and 128") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for numeric literal", suf); + diag.struct_span_err(span, &msg) + .help("the suffix must be one of the integral types \ + (`u32`, `isize`, etc)") + .emit(); + } + }); ty } @@ -576,7 +620,7 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); - match u128::from_str_radix(s, base) { + Some(match u128::from_str_radix(s, base) { Ok(r) => ast::LitKind::Int(r, ty), Err(_) => { // small bases are lexed as if they were base 10, e.g, the string @@ -588,11 +632,11 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); if !already_errored { - sd.span_err(sp, "int literal is too large"); + err!(diag, |span, diag| diag.span_err(span, "int literal is too large")); } ast::LitKind::Int(0, ty) } - } + }) } #[cfg(test)] @@ -614,7 +658,11 @@ mod tests { // produce a syntax_pos::span fn sp(a: u32, b: u32) -> Span { - Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION} + Span {lo: BytePos(a), hi: BytePos(b), ctxt: NO_EXPANSION} + } + + fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment { + ast::PathSegment::from_ident(Ident::from_str(s), sp(lo, hi)) } #[test] fn path_exprs_1() { @@ -623,7 +671,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), - segments: vec![Ident::from_str("a").into()], + segments: vec![str2seg("a", 0, 1)], }), span: sp(0, 1), attrs: ThinVec::new(), @@ -637,8 +685,8 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), segments: vec![ast::PathSegment::crate_root(), - Ident::from_str("a").into(), - Ident::from_str("b").into()] + str2seg("a", 2, 3), + str2seg("b", 5, 6)] }), span: sp(0, 6), attrs: ThinVec::new(), @@ -744,7 +792,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), - segments: vec![Ident::from_str("d").into()], + segments: vec![str2seg("d", 7, 8)], }), span:sp(7,8), attrs: ThinVec::new(), @@ -761,7 +809,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 0, 1)], }), span: sp(0,1), attrs: ThinVec::new()})), @@ -775,7 +823,7 @@ mod tests { } #[test] fn parse_ident_pat () { - let sess = ParseSess::new(); + let sess = ParseSess::new(FilePathMapping::empty()); let mut parser = string_to_parser(&sess, "b".to_string()); assert!(panictry!(parser.parse_pat()) == P(ast::Pat{ @@ -802,7 +850,7 @@ mod tests { ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, node: ast::TyKind::Path(None, ast::Path{ span:sp(10,13), - segments: vec![Ident::from_str("i32").into()], + segments: vec![str2seg("i32", 10, 13)], }), span:sp(10,13) }), @@ -844,7 +892,7 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path{ span:sp(17,18), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 17, 18)], }), span: sp(17,18), attrs: ThinVec::new()})), @@ -945,7 +993,7 @@ mod tests { } #[test] fn crlf_doc_comments() { - let sess = ParseSess::new(); + let sess = ParseSess::new(FilePathMapping::empty()); let name = "<source>".to_string(); let source = "/// doc comment\r\nfn foo() {}".to_string(); @@ -957,7 +1005,7 @@ mod tests { let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name.clone(), source, &sess) .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.name() == "doc") + let docs = item.attrs.iter().filter(|a| a.path == "doc") .map(|a| a.value_str().unwrap().to_string()).collect::<Vec<_>>(); let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; assert_eq!(&docs[..], b); @@ -970,7 +1018,7 @@ mod tests { #[test] fn ttdelim_span() { - let sess = ParseSess::new(); + let sess = ParseSess::new(FilePathMapping::empty()); let expr = parse::parse_expr_from_source_str("foo".to_string(), "foo!( fn main() { body } )".to_string(), &sess).unwrap(); @@ -986,4 +1034,23 @@ mod tests { Err(_) => panic!("could not get snippet"), } } + + // This tests that when parsing a string (rather than a file) we don't try + // and read in a file for a module declaration and just parse a stub. + // See `recurse_into_file_modules` in the parser. + #[test] + fn out_of_line_mod() { + let sess = ParseSess::new(FilePathMapping::empty()); + let item = parse_item_from_source_str( + "foo".to_owned(), + "mod foo { struct S; mod this_does_not_exist; }".to_owned(), + &sess, + ).unwrap().unwrap(); + + if let ast::ItemKind::Mod(ref m) = item.node { + assert!(m.items.len() == 2); + } else { + panic!(); + } + } } diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index a46a788ca08..078e86aa294 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -36,6 +36,7 @@ pub trait ParserObsoleteMethods { impl<'a> ParserObsoleteMethods for parser::Parser<'a> { /// Reports an obsolete syntax non-fatal error. #[allow(unused_variables)] + #[allow(unreachable_code)] fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) { let (kind_str, desc, error) = match kind { // Nothing here at the moment @@ -58,7 +59,7 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> { if !self.obsolete_set.contains(&kind) && (error || self.sess.span_diagnostic.can_emit_warnings) { - err.note(&format!("{}", desc)); + err.note(desc); self.obsolete_set.insert(kind); } err.emit(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6446d38e5ef..8d7c8c5248b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -27,7 +27,7 @@ use ast::Local; use ast::MacStmtStyle; use ast::Mac_; use ast::{MutTy, Mutability}; -use ast::{Pat, PatKind}; +use ast::{Pat, PatKind, PathSegment}; use ast::{PolyTraitRef, QSelf}; use ast::{Stmt, StmtKind}; use ast::{VariantData, StructField}; @@ -40,8 +40,8 @@ use ast::{Visibility, WhereClause}; use ast::{BinOpKind, UnOp}; use ast::RangeEnd; use {ast, attr}; -use codemap::{self, CodeMap, Spanned, spanned, respan}; -use syntax_pos::{self, Span, Pos, BytePos, mk_sp}; +use codemap::{self, CodeMap, Spanned, respan}; +use syntax_pos::{self, Span, BytePos}; use errors::{self, DiagnosticBuilder}; use parse::{self, classify, token}; use parse::common::SeqSep; @@ -57,13 +57,14 @@ use tokenstream::{self, Delimited, ThinTokenStream, TokenTree, TokenStream}; use symbol::{Symbol, keywords}; use util::ThinVec; +use std::cmp; use std::collections::HashSet; -use std::{cmp, mem, slice}; -use std::path::{Path, PathBuf}; -use std::rc::Rc; +use std::mem; +use std::path::{self, Path, PathBuf}; +use std::slice; bitflags! { - flags Restrictions: u8 { + pub flags Restrictions: u8 { const RESTRICTION_STMT_EXPR = 1 << 0, const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1, } @@ -86,12 +87,18 @@ pub enum PathStyle { Expr, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum SemiColonMode { Break, Ignore, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum BlockMode { + Break, + Ignore, +} + /// Possibly accept an `token::Interpolated` expression (a pre-parsed expression /// dropped into the token stream, which happens while parsing the result of /// macro expansion). Placement of these is not as complex as I feared it would @@ -109,13 +116,13 @@ macro_rules! maybe_whole_expr { $p.bump(); let span = $p.span; let kind = ExprKind::Path(None, (*path).clone()); - return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + return Ok($p.mk_expr(span, kind, ThinVec::new())); } token::NtBlock(ref block) => { $p.bump(); let span = $p.span; let kind = ExprKind::Block((*block).clone()); - return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + return Ok($p.mk_expr(span, kind, ThinVec::new())); } _ => {}, }; @@ -147,6 +154,7 @@ fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>) enum PrevTokenKind { DocComment, Comma, + Plus, Interpolated, Eof, Other, @@ -161,6 +169,7 @@ pub struct Parser<'a> { /// the span of the current token: pub span: Span, /// the span of the previous token: + pub meta_var_span: Option<Span>, pub prev_span: Span, /// the previous token kind prev_token_kind: PrevTokenKind, @@ -170,6 +179,8 @@ pub struct Parser<'a> { pub obsolete_set: HashSet<ObsoleteSyntax>, /// Used to determine the path to externally loaded source files pub directory: Directory, + /// Whether to parse sub-modules in other files. + pub recurse_into_file_modules: bool, /// Name of the root module this parser originated from. If `None`, then the /// name is not known. This does not change while the parser is descending /// into modules, and sub-parsers have new values for this name. @@ -181,6 +192,7 @@ pub struct Parser<'a> { pub cfg_mods: bool, } + struct TokenCursor { frame: TokenCursorFrame, stack: Vec<TokenCursorFrame>, @@ -239,7 +251,7 @@ impl TokenCursor { fn next_desugared(&mut self) -> TokenAndSpan { let (sp, name) = match self.next() { TokenAndSpan { sp, tok: token::DocComment(name) } => (sp, name), - tok @ _ => return tok, + tok => return tok, }; let stripped = strip_doc_comment_decoration(&name.as_str()); @@ -345,7 +357,7 @@ pub enum Error { } impl Error { - pub fn span_err<'a>(self, sp: Span, handler: &'a errors::Handler) -> DiagnosticBuilder<'a> { + pub fn span_err(self, sp: Span, handler: &errors::Handler) -> DiagnosticBuilder { match self { Error::FileNotFoundForModule { ref mod_name, ref default_path, @@ -407,10 +419,30 @@ impl From<P<Expr>> for LhsExpr { } } +/// Create a placeholder argument. +fn dummy_arg(span: Span) -> Arg { + let spanned = Spanned { + span: span, + node: keywords::Invalid.ident() + }; + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), spanned, None), + span: span + }); + let ty = Ty { + node: TyKind::Err, + span: span, + id: ast::DUMMY_NODE_ID + }; + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } +} + impl<'a> Parser<'a> { pub fn new(sess: &'a ParseSess, tokens: TokenStream, directory: Option<Directory>, + recurse_into_file_modules: bool, desugar_doc_comments: bool) -> Self { let mut parser = Parser { @@ -418,9 +450,11 @@ impl<'a> Parser<'a> { token: token::Underscore, span: syntax_pos::DUMMY_SP, prev_span: syntax_pos::DUMMY_SP, + meta_var_span: None, prev_token_kind: PrevTokenKind::Other, restrictions: Restrictions::empty(), obsolete_set: HashSet::new(), + recurse_into_file_modules: recurse_into_file_modules, directory: Directory { path: PathBuf::new(), ownership: DirectoryOwnership::Owned }, root_module_name: None, expected_tokens: Vec::new(), @@ -438,19 +472,23 @@ impl<'a> Parser<'a> { let tok = parser.next_tok(); parser.token = tok.tok; parser.span = tok.sp; + if let Some(directory) = directory { parser.directory = directory; } else if parser.span != syntax_pos::DUMMY_SP { parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span)); parser.directory.path.pop(); } + + parser.process_potential_macro_variable(); parser } fn next_tok(&mut self) -> TokenAndSpan { - let mut next = match self.desugar_doc_comments { - true => self.token_cursor.next_desugared(), - false => self.token_cursor.next(), + let mut next = if self.desugar_doc_comments { + self.token_cursor.next_desugared() + } else { + self.token_cursor.next() }; if next.sp == syntax_pos::DUMMY_SP { next.sp = self.prev_span; @@ -521,7 +559,7 @@ impl<'a> Parser<'a> { // This might be a sign we need a connect method on Iterator. let b = i.next() .map_or("".to_string(), |t| t.to_string()); - i.enumerate().fold(b, |mut b, (i, ref a)| { + i.enumerate().fold(b, |mut b, (i, a)| { if tokens.len() > 2 && i == tokens.len() - 2 { b.push_str(", or "); } else if tokens.len() == 2 && i == tokens.len() - 2 { @@ -549,20 +587,35 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - Err(self.fatal( - &(if expected.len() > 1 { - (format!("expected one of {}, found `{}`", - expect, - actual)) - } else if expected.is_empty() { - (format!("unexpected token: `{}`", - actual)) + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) } else { - (format!("expected {}, found `{}`", - expect, - actual)) - })[..] - )) + expect.clone() + }; + (format!("expected one of {}, found `{}`", expect, actual), + (self.prev_span.next_point(), format!("expected one of {} here", short_expect))) + } else if expected.is_empty() { + (format!("unexpected token: `{}`", actual), + (self.prev_span, "unexpected token after this".to_string())) + } else { + (format!("expected {}, found `{}`", expect, actual), + (self.prev_span.next_point(), format!("expected {} here", expect))) + }; + let mut err = self.fatal(&msg_exp); + let sp = if self.token == token::Token::Eof { + // This is EOF, don't want to point at the following char, but rather the last token + self.prev_span + } else { + label_sp + }; + if self.span.contains(sp) { + err.span_label(self.span, label_exp); + } else { + err.span_label(sp, label_exp); + err.span_label(self.span, "unexpected token"); + } + Err(err) } } @@ -732,7 +785,7 @@ impl<'a> Parser<'a> { token::AndAnd => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::BinOp(token::And), lo, span.hi)) + Ok(self.bump_with(token::BinOp(token::And), Span { lo: lo, ..span })) } _ => self.unexpected() } @@ -766,7 +819,7 @@ impl<'a> Parser<'a> { token::BinOp(token::Shl) => { let span = self.span; let lo = span.lo + BytePos(1); - self.bump_with(token::Lt, lo, span.hi); + self.bump_with(token::Lt, Span { lo: lo, ..span }); true } _ => false, @@ -794,17 +847,17 @@ impl<'a> Parser<'a> { token::BinOp(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Gt, lo, span.hi)) + Ok(self.bump_with(token::Gt, Span { lo: lo, ..span })) } token::BinOpEq(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Ge, lo, span.hi)) + Ok(self.bump_with(token::Ge, Span { lo: lo, ..span })) } token::Ge => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Eq, lo, span.hi)) + Ok(self.bump_with(token::Eq, Span { lo: lo, ..span })) } _ => self.unexpected() } @@ -891,7 +944,7 @@ impl<'a> Parser<'a> { self.parse_seq_to_before_tokens(kets, SeqSep::none(), - |p| p.parse_token_tree(), + |p| Ok(p.parse_token_tree()), |mut e| handler.cancel(&mut e)); } @@ -940,18 +993,15 @@ impl<'a> Parser<'a> { token::CloseDelim(..) | token::Eof => break, _ => {} }; - match sep.sep { - Some(ref t) => { - if first { - first = false; - } else { - if let Err(e) = self.expect(t) { - fe(e); - break; - } + if let Some(ref t) = sep.sep { + if first { + first = false; + } else { + if let Err(e) = self.expect(t) { + fe(e); + break; } } - _ => () } if sep.trailing_sep_allowed && kets.iter().any(|k| self.check(k)) { break; @@ -998,12 +1048,12 @@ impl<'a> Parser<'a> { -> PResult<'a, Spanned<Vec<T>>> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { - let lo = self.span.lo; + let lo = self.span; self.expect(bra)?; let result = self.parse_seq_to_before_end(ket, sep, f); - let hi = self.span.hi; + let hi = self.span; self.bump(); - Ok(spanned(lo, hi, result)) + Ok(respan(lo.to(hi), result)) } /// Advance the parser by one token @@ -1013,12 +1063,13 @@ impl<'a> Parser<'a> { self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); } - self.prev_span = self.span; + self.prev_span = self.meta_var_span.take().unwrap_or(self.span); // Record last token kind for possible error recovery. self.prev_token_kind = match self.token { token::DocComment(..) => PrevTokenKind::DocComment, token::Comma => PrevTokenKind::Comma, + token::BinOp(token::Plus) => PrevTokenKind::Plus, token::Interpolated(..) => PrevTokenKind::Interpolated, token::Eof => PrevTokenKind::Eof, _ => PrevTokenKind::Other, @@ -1029,21 +1080,18 @@ impl<'a> Parser<'a> { self.token = next.tok; self.expected_tokens.clear(); // check after each token - self.check_unknown_macro_variable(); + self.process_potential_macro_variable(); } /// Advance the parser using provided token as a next one. Use this when /// consuming a part of a token. For example a single `<` from `<<`. - pub fn bump_with(&mut self, - next: token::Token, - lo: BytePos, - hi: BytePos) { - self.prev_span = mk_sp(self.span.lo, lo); + pub fn bump_with(&mut self, next: token::Token, span: Span) { + self.prev_span = Span { hi: span.lo, ..self.span }; // It would be incorrect to record the kind of the current token, but // fortunately for tokens currently using `bump_with`, the // prev_token_kind will be of no use anyway. self.prev_token_kind = PrevTokenKind::Other; - self.span = mk_sp(lo, hi); + self.span = span; self.token = next; self.expected_tokens.clear(); } @@ -1117,57 +1165,13 @@ impl<'a> Parser<'a> { self.check_keyword(keywords::Extern) } - pub fn get_lifetime(&mut self) -> ast::Ident { + fn get_label(&mut self) -> ast::Ident { match self.token { token::Lifetime(ref ident) => *ident, _ => self.bug("not a lifetime"), } } - pub fn parse_for_in_type(&mut self) -> PResult<'a, TyKind> { - /* - Parses whatever can come after a `for` keyword in a type. - The `for` hasn't been consumed. - - - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T - - for <'lt> path::foo(a, b) + Trait + 'a - */ - - let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - - // examine next token to decide to do - if self.token_is_bare_fn_keyword() { - self.parse_ty_bare_fn(lifetime_defs) - } else { - let hi = self.span.hi; - let trait_ref = self.parse_trait_ref()?; - let poly_trait_ref = PolyTraitRef { bound_lifetimes: lifetime_defs, - trait_ref: trait_ref, - span: mk_sp(lo, hi)}; - let other_bounds = if self.eat(&token::BinOp(token::Plus)) { - self.parse_ty_param_bounds()? - } else { - Vec::new() - }; - let all_bounds = - Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter() - .chain(other_bounds) - .collect(); - Ok(ast::TyKind::TraitObject(all_bounds)) - } - } - - pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> { - // Parses whatever can come after a `impl` keyword in a type. - // The `impl` has already been consumed. - Ok(ast::TyKind::ImplTrait(self.parse_ty_param_bounds()?)) - } - - pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> { - Ok(TyKind::Path(None, self.parse_path(PathStyle::Type)?)) - } - /// parse a TyKind::BareFn type: pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<LifetimeDef>) -> PResult<'a, TyKind> { @@ -1215,17 +1219,17 @@ impl<'a> Parser<'a> { } /// Parse the items in a trait declaration - pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> { + pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { maybe_whole!(self, NtTraitItem, |x| x); let mut attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let (name, node) = if self.eat_keyword(keywords::Type) { let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?; self.expect(&token::Semi)?; (ident, TraitItemKind::Type(bounds, default)) } else if self.is_const_item() { - self.expect_keyword(keywords::Const)?; + self.expect_keyword(keywords::Const)?; let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; @@ -1242,9 +1246,17 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { // trait item macro. // code copied from parse_macro_use_or_failure... abstraction! - let lo = self.span.lo; + let prev_span = self.prev_span; + let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + + if pth.segments.len() == 1 { + if !self.eat(&token::Not) { + return Err(self.missing_assoc_item_kind_err("trait", prev_span)); + } + } else { + self.expect(&token::Not)?; + } // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; @@ -1252,30 +1264,12 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)? } - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac)) } else { let (constness, unsafety, abi) = match self.parse_fn_front_matter() { Ok(cua) => cua, - Err(e) => { - loop { - match self.token { - token::Eof => break, - token::CloseDelim(token::Brace) | - token::Semi => { - self.bump(); - break; - } - token::OpenDelim(token::Brace) => { - self.parse_token_tree()?; - break; - } - _ => self.bump(), - } - } - - return Err(e); - } + Err(e) => return Err(e), }; let ident = self.parse_ident()?; @@ -1300,11 +1294,13 @@ impl<'a> Parser<'a> { let body = match self.token { token::Semi => { self.bump(); + *at_end = true; debug!("parse_trait_methods(): parsing required method"); None } token::OpenDelim(token::Brace) => { debug!("parse_trait_methods(): parsing provided method"); + *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(inner_attrs.iter().cloned()); Some(body) @@ -1322,110 +1318,22 @@ impl<'a> Parser<'a> { ident: name, attrs: attrs, node: node, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), }) } - - /// Parse the items in a trait declaration - pub fn parse_trait_items(&mut self) -> PResult<'a, Vec<TraitItem>> { - self.parse_unspanned_seq( - &token::OpenDelim(token::Brace), - &token::CloseDelim(token::Brace), - SeqSep::none(), - |p| -> PResult<'a, TraitItem> { - p.parse_trait_item() - }) - } - /// Parse optional return type [ -> TY ] in function decl pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> { if self.eat(&token::RArrow) { Ok(FunctionRetTy::Ty(self.parse_ty_no_plus()?)) } else { - let pos = self.span.lo; - Ok(FunctionRetTy::Default(mk_sp(pos, pos))) + Ok(FunctionRetTy::Default(Span { hi: self.span.lo, ..self.span })) } } - /// Parse a type. + // Parse a type pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> { - let lo = self.span.lo; - let lhs = self.parse_ty_no_plus()?; - - if !self.eat(&token::BinOp(token::Plus)) { - return Ok(lhs); - } - - let mut bounds = self.parse_ty_param_bounds()?; - - // In type grammar, `+` is treated like a binary operator, - // and hence both L and R side are required. - if bounds.is_empty() { - let prev_span = self.prev_span; - self.span_err(prev_span, - "at least one type parameter bound \ - must be specified"); - } - - let mut lhs = lhs.unwrap(); - if let TyKind::Paren(ty) = lhs.node { - // We have to accept the first bound in parens for backward compatibility. - // Example: `(Bound) + Bound + Bound` - lhs = ty.unwrap(); - } - if let TyKind::Path(None, path) = lhs.node { - let poly_trait_ref = PolyTraitRef { - bound_lifetimes: Vec::new(), - trait_ref: TraitRef { path: path, ref_id: lhs.id }, - span: lhs.span, - }; - let poly_trait_ref = TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None); - bounds.insert(0, poly_trait_ref); - } else { - let mut err = struct_span_err!(self.sess.span_diagnostic, lhs.span, E0178, - "expected a path on the left-hand side \ - of `+`, not `{}`", - pprust::ty_to_string(&lhs)); - err.span_label(lhs.span, &format!("expected a path")); - let hi = bounds.iter().map(|x| match *x { - TraitTyParamBound(ref tr, _) => tr.span.hi, - RegionTyParamBound(ref r) => r.span.hi, - }).max_by_key(|x| x.to_usize()); - let full_span = hi.map(|hi| Span { - lo: lhs.span.lo, - hi: hi, - expn_id: lhs.span.expn_id, - }); - match (&lhs.node, full_span) { - (&TyKind::Rptr(ref lifetime, ref mut_ty), Some(full_span)) => { - let ty_str = pprust::to_string(|s| { - use print::pp::word; - use print::pprust::PrintState; - - word(&mut s.s, "&")?; - s.print_opt_lifetime(lifetime)?; - s.print_mutability(mut_ty.mutbl)?; - s.popen()?; - s.print_type(&mut_ty.ty)?; - s.print_bounds(" +", &bounds)?; - s.pclose() - }); - err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", - ty_str); - } - - _ => { - help!(&mut err, - "perhaps you forgot parentheses? (per RFC 438)"); - } - } - err.emit(); - } - - let sp = mk_sp(lo, self.prev_span.hi); - let sum = TyKind::TraitObject(bounds); - Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp})) + self.parse_ty_common(true) } /// Parse a type in restricted contexts where `+` is not permitted. @@ -1433,15 +1341,17 @@ impl<'a> Parser<'a> { /// `+` is prohibited to maintain operator priority (P(+) < P(&)). /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. - pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> { - maybe_whole!(self, NtTy, |x| x); + fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> { + self.parse_ty_common(false) + } - let lo = self.span.lo; + fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> { + maybe_whole!(self, NtTy, |x| x); - let t = if self.eat(&token::OpenDelim(token::Paren)) { - // (t) is a parenthesized ty - // (t,) is the type of a tuple with only one field, - // of type t + let lo = self.span; + let node = if self.eat(&token::OpenDelim(token::Paren)) { + // `(TYPE)` is a parenthesized type. + // `(TYPE,)` is a tuple with a single field of type TYPE. let mut ts = vec![]; let mut last_comma = false; while self.token != token::CloseDelim(token::Paren) { @@ -1453,81 +1363,173 @@ impl<'a> Parser<'a> { break; } } - + let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; self.expect(&token::CloseDelim(token::Paren))?; + if ts.len() == 1 && !last_comma { - TyKind::Paren(ts.into_iter().nth(0).unwrap()) + let ty = ts.into_iter().nth(0).unwrap().unwrap(); + let maybe_bounds = allow_plus && self.token == token::BinOp(token::Plus); + match ty.node { + // `(TY_BOUND_NOPAREN) + BOUND + ...`. + TyKind::Path(None, ref path) if maybe_bounds => { + self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? + } + TyKind::TraitObject(ref bounds) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + let path = match bounds[0] { + TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(), + _ => self.bug("unexpected lifetime bound"), + }; + self.parse_remaining_bounds(Vec::new(), path, lo, true)? + } + // `(TYPE)` + _ => TyKind::Paren(P(ty)) + } } else { TyKind::Tup(ts) } } else if self.eat(&token::Not) { + // Never type `!` TyKind::Never } else if self.eat(&token::BinOp(token::Star)) { - // STAR POINTER (bare pointer?) + // Raw pointer TyKind::Ptr(self.parse_ptr()?) } else if self.eat(&token::OpenDelim(token::Bracket)) { - // VECTOR + // Array or slice let t = self.parse_ty()?; - - // Parse the `; e` in `[ i32; e ]` - // where `e` is a const expression + // Parse optional `; EXPR` in `[TYPE; EXPR]` let t = match self.maybe_parse_fixed_length_of_vec()? { None => TyKind::Slice(t), - Some(suffix) => TyKind::Array(t, suffix) + Some(suffix) => TyKind::Array(t, suffix), }; self.expect(&token::CloseDelim(token::Bracket))?; t - } else if self.check(&token::BinOp(token::And)) || - self.check(&token::AndAnd) { - // BORROWED POINTER + } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { + // Reference self.expect_and()?; self.parse_borrowed_pointee()? - } else if self.check_keyword(keywords::For) { - // FIXME `+` has incorrect priority in trait object types starting with `for` (#39317). - self.parse_for_in_type()? - } else if self.eat_keyword(keywords::Impl) { - // FIXME figure out priority of `+` in `impl Trait1 + Trait2` (#34511). - self.parse_impl_trait_type()? - } else if self.token_is_bare_fn_keyword() { - // BARE FUNCTION - self.parse_ty_bare_fn(Vec::new())? } else if self.eat_keyword_noexpect(keywords::Typeof) { - // TYPEOF + // `typeof(EXPR)` // In order to not be ambiguous, the type must be surrounded by parens. self.expect(&token::OpenDelim(token::Paren))?; let e = self.parse_expr()?; self.expect(&token::CloseDelim(token::Paren))?; TyKind::Typeof(e) + } else if self.eat(&token::Underscore) { + // A type to be inferred `_` + TyKind::Infer } else if self.eat_lt() { + // Qualified path let (qself, path) = self.parse_qualified_path(PathStyle::Type)?; TyKind::Path(Some(qself), path) } else if self.token.is_path_start() { + // Simple path let path = self.parse_path(PathStyle::Type)?; if self.eat(&token::Not) { - // MACRO INVOCATION + // Macro invocation in type position let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.span.hi; - TyKind::Mac(spanned(lo, hi, Mac_ { path: path, tts: tts })) + TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts })) } else { - // NAMED TYPE - TyKind::Path(None, path) + // Just a type path or bound list (trait object type) starting with a trait. + // `Type` + // `Trait1 + Trait2 + 'a` + if allow_plus && self.check(&token::BinOp(token::Plus)) { + self.parse_remaining_bounds(Vec::new(), path, lo, true)? + } else { + TyKind::Path(None, path) + } } - } else if self.eat(&token::Underscore) { - // TYPE TO BE INFERRED - TyKind::Infer + } else if self.token_is_bare_fn_keyword() { + // Function pointer type + self.parse_ty_bare_fn(Vec::new())? + } else if self.check_keyword(keywords::For) { + // Function pointer type or bound list (trait object type) starting with a poly-trait. + // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` + // `for<'lt> Trait1<'lt> + Trait2 + 'a` + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + if self.token_is_bare_fn_keyword() { + self.parse_ty_bare_fn(lifetime_defs)? + } else { + let path = self.parse_path(PathStyle::Type)?; + let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus)); + self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? + } + } else if self.eat_keyword(keywords::Impl) { + // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). + TyKind::ImplTrait(self.parse_ty_param_bounds()?) + } else if self.check(&token::Question) || + self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)){ + // Bound list (trait object type) + TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?) } else { let msg = format!("expected type, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); }; - let sp = mk_sp(lo, self.prev_span.hi); - Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp})) + let span = lo.to(self.prev_span); + let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID }; + + // Try to recover from use of `+` with incorrect priority. + self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; + + Ok(P(ty)) + } + + fn parse_remaining_bounds(&mut self, lifetime_defs: Vec<LifetimeDef>, path: ast::Path, + lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { + let poly_trait_ref = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)]; + if parse_plus { + self.bump(); // `+` + bounds.append(&mut self.parse_ty_param_bounds()?); + } + Ok(TyKind::TraitObject(bounds)) } - pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: - let opt_lifetime = self.eat_lifetime(); - let mutbl = self.parse_mutability()?; + fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { + // Do not add `+` to expected tokens. + if !allow_plus || self.token != token::BinOp(token::Plus) { + return Ok(()) + } + + self.bump(); // `+` + let bounds = self.parse_ty_param_bounds()?; + let sum_span = ty.span.to(self.prev_span); + + let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178, + "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty)); + + match ty.node { + TyKind::Rptr(ref lifetime, ref mut_ty) => { + let sum_with_parens = pprust::to_string(|s| { + use print::pp::word; + use print::pprust::PrintState; + + word(&mut s.s, "&")?; + s.print_opt_lifetime(lifetime)?; + s.print_mutability(mut_ty.mutbl)?; + s.popen()?; + s.print_type(&mut_ty.ty)?; + s.print_bounds(" +", &bounds)?; + s.pclose() + }); + err.span_suggestion(sum_span, "try adding parentheses:", sum_with_parens); + } + TyKind::Ptr(..) | TyKind::BareFn(..) => { + err.span_label(sum_span, "perhaps you forgot parentheses?"); + } + _ => { + err.span_label(sum_span, "expected a path"); + }, + } + err.emit(); + Ok(()) + } + + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { + let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; + let mutbl = self.parse_mutability(); let ty = self.parse_ty_no_plus()?; return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); } @@ -1550,7 +1552,7 @@ impl<'a> Parser<'a> { pub fn is_named_argument(&mut self) -> bool { let offset = match self.token { - token::BinOp(token::And) => 1, + token::BinOp(token::And) | token::AndAnd => 1, _ if self.token.is_keyword(keywords::Mut) => 1, _ => 0 @@ -1614,7 +1616,7 @@ impl<'a> Parser<'a> { P(Ty { id: ast::DUMMY_NODE_ID, node: TyKind::Infer, - span: mk_sp(self.span.lo, self.span.hi), + span: self.span, }) }; Ok(Arg { @@ -1643,44 +1645,15 @@ impl<'a> Parser<'a> { _ => { return self.unexpected_last(&self.token); } }, token::Literal(lit, suf) => { - let (suffix_illegal, out) = match lit { - token::Byte(i) => (true, LitKind::Byte(parse::byte_lit(&i.as_str()).0)), - token::Char(i) => (true, LitKind::Char(parse::char_lit(&i.as_str()).0)), - - // there are some valid suffixes for integer and - // float literals, so all the handling is done - // internally. - token::Integer(s) => { - let diag = &self.sess.span_diagnostic; - (false, parse::integer_lit(&s.as_str(), suf, diag, self.span)) - } - token::Float(s) => { - let diag = &self.sess.span_diagnostic; - (false, parse::float_lit(&s.as_str(), suf, diag, self.span)) - } - - token::Str_(s) => { - let s = Symbol::intern(&parse::str_lit(&s.as_str())); - (true, LitKind::Str(s, ast::StrStyle::Cooked)) - } - token::StrRaw(s, n) => { - let s = Symbol::intern(&parse::raw_str_lit(&s.as_str())); - (true, LitKind::Str(s, ast::StrStyle::Raw(n))) - } - token::ByteStr(i) => { - (true, LitKind::ByteStr(parse::byte_str_lit(&i.as_str()))) - } - token::ByteStrRaw(i, _) => { - (true, LitKind::ByteStr(Rc::new(i.to_string().into_bytes()))) - } - }; + let diag = Some((self.span, &self.sess.span_diagnostic)); + let (suffix_illegal, result) = parse::lit_token(lit, suf, diag); if suffix_illegal { let sp = self.span; self.expect_no_suffix(sp, &format!("{} literal", lit.short_name()), suf) } - out + result.unwrap() } _ => { return self.unexpected_last(&self.token); } }; @@ -1691,7 +1664,7 @@ impl<'a> Parser<'a> { /// Matches lit = true | false | token_lit pub fn parse_lit(&mut self) -> PResult<'a, Lit> { - let lo = self.span.lo; + let lo = self.span; let lit = if self.eat_keyword(keywords::True) { LitKind::Bool(true) } else if self.eat_keyword(keywords::False) { @@ -1700,22 +1673,22 @@ impl<'a> Parser<'a> { let lit = self.parse_lit_token()?; lit }; - Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.prev_span.hi) }) + Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) }) } /// matches '-' lit | lit pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> { - let minus_lo = self.span.lo; + let minus_lo = self.span; let minus_present = self.eat(&token::BinOp(token::Minus)); - let lo = self.span.lo; + let lo = self.span; let literal = P(self.parse_lit()?); - let hi = self.prev_span.hi; - let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new()); + let hi = self.prev_span; + let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); if minus_present { - let minus_hi = self.prev_span.hi; + let minus_hi = self.prev_span; let unary = self.mk_unary(UnOp::Neg, expr); - Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new())) + Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) } else { Ok(expr) } @@ -1792,7 +1765,7 @@ impl<'a> Parser<'a> { pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { maybe_whole!(self, NtPath, |x| x); - let lo = self.span.lo; + let lo = self.meta_var_span.unwrap_or(self.span); let is_global = self.eat(&token::ModSep); // Parse any number of segments and bound sets. A segment is an @@ -1811,28 +1784,45 @@ impl<'a> Parser<'a> { }; if is_global { - segments.insert(0, ast::PathSegment::crate_root()); + segments.insert(0, PathSegment::crate_root()); } - // Assemble the span. - // FIXME(#39450) This is bogus if part of the path is macro generated. - let span = mk_sp(lo, self.prev_span.hi); - // Assemble the result. Ok(ast::Path { - span: span, + span: lo.to(self.prev_span), segments: segments, }) } + /// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat. + /// This is used when parsing derive macro paths in `#[derive]` attributes. + pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { + let meta_ident = match self.token { + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref meta) => match meta.node { + ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)), + _ => None, + }, + _ => None, + }, + _ => None, + }; + if let Some(ident) = meta_ident { + self.bump(); + return Ok(ast::Path::from_ident(self.prev_span, ident)); + } + self.parse_path(mode) + } + /// Examples: /// - `a::b<T,U>::c<V,W>` /// - `a::b<T,U>::c(V) -> W` /// - `a::b<T,U>::c(V)` - pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec<ast::PathSegment>> { + pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec<PathSegment>> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { @@ -1856,7 +1846,7 @@ impl<'a> Parser<'a> { bindings: bindings, }.into() } else if self.eat(&token::OpenDelim(token::Paren)) { - let lo = self.prev_span.lo; + let lo = self.prev_span; let inputs = self.parse_seq_to_end( &token::CloseDelim(token::Paren), @@ -1869,10 +1859,10 @@ impl<'a> Parser<'a> { None }; - let hi = self.prev_span.hi; + let hi = self.prev_span; Some(P(ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData { - span: mk_sp(lo, hi), + span: lo.to(hi), inputs: inputs, output: output_ty, }))) @@ -1881,7 +1871,11 @@ impl<'a> Parser<'a> { }; // Assemble and push the result. - segments.push(ast::PathSegment { identifier: identifier, parameters: parameters }); + segments.push(PathSegment { + identifier: identifier, + span: ident_span, + parameters: parameters + }); // Continue only if we see a `::` if !self.eat(&token::ModSep) { @@ -1892,15 +1886,16 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::<T,U>::c` - pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec<ast::PathSegment>> { + pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec<PathSegment>> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); return Ok(segments); } @@ -1909,8 +1904,9 @@ impl<'a> Parser<'a> { // Consumed `a::b::<`, go look for types let (lifetimes, types, bindings) = self.parse_generic_args()?; self.expect_gt()?; - segments.push(ast::PathSegment { + segments.push(PathSegment { identifier: identifier, + span: ident_span, parameters: ast::AngleBracketedParameterData { lifetimes: lifetimes, types: types, @@ -1924,7 +1920,7 @@ impl<'a> Parser<'a> { } } else { // Consumed `a::`, go look for `b` - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); } } } @@ -1932,14 +1928,15 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::c` pub fn parse_path_segments_without_types(&mut self) - -> PResult<'a, Vec<ast::PathSegment>> { + -> PResult<'a, Vec<PathSegment>> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -1950,30 +1947,29 @@ impl<'a> Parser<'a> { } } - /// Parse single lifetime 'a or nothing. - pub fn eat_lifetime(&mut self) -> Option<Lifetime> { + fn check_lifetime(&mut self) -> bool { + self.expected_tokens.push(TokenType::Lifetime); + self.token.is_lifetime() + } + + /// Parse single lifetime 'a or panic. + fn expect_lifetime(&mut self) -> Lifetime { match self.token { token::Lifetime(ident) => { + let ident_span = self.span; self.bump(); - Some(Lifetime { - id: ast::DUMMY_NODE_ID, - span: self.prev_span, - name: ident.name - }) - } - _ => { - self.expected_tokens.push(TokenType::Lifetime); - None + Lifetime { ident: ident, span: ident_span, id: ast::DUMMY_NODE_ID } } + _ => self.span_bug(self.span, "not a lifetime") } } /// Parse mutability (`mut` or nothing). - pub fn parse_mutability(&mut self) -> PResult<'a, Mutability> { + fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(keywords::Mut) { - Ok(Mutability::Mutable) + Mutability::Mutable } else { - Ok(Mutability::Immutable) + Mutability::Immutable } } @@ -1989,38 +1985,37 @@ impl<'a> Parser<'a> { /// Parse ident (COLON expr)? pub fn parse_field(&mut self) -> PResult<'a, Field> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let hi; // Check if a colon exists one ahead. This means we're parsing a fieldname. let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { let fieldname = self.parse_field_name()?; self.bump(); - hi = self.prev_span.hi; + hi = self.prev_span; (fieldname, self.parse_expr()?, false) } else { let fieldname = self.parse_ident()?; - hi = self.prev_span.hi; + hi = self.prev_span; // Mimic `x: x` for the `x` field shorthand. - let path = ast::Path::from_ident(mk_sp(lo, hi), fieldname); - (fieldname, self.mk_expr(lo, hi, ExprKind::Path(None, path), ThinVec::new()), true) + let path = ast::Path::from_ident(lo.to(hi), fieldname); + (fieldname, self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()), true) }; Ok(ast::Field { - ident: spanned(lo, hi, fieldname), - span: mk_sp(lo, expr.span.hi), + ident: respan(lo.to(hi), fieldname), + span: lo.to(expr.span), expr: expr, is_shorthand: is_shorthand, attrs: attrs.into(), }) } - pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: ExprKind, attrs: ThinVec<Attribute>) - -> P<Expr> { + pub fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> { P(Expr { id: ast::DUMMY_NODE_ID, node: node, - span: mk_sp(lo, hi), + span: span, attrs: attrs.into(), }) } @@ -2074,12 +2069,11 @@ impl<'a> Parser<'a> { ExprKind::AssignOp(binop, lhs, rhs) } - pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos, - m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> { + pub fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> { P(Expr { id: ast::DUMMY_NODE_ID, - node: ExprKind::Mac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}), - span: mk_sp(lo, hi), + node: ExprKind::Mac(codemap::Spanned {node: m, span: span}), + span: span, attrs: attrs, }) } @@ -2101,10 +2095,10 @@ impl<'a> Parser<'a> { fn expect_delimited_token_tree(&mut self) -> PResult<'a, (token::DelimToken, ThinTokenStream)> { match self.token { - token::OpenDelim(delim) => self.parse_token_tree().map(|tree| match tree { - TokenTree::Delimited(_, delimited) => (delim, delimited.stream().into()), + token::OpenDelim(delim) => match self.parse_token_tree() { + TokenTree::Delimited(_, delimited) => Ok((delim, delimited.stream().into())), _ => unreachable!(), - }), + }, _ => Err(self.fatal("expected open delimiter")), } } @@ -2126,8 +2120,8 @@ impl<'a> Parser<'a> { // attributes by giving them a empty "already parsed" list. let mut attrs = ThinVec::new(); - let lo = self.span.lo; - let mut hi = self.span.hi; + let lo = self.span; + let mut hi = self.span; let ex: ExprKind; @@ -2156,18 +2150,19 @@ impl<'a> Parser<'a> { } self.bump(); - hi = self.prev_span.hi; + hi = self.prev_span; + let span = lo.to(hi); return if es.len() == 1 && !trailing_comma { - Ok(self.mk_expr(lo, hi, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) + Ok(self.mk_expr(span, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) } else { - Ok(self.mk_expr(lo, hi, ExprKind::Tup(es), attrs)) + Ok(self.mk_expr(span, ExprKind::Tup(es), attrs)) } }, token::OpenDelim(token::Brace) => { return self.parse_block_expr(lo, BlockCheckMode::Default, attrs); }, token::BinOp(token::Or) | token::OrOr => { - let lo = self.span.lo; + let lo = self.span; return self.parse_lambda_expr(lo, CaptureBy::Ref, attrs); }, token::OpenDelim(token::Bracket) => { @@ -2205,34 +2200,34 @@ impl<'a> Parser<'a> { ex = ExprKind::Array(vec![first_expr]); } } - hi = self.prev_span.hi; + hi = self.prev_span; } _ => { if self.eat_lt() { let (qself, path) = self.parse_qualified_path(PathStyle::Expr)?; - hi = path.span.hi; - return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs)); + hi = path.span; + return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } if self.eat_keyword(keywords::Move) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_lambda_expr(lo, CaptureBy::Value, attrs); } if self.eat_keyword(keywords::If) { return self.parse_if_expr(attrs); } if self.eat_keyword(keywords::For) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_for_expr(None, lo, attrs); } if self.eat_keyword(keywords::While) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_while_expr(None, lo, attrs); } if self.token.is_lifetime() { - let label = Spanned { node: self.get_lifetime(), + let label = Spanned { node: self.get_label(), span: self.span }; - let lo = self.span.lo; + let lo = self.span; self.bump(); self.expect(&token::Colon)?; if self.eat_keyword(keywords::While) { @@ -2247,13 +2242,13 @@ impl<'a> Parser<'a> { return Err(self.fatal("expected `while`, `for`, or `loop` after a label")) } if self.eat_keyword(keywords::Loop) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_loop_expr(None, lo, attrs); } if self.eat_keyword(keywords::Continue) { let ex = if self.token.is_lifetime() { let ex = ExprKind::Continue(Some(Spanned{ - node: self.get_lifetime(), + node: self.get_label(), span: self.span })); self.bump(); @@ -2261,8 +2256,8 @@ impl<'a> Parser<'a> { } else { ExprKind::Continue(None) }; - let hi = self.prev_span.hi; - return Ok(self.mk_expr(lo, hi, ex, attrs)); + let hi = self.prev_span; + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } if self.eat_keyword(keywords::Match) { return self.parse_match_expr(attrs); @@ -2273,10 +2268,16 @@ impl<'a> Parser<'a> { BlockCheckMode::Unsafe(ast::UserProvided), attrs); } + if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Do)); + assert!(self.eat_keyword(keywords::Catch)); + let lo = self.prev_span; + return self.parse_catch_expr(lo, attrs); + } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; - hi = e.span.hi; + hi = e.span; ex = ExprKind::Ret(Some(e)); } else { ex = ExprKind::Ret(None); @@ -2284,7 +2285,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Break) { let lt = if self.token.is_lifetime() { let spanned_lt = Spanned { - node: self.get_lifetime(), + node: self.get_label(), span: self.span }; self.bump(); @@ -2295,13 +2296,13 @@ impl<'a> Parser<'a> { let e = if self.token.can_begin_expr() && !(self.token == token::OpenDelim(token::Brace) && self.restrictions.contains( - Restrictions::RESTRICTION_NO_STRUCT_LITERAL)) { + RESTRICTION_NO_STRUCT_LITERAL)) { Some(self.parse_expr()?) } else { None }; ex = ExprKind::Break(lt, e); - hi = self.prev_span.hi; + hi = self.prev_span; } else if self.token.is_keyword(keywords::Let) { // Catch this syntax error here, instead of in `check_strict_keywords`, so // that we can explicitly mention that let is not to be used as an expression @@ -2315,26 +2316,26 @@ impl<'a> Parser<'a> { if self.eat(&token::Not) { // MACRO INVOCATION expression let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.prev_span.hi; - return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs)); + let hi = self.prev_span; + return Ok(self.mk_mac_expr(lo.to(hi), Mac_ { path: pth, tts: tts }, attrs)); } if self.check(&token::OpenDelim(token::Brace)) { // This is a struct literal, unless we're prohibited // from parsing struct literals here. let prohibited = self.restrictions.contains( - Restrictions::RESTRICTION_NO_STRUCT_LITERAL + RESTRICTION_NO_STRUCT_LITERAL ); if !prohibited { return self.parse_struct_expr(lo, pth, attrs); } } - hi = pth.span.hi; + hi = pth.span; ex = ExprKind::Path(None, pth); } else { match self.parse_lit() { Ok(lit) => { - hi = lit.span.hi; + hi = lit.span; ex = ExprKind::Lit(P(lit)); } Err(mut err) => { @@ -2348,10 +2349,10 @@ impl<'a> Parser<'a> { } } - return Ok(self.mk_expr(lo, hi, ex, attrs)); + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } - fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec<Attribute>) + fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { self.bump(); let mut fields = Vec::new(); @@ -2393,9 +2394,9 @@ impl<'a> Parser<'a> { } } - let hi = self.span.hi; + let span = lo.to(self.span); self.expect(&token::CloseDelim(token::Brace))?; - return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs)); + return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs)); } fn parse_or_use_outer_attributes(&mut self, @@ -2409,7 +2410,7 @@ impl<'a> Parser<'a> { } /// Parse a block or unsafe block - pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode, + pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode, outer_attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { @@ -2419,7 +2420,7 @@ impl<'a> Parser<'a> { attrs.extend(self.parse_inner_attributes()?); let blk = self.parse_block_tail(lo, blk_mode)?; - return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), attrs)); + return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs)); } /// parse a.b or a(13) or a[4] or just a @@ -2430,12 +2431,12 @@ impl<'a> Parser<'a> { let b = self.parse_bottom_expr(); let (span, b) = self.interpolated_or_expr_span(b)?; - self.parse_dot_or_call_expr_with(b, span.lo, attrs) + self.parse_dot_or_call_expr_with(b, span, attrs) } pub fn parse_dot_or_call_expr_with(&mut self, e0: P<Expr>, - lo: BytePos, + lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { // Stitch the list of outer attributes onto the return value. @@ -2466,11 +2467,7 @@ impl<'a> Parser<'a> { // Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue // parsing into an expression. - fn parse_dot_suffix(&mut self, - ident: Ident, - ident_span: Span, - self_value: P<Expr>, - lo: BytePos) + fn parse_dot_suffix(&mut self, ident: Ident, ident_span: Span, self_value: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> { let (_, tys, bindings) = if self.eat(&token::ModSep) { self.expect_lt()?; @@ -2495,12 +2492,12 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - let hi = self.prev_span.hi; + let hi = self.prev_span; es.insert(0, self_value); - let id = spanned(ident_span.lo, ident_span.hi, ident); + let id = respan(ident_span.to(ident_span), ident); let nd = self.mk_method_call(id, tys, es); - self.mk_expr(lo, hi, nd, ThinVec::new()) + self.mk_expr(lo.to(hi), nd, ThinVec::new()) } // Field access. _ => { @@ -2511,32 +2508,30 @@ impl<'a> Parser<'a> { have type parameters"); } - let id = spanned(ident_span.lo, ident_span.hi, ident); + let id = respan(ident_span.to(ident_span), ident); let field = self.mk_field(self_value, id); - self.mk_expr(lo, ident_span.hi, field, ThinVec::new()) + self.mk_expr(lo.to(ident_span), field, ThinVec::new()) } }) } - fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: BytePos) -> PResult<'a, P<Expr>> { + fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> { let mut e = e0; let mut hi; loop { // expr? while self.eat(&token::Question) { - let hi = self.prev_span.hi; - e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new()); + let hi = self.prev_span; + e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new()); } // expr.f if self.eat(&token::Dot) { match self.token { token::Ident(i) => { - let dot_pos = self.prev_span.hi; - hi = self.span.hi; + let ident_span = self.span; self.bump(); - - e = self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e, lo)?; + e = self.parse_dot_suffix(i, ident_span, e, lo)?; } token::Literal(token::Integer(n), suf) => { let sp = self.span; @@ -2544,16 +2539,16 @@ impl<'a> Parser<'a> { // A tuple index may not have a suffix self.expect_no_suffix(sp, "tuple index", suf); - let dot = self.prev_span.hi; - hi = self.span.hi; + let dot_span = self.prev_span; + hi = self.span; self.bump(); let index = n.as_str().parse::<usize>().ok(); match index { Some(n) => { - let id = spanned(dot, hi, n); + let id = respan(dot_span.to(hi), n); let field = self.mk_tup_field(e, id); - e = self.mk_expr(lo, hi, field, ThinVec::new()); + e = self.mk_expr(lo.to(hi), field, ThinVec::new()); } None => { let prev_span = self.prev_span; @@ -2563,10 +2558,10 @@ impl<'a> Parser<'a> { } token::Literal(token::Float(n), _suf) => { self.bump(); - let prev_span = self.prev_span; let fstr = n.as_str(); - let mut err = self.diagnostic().struct_span_err(prev_span, + let mut err = self.diagnostic().struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n)); + err.span_label(self.prev_span, "unexpected token"); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::<f64>().ok() { Some(f) => f, @@ -2584,7 +2579,7 @@ impl<'a> Parser<'a> { word(&mut s.s, fstr.splitn(2, ".").last().unwrap()) }); err.span_suggestion( - prev_span, + lo.to(self.prev_span), "try parenthesizing the first index", sugg); } @@ -2596,10 +2591,8 @@ impl<'a> Parser<'a> { let actual = self.this_token_to_string(); self.span_err(self.span, &format!("unexpected token: `{}`", actual)); - let dot_pos = self.prev_span.hi; - e = self.parse_dot_suffix(keywords::Invalid.ident(), - mk_sp(dot_pos, dot_pos), - e, lo)?; + let dot_span = self.prev_span; + e = self.parse_dot_suffix(keywords::Invalid.ident(), dot_span, e, lo)?; } } continue; @@ -2614,10 +2607,10 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - hi = self.prev_span.hi; + hi = self.prev_span; let nd = self.mk_call(e, es); - e = self.mk_expr(lo, hi, nd, ThinVec::new()); + e = self.mk_expr(lo.to(hi), nd, ThinVec::new()); } // expr[...] @@ -2625,10 +2618,10 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Bracket) => { self.bump(); let ix = self.parse_expr()?; - hi = self.span.hi; + hi = self.span; self.expect(&token::CloseDelim(token::Bracket))?; let index = self.mk_index(e, ix); - e = self.mk_expr(lo, hi, index, ThinVec::new()) + e = self.mk_expr(lo.to(hi), index, ThinVec::new()) } _ => return Ok(e) } @@ -2636,31 +2629,43 @@ impl<'a> Parser<'a> { return Ok(e); } - pub fn check_unknown_macro_variable(&mut self) { - if let token::SubstNt(name) = self.token { - self.fatal(&format!("unknown macro variable `{}`", name)).emit() - } + pub fn process_potential_macro_variable(&mut self) { + let ident = match self.token { + token::SubstNt(name) => { + self.fatal(&format!("unknown macro variable `{}`", name)).emit(); + return + } + token::Interpolated(ref nt) => { + self.meta_var_span = Some(self.span); + match **nt { + token::NtIdent(ident) => ident, + _ => return, + } + } + _ => return, + }; + self.token = token::Ident(ident.node); + self.span = ident.span; } /// parse a single token tree from the input. - pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> { + pub fn parse_token_tree(&mut self) -> TokenTree { match self.token { token::OpenDelim(..) => { let frame = mem::replace(&mut self.token_cursor.frame, self.token_cursor.stack.pop().unwrap()); self.span = frame.span; self.bump(); - return Ok(TokenTree::Delimited(frame.span, Delimited { + TokenTree::Delimited(frame.span, Delimited { delim: frame.delim, tts: frame.tree_cursor.original_stream().into(), - })); + }) }, token::CloseDelim(_) | token::Eof => unreachable!(), _ => { - let token = mem::replace(&mut self.token, token::Underscore); - let res = Ok(TokenTree::Token(self.span, token)); + let (token, span) = (mem::replace(&mut self.token, token::Underscore), self.span); self.bump(); - res + TokenTree::Token(span, token) } } } @@ -2670,71 +2675,88 @@ impl<'a> Parser<'a> { pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec<TokenTree>> { let mut tts = Vec::new(); while self.token != token::Eof { - tts.push(self.parse_token_tree()?); + tts.push(self.parse_token_tree()); } Ok(tts) } + pub fn parse_tokens(&mut self) -> TokenStream { + let mut result = Vec::new(); + loop { + match self.token { + token::Eof | token::CloseDelim(..) => break, + _ => result.push(self.parse_token_tree().into()), + } + } + TokenStream::concat(result) + } + /// Parse a prefix-unary-operator expr pub fn parse_prefix_expr(&mut self, already_parsed_attrs: Option<ThinVec<Attribute>>) -> PResult<'a, P<Expr>> { let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; - let lo = self.span.lo; - let hi; + let lo = self.span; // Note: when adding new unary operators, don't forget to adjust Token::can_begin_expr() - let ex = match self.token { + let (hi, ex) = match self.token { token::Not => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Not, e) + (span, self.mk_unary(UnOp::Not, e)) + } + // Suggest `!` for bitwise negation when encountering a `~` + token::Tilde => { + self.bump(); + let e = self.parse_prefix_expr(None); + let (span, e) = self.interpolated_or_expr_span(e)?; + let span_of_tilde = lo; + let mut err = self.diagnostic().struct_span_err(span_of_tilde, + "`~` can not be used as a unary operator"); + err.span_label(span_of_tilde, "did you mean `!`?"); + err.help("use `!` instead of `~` if you meant to perform bitwise negation"); + err.emit(); + (span, self.mk_unary(UnOp::Not, e)) } token::BinOp(token::Minus) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Neg, e) + (span, self.mk_unary(UnOp::Neg, e)) } token::BinOp(token::Star) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Deref, e) + (span, self.mk_unary(UnOp::Deref, e)) } token::BinOp(token::And) | token::AndAnd => { self.expect_and()?; - let m = self.parse_mutability()?; + let m = self.parse_mutability(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - ExprKind::AddrOf(m, e) + (span, ExprKind::AddrOf(m, e)) } token::Ident(..) if self.token.is_keyword(keywords::In) => { self.bump(); let place = self.parse_expr_res( - Restrictions::RESTRICTION_NO_STRUCT_LITERAL, + RESTRICTION_NO_STRUCT_LITERAL, None, )?; let blk = self.parse_block()?; let span = blk.span; - hi = span.hi; - let blk_expr = self.mk_expr(span.lo, hi, ExprKind::Block(blk), ThinVec::new()); - ExprKind::InPlace(place, blk_expr) + let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new()); + (span, ExprKind::InPlace(place, blk_expr)) } token::Ident(..) if self.token.is_keyword(keywords::Box) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - ExprKind::Box(e) + (span, ExprKind::Box(e)) } _ => return self.parse_dot_or_call_expr(Some(attrs)) }; - return Ok(self.mk_expr(lo, hi, ex, attrs)); + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } /// Parse an associative expression @@ -2781,7 +2803,7 @@ impl<'a> Parser<'a> { let cur_op_span = self.span; let restrictions = if op.is_assign_like() { - self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL + self.restrictions & RESTRICTION_NO_STRUCT_LITERAL } else { self.restrictions }; @@ -2795,13 +2817,11 @@ impl<'a> Parser<'a> { // Special cases: if op == AssocOp::As { let rhs = self.parse_ty_no_plus()?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); - lhs = self.mk_expr(lo, hi, ExprKind::Cast(lhs, rhs), ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Cast(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::Colon { let rhs = self.parse_ty_no_plus()?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); - lhs = self.mk_expr(lo, hi, ExprKind::Type(lhs, rhs), ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Type(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot { // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to @@ -2827,19 +2847,19 @@ impl<'a> Parser<'a> { }; let r = try!(self.mk_range(Some(lhs), rhs, limits)); - lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs_span), r, ThinVec::new()); break } let rhs = match op.fixity() { Fixity::Right => self.with_res( - restrictions - Restrictions::RESTRICTION_STMT_EXPR, + restrictions - RESTRICTION_STMT_EXPR, |this| { this.parse_assoc_expr_with(op.precedence(), LhsExpr::NotYetParsed) }), Fixity::Left => self.with_res( - restrictions - Restrictions::RESTRICTION_STMT_EXPR, + restrictions - RESTRICTION_STMT_EXPR, |this| { this.parse_assoc_expr_with(op.precedence() + 1, LhsExpr::NotYetParsed) @@ -2847,14 +2867,14 @@ impl<'a> Parser<'a> { // We currently have no non-associative operators that are not handled above by // the special cases. The code is here only for future convenience. Fixity::None => self.with_res( - restrictions - Restrictions::RESTRICTION_STMT_EXPR, + restrictions - RESTRICTION_STMT_EXPR, |this| { this.parse_assoc_expr_with(op.precedence() + 1, LhsExpr::NotYetParsed) }), }?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); + let span = lhs_span.to(rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor | @@ -2863,12 +2883,12 @@ impl<'a> Parser<'a> { AssocOp::Greater | AssocOp::GreaterEqual => { let ast_op = op.to_ast_binop().unwrap(); let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs); - self.mk_expr(lo, hi, binary, ThinVec::new()) + self.mk_expr(span, binary, ThinVec::new()) } AssocOp::Assign => - self.mk_expr(lo, hi, ExprKind::Assign(lhs, rhs), ThinVec::new()), + self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), AssocOp::Inplace => - self.mk_expr(lo, hi, ExprKind::InPlace(lhs, rhs), ThinVec::new()), + self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, @@ -2883,7 +2903,7 @@ impl<'a> Parser<'a> { token::Shr => BinOpKind::Shr, }; let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); - self.mk_expr(lo, hi, aopexpr, ThinVec::new()) + self.mk_expr(span, aopexpr, ThinVec::new()) } AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => { self.bug("As, Colon, DotDot or DotDotDot branch reached") @@ -2903,10 +2923,13 @@ impl<'a> Parser<'a> { match lhs.node { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // respan to include both operators - let op_span = mk_sp(op.span.lo, self.span.hi); + let op_span = op.span.to(self.span); let mut err = self.diagnostic().struct_span_err(op_span, "chained comparison operators require parentheses"); - if op.node == BinOpKind::Lt && *outer_op == AssocOp::Greater { + if op.node == BinOpKind::Lt && + *outer_op == AssocOp::Less || // Include `<` to provide this recommendation + *outer_op == AssocOp::Greater // even in a case like the following: + { // Foo<Bar<Baz<Qux, ()>>> err.help( "use `::<...>` instead of `<...>` if you meant to specify type arguments"); } @@ -2923,8 +2946,8 @@ impl<'a> Parser<'a> { debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot); let tok = self.token.clone(); let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; - let lo = self.span.lo; - let mut hi = self.span.hi; + let lo = self.span; + let mut hi = self.span; self.bump(); let opt_end = if self.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. @@ -2932,7 +2955,7 @@ impl<'a> Parser<'a> { Some(self.parse_assoc_expr_with(next_prec, LhsExpr::NotYetParsed) .map(|x|{ - hi = x.span.hi; + hi = x.span; x })?) } else { @@ -2947,14 +2970,14 @@ impl<'a> Parser<'a> { let r = try!(self.mk_range(None, opt_end, limits)); - Ok(self.mk_expr(lo, hi, r, attrs)) + Ok(self.mk_expr(lo.to(hi), r, attrs)) } fn is_at_start_of_range_notation_rhs(&self) -> bool { if self.token.can_begin_expr() { // parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`. if self.token == token::OpenDelim(token::Brace) { - return !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL); + return !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL); } true } else { @@ -2967,60 +2990,59 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Let) { return self.parse_if_let_expr(attrs); } - let lo = self.prev_span.lo; - let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; + let lo = self.prev_span; + let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?; let thn = self.parse_block()?; let mut els: Option<P<Expr>> = None; - let mut hi = thn.span.hi; + let mut hi = thn.span; if self.eat_keyword(keywords::Else) { let elexpr = self.parse_else_expr()?; - hi = elexpr.span.hi; + hi = elexpr.span; els = Some(elexpr); } - Ok(self.mk_expr(lo, hi, ExprKind::If(cond, thn, els), attrs)) + Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs)) } /// Parse an 'if let' expression ('if' token already eaten) pub fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { - let lo = self.prev_span.lo; + let lo = self.prev_span; self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; self.expect(&token::Eq)?; - let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; + let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?; let thn = self.parse_block()?; let (hi, els) = if self.eat_keyword(keywords::Else) { let expr = self.parse_else_expr()?; - (expr.span.hi, Some(expr)) + (expr.span, Some(expr)) } else { - (thn.span.hi, None) + (thn.span, None) }; - Ok(self.mk_expr(lo, hi, ExprKind::IfLet(pat, expr, thn, els), attrs)) + Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs)) } // `move |args| expr` pub fn parse_lambda_expr(&mut self, - lo: BytePos, + lo: Span, capture_clause: CaptureBy, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { let decl = self.parse_fn_block_decl()?; - let decl_hi = self.prev_span.hi; + let decl_hi = self.prev_span; let body = match decl.output { FunctionRetTy::Default(_) => self.parse_expr()?, _ => { // If an explicit return type is given, require a // block to appear (RFC 968). - let body_lo = self.span.lo; + let body_lo = self.span; self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())? } }; Ok(self.mk_expr( - lo, - body.span.hi, - ExprKind::Closure(capture_clause, decl, body, mk_sp(lo, decl_hi)), + lo.to(body.span), + ExprKind::Closure(capture_clause, decl, body, lo.to(decl_hi)), attrs)) } @@ -3030,73 +3052,78 @@ impl<'a> Parser<'a> { return self.parse_if_expr(ThinVec::new()); } else { let blk = self.parse_block()?; - return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), ThinVec::new())); + return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), ThinVec::new())); } } /// Parse a 'for' .. 'in' expression ('for' token already eaten) pub fn parse_for_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { // Parse: `for <src_pat> in <src_expr> <src_loop_block>` let pat = self.parse_pat()?; self.expect_keyword(keywords::In)?; - let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; + let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = self.prev_span.hi; - - Ok(self.mk_expr(span_lo, hi, - ExprKind::ForLoop(pat, expr, loop_block, opt_ident), - attrs)) + let hi = self.prev_span; + Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs)) } /// Parse a 'while' or 'while let' expression ('while' token already eaten) pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { if self.token.is_keyword(keywords::Let) { return self.parse_while_let_expr(opt_ident, span_lo, attrs); } - let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; + let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - return Ok(self.mk_expr(span_lo, hi, ExprKind::While(cond, body, opt_ident), - attrs)); + let span = span_lo.to(body.span); + return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs)); } /// Parse a 'while let' expression ('while' token already eaten) pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; self.expect(&token::Eq)?; - let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; + let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - return Ok(self.mk_expr(span_lo, hi, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); + let span = span_lo.to(body.span); + return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); } // parse `loop {...}`, `loop` token already eaten pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) + let span = span_lo.to(body.span); + Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs)) + } + + /// Parse a `do catch {...}` expression (`do catch` token already eaten) + pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>) + -> PResult<'a, P<Expr>> + { + let (iattrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(iattrs); + Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs)) } // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { let match_span = self.prev_span; - let lo = self.prev_span.lo; - let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, + let lo = self.prev_span; + let discriminant = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?; if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) { if self.token == token::Token::Semi { @@ -3114,17 +3141,17 @@ impl<'a> Parser<'a> { // Recover by skipping to the end of the block. e.emit(); self.recover_stmt(); - let hi = self.span.hi; + let span = lo.to(self.span); if self.token == token::CloseDelim(token::Brace) { self.bump(); } - return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(span, ExprKind::Match(discriminant, arms), attrs)); } } } - let hi = self.span.hi; + let hi = self.span; self.bump(); - return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs)); } pub fn parse_arm(&mut self) -> PResult<'a, Arm> { @@ -3132,12 +3159,13 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; let pats = self.parse_pats()?; - let mut guard = None; - if self.eat_keyword(keywords::If) { - guard = Some(self.parse_expr()?); - } + let guard = if self.eat_keyword(keywords::If) { + Some(self.parse_expr()?) + } else { + None + }; self.expect(&token::FatArrow)?; - let expr = self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR, None)?; + let expr = self.parse_expr_res(RESTRICTION_STMT_EXPR, None)?; let require_comma = !classify::expr_is_simple_block(&expr) @@ -3298,7 +3326,7 @@ impl<'a> Parser<'a> { } let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let hi; if self.check(&token::DotDot) { @@ -3318,16 +3346,16 @@ impl<'a> Parser<'a> { let fieldname = self.parse_field_name()?; self.bump(); let pat = self.parse_pat()?; - hi = pat.span.hi; + hi = pat.span; (pat, fieldname, false) } else { // Parsing a pattern of the form "(box) (ref) (mut) fieldname" let is_box = self.eat_keyword(keywords::Box); - let boxed_span_lo = self.span.lo; + let boxed_span = self.span; let is_ref = self.eat_keyword(keywords::Ref); let is_mut = self.eat_keyword(keywords::Mut); let fieldname = self.parse_ident()?; - hi = self.prev_span.hi; + hi = self.prev_span; let bind_type = match (is_ref, is_mut) { (true, true) => BindingMode::ByRef(Mutability::Mutable), @@ -3339,14 +3367,14 @@ impl<'a> Parser<'a> { let fieldpat = P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: PatKind::Ident(bind_type, fieldpath, None), - span: mk_sp(boxed_span_lo, hi), + span: boxed_span.to(hi), }); let subpat = if is_box { P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: PatKind::Box(fieldpat), - span: mk_sp(lo, hi), + span: lo.to(hi), }) } else { fieldpat @@ -3354,7 +3382,7 @@ impl<'a> Parser<'a> { (subpat, fieldname, true) }; - fields.push(codemap::Spanned { span: mk_sp(lo, hi), + fields.push(codemap::Spanned { span: lo.to(hi), node: ast::FieldPat { ident: fieldname, pat: subpat, @@ -3368,7 +3396,7 @@ impl<'a> Parser<'a> { fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> { if self.token.is_path_start() { - let lo = self.span.lo; + let lo = self.span; let (qself, path) = if self.eat_lt() { // Parse a qualified path let (qself, path) = @@ -3378,8 +3406,8 @@ impl<'a> Parser<'a> { // Parse an unqualified path (None, self.parse_path(PathStyle::Expr)?) }; - let hi = self.prev_span.hi; - Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new())) + let hi = self.prev_span; + Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new())) } else { self.parse_pat_literal_maybe_minus() } @@ -3405,7 +3433,7 @@ impl<'a> Parser<'a> { pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> { maybe_whole!(self, NtPat, |x| x); - let lo = self.span.lo; + let lo = self.span; let pat; match self.token { token::Underscore => { @@ -3416,7 +3444,7 @@ impl<'a> Parser<'a> { token::BinOp(token::And) | token::AndAnd => { // Parse &pat / &mut pat self.expect_and()?; - let mutbl = self.parse_mutability()?; + let mutbl = self.parse_mutability(); if let token::Lifetime(ident) = self.token { return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident))); } @@ -3443,7 +3471,7 @@ impl<'a> Parser<'a> { pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?; } else if self.eat_keyword(keywords::Ref) { // Parse ref ident @ pat / ref mut ident @ pat - let mutbl = self.parse_mutability()?; + let mutbl = self.parse_mutability(); pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?; } else if self.eat_keyword(keywords::Box) { // Parse box pat @@ -3471,7 +3499,7 @@ impl<'a> Parser<'a> { // Parse macro invocation self.bump(); let (_, tts) = self.expect_delimited_token_tree()?; - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts }); pat = PatKind::Mac(mac); } token::DotDotDot | token::DotDot => { @@ -3481,9 +3509,8 @@ impl<'a> Parser<'a> { _ => panic!("can only parse `..` or `...` for ranges (checked above)"), }; // Parse range - let hi = self.prev_span.hi; - let begin = - self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()); + 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()?; pat = PatKind::Range(begin, end, end_kind); @@ -3537,11 +3564,10 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; Ok(P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, - span: mk_sp(lo, hi), + span: lo.to(self.prev_span), })) } @@ -3551,9 +3577,9 @@ impl<'a> Parser<'a> { fn parse_pat_ident(&mut self, binding_mode: ast::BindingMode) -> PResult<'a, PatKind> { + let ident_span = self.span; let ident = self.parse_ident()?; - let prev_span = self.prev_span; - let name = codemap::Spanned{span: prev_span, node: ident}; + let name = codemap::Spanned{span: ident_span, node: ident}; let sub = if self.eat(&token::At) { Some(self.parse_pat()?) } else { @@ -3577,27 +3603,28 @@ impl<'a> Parser<'a> { /// Parse a local variable declaration fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> { - let lo = self.span.lo; + let lo = self.span; let pat = self.parse_pat()?; - let mut ty = None; - if self.eat(&token::Colon) { - ty = Some(self.parse_ty()?); - } + let ty = if self.eat(&token::Colon) { + Some(self.parse_ty()?) + } else { + None + }; let init = self.parse_initializer()?; Ok(P(ast::Local { ty: ty, pat: pat, init: init, id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), attrs: attrs, })) } /// Parse a structure field fn parse_name_and_ty(&mut self, - lo: BytePos, + lo: Span, vis: Visibility, attrs: Vec<Attribute>) -> PResult<'a, StructField> { @@ -3605,7 +3632,7 @@ impl<'a> Parser<'a> { self.expect(&token::Colon)?; let ty = self.parse_ty()?; Ok(StructField { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), ident: Some(name), vis: vis, id: ast::DUMMY_NODE_ID, @@ -3635,22 +3662,33 @@ impl<'a> Parser<'a> { // // We terminate when we find an unmatched `}` (without consuming it). fn recover_stmt(&mut self) { - self.recover_stmt_(SemiColonMode::Ignore) + self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) } + // If `break_on_semi` is `Break`, then we will stop consuming tokens after // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is // approximate - it can mean we break too early due to macros, but that // shoud only lead to sub-optimal recovery, not inaccurate parsing). - fn recover_stmt_(&mut self, break_on_semi: SemiColonMode) { + // + // If `break_on_block` is `Break`, then we will stop consuming tokens + // after finding (and consuming) a brace-delimited block. + fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { let mut brace_depth = 0; let mut bracket_depth = 0; - debug!("recover_stmt_ enter loop"); + let mut in_block = false; + debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", + break_on_semi, break_on_block); loop { debug!("recover_stmt_ loop {:?}", self.token); match self.token { token::OpenDelim(token::DelimToken::Brace) => { brace_depth += 1; self.bump(); + if break_on_block == BlockMode::Break && + brace_depth == 1 && + bracket_depth == 0 { + in_block = true; + } } token::OpenDelim(token::DelimToken::Bracket) => { bracket_depth += 1; @@ -3663,6 +3701,10 @@ impl<'a> Parser<'a> { } brace_depth -= 1; self.bump(); + if in_block && bracket_depth == 0 && brace_depth == 0 { + debug!("recover_stmt_ return - block end {:?}", self.token); + return; + } } token::CloseDelim(token::DelimToken::Bracket) => { bracket_depth -= 1; @@ -3694,11 +3736,20 @@ impl<'a> Parser<'a> { fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> { self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| { e.emit(); - self.recover_stmt_(SemiColonMode::Break); + self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None }) } + fn is_catch_expr(&mut self) -> bool { + self.token.is_keyword(keywords::Do) && + self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && + self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) && + + // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. + !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL) + } + fn is_union_item(&self) -> bool { self.token.is_keyword(keywords::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) @@ -3706,32 +3757,60 @@ impl<'a> Parser<'a> { fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility) -> PResult<'a, Option<P<Item>>> { - let lo = self.span.lo; - match self.token { - token::Ident(ident) if ident.name == "macro_rules" => { - if self.look_ahead(1, |t| *t == token::Not) { - let prev_span = self.prev_span; - self.complain_if_pub_macro(vis, prev_span); - self.bump(); - self.bump(); + let lo = self.span; + let (ident, def) = match self.token { + token::Ident(ident) if ident.name == keywords::Macro.name() => { + self.bump(); + let ident = self.parse_ident()?; + let tokens = if self.check(&token::OpenDelim(token::Brace)) { + match self.parse_token_tree() { + TokenTree::Delimited(_, ref delimited) => delimited.stream(), + _ => unreachable!(), + } + } else if self.check(&token::OpenDelim(token::Paren)) { + let args = self.parse_token_tree(); + let body = if self.check(&token::OpenDelim(token::Brace)) { + self.parse_token_tree() + } else { + self.unexpected()?; + unreachable!() + }; + TokenStream::concat(vec![ + args.into(), + TokenTree::Token(lo.to(self.prev_span), token::FatArrow).into(), + body.into(), + ]) + } else { + self.unexpected()?; + unreachable!() + }; + + (ident, ast::MacroDef { tokens: tokens.into(), legacy: false }) + } + token::Ident(ident) if ident.name == "macro_rules" && + self.look_ahead(1, |t| *t == token::Not) => { + let prev_span = self.prev_span; + self.complain_if_pub_macro(vis, prev_span); + self.bump(); + self.bump(); + + let ident = self.parse_ident()?; + let (delim, tokens) = self.expect_delimited_token_tree()?; + if delim != token::Brace { + if !self.eat(&token::Semi) { + let msg = "macros that expand to items must either \ + be surrounded with braces or followed by a semicolon"; + self.span_err(self.prev_span, msg); + } } + + (ident, ast::MacroDef { tokens: tokens, legacy: true }) } _ => return Ok(None), }; - let id = self.parse_ident()?; - let (delim, tts) = self.expect_delimited_token_tree()?; - if delim != token::Brace { - if !self.eat(&token::Semi) { - let msg = "macros that expand to items must either be surrounded with braces \ - or followed by a semicolon"; - self.span_err(self.prev_span, msg); - } - } - - let hi = self.prev_span.hi; - let kind = ItemKind::MacroDef(tts); - Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned()))) + let span = lo.to(self.prev_span); + Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec()))) } fn parse_stmt_without_recovery(&mut self, @@ -3740,19 +3819,19 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtStmt, |x| Some(x)); let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; Ok(Some(if self.eat_keyword(keywords::Let) { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Local(self.parse_local(attrs.into())?), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), } } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Item(macro_def), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), } // Starts like a simple path, but not a union item. } else if self.token.is_path_start() && @@ -3764,11 +3843,11 @@ impl<'a> Parser<'a> { let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, pth, ThinVec::new())? } else { - let hi = self.prev_span.hi; - self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new()) + let hi = self.prev_span; + self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new()) }; - let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| { + let expr = self.with_res(RESTRICTION_STMT_EXPR, |this| { let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) })?; @@ -3776,7 +3855,7 @@ impl<'a> Parser<'a> { return Ok(Some(Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Expr(expr), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), })); } @@ -3807,7 +3886,7 @@ impl<'a> Parser<'a> { }; let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.prev_span.hi; + let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces @@ -3816,7 +3895,7 @@ impl<'a> Parser<'a> { }; if id.name == keywords::Invalid.name() { - let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(hi), Mac_ { path: pth, tts: tts }); let node = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) @@ -3836,14 +3915,14 @@ impl<'a> Parser<'a> { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs.into()))) } else { - let e = self.mk_mac_expr(lo, hi, mac.node, ThinVec::new()); + let e = self.mk_mac_expr(lo.to(hi), mac.node, ThinVec::new()); let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), node: node, } } else { @@ -3858,13 +3937,14 @@ impl<'a> Parser<'a> { followed by a semicolon"); } } + let span = lo.to(hi); Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: span, node: StmtKind::Item({ self.mk_item( - lo, hi, id /*id is good here*/, - ItemKind::Mac(spanned(lo, hi, Mac_ { path: pth, tts: tts })), + span, id /*id is good here*/, + ItemKind::Mac(respan(span, Mac_ { path: pth, tts: tts })), Visibility::Inherited, attrs) }), @@ -3876,15 +3956,16 @@ impl<'a> Parser<'a> { mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); let item = self.parse_item_(attrs.clone(), false, true)?; self.directory.ownership = old_directory_ownership; + match item { Some(i) => Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, i.span.hi), + span: lo.to(i.span), node: StmtKind::Item(i), }, None => { let unused_attrs = |attrs: &[_], s: &mut Self| { - if attrs.len() > 0 { + if !attrs.is_empty() { if s.prev_token_kind == PrevTokenKind::DocComment { s.span_fatal_err(s.prev_span, Error::UselessDocComment).emit(); } else { @@ -3907,10 +3988,10 @@ impl<'a> Parser<'a> { // Remainder are line-expr stmts. let e = self.parse_expr_res( - Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into()))?; + RESTRICTION_STMT_EXPR, Some(attrs.into()))?; Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, e.span.hi), + span: lo.to(e.span), node: StmtKind::Expr(e), } } @@ -3920,7 +4001,7 @@ impl<'a> Parser<'a> { /// Is this expression a successfully-parsed statement? fn expr_is_complete(&mut self, e: &Expr) -> bool { - self.restrictions.contains(Restrictions::RESTRICTION_STMT_EXPR) && + self.restrictions.contains(RESTRICTION_STMT_EXPR) && !classify::expr_requires_semi_to_be_stmt(e) } @@ -3928,7 +4009,7 @@ impl<'a> Parser<'a> { pub fn parse_block(&mut self) -> PResult<'a, P<Block>> { maybe_whole!(self, NtBlock, |x| x); - let lo = self.span.lo; + let lo = self.span; if !self.eat(&token::OpenDelim(token::Brace)) { let sp = self.span; @@ -3958,7 +4039,7 @@ impl<'a> Parser<'a> { e.span_suggestion(stmt_span, "try placing this code inside a block", sugg); } Err(mut e) => { - self.recover_stmt_(SemiColonMode::Break); + self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); self.cancel(&mut e); } _ => () @@ -3973,7 +4054,7 @@ impl<'a> Parser<'a> { fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec<Attribute>, P<Block>)> { maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); - let lo = self.span.lo; + let lo = self.span; self.expect(&token::OpenDelim(token::Brace))?; Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, BlockCheckMode::Default)?)) @@ -3981,7 +4062,7 @@ impl<'a> Parser<'a> { /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. - fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P<Block>> { + fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> { let mut stmts = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { @@ -3999,7 +4080,7 @@ impl<'a> Parser<'a> { stmts: stmts, id: ast::DUMMY_NODE_ID, rules: s, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), })) } @@ -4050,34 +4131,51 @@ impl<'a> Parser<'a> { }).emit(); } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. + // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) - // TY_BOUND = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) - fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> - { + // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) + // TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) + fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if let Some(lifetime) = self.eat_lifetime() { - if let Some(question_span) = question { - self.span_err(question_span, - "`?` may only modify trait bounds, not lifetime bounds"); - } - bounds.push(RegionTyParamBound(lifetime)); - } else {if self.check_keyword(keywords::For) || self.check_path() { - let poly_trait_ref = self.parse_poly_trait_ref()?; - let modifier = if question.is_some() { - TraitBoundModifier::Maybe + let is_bound_start = self.check_path() || self.check_lifetime() || + self.check(&token::Question) || + self.check_keyword(keywords::For) || + self.check(&token::OpenDelim(token::Paren)); + if is_bound_start { + let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if self.token.is_lifetime() { + if let Some(question_span) = question { + self.span_err(question_span, + "`?` may only modify trait bounds, not lifetime bounds"); + } + bounds.push(RegionTyParamBound(self.expect_lifetime())); } else { - TraitBoundModifier::None - }; - bounds.push(TraitTyParamBound(poly_trait_ref, modifier)); + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let modifier = if question.is_some() { + TraitBoundModifier::Maybe + } else { + TraitBoundModifier::None + }; + bounds.push(TraitTyParamBound(poly_trait, modifier)); + } + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + if let Some(&RegionTyParamBound(..)) = bounds.last() { + self.span_err(self.prev_span, + "parenthesized lifetime bounds are not supported"); + } + } } else { break - }} + } - if !self.eat(&token::BinOp(token::Plus)) { + if !allow_plus || !self.eat(&token::BinOp(token::Plus)) { break } } @@ -4085,12 +4183,16 @@ impl<'a> Parser<'a> { return Ok(bounds); } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. + fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> { + self.parse_ty_param_bounds_common(true) + } + + // Parse bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = LT_BOUND (e.g. `'a`) fn parse_lt_param_bounds(&mut self) -> Vec<Lifetime> { let mut lifetimes = Vec::new(); - while let Some(lifetime) = self.eat_lifetime() { - lifetimes.push(lifetime); + while self.check_lifetime() { + lifetimes.push(self.expect_lifetime()); if !self.eat(&token::BinOp(token::Plus)) { break @@ -4135,7 +4237,8 @@ impl<'a> Parser<'a> { let mut seen_ty_param = false; loop { let attrs = self.parse_outer_attributes()?; - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() { + let lifetime = self.expect_lifetime(); // Parse lifetime parameter. let bounds = if self.eat(&token::Colon) { self.parse_lt_param_bounds() @@ -4151,7 +4254,7 @@ impl<'a> Parser<'a> { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else {if self.check_ident() { + } else if self.check_ident() { // Parse type parameter. ty_params.push(self.parse_ty_param(attrs)?); seen_ty_param = true; @@ -4163,7 +4266,7 @@ impl<'a> Parser<'a> { &format!("trailing attribute after {} parameters", param_kind)); } break - }} + } if !self.eat(&token::Comma) { break @@ -4182,7 +4285,7 @@ impl<'a> Parser<'a> { pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { maybe_whole!(self, NtGenerics, |x| x); - let span_lo = self.span.lo; + let span_lo = self.span; if self.eat_lt() { let (lifetime_defs, ty_params) = self.parse_generic_params()?; self.expect_gt()?; @@ -4193,7 +4296,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, - span: mk_sp(span_lo, self.prev_span.hi), + span: span_lo.to(self.prev_span), }) } else { Ok(ast::Generics::default()) @@ -4209,16 +4312,16 @@ impl<'a> Parser<'a> { let mut seen_type = false; let mut seen_binding = false; loop { - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { // Parse lifetime argument. - lifetimes.push(lifetime); + lifetimes.push(self.expect_lifetime()); if seen_type || seen_binding { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else {if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { + } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { // Parse associated type binding. - let lo = self.span.lo; + let lo = self.span; let ident = self.parse_ident()?; self.bump(); let ty = self.parse_ty()?; @@ -4226,7 +4329,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, ident: ident, ty: ty, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), }); seen_binding = true; } else if self.check_type() { @@ -4239,7 +4342,7 @@ impl<'a> Parser<'a> { seen_type = true; } else { break - }} + } if !self.eat(&token::Comma) { break @@ -4283,19 +4386,20 @@ impl<'a> Parser<'a> { } loop { - let lo = self.span.lo; - if let Some(lifetime) = self.eat_lifetime() { + let lo = self.span; + if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { + let lifetime = self.expect_lifetime(); // Bounds starting with a colon are mandatory, but possibly empty. self.expect(&token::Colon)?; let bounds = self.parse_lt_param_bounds(); where_clause.predicates.push(ast::WherePredicate::RegionPredicate( ast::WhereRegionPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), lifetime: lifetime, bounds: bounds, } )); - } else {if self.check_type() { + } else if self.check_type() { // Parse optional `for<'a, 'b>`. // This `for` is parsed greedily and applies to the whole predicate, // the bounded type can have its own `for` applying only to it. @@ -4311,7 +4415,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_ty_param_bounds()?; where_clause.predicates.push(ast::WherePredicate::BoundPredicate( ast::WhereBoundPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), bound_lifetimes: lifetime_defs, bounded_ty: ty, bounds: bounds, @@ -4322,7 +4426,7 @@ impl<'a> Parser<'a> { let rhs_ty = self.parse_ty()?; where_clause.predicates.push(ast::WherePredicate::EqPredicate( ast::WhereEqPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), lhs_ty: ty, rhs_ty: rhs_ty, id: ast::DUMMY_NODE_ID, @@ -4333,7 +4437,7 @@ impl<'a> Parser<'a> { } } else { break - }} + } if !self.eat(&token::Comma) { break @@ -4373,8 +4477,12 @@ impl<'a> Parser<'a> { Ok(arg) => 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)]); - Ok(None) + // Create a placeholder argument for proper arg count (#34264). + let span = lo.to(p.prev_span); + Ok(Some(dummy_arg(span))) } } } @@ -4408,7 +4516,7 @@ impl<'a> Parser<'a> { fn parse_self_arg(&mut self) -> PResult<'a, Option<Arg>> { let expect_ident = |this: &mut Self| match this.token { // Preserve hygienic context. - token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) } + token::Ident(ident) => { let sp = this.span; this.bump(); codemap::respan(sp, ident) } _ => unreachable!() }; let isolated_self = |this: &mut Self, n| { @@ -4419,7 +4527,7 @@ impl<'a> Parser<'a> { // Parse optional self parameter of a method. // Only a limited set of initial token sequences is considered self parameters, anything // else is parsed as a normal function parameter list, so some lookahead is required. - let eself_lo = self.span.lo; + let eself_lo = self.span; let (eself, eself_ident) = match self.token { token::BinOp(token::And) => { // &self @@ -4438,13 +4546,13 @@ impl<'a> Parser<'a> { } else if self.look_ahead(1, |t| t.is_lifetime()) && isolated_self(self, 2) { self.bump(); - let lt = self.eat_lifetime().expect("not a lifetime"); + let lt = self.expect_lifetime(); (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && isolated_self(self, 3) { self.bump(); - let lt = self.eat_lifetime().expect("not a lifetime"); + let lt = self.expect_lifetime(); self.bump(); (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { @@ -4501,7 +4609,7 @@ impl<'a> Parser<'a> { _ => return Ok(None), }; - let eself = codemap::respan(mk_sp(eself_lo, self.prev_span.hi), eself); + let eself = codemap::respan(eself_lo.to(self.prev_span), eself); Ok(Some(Arg::from_self(eself, eself_ident))) } @@ -4573,8 +4681,7 @@ impl<'a> Parser<'a> { Ok((id, generics)) } - fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident, - node: ItemKind, vis: Visibility, + fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility, attrs: Vec<Attribute>) -> P<Item> { P(Item { ident: ident, @@ -4582,7 +4689,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, node: node, vis: vis, - span: mk_sp(lo, hi) + span: span, }) } @@ -4636,12 +4743,12 @@ impl<'a> Parser<'a> { } /// Parse an impl item. - pub fn parse_impl_item(&mut self) -> PResult<'a, ImplItem> { + pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> { maybe_whole!(self, NtImplItem, |x| x); let mut attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let lo = self.span; + let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; @@ -4659,14 +4766,14 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; (name, ast::ImplItemKind::Const(typ, expr)) } else { - let (name, inner_attrs, node) = self.parse_impl_method(&vis)?; + let (name, inner_attrs, node) = self.parse_impl_method(&vis, at_end)?; attrs.extend(inner_attrs); (name, node) }; Ok(ImplItem { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), ident: name, vis: vis, defaultness: defaultness, @@ -4675,51 +4782,85 @@ impl<'a> Parser<'a> { }) } - fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) { - match *visa { - Visibility::Inherited => (), + fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) { + if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) { + err.emit(); + } + } + + fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> { + match *vis { + Visibility::Inherited => Ok(()), _ => { let is_macro_rules: bool = match self.token { token::Ident(sid) => sid.name == Symbol::intern("macro_rules"), _ => false, }; if is_macro_rules { - self.diagnostic().struct_span_err(span, "can't qualify macro_rules \ - invocation with `pub`") - .help("did you mean #[macro_export]?") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); + err.help("did you mean #[macro_export]?"); + Err(err) } else { - self.diagnostic().struct_span_err(span, "can't qualify macro \ - invocation with `pub`") - .help("try adjusting the macro to put `pub` \ - inside the invocation") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro invocation with `pub`"); + err.help("try adjusting the macro to put `pub` inside the invocation"); + Err(err) } } } } + fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span) + -> DiagnosticBuilder<'a> + { + // Given this code `path(`, it seems like this is not + // setting the visibility of a macro invocation, but rather + // a mistyped method declaration. + // Create a diagnostic pointing out that `fn` is missing. + // + // x | pub path(&self) { + // | ^ missing `fn`, `type`, or `const` + // pub path( + // ^^ `sp` below will point to this + let sp = prev_span.between(self.prev_span); + let mut err = self.diagnostic().struct_span_err( + sp, + &format!("missing `fn`, `type`, or `const` for {}-item declaration", + item_type)); + err.span_label(sp, "missing `fn`, `type`, or `const`"); + err + } + /// Parse a method or a macro invocation in a trait impl. - fn parse_impl_method(&mut self, vis: &Visibility) + fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool) -> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if self.token.is_path_start() { - // method macro. + // Method macro. let prev_span = self.prev_span; - self.complain_if_pub_macro(&vis, prev_span); - let lo = self.span.lo; + let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + if pth.segments.len() == 1 { + if !self.eat(&token::Not) { + return Err(self.missing_assoc_item_kind_err("impl", prev_span)); + } + } else { + self.expect(&token::Not)?; + } + + self.complain_if_pub_macro(vis, prev_span); // eat a matched-delimiter token tree: + *at_end = true; let (delim, tts) = self.expect_delimited_token_tree()?; if delim != token::Brace { self.expect(&token::Semi)? } - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac))) } else { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; @@ -4727,6 +4868,7 @@ impl<'a> Parser<'a> { let mut generics = self.parse_generics()?; let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?; generics.where_clause = self.parse_where_clause()?; + *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig { generics: generics, @@ -4752,15 +4894,30 @@ impl<'a> Parser<'a> { tps.where_clause = self.parse_where_clause()?; - let meths = self.parse_trait_items()?; - Ok((ident, ItemKind::Trait(unsafety, tps, bounds, meths), None)) + self.expect(&token::OpenDelim(token::Brace))?; + let mut trait_items = vec![]; + while !self.eat(&token::CloseDelim(token::Brace)) { + let mut at_end = false; + match self.parse_trait_item(&mut at_end) { + Ok(item) => trait_items.push(item), + Err(mut e) => { + e.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } + } + } + } + Ok((ident, ItemKind::Trait(unsafety, tps, bounds, trait_items), None)) } /// Parses items implementations variants /// impl<T> Foo { ... } /// impl<T> ToString for &'static T { ... } /// impl Send for .. {} - fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo> { + fn parse_item_impl(&mut self, + unsafety: ast::Unsafety, + defaultness: Defaultness) -> PResult<'a, ItemInfo> { let impl_span = self.span; // First, parse type parameters if necessary. @@ -4796,13 +4953,10 @@ impl<'a> Parser<'a> { } } } else { - match polarity { - ast::ImplPolarity::Negative => { - // This is a negated type implementation - // `impl !MyType {}`, which is not allowed. - self.span_err(neg_span, "inherent implementation can't be negated"); - }, - _ => {} + if polarity == ast::ImplPolarity::Negative { + // This is a negated type implementation + // `impl !MyType {}`, which is not allowed. + self.span_err(neg_span, "inherent implementation can't be negated"); } None }; @@ -4813,6 +4967,11 @@ impl<'a> Parser<'a> { allowed to have generics"); } + if let ast::Defaultness::Default = defaultness { + self.span_err(impl_span, "`default impl` is not allowed for \ + default trait implementations"); + } + self.expect(&token::OpenDelim(token::Brace))?; self.expect(&token::CloseDelim(token::Brace))?; Ok((keywords::Invalid.ident(), @@ -4828,23 +4987,24 @@ impl<'a> Parser<'a> { let mut impl_items = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { - impl_items.push(self.parse_impl_item()?); + let mut at_end = false; + match self.parse_impl_item(&mut at_end) { + Ok(item) => impl_items.push(item), + Err(mut e) => { + e.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } + } + } } Ok((keywords::Invalid.ident(), - ItemKind::Impl(unsafety, polarity, generics, opt_trait, ty, impl_items), + ItemKind::Impl(unsafety, polarity, defaultness, generics, opt_trait, ty, impl_items), Some(attrs))) } } - /// Parse a::B<String,i32> - fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> { - Ok(TraitRef { - path: self.parse_path(PathStyle::Type)?, - ref_id: ast::DUMMY_NODE_ID, - }) - } - fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<LifetimeDef>> { if self.eat_keyword(keywords::For) { self.expect_lt()?; @@ -4860,21 +5020,10 @@ impl<'a> Parser<'a> { } } - /// Parse for<'l> a::B<String,i32> - fn parse_poly_trait_ref(&mut self) -> PResult<'a, PolyTraitRef> { - let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - - Ok(PolyTraitRef { - bound_lifetimes: lifetime_defs, - trait_ref: self.parse_trait_ref()?, - span: mk_sp(lo, self.prev_span.hi), - }) - } - /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + let mut generics = self.parse_generics()?; // There is a special case worth noting here, as reported in issue #17904. @@ -4924,6 +5073,7 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + let mut generics = self.parse_generics()?; let vdata = if self.token.is_keyword(keywords::Where) { @@ -4971,28 +5121,11 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| { let attrs = p.parse_outer_attributes()?; - let lo = p.span.lo; - let mut vis = p.parse_visibility(false)?; - let ty_is_interpolated = - p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated()); - let mut ty = p.parse_ty()?; - - // Handle `pub(path) type`, in which `vis` will be `pub` and `ty` will be `(path)`. - if vis == Visibility::Public && !ty_is_interpolated && - p.token != token::Comma && p.token != token::CloseDelim(token::Paren) { - ty = if let TyKind::Paren(ref path_ty) = ty.node { - if let TyKind::Path(None, ref path) = path_ty.node { - vis = Visibility::Restricted { path: P(path.clone()), id: path_ty.id }; - Some(p.parse_ty()?) - } else { - None - } - } else { - None - }.unwrap_or(ty); - } + let lo = p.span; + let vis = p.parse_visibility(true)?; + let ty = p.parse_ty()?; Ok(StructField { - span: mk_sp(lo, p.span.hi), + span: lo.to(p.span), vis: vis, ident: None, id: ast::DUMMY_NODE_ID, @@ -5006,7 +5139,7 @@ impl<'a> Parser<'a> { /// Parse a structure field declaration pub fn parse_single_struct_field(&mut self, - lo: BytePos, + lo: Span, vis: Visibility, attrs: Vec<Attribute> ) -> PResult<'a, StructField> { @@ -5028,39 +5161,70 @@ impl<'a> Parser<'a> { /// Parse an element of a struct definition fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let lo = self.span; + let vis = self.parse_visibility(false)?; self.parse_single_struct_field(lo, vis, attrs) } - // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`) - fn parse_visibility(&mut self, allow_path: bool) -> PResult<'a, Visibility> { - let pub_crate = |this: &mut Self| { - let span = this.prev_span; - this.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Crate(span)) - }; + /// Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `pub(self)` for `pub(in self)` + /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's + /// a function definition, it's not a tuple struct field) and the contents within the parens + /// isn't valid, emit a proper diagnostic. + pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { + maybe_whole!(self, NtVis, |x| x); if !self.eat_keyword(keywords::Pub) { - Ok(Visibility::Inherited) - } else if !allow_path { - // Look ahead to avoid eating the `(` in `pub(path)` while still parsing `pub(crate)` - if self.token == token::OpenDelim(token::Paren) && - self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { - self.bump(); self.bump(); - pub_crate(self) - } else { - Ok(Visibility::Public) - } - } else if !self.eat(&token::OpenDelim(token::Paren)) { - Ok(Visibility::Public) - } else if self.eat_keyword(keywords::Crate) { - pub_crate(self) - } else { - let path = self.parse_path(PathStyle::Mod)?.default_to_global(); - self.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }) - } + return Ok(Visibility::Inherited) + } + + if self.check(&token::OpenDelim(token::Paren)) { + // We don't `self.bump()` the `(` yet because this might be a struct definition where + // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. + // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so + // by the following tokens. + if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { + // `pub(crate)` + self.bump(); // `(` + self.bump(); // `crate` + let vis = Visibility::Crate(self.prev_span); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(1, |t| t.is_keyword(keywords::In)) { + // `pub(in path)` + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `path` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && + self.look_ahead(1, |t| t.is_keyword(keywords::Super) || + t.is_keyword(keywords::SelfValue)) { + // `pub(self)` or `pub(super)` + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `super`/`self` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct + // `pub(something) fn ...` or `struct X { pub(something) y: Z }` + self.bump(); // `(` + let msg = "incorrect visibility restriction"; + let suggestion = r##"some possible visibility restrictions are: +`pub(crate)`: visible only on the current crate +`pub(super)`: visible only in the current module's parent +`pub(in path::to::module)`: visible only on the specified path"##; + let path = self.parse_path(PathStyle::Mod)?; + let path_span = self.prev_span; + let help_msg = format!("make this visible only to module `{}` with `in`:", path); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let mut err = self.span_fatal_help(path_span, msg, suggestion); + err.span_suggestion(path_span, &help_msg, format!("in {}", path)); + err.emit(); // emit diagnostic, but continue with public visibility + } + } + + Ok(Visibility::Public) } /// Parse defaultness: DEFAULT or nothing @@ -5073,7 +5237,7 @@ impl<'a> Parser<'a> { } /// Given a termination token, parse all of the items in a module - fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> { + fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = self.parse_item()? { items.push(item); @@ -5087,11 +5251,11 @@ impl<'a> Parser<'a> { let hi = if self.span == syntax_pos::DUMMY_SP { inner_lo } else { - self.prev_span.hi + self.prev_span }; Ok(ast::Mod { - inner: mk_sp(inner_lo, hi), + inner: inner_lo.to(hi), items: items }) } @@ -5126,7 +5290,7 @@ impl<'a> Parser<'a> { let id = self.parse_ident()?; if self.check(&token::Semi) { self.bump(); - if in_cfg { + if in_cfg && self.recurse_into_file_modules { // This mod is in an external file. Let's go get it! let ModulePathSuccess { path, directory_ownership, warn } = self.submod_path(id, &outer_attrs, id_span)?; @@ -5136,11 +5300,9 @@ impl<'a> Parser<'a> { let attr = ast::Attribute { id: attr::mk_attr_id(), style: ast::AttrStyle::Outer, - value: ast::MetaItem { - name: Symbol::intern("warn_directory_ownership"), - node: ast::MetaItemKind::Word, - span: syntax_pos::DUMMY_SP, - }, + path: ast::Path::from_ident(syntax_pos::DUMMY_SP, + Ident::from_str("warn_directory_ownership")), + tokens: TokenStream::empty(), is_sugared_doc: false, span: syntax_pos::DUMMY_SP, }; @@ -5155,10 +5317,12 @@ impl<'a> Parser<'a> { } else { let old_directory = self.directory.clone(); self.push_directory(id, &outer_attrs); + self.expect(&token::OpenDelim(token::Brace))?; - let mod_inner_lo = self.span.lo; + let mod_inner_lo = self.span; let attrs = self.parse_inner_attributes()?; let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; + self.directory = old_directory; Ok((id, ItemKind::Mod(module), Some(attrs))) } @@ -5166,22 +5330,22 @@ impl<'a> Parser<'a> { fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") { - self.directory.path.push(&*path.as_str()); + self.directory.path.push(&path.as_str()); self.directory.ownership = DirectoryOwnership::Owned; } else { - self.directory.path.push(&*id.name.as_str()); + self.directory.path.push(&id.name.as_str()); } } pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> { - attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str())) + attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&d.as_str())) } /// Returns either a path to a module, or . pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath { let mod_name = id.to_string(); let default_path_str = format!("{}.rs", mod_name); - let secondary_path_str = format!("{}/mod.rs", mod_name); + let secondary_path_str = format!("{}{}mod.rs", mod_name, path::MAIN_SEPARATOR); let default_path = dir_path.join(&default_path_str); let secondary_path = dir_path.join(&secondary_path_str); let default_exists = codemap.file_exists(&default_path); @@ -5221,7 +5385,8 @@ impl<'a> Parser<'a> { fn submod_path(&mut self, id: ast::Ident, outer_attrs: &[ast::Attribute], - id_sp: Span) -> PResult<'a, ModulePathSuccess> { + id_sp: Span) + -> PResult<'a, ModulePathSuccess> { if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) { return Ok(ModulePathSuccess { directory_ownership: match path.file_name().and_then(|s| s.to_str()) { @@ -5253,23 +5418,25 @@ impl<'a> Parser<'a> { } let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); - let this_module = match self.directory.path.file_name() { - Some(file_name) => file_name.to_str().unwrap().to_owned(), - None => self.root_module_name.as_ref().unwrap().clone(), - }; - err.span_note(id_sp, - &format!("maybe move this module `{0}` to its own directory \ - via `{0}/mod.rs`", - this_module)); + if id_sp != syntax_pos::DUMMY_SP { + let src_path = PathBuf::from(self.sess.codemap().span_to_filename(id_sp)); + if let Some(stem) = src_path.file_stem() { + let mut dest_path = src_path.clone(); + dest_path.set_file_name(stem); + dest_path.push("mod.rs"); + err.span_note(id_sp, + &format!("maybe move this module `{}` to its own \ + directory via `{}`", src_path.to_string_lossy(), + dest_path.to_string_lossy())); + } + } if paths.path_exists { err.span_note(id_sp, &format!("... or maybe `use` the module `{}` instead \ of possibly redeclaring it", paths.name)); - Err(err) - } else { - Err(err) } + Err(err) } else { paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) } @@ -5299,7 +5466,7 @@ impl<'a> Parser<'a> { let mut p0 = new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp); p0.cfg_mods = self.cfg_mods; - let mod_inner_lo = p0.span.lo; + let mod_inner_lo = p0.span; let mod_attrs = p0.parse_inner_attributes()?; let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?; self.sess.included_mod_stack.borrow_mut().pop(); @@ -5307,42 +5474,42 @@ impl<'a> Parser<'a> { } /// Parse a function declaration from a foreign module - fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec<Attribute>) -> PResult<'a, ForeignItem> { + fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>) + -> PResult<'a, ForeignItem> { self.expect_keyword(keywords::Fn)?; let (ident, mut generics) = self.parse_fn_header()?; let decl = self.parse_fn_decl(true)?; generics.where_clause = self.parse_where_clause()?; - let hi = self.span.hi; + let hi = self.span; self.expect(&token::Semi)?; Ok(ast::ForeignItem { ident: ident, attrs: attrs, node: ForeignItemKind::Fn(decl, generics), id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), vis: vis }) } /// Parse a static item from a foreign module - fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec<Attribute>) -> PResult<'a, ForeignItem> { + fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>) + -> PResult<'a, ForeignItem> { self.expect_keyword(keywords::Static)?; let mutbl = self.eat_keyword(keywords::Mut); let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; - let hi = self.span.hi; + let hi = self.span; self.expect(&token::Semi)?; Ok(ForeignItem { ident: ident, attrs: attrs, node: ForeignItemKind::Static(ty, mutbl), id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), vis: vis }) } @@ -5354,7 +5521,7 @@ impl<'a> Parser<'a> { /// extern crate foo; /// extern crate bar as foo; fn parse_item_extern_crate(&mut self, - lo: BytePos, + lo: Span, visibility: Visibility, attrs: Vec<Attribute>) -> PResult<'a, P<Item>> { @@ -5368,8 +5535,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; let prev_span = self.prev_span; - Ok(self.mk_item(lo, - prev_span.hi, + Ok(self.mk_item(lo.to(prev_span), ident, ItemKind::ExternCrate(maybe_path), visibility, @@ -5387,7 +5553,7 @@ impl<'a> Parser<'a> { /// extern "C" {} /// extern {} fn parse_item_foreign_mod(&mut self, - lo: BytePos, + lo: Span, opt_abi: Option<abi::Abi>, visibility: Visibility, mut attrs: Vec<Attribute>) @@ -5409,12 +5575,8 @@ impl<'a> Parser<'a> { abi: abi, items: foreign_items }; - Ok(self.mk_item(lo, - prev_span.hi, - keywords::Invalid.ident(), - ItemKind::ForeignMod(m), - visibility, - attrs)) + let invalid = keywords::Invalid.ident(); + Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) } /// Parse type Foo = Bar; @@ -5435,7 +5597,7 @@ impl<'a> Parser<'a> { let mut any_disr = None; while self.token != token::CloseDelim(token::Brace) { let variant_attrs = self.parse_outer_attributes()?; - let vlo = self.span.lo; + let vlo = self.span; let struct_def; let mut disr_expr = None; @@ -5463,7 +5625,7 @@ impl<'a> Parser<'a> { data: struct_def, disr_expr: disr_expr, }; - variants.push(spanned(vlo, self.prev_span.hi, vr)); + variants.push(respan(vlo.to(self.prev_span), vr)); if !self.eat(&token::Comma) { break; } } @@ -5533,9 +5695,9 @@ impl<'a> Parser<'a> { Some(P(item)) }); - let lo = self.span.lo; + let lo = self.span; - let visibility = self.parse_visibility(true)?; + let visibility = self.parse_visibility(false)?; if self.eat_keyword(keywords::Use) { // USE ITEM @@ -5543,12 +5705,8 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, - keywords::Invalid.ident(), - item_, - visibility, - attrs); + let invalid = keywords::Invalid.ident(); + let item = self.mk_item(lo.to(prev_span), invalid, item_, visibility, attrs); return Ok(Some(item)); } @@ -5568,8 +5726,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5591,8 +5748,7 @@ impl<'a> Parser<'a> { }; let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5616,8 +5772,7 @@ impl<'a> Parser<'a> { respan(const_span, Constness::Const), Abi::Rust)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5634,8 +5789,7 @@ impl<'a> Parser<'a> { } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5651,24 +5805,28 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Unsafe)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.check_keyword(keywords::Unsafe) && - self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) + if (self.check_keyword(keywords::Unsafe) && + self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) || + (self.check_keyword(keywords::Default) && + self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) && + self.look_ahead(2, |t| t.is_keyword(keywords::Impl))) { // IMPL ITEM + let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Unsafe)?; self.expect_keyword(keywords::Impl)?; - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?; + let (ident, + item_, + extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe, defaultness)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5684,8 +5842,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5708,8 +5865,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5721,8 +5877,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5733,8 +5888,7 @@ impl<'a> Parser<'a> { // TYPE ITEM let (ident, item_, extra_attrs) = self.parse_item_type()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5745,8 +5899,7 @@ impl<'a> Parser<'a> { // ENUM ITEM let (ident, item_, extra_attrs) = self.parse_item_enum()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5758,20 +5911,25 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Normal)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.eat_keyword(keywords::Impl) { + if (self.check_keyword(keywords::Impl)) || + (self.check_keyword(keywords::Default) && + self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) + { // IMPL ITEM - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?; + let defaultness = self.parse_defaultness()?; + self.expect_keyword(keywords::Impl)?; + let (ident, + item_, + extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal, defaultness)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5782,8 +5940,7 @@ impl<'a> Parser<'a> { // STRUCT ITEM let (ident, item_, extra_attrs) = self.parse_item_struct()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5795,8 +5952,7 @@ impl<'a> Parser<'a> { self.bump(); let (ident, item_, extra_attrs) = self.parse_item_union()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5813,8 +5969,8 @@ impl<'a> Parser<'a> { /// Parse a foreign item. fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; - let visibility = self.parse_visibility(true)?; + let lo = self.span; + let visibility = self.parse_visibility(false)?; if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM @@ -5840,7 +5996,7 @@ impl<'a> Parser<'a> { attrs: Vec<Attribute> , macros_allowed: bool, attributes_allowed: bool, - lo: BytePos, + lo: Span, visibility: Visibility ) -> PResult<'a, Option<P<Item>>> { if macros_allowed && self.token.is_path_start() { @@ -5849,7 +6005,7 @@ impl<'a> Parser<'a> { let prev_span = self.prev_span; self.complain_if_pub_macro(&visibility, prev_span); - let mac_lo = self.span.lo; + let mac_lo = self.span; // item macro. let pth = self.parse_path(PathStyle::Mod)?; @@ -5875,9 +6031,9 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; - let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts }); - let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs); + let hi = self.prev_span; + let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts: tts }); + let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs); return Ok(Some(item)); } @@ -5905,7 +6061,7 @@ impl<'a> Parser<'a> { self.parse_unspanned_seq(&token::OpenDelim(token::Brace), &token::CloseDelim(token::Brace), SeqSep::trailing_allowed(token::Comma), |this| { - let lo = this.span.lo; + let lo = this.span; let ident = if this.eat_keyword(keywords::SelfValue) { keywords::SelfValue.ident() } else { @@ -5917,8 +6073,7 @@ impl<'a> Parser<'a> { rename: rename, id: ast::DUMMY_NODE_ID }; - let hi = this.prev_span.hi; - Ok(spanned(lo, hi, node)) + Ok(respan(lo.to(this.prev_span), node)) }) } @@ -5936,21 +6091,21 @@ impl<'a> Parser<'a> { /// MOD_SEP? non_global_path MOD_SEP LBRACE item_seq RBRACE /// MOD_SEP? LBRACE item_seq RBRACE fn parse_view_path(&mut self) -> PResult<'a, P<ViewPath>> { - let lo = self.span.lo; + let lo = self.span; if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. self.eat(&token::ModSep); let prefix = ast::Path { - segments: vec![ast::PathSegment::crate_root()], - span: mk_sp(lo, self.span.hi), + segments: vec![PathSegment::crate_root()], + span: lo.to(self.span), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { ViewPathGlob(prefix) } else { ViewPathList(prefix, self.parse_path_list_items()?) }; - Ok(P(spanned(lo, self.span.hi, view_path_kind))) + Ok(P(respan(lo.to(self.span), view_path_kind))) } else { let prefix = self.parse_path(PathStyle::Mod)?.default_to_global(); if self.is_import_coupler() { @@ -5958,16 +6113,16 @@ impl<'a> Parser<'a> { self.bump(); if self.check(&token::BinOp(token::Star)) { self.bump(); - Ok(P(spanned(lo, self.span.hi, ViewPathGlob(prefix)))) + Ok(P(respan(lo.to(self.span), ViewPathGlob(prefix)))) } else { let items = self.parse_path_list_items()?; - Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items)))) + Ok(P(respan(lo.to(self.span), ViewPathList(prefix, items)))) } } else { // `foo::bar` or `foo::bar as baz` let rename = self.parse_rename()?. unwrap_or(prefix.segments.last().unwrap().identifier); - Ok(P(spanned(lo, self.prev_span.hi, ViewPathSimple(rename, prefix)))) + Ok(P(respan(lo.to(self.prev_span), ViewPathSimple(rename, prefix)))) } } } @@ -5983,11 +6138,11 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main /// entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { - let lo = self.span.lo; + let lo = self.span; Ok(ast::Crate { attrs: self.parse_inner_attributes()?, module: self.parse_mod_items(&token::Eof, lo)?, - span: mk_sp(lo, self.span.lo), + span: lo.to(self.span), }) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5b65aac92b8..77db604c56e 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -17,7 +17,7 @@ pub use self::Token::*; use ast::{self}; use ptr::P; use symbol::keywords; -use tokenstream; +use tokenstream::TokenTree; use std::fmt; use std::rc::Rc; @@ -53,6 +53,10 @@ impl DelimToken { pub fn len(self) -> usize { if self == NoDelim { 0 } else { 1 } } + + pub fn is_empty(self) -> bool { + self == NoDelim + } } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -86,6 +90,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { !ident_token.is_any_keyword() || ident_token.is_path_segment_keyword() || [ + keywords::Do.name(), keywords::Box.name(), keywords::Break.name(), keywords::Continue.name(), @@ -102,6 +107,21 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { ].contains(&ident.name) } +fn ident_can_begin_type(ident: ast::Ident) -> bool { + let ident_token: Token = Ident(ident); + + !ident_token.is_any_keyword() || + ident_token.is_path_segment_keyword() || + [ + keywords::For.name(), + keywords::Impl.name(), + keywords::Fn.name(), + keywords::Unsafe.name(), + keywords::Extern.name(), + keywords::Typeof.name(), + ].contains(&ident.name) +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)] pub enum Token { /* Expression-operator symbols. */ @@ -181,25 +201,21 @@ impl Token { /// Returns `true` if the token can appear at the start of an expression. pub fn can_begin_expr(&self) -> bool { match *self { - OpenDelim(..) => true, - Ident(ident) => ident_can_begin_expr(ident), - Literal(..) => true, - Not => true, - BinOp(Minus) => true, - BinOp(Star) => true, - BinOp(And) => true, - BinOp(Or) => true, // in lambda syntax - OrOr => true, // in lambda syntax - AndAnd => true, // double borrow - DotDot | DotDotDot => true, // range notation - Lt | BinOp(Shl) => true, // associated path - ModSep => true, - Pound => true, // for expression attributes + Ident(ident) => ident_can_begin_expr(ident), // value name or keyword + OpenDelim(..) | // tuple, array or block + Literal(..) | // literal + Not | // operator not + BinOp(Minus) | // unary minus + BinOp(Star) | // dereference + BinOp(Or) | OrOr | // closure + BinOp(And) | // reference + AndAnd | // double reference + DotDot | DotDotDot | // range notation + Lt | BinOp(Shl) | // associated path + ModSep | // global path + Pound => true, // expression attributes Interpolated(ref nt) => match **nt { - NtExpr(..) => true, - NtIdent(..) => true, - NtBlock(..) => true, - NtPath(..) => true, + NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -209,20 +225,20 @@ impl Token { /// Returns `true` if the token can appear at the start of a type. pub fn can_begin_type(&self) -> bool { match *self { - OpenDelim(Paren) => true, // tuple - OpenDelim(Bracket) => true, // array - Ident(..) => true, // type name or keyword - Underscore => true, // placeholder - Not => true, // never - BinOp(Star) => true, // raw pointer - BinOp(And) => true, // reference - AndAnd => true, // double reference - Lt | BinOp(Shl) => true, // associated path + Ident(ident) => ident_can_begin_type(ident), // type name or keyword + OpenDelim(Paren) | // tuple + OpenDelim(Bracket) | // array + Underscore | // placeholder + Not | // never + BinOp(Star) | // raw pointer + BinOp(And) | // reference + AndAnd | // double reference + Question | // maybe bound in trait object + Lifetime(..) | // lifetime bound in trait object + Lt | BinOp(Shl) | // associated path ModSep => true, // global path Interpolated(ref nt) => match **nt { - NtTy(..) => true, - NtIdent(..) => true, - NtPath(..) => true, + NtIdent(..) | NtTy(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -237,14 +253,22 @@ impl Token { } } - /// Returns `true` if the token is an identifier. - pub fn is_ident(&self) -> bool { + pub fn ident(&self) -> Option<ast::Ident> { match *self { - Ident(..) => true, - _ => false, + Ident(ident) => Some(ident), + Interpolated(ref nt) => match **nt { + NtIdent(ident) => Some(ident.node), + _ => None, + }, + _ => None, } } + /// Returns `true` if the token is an identifier. + pub fn is_ident(&self) -> bool { + self.ident().is_some() + } + /// Returns `true` if the token is a documentation comment. pub fn is_doc_comment(&self) -> bool { match *self { @@ -296,18 +320,15 @@ impl Token { /// Returns `true` if the token is a given keyword, `kw`. pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { - match *self { - Ident(id) => id.name == kw.name(), - _ => false, - } + self.ident().map(|ident| ident.name == kw.name()).unwrap_or(false) } pub fn is_path_segment_keyword(&self) -> bool { - match *self { - Ident(id) => id.name == keywords::Super.name() || - id.name == keywords::SelfValue.name() || - id.name == keywords::SelfType.name(), - _ => false, + match self.ident() { + Some(id) => id.name == keywords::Super.name() || + id.name == keywords::SelfValue.name() || + id.name == keywords::SelfType.name(), + None => false, } } @@ -318,18 +339,16 @@ impl Token { /// Returns `true` if the token is a strict keyword. pub fn is_strict_keyword(&self) -> bool { - match *self { - Ident(id) => id.name >= keywords::As.name() && - id.name <= keywords::While.name(), + match self.ident() { + Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(), _ => false, } } /// Returns `true` if the token is a keyword reserved for possible future use. pub fn is_reserved_keyword(&self) -> bool { - match *self { - Ident(id) => id.name >= keywords::Abstract.name() && - id.name <= keywords::Yield.name(), + match self.ident() { + Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(), _ => false, } } @@ -348,7 +367,8 @@ pub enum Nonterminal { /// Stuff inside brackets for attributes NtMeta(ast::MetaItem), NtPath(ast::Path), - NtTT(tokenstream::TokenTree), + NtVis(ast::Visibility), + NtTT(TokenTree), // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), NtImplItem(ast::ImplItem), @@ -377,6 +397,7 @@ impl fmt::Debug for Nonterminal { NtGenerics(..) => f.pad("NtGenerics(..)"), NtWhereClause(..) => f.pad("NtWhereClause(..)"), NtArg(..) => f.pad("NtArg(..)"), + NtVis(..) => f.pad("NtVis(..)"), } } } |
