Auto merge of #45773 - Badel2:dotdoteq, r=petrochenkov

Add error for `...` in expressions

Follow-up to https://github.com/rust-lang/rust/pull/44709
Tracking issue: https://github.com/rust-lang/rust/issues/28237

* Using `...` in expressions was a warning, now it's an error
* The error message suggests using `..` or `..=` instead, and explains the difference
* Updated remaining occurrences of `...` to `..=`

r? petrochenkov
This commit is contained in:
bors 2017-11-10 01:40:21 +00:00
commit d5ff0e6422
8 changed files with 69 additions and 29 deletions

View File

@ -16,9 +16,6 @@
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
// FIXME: after next stage0, change RangeInclusive { ... } back to ..=
use ops::RangeInclusive;
// How this module is organized. // How this module is organized.
// //
// The library infrastructure for slices is fairly messy. There's // The library infrastructure for slices is fairly messy. There's
@ -1047,32 +1044,32 @@ impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
#[inline] #[inline]
fn get(self, slice: &[T]) -> Option<&[T]> { fn get(self, slice: &[T]) -> Option<&[T]> {
(RangeInclusive { start: 0, end: self.end }).get(slice) (0..=self.end).get(slice)
} }
#[inline] #[inline]
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
(RangeInclusive { start: 0, end: self.end }).get_mut(slice) (0..=self.end).get_mut(slice)
} }
#[inline] #[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
(RangeInclusive { start: 0, end: self.end }).get_unchecked(slice) (0..=self.end).get_unchecked(slice)
} }
#[inline] #[inline]
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
(RangeInclusive { start: 0, end: self.end }).get_unchecked_mut(slice) (0..=self.end).get_unchecked_mut(slice)
} }
#[inline] #[inline]
fn index(self, slice: &[T]) -> &[T] { fn index(self, slice: &[T]) -> &[T] {
(RangeInclusive { start: 0, end: self.end }).index(slice) (0..=self.end).index(slice)
} }
#[inline] #[inline]
fn index_mut(self, slice: &mut [T]) -> &mut [T] { fn index_mut(self, slice: &mut [T]) -> &mut [T] {
(RangeInclusive { start: 0, end: self.end }).index_mut(slice) (0..=self.end).index_mut(slice)
} }
} }

View File

@ -165,7 +165,7 @@ impl<'a> CacheDecoder<'a> {
fn find_filemap_prev_bytepos(&self, fn find_filemap_prev_bytepos(&self,
prev_bytepos: BytePos) prev_bytepos: BytePos)
-> Option<(BytePos, StableFilemapId)> { -> Option<(BytePos, StableFilemapId)> {
for (start, id) in self.prev_filemap_starts.range(BytePos(0) ... prev_bytepos).rev() { for (start, id) in self.prev_filemap_starts.range(BytePos(0) ..= prev_bytepos).rev() {
return Some((*start, *id)) return Some((*start, *id))
} }

View File

@ -2783,10 +2783,11 @@ impl<'a> Parser<'a> {
if op.precedence() < min_prec { if op.precedence() < min_prec {
break; break;
} }
// Warn about deprecated ... syntax (until SNAP) // Check for deprecated `...` syntax
if self.token == token::DotDotDot { if self.token == token::DotDotDot && op == AssocOp::DotDotEq {
self.warn_dotdoteq(self.span); self.err_dotdotdot_syntax(self.span);
} }
self.bump(); self.bump();
if op.is_comparison() { if op.is_comparison() {
self.check_no_chained_comparison(&lhs, &op); self.check_no_chained_comparison(&lhs, &op);
@ -2819,7 +2820,6 @@ impl<'a> Parser<'a> {
// //
// 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. // 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() { let rhs = if self.is_at_start_of_range_notation_rhs() {
Some(self.parse_assoc_expr_with(op.precedence() + 1, Some(self.parse_assoc_expr_with(op.precedence() + 1,
LhsExpr::NotYetParsed)?) LhsExpr::NotYetParsed)?)
@ -3007,22 +3007,22 @@ impl<'a> Parser<'a> {
} }
} }
/// Parse prefix-forms of range notation: `..expr`, `..`, `..=expr` (and `...expr` until SNAP) /// Parse prefix-forms of range notation: `..expr`, `..`, `..=expr`
fn parse_prefix_range_expr(&mut self, fn parse_prefix_range_expr(&mut self,
already_parsed_attrs: Option<ThinVec<Attribute>>) already_parsed_attrs: Option<ThinVec<Attribute>>)
-> PResult<'a, P<Expr>> { -> PResult<'a, P<Expr>> {
// SNAP remove DotDotDot // Check for deprecated `...` syntax
if self.token == token::DotDotDot {
self.err_dotdotdot_syntax(self.span);
}
debug_assert!([token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token), debug_assert!([token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token),
"parse_prefix_range_expr: token {:?} is not DotDot/DotDotDot/DotDotEq", "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
self.token); self.token);
let tok = self.token.clone(); let tok = self.token.clone();
let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
let lo = self.span; let lo = self.span;
let mut hi = self.span; let mut hi = self.span;
// Warn about deprecated ... syntax (until SNAP)
if tok == token::DotDotDot {
self.warn_dotdoteq(self.span);
}
self.bump(); self.bump();
let opt_end = if self.is_at_start_of_range_notation_rhs() { let opt_end = if self.is_at_start_of_range_notation_rhs() {
// RHS must be parsed with more associativity than the dots. // RHS must be parsed with more associativity than the dots.
@ -4332,9 +4332,13 @@ impl<'a> Parser<'a> {
}).emit(); }).emit();
} }
fn warn_dotdoteq(&self, span: Span) { fn err_dotdotdot_syntax(&self, span: Span) {
self.diagnostic().struct_span_warn(span, { self.diagnostic().struct_span_err(span, {
"`...` is being replaced by `..=`" "`...` syntax cannot be used in expressions"
}).help({
"Use `..` if you need an exclusive range (a < b)"
}).help({
"or `..=` if you need an inclusive range (a <= b)"
}).emit(); }).emit();
} }

View File

@ -222,8 +222,8 @@ impl Token {
BinOp(Or) | OrOr | // closure BinOp(Or) | OrOr | // closure
BinOp(And) | // reference BinOp(And) | // reference
AndAnd | // double reference AndAnd | // double reference
// DotDotDot is no longer supported, but we need some way to display the error
DotDot | DotDotDot | DotDotEq | // range notation DotDot | DotDotDot | DotDotEq | // range notation
// SNAP remove DotDotDot
Lt | BinOp(Shl) | // associated path Lt | BinOp(Shl) | // associated path
ModSep | // global path ModSep | // global path
Pound => true, // expression attributes Pound => true, // expression attributes

View File

@ -2213,7 +2213,7 @@ impl<'a> State<'a> {
if limits == ast::RangeLimits::HalfOpen { if limits == ast::RangeLimits::HalfOpen {
self.s.word("..")?; self.s.word("..")?;
} else { } else {
self.s.word("...")?; self.s.word("..=")?;
} }
if let Some(ref e) = *end { if let Some(ref e) = *end {
self.print_expr_maybe_paren(e, fake_prec)?; self.print_expr_maybe_paren(e, fake_prec)?;

View File

@ -106,7 +106,8 @@ impl AssocOp {
Token::OrOr => Some(LOr), Token::OrOr => Some(LOr),
Token::DotDot => Some(DotDot), Token::DotDot => Some(DotDot),
Token::DotDotEq => Some(DotDotEq), Token::DotDotEq => Some(DotDotEq),
Token::DotDotDot => Some(DotDotEq), // remove this after SNAP // DotDotDot is no longer supported, but we need some way to display the error
Token::DotDotDot => Some(DotDotEq),
Token::Colon => Some(Colon), Token::Colon => Some(Colon),
_ if t.is_keyword(keywords::As) => Some(As), _ if t.is_keyword(keywords::As) => Some(As),
_ => None _ => None

View File

@ -0,0 +1,38 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only -Z continue-parse-after-error
// Make sure that inclusive ranges with `...` syntax don't parse.
#![feature(inclusive_range_syntax, inclusive_range)]
use std::ops::RangeToInclusive;
fn return_range_to() -> RangeToInclusive<i32> {
return ...1; //~ERROR `...` syntax cannot be used in expressions
//~^HELP Use `..` if you need an exclusive range (a < b)
//~^^HELP or `..=` if you need an inclusive range (a <= b)
}
pub fn main() {
let x = ...0; //~ERROR `...` syntax cannot be used in expressions
//~^HELP Use `..` if you need an exclusive range (a < b)
//~^^HELP or `..=` if you need an inclusive range (a <= b)
let x = 5...5; //~ERROR `...` syntax cannot be used in expressions
//~^HELP Use `..` if you need an exclusive range (a < b)
//~^^HELP or `..=` if you need an inclusive range (a <= b)
for _ in 0...1 {} //~ERROR `...` syntax cannot be used in expressions
//~^HELP Use `..` if you need an exclusive range (a < b)
//~^^HELP or `..=` if you need an inclusive range (a <= b)
}

View File

@ -41,8 +41,8 @@ fn main() {
let raw_byte_string_lit_kind = LitKind::ByteStr(Rc::new(b"#\"two\"#".to_vec())); let raw_byte_string_lit_kind = LitKind::ByteStr(Rc::new(b"#\"two\"#".to_vec()));
assert_eq!(raw_byte_string.node, ExprKind::Lit(P(dummy_spanned(raw_byte_string_lit_kind)))); assert_eq!(raw_byte_string.node, ExprKind::Lit(P(dummy_spanned(raw_byte_string_lit_kind))));
// check dotdotdot // check dotdoteq
let closed_range = quote_expr!(&cx, 0 ... 1); let closed_range = quote_expr!(&cx, 0 ..= 1);
assert_eq!(closed_range.node, ExprKind::Range( assert_eq!(closed_range.node, ExprKind::Range(
Some(quote_expr!(&cx, 0)), Some(quote_expr!(&cx, 0)),
Some(quote_expr!(&cx, 1)), Some(quote_expr!(&cx, 1)),