diff options
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 71 |
1 files changed, 47 insertions, 24 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a2514a04254..d5ba4b54d90 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -38,7 +38,7 @@ use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; use ast::{BinOpKind, UnOp}; -use ast::RangeEnd; +use ast::{RangeEnd, RangeSyntax}; use {ast, attr}; use codemap::{self, CodeMap, Spanned, respan}; use syntax_pos::{self, Span, BytePos}; @@ -432,7 +432,7 @@ impl Error { Error::InclusiveRangeWithNoEnd => { let mut err = struct_span_err!(handler, sp, E0586, "inclusive range with no end"); - err.help("inclusive ranges must be bounded at the end (`...b` or `a...b`)"); + err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); err } } @@ -2632,7 +2632,7 @@ impl<'a> Parser<'a> { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - (span, self.mk_unary(UnOp::Not, e)) + (lo.to(span), self.mk_unary(UnOp::Not, e)) } // Suggest `!` for bitwise negation when encountering a `~` token::Tilde => { @@ -2645,26 +2645,26 @@ impl<'a> Parser<'a> { 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)) + (lo.to(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)?; - (span, self.mk_unary(UnOp::Neg, e)) + (lo.to(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)?; - (span, self.mk_unary(UnOp::Deref, e)) + (lo.to(span), self.mk_unary(UnOp::Deref, e)) } token::BinOp(token::And) | token::AndAnd => { self.expect_and()?; let m = self.parse_mutability(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - (span, ExprKind::AddrOf(m, e)) + (lo.to(span), ExprKind::AddrOf(m, e)) } token::Ident(..) if self.token.is_keyword(keywords::In) => { self.bump(); @@ -2675,13 +2675,13 @@ impl<'a> Parser<'a> { let blk = self.parse_block()?; let span = blk.span; let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new()); - (span, ExprKind::InPlace(place, blk_expr)) + (lo.to(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)?; - (span, ExprKind::Box(e)) + (lo.to(span), ExprKind::Box(e)) } _ => return self.parse_dot_or_call_expr(Some(attrs)) }; @@ -2710,7 +2710,7 @@ impl<'a> Parser<'a> { LhsExpr::AttributesParsed(attrs) => Some(attrs), _ => None, }; - if self.token == token::DotDot || self.token == token::DotDotDot { + if [token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token) { return self.parse_prefix_range_expr(attrs); } else { self.parse_prefix_expr(attrs)? @@ -2744,6 +2744,10 @@ impl<'a> Parser<'a> { if op.precedence() < min_prec { break; } + // Warn about deprecated ... syntax (until SNAP) + if self.token == token::DotDotDot { + self.warn_dotdoteq(self.span); + } self.bump(); if op.is_comparison() { self.check_no_chained_comparison(&lhs, &op); @@ -2770,12 +2774,13 @@ impl<'a> Parser<'a> { } }; continue - } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot { - // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to + } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq { + // If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to // generalise it to the Fixity::None code. // - // We have 2 alternatives here: `x..y`/`x...y` and `x..`/`x...` The other + // We have 2 alternatives here: `x..y`/`x..=y` and `x..`/`x..=` The other // two variants are handled with `parse_prefix_range_expr` call above. + // (and `x...y`/`x...` until SNAP) let rhs = if self.is_at_start_of_range_notation_rhs() { Some(self.parse_assoc_expr_with(op.precedence() + 1, LhsExpr::NotYetParsed)?) @@ -2852,8 +2857,8 @@ impl<'a> Parser<'a> { let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); self.mk_expr(span, aopexpr, ThinVec::new()) } - AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => { - self.bug("As, Colon, DotDot or DotDotDot branch reached") + AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => { + self.bug("AssocOp should have been handled by special case") } }; @@ -2949,17 +2954,22 @@ impl<'a> Parser<'a> { } } - /// Parse prefix-forms of range notation: `..expr`, `..`, `...expr` + /// Parse prefix-forms of range notation: `..expr`, `..`, `..=expr` (and `...expr` until SNAP) fn parse_prefix_range_expr(&mut self, already_parsed_attrs: Option<ThinVec<Attribute>>) -> PResult<'a, P<Expr>> { - debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot, - "parse_prefix_range_expr: token {:?} is not DotDot or DotDotDot", + // SNAP remove DotDotDot + debug_assert!([token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token), + "parse_prefix_range_expr: token {:?} is not DotDot/DotDotDot/DotDotEq", self.token); let tok = self.token.clone(); let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; let lo = self.span; let mut hi = self.span; + // Warn about deprecated ... syntax (until SNAP) + if tok == token::DotDotDot { + self.warn_dotdoteq(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. @@ -3450,7 +3460,7 @@ impl<'a> Parser<'a> { fn parse_as_ident(&mut self) -> bool { self.look_ahead(1, |t| match *t { token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | - token::DotDotDot | token::ModSep | token::Not => Some(false), + token::DotDotDot | token::DotDotEq | token::ModSep | token::Not => Some(false), // ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the // range pattern branch token::DotDot => None, @@ -3544,11 +3554,13 @@ impl<'a> Parser<'a> { let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts }); pat = PatKind::Mac(mac); } - token::DotDotDot | token::DotDot => { + token::DotDotDot | token::DotDotEq | token::DotDot => { let end_kind = match self.token { token::DotDot => RangeEnd::Excluded, - token::DotDotDot => RangeEnd::Included, - _ => panic!("can only parse `..` or `...` for ranges (checked above)"), + token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot), + token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq), + _ => panic!("can only parse `..`/`...`/`..=` for ranges \ + (checked above)"), }; // Parse range let span = lo.to(self.prev_span); @@ -3589,7 +3601,12 @@ impl<'a> Parser<'a> { Ok(begin) => { if self.eat(&token::DotDotDot) { let end = self.parse_pat_range_end()?; - pat = PatKind::Range(begin, end, RangeEnd::Included); + pat = PatKind::Range(begin, end, + RangeEnd::Included(RangeSyntax::DotDotDot)); + } else if self.eat(&token::DotDotEq) { + let end = self.parse_pat_range_end()?; + pat = PatKind::Range(begin, end, + RangeEnd::Included(RangeSyntax::DotDotEq)); } else if self.eat(&token::DotDot) { let end = self.parse_pat_range_end()?; pat = PatKind::Range(begin, end, RangeEnd::Excluded); @@ -3973,7 +3990,7 @@ impl<'a> Parser<'a> { token::BinOp(token::Minus) | token::BinOp(token::Star) | token::BinOp(token::And) | token::BinOp(token::Or) | token::AndAnd | token::OrOr | - token::DotDot | token::DotDotDot => false, + token::DotDot | token::DotDotDot | token::DotDotEq => false, _ => true, } { self.warn_missing_semicolon(); @@ -4195,6 +4212,12 @@ impl<'a> Parser<'a> { }).emit(); } + fn warn_dotdoteq(&self, span: Span) { + self.diagnostic().struct_span_warn(span, { + "`...` is being replaced by `..=`" + }).emit(); + } + // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) |
