Auto merge of #44709 - Badel2:inclusive-range-dotdoteq, r=petrochenkov
Initial support for `..=` syntax #28237 This PR adds `..=` as a synonym for `...` in patterns and expressions. Since `...` in expressions was never stable, we now issue a warning. cc @durka r? @aturon
This commit is contained in:
commit
0e6f4cf51c
38 changed files with 295 additions and 199 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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`)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue