提交 0e6f4cf5 编写于 作者: B bors

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
......@@ -1356,7 +1356,7 @@ dependencies = [
"rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustfmt-nightly 0.2.5",
"rustfmt-nightly 0.2.7",
"serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1837,7 +1837,7 @@ dependencies = [
[[package]]
name = "rustfmt-nightly"
version = "0.2.5"
version = "0.2.7"
dependencies = [
"diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
......
......@@ -7,13 +7,13 @@ The tracking issue for this feature is: [#28237]
------------------------
To get a range that goes from 0 to 10 and includes the value 10, you
can write `0...10`:
can write `0..=10`:
```rust
#![feature(inclusive_range_syntax)]
fn main() {
for i in 0...10 {
for i in 0..=10 {
println!("{}", i);
}
}
......
......@@ -182,7 +182,7 @@ fn test_range_small() {
fn test_range_inclusive() {
let size = 500;
let map: BTreeMap<_, _> = (0...size).map(|i| (i, i)).collect();
let map: BTreeMap<_, _> = (0..=size).map(|i| (i, i)).collect();
fn check<'a, L, R>(lhs: L, rhs: R)
where L: IntoIterator<Item=(&'a i32, &'a i32)>,
......@@ -193,18 +193,18 @@ fn check<'a, L, R>(lhs: L, rhs: R)
assert_eq!(lhs, rhs);
}
check(map.range(size + 1...size + 1), vec![]);
check(map.range(size...size), vec![(&size, &size)]);
check(map.range(size...size + 1), vec![(&size, &size)]);
check(map.range(0...0), vec![(&0, &0)]);
check(map.range(0...size - 1), map.range(..size));
check(map.range(-1...-1), vec![]);
check(map.range(-1...size), map.range(..));
check(map.range(...size), map.range(..));
check(map.range(...200), map.range(..201));
check(map.range(5...8), vec![(&5, &5), (&6, &6), (&7, &7), (&8, &8)]);
check(map.range(-1...0), vec![(&0, &0)]);
check(map.range(-1...2), vec![(&0, &0), (&1, &1), (&2, &2)]);
check(map.range(size + 1..=size + 1), vec![]);
check(map.range(size..=size), vec![(&size, &size)]);
check(map.range(size..=size + 1), vec![(&size, &size)]);
check(map.range(0..=0), vec![(&0, &0)]);
check(map.range(0..=size - 1), map.range(..size));
check(map.range(-1..=-1), vec![]);
check(map.range(-1..=size), map.range(..));
check(map.range(..=size), map.range(..));
check(map.range(..=200), map.range(..201));
check(map.range(5..=8), vec![(&5, &5), (&6, &6), (&7, &7), (&8, &8)]);
check(map.range(-1..=0), vec![(&0, &0)]);
check(map.range(-1..=2), vec![(&0, &0), (&1, &1), (&2, &2)]);
}
#[test]
......@@ -212,7 +212,7 @@ fn test_range_inclusive_max_value() {
let max = ::std::usize::MAX;
let map: BTreeMap<_, _> = vec![(max, 0)].into_iter().collect();
assert_eq!(map.range(max...max).collect::<Vec<_>>(), &[(&max, &0)]);
assert_eq!(map.range(max..=max).collect::<Vec<_>>(), &[(&max, &0)]);
}
#[test]
......
......@@ -361,13 +361,13 @@ fn test_slice_fail() {
#[test]
#[should_panic]
fn test_str_slice_rangetoinclusive_max_panics() {
&"hello"[...usize::max_value()];
&"hello"[..=usize::max_value()];
}
#[test]
#[should_panic]
fn test_str_slice_rangeinclusive_max_panics() {
&"hello"[1...usize::max_value()];
&"hello"[1..=usize::max_value()];
}
#[test]
......@@ -375,7 +375,7 @@ fn test_str_slice_rangeinclusive_max_panics() {
fn test_str_slicemut_rangetoinclusive_max_panics() {
let mut s = "hello".to_owned();
let s: &mut str = &mut s;
&mut s[...usize::max_value()];
&mut s[..=usize::max_value()];
}
#[test]
......@@ -383,7 +383,7 @@ fn test_str_slicemut_rangetoinclusive_max_panics() {
fn test_str_slicemut_rangeinclusive_max_panics() {
let mut s = "hello".to_owned();
let s: &mut str = &mut s;
&mut s[1...usize::max_value()];
&mut s[1..=usize::max_value()];
}
#[test]
......@@ -391,13 +391,13 @@ fn test_str_get_maxinclusive() {
let mut s = "hello".to_owned();
{
let s: &str = &s;
assert_eq!(s.get(...usize::max_value()), None);
assert_eq!(s.get(1...usize::max_value()), None);
assert_eq!(s.get(..=usize::max_value()), None);
assert_eq!(s.get(1..=usize::max_value()), None);
}
{
let s: &mut str = &mut s;
assert_eq!(s.get(...usize::max_value()), None);
assert_eq!(s.get(1...usize::max_value()), None);
assert_eq!(s.get(..=usize::max_value()), None);
assert_eq!(s.get(1..=usize::max_value()), None);
}
}
......
......@@ -456,9 +456,9 @@ fn test_splice_char_boundary() {
#[test]
fn test_splice_inclusive_range() {
let mut v = String::from("12345");
v.splice(2...3, "789");
v.splice(2..=3, "789");
assert_eq!(v, "127895");
v.splice(1...2, "A");
v.splice(1..=2, "A");
assert_eq!(v, "1A895");
}
......@@ -473,7 +473,7 @@ fn test_splice_out_of_bounds() {
#[should_panic]
fn test_splice_inclusive_out_of_bounds() {
let mut s = String::from("12345");
s.splice(5...5, "789");
s.splice(5..=5, "789");
}
#[test]
......
......@@ -537,27 +537,27 @@ fn test_drain_range() {
#[test]
fn test_drain_inclusive_range() {
let mut v = vec!['a', 'b', 'c', 'd', 'e'];
for _ in v.drain(1...3) {
for _ in v.drain(1..=3) {
}
assert_eq!(v, &['a', 'e']);
let mut v: Vec<_> = (0...5).map(|x| x.to_string()).collect();
for _ in v.drain(1...5) {
let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect();
for _ in v.drain(1..=5) {
}
assert_eq!(v, &["0".to_string()]);
let mut v: Vec<String> = (0...5).map(|x| x.to_string()).collect();
for _ in v.drain(0...5) {
let mut v: Vec<String> = (0..=5).map(|x| x.to_string()).collect();
for _ in v.drain(0..=5) {
}
assert_eq!(v, Vec::<String>::new());
let mut v: Vec<_> = (0...5).map(|x| x.to_string()).collect();
for _ in v.drain(0...3) {
let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect();
for _ in v.drain(0..=3) {
}
assert_eq!(v, &["4".to_string(), "5".to_string()]);
let mut v: Vec<_> = (0...1).map(|x| x.to_string()).collect();
for _ in v.drain(...0) {
let mut v: Vec<_> = (0..=1).map(|x| x.to_string()).collect();
for _ in v.drain(..=0) {
}
assert_eq!(v, &["1".to_string()]);
}
......@@ -572,7 +572,7 @@ fn test_drain_max_vec_size() {
let mut v = Vec::<()>::with_capacity(usize::max_value());
unsafe { v.set_len(usize::max_value()); }
for _ in v.drain(usize::max_value() - 1...usize::max_value() - 1) {
for _ in v.drain(usize::max_value() - 1..=usize::max_value() - 1) {
}
assert_eq!(v.len(), usize::max_value() - 1);
}
......@@ -581,7 +581,7 @@ fn test_drain_max_vec_size() {
#[should_panic]
fn test_drain_inclusive_out_of_bounds() {
let mut v = vec![1, 2, 3, 4, 5];
v.drain(5...5);
v.drain(5..=5);
}
#[test]
......@@ -598,10 +598,10 @@ fn test_splice() {
fn test_splice_inclusive_range() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
let t1: Vec<_> = v.splice(2...3, a.iter().cloned()).collect();
let t1: Vec<_> = v.splice(2..=3, a.iter().cloned()).collect();
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
assert_eq!(t1, &[3, 4]);
let t2: Vec<_> = v.splice(1...2, Some(20)).collect();
let t2: Vec<_> = v.splice(1..=2, Some(20)).collect();
assert_eq!(v, &[1, 20, 11, 12, 5]);
assert_eq!(t2, &[2, 10]);
}
......@@ -619,7 +619,7 @@ fn test_splice_out_of_bounds() {
fn test_splice_inclusive_out_of_bounds() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
v.splice(5...5, a.iter().cloned());
v.splice(5..=5, a.iter().cloned());
}
#[test]
......
......@@ -241,9 +241,9 @@ pub fn contains(&self, item: Idx) -> bool {
}
}
/// An range bounded inclusively below and above (`start...end`).
/// An range bounded inclusively below and above (`start..=end`).
///
/// The `RangeInclusive` `start...end` contains all values with `x >= start`
/// The `RangeInclusive` `start..=end` contains all values with `x >= start`
/// and `x <= end`.
///
/// # Examples
......@@ -251,12 +251,12 @@ pub fn contains(&self, item: Idx) -> bool {
/// ```
/// #![feature(inclusive_range,inclusive_range_syntax)]
///
/// assert_eq!((3...5), std::ops::RangeInclusive { start: 3, end: 5 });
/// assert_eq!(3 + 4 + 5, (3...5).sum());
/// assert_eq!((3..=5), std::ops::RangeInclusive { start: 3, end: 5 });
/// assert_eq!(3 + 4 + 5, (3..=5).sum());
///
/// let arr = [0, 1, 2, 3];
/// assert_eq!(arr[ ...2], [0,1,2 ]);
/// assert_eq!(arr[1...2], [ 1,2 ]); // RangeInclusive
/// assert_eq!(arr[ ..=2], [0,1,2 ]);
/// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive
/// ```
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
......@@ -276,7 +276,7 @@ pub struct RangeInclusive<Idx> {
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{:?}...{:?}", self.start, self.end)
write!(fmt, "{:?}..={:?}", self.start, self.end)
}
}
......@@ -289,32 +289,32 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
/// ```
/// #![feature(range_contains,inclusive_range_syntax)]
///
/// assert!(!(3...5).contains(2));
/// assert!( (3...5).contains(3));
/// assert!( (3...5).contains(4));
/// assert!( (3...5).contains(5));
/// assert!(!(3...5).contains(6));
/// assert!(!(3..=5).contains(2));
/// assert!( (3..=5).contains(3));
/// assert!( (3..=5).contains(4));
/// assert!( (3..=5).contains(5));
/// assert!(!(3..=5).contains(6));
///
/// assert!( (3...3).contains(3));
/// assert!(!(3...2).contains(3));
/// assert!( (3..=3).contains(3));
/// assert!(!(3..=2).contains(3));
/// ```
pub fn contains(&self, item: Idx) -> bool {
self.start <= item && item <= self.end
}
}
/// A range only bounded inclusively above (`...end`).
/// A range only bounded inclusively above (`..=end`).
///
/// The `RangeToInclusive` `...end` contains all values with `x <= end`.
/// The `RangeToInclusive` `..=end` contains all values with `x <= end`.
/// It cannot serve as an [`Iterator`] because it doesn't have a starting point.
///
/// # Examples
///
/// The `...end` syntax is a `RangeToInclusive`:
/// The `..=end` syntax is a `RangeToInclusive`:
///
/// ```
/// #![feature(inclusive_range,inclusive_range_syntax)]
/// assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 });
/// assert_eq!((..=5), std::ops::RangeToInclusive{ end: 5 });
/// ```
///
/// It does not have an [`IntoIterator`] implementation, so you can't use it in a
......@@ -325,7 +325,7 @@ pub fn contains(&self, item: Idx) -> bool {
///
/// // error[E0277]: the trait bound `std::ops::RangeToInclusive<{integer}>:
/// // std::iter::Iterator` is not satisfied
/// for i in ...5 {
/// for i in ..=5 {
/// // ...
/// }
/// ```
......@@ -337,8 +337,8 @@ pub fn contains(&self, item: Idx) -> bool {
/// #![feature(inclusive_range_syntax)]
///
/// let arr = [0, 1, 2, 3];
/// assert_eq!(arr[ ...2], [0,1,2 ]); // RangeToInclusive
/// assert_eq!(arr[1...2], [ 1,2 ]);
/// assert_eq!(arr[ ..=2], [0,1,2 ]); // RangeToInclusive
/// assert_eq!(arr[1..=2], [ 1,2 ]);
/// ```
///
/// [`IntoIterator`]: ../iter/trait.Iterator.html
......@@ -357,7 +357,7 @@ pub struct RangeToInclusive<Idx> {
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "...{:?}", self.end)
write!(fmt, "..={:?}", self.end)
}
}
......@@ -370,9 +370,9 @@ impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
/// ```
/// #![feature(range_contains,inclusive_range_syntax)]
///
/// assert!( (...5).contains(-1_000_000_000));
/// assert!( (...5).contains(5));
/// assert!(!(...5).contains(6));
/// assert!( (..=5).contains(-1_000_000_000));
/// assert!( (..=5).contains(5));
/// assert!(!(..=5).contains(6));
/// ```
pub fn contains(&self, item: Idx) -> bool {
(item <= self.end)
......
......@@ -16,6 +16,9 @@
#![stable(feature = "rust1", since = "1.0.0")]
// FIXME: after next stage0, change RangeInclusive { ... } back to ..=
use ops::RangeInclusive;
// How this module is organized.
//
// The library infrastructure for slices is fairly messy. There's
......@@ -1044,32 +1047,32 @@ impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
#[inline]
fn get(self, slice: &[T]) -> Option<&[T]> {
(0...self.end).get(slice)
(RangeInclusive { start: 0, end: self.end }).get(slice)
}
#[inline]
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
(0...self.end).get_mut(slice)
(RangeInclusive { start: 0, end: self.end }).get_mut(slice)
}
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
(0...self.end).get_unchecked(slice)
(RangeInclusive { start: 0, end: self.end }).get_unchecked(slice)
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
(0...self.end).get_unchecked_mut(slice)
(RangeInclusive { start: 0, end: self.end }).get_unchecked_mut(slice)
}
#[inline]
fn index(self, slice: &[T]) -> &[T] {
(0...self.end).index(slice)
(RangeInclusive { start: 0, end: self.end }).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
(0...self.end).index_mut(slice)
(RangeInclusive { start: 0, end: self.end }).index_mut(slice)
}
}
......
......@@ -1094,21 +1094,21 @@ fn test_range() {
#[test]
fn test_range_inclusive_exhaustion() {
let mut r = 10...10;
let mut r = 10..=10;
assert_eq!(r.next(), Some(10));
assert_eq!(r, 1...0);
assert_eq!(r, 1..=0);
let mut r = 10...10;
let mut r = 10..=10;
assert_eq!(r.next_back(), Some(10));
assert_eq!(r, 1...0);
assert_eq!(r, 1..=0);
let mut r = 10...12;
let mut r = 10..=12;
assert_eq!(r.nth(2), Some(12));
assert_eq!(r, 1...0);
assert_eq!(r, 1..=0);
let mut r = 10...12;
let mut r = 10..=12;
assert_eq!(r.nth(5), None);
assert_eq!(r, 1...0);
assert_eq!(r, 1..=0);
}
......@@ -1145,20 +1145,20 @@ fn test_range_from_nth() {
#[test]
fn test_range_inclusive_nth() {
assert_eq!((10...15).nth(0), Some(10));
assert_eq!((10...15).nth(1), Some(11));
assert_eq!((10...15).nth(5), Some(15));
assert_eq!((10...15).nth(6), None);
assert_eq!((10..=15).nth(0), Some(10));
assert_eq!((10..=15).nth(1), Some(11));
assert_eq!((10..=15).nth(5), Some(15));
assert_eq!((10..=15).nth(6), None);
let mut r = 10_u8...20;
let mut r = 10_u8..=20;
assert_eq!(r.nth(2), Some(12));
assert_eq!(r, 13...20);
assert_eq!(r, 13..=20);
assert_eq!(r.nth(2), Some(15));
assert_eq!(r, 16...20);
assert_eq!(r, 16..=20);
assert_eq!(r.is_empty(), false);
assert_eq!(r.nth(10), None);
assert_eq!(r.is_empty(), true);
assert_eq!(r, 1...0); // We may not want to document/promise this detail
assert_eq!(r, 1..=0); // We may not want to document/promise this detail
}
#[test]
......
......@@ -509,6 +509,7 @@ fn joint(first: char, rest: Token, is_joint: bool, span: &mut syntax_pos::Span,
Dot => op!('.'),
DotDot => joint!('.', Dot),
DotDotDot => joint!('.', DotDot),
DotDotEq => joint!('.', DotEq),
Comma => op!(','),
Semi => op!(';'),
Colon => op!(':'),
......@@ -531,6 +532,7 @@ fn joint(first: char, rest: Token, is_joint: bool, span: &mut syntax_pos::Span,
})
}
DotEq => unreachable!(),
OpenDelim(..) | CloseDelim(..) => unreachable!(),
Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
};
......
......@@ -202,8 +202,8 @@ fn quote(&self) -> TokenStream {
gen_match! {
Eq, Lt, Le, EqEq, Ne, Ge, Gt, AndAnd, OrOr, Not, Tilde, At, Dot, DotDot, DotDotDot,
Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar, Question,
Underscore;
DotDotEq, Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar,
Question, Underscore;
Token::OpenDelim(delim) => quote!(rt::token::OpenDelim((quote delim))),
Token::CloseDelim(delim) => quote!(rt::token::CloseDelim((quote delim))),
......
......@@ -1864,7 +1864,7 @@ fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
match *e {
RangeEnd::Included => hir::RangeEnd::Included,
RangeEnd::Included(_) => hir::RangeEnd::Included,
RangeEnd::Excluded => hir::RangeEnd::Excluded,
}
}
......
......@@ -272,6 +272,8 @@ fn hash_token<'gcx, W: StableHasherResult>(token: &token::Token,
token::Token::Dot |
token::Token::DotDot |
token::Token::DotDotDot |
token::Token::DotDotEq |
token::Token::DotEq |
token::Token::Comma |
token::Token::Semi |
token::Token::Colon |
......
......@@ -249,8 +249,8 @@ fn write_token<W: Writer>(&mut self,
token::BinOpEq(..) | token::FatArrow => Class::Op,
// Miscellaneous, no highlighting.
token::Dot | token::DotDot | token::DotDotDot | token::Comma | token::Semi |
token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) |
token::Dot | token::DotDot | token::DotDotDot | token::DotDotEq | token::Comma |
token::Semi | token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) |
token::CloseDelim(token::Brace) | token::CloseDelim(token::Paren) |
token::CloseDelim(token::NoDelim) => Class::None,
......@@ -353,7 +353,7 @@ fn write_token<W: Writer>(&mut self,
token::Lifetime(..) => Class::Lifetime,
token::Underscore | token::Eof | token::Interpolated(..) |
token::Tilde | token::At => Class::None,
token::Tilde | token::At | token::DotEq => Class::None,
};
// Anything that didn't return above is the simple case where we the
......
......@@ -538,10 +538,16 @@ pub enum BindingMode {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum RangeEnd {
Included,
Included(RangeSyntax),
Excluded,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum RangeSyntax {
DotDotDot,
DotDotEq,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum PatKind {
/// Represents a wildcard pattern (`_`)
......@@ -578,7 +584,7 @@ pub enum PatKind {
Ref(P<Pat>, Mutability),
/// A literal
Lit(P<Expr>),
/// A range pattern, e.g. `1...2` or `1..2`
/// A range pattern, e.g. `1...2`, `1..=2` or `1..2`
Range(P<Expr>, P<Expr>, RangeEnd),
/// `[a, b, ..i, y, z]` is represented as:
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
......
......@@ -291,7 +291,7 @@ fn foo() {}
fn main() {
let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
let x = &tmp[1...]; // error: inclusive range was used with no end
let x = &tmp[1..=]; // error: inclusive range was used with no end
}
```
......@@ -312,7 +312,7 @@ fn main() {
fn main() {
let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
let x = &tmp[1...3]; // ok!
let x = &tmp[1..=3]; // ok!
}
```
"##,
......
......@@ -686,7 +686,9 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
token::At => "At",
token::Dot => "Dot",
token::DotDot => "DotDot",
token::DotEq => "DotEq",
token::DotDotDot => "DotDotDot",
token::DotDotEq => "DotDotEq",
token::Comma => "Comma",
token::Semi => "Semi",
token::Colon => "Colon",
......
......@@ -26,7 +26,7 @@
use self::AttributeGate::*;
use abi::Abi;
use ast::{self, NodeId, PatKind, RangeEnd};
use ast::{self, NodeId, PatKind, RangeEnd, RangeSyntax};
use attr;
use codemap::Spanned;
use syntax_pos::Span;
......@@ -261,7 +261,7 @@ pub fn new() -> Features {
// rustc internal
(active, abi_vectorcall, "1.7.0", None),
// a...b and ...b
// a..=b and ..=b
(active, inclusive_range_syntax, "1.7.0", Some(28237)),
// X..Y patterns
......@@ -392,6 +392,9 @@ pub fn new() -> Features {
// allow `'_` placeholder lifetimes
(active, underscore_lifetimes, "1.22.0", Some(44524)),
// allow `..=` in patterns (RFC 1192)
(active, dotdoteq_in_patterns, "1.22.0", Some(28237)),
);
declare_features! (
......@@ -1491,6 +1494,10 @@ fn visit_pat(&mut self, pattern: &'a ast::Pat) {
gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
"exclusive range pattern syntax is experimental");
}
PatKind::Range(_, _, RangeEnd::Included(RangeSyntax::DotDotEq)) => {
gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span,
"`..=` syntax in patterns is experimental");
}
_ => {}
}
visit::walk_pat(self, pattern)
......
......@@ -1131,6 +1131,9 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
if self.ch_is('.') {
self.bump();
Ok(token::DotDotDot)
} else if self.ch_is('=') {
self.bump();
Ok(token::DotDotEq)
} else {
Ok(token::DotDot)
}
......
......@@ -38,7 +38,7 @@
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 @@ pub fn span_err(self, sp: Span, handler: &errors::Handler) -> DiagnosticBuilder
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 @@ pub fn parse_assoc_expr_with(&mut self,
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 @@ pub fn parse_assoc_expr_with(&mut self,
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 @@ pub fn parse_assoc_expr_with(&mut self,
}
};
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 @@ pub fn parse_assoc_expr_with(&mut self,
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 @@ fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) {
}
}
/// 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 @@ fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
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 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
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 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
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 @@ fn parse_stmt_without_recovery(&mut self,
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 @@ fn warn_missing_semicolon(&self) {
}).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`)
......
......@@ -152,6 +152,8 @@ pub enum Token {
Dot,
DotDot,
DotDotDot,
DotDotEq,
DotEq, // HACK(durka42) never produced by the parser, only used for libproc_macro
Comma,
Semi,
Colon,
......@@ -212,18 +214,19 @@ pub fn is_like_gt(&self) -> bool {
pub fn can_begin_expr(&self) -> bool {
match *self {
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
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 | DotDotEq | // range notation
// SNAP remove DotDotDot
Lt | BinOp(Shl) | // associated path
ModSep | // global path
Pound => true, // expression attributes
Interpolated(ref nt) => match nt.0 {
NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true,
_ => false,
......@@ -402,10 +405,12 @@ pub fn glue(self, joint: Token) -> Option<Token> {
Dot => match joint {
Dot => DotDot,
DotDot => DotDotDot,
DotEq => DotDotEq,
_ => return None,
},
DotDot => match joint {
Dot => DotDotDot,
Eq => DotDotEq,
_ => return None,
},
Colon => match joint {
......@@ -413,9 +418,9 @@ pub fn glue(self, joint: Token) -> Option<Token> {
_ => return None,
},
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | Comma |
Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question |
OpenDelim(..) | CloseDelim(..) | Underscore => return None,
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq |
DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |
Question | OpenDelim(..) | CloseDelim(..) | Underscore => return None,
Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) |
Whitespace | Comment | Shebang(..) | Eof => return None,
......
......@@ -11,7 +11,7 @@
pub use self::AnnNode::*;
use abi::{self, Abi};
use ast::{self, BlockCheckMode, PatKind, RangeEnd};
use ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use ast::Attribute;
use util::parser::{self, AssocOp, Fixity};
......@@ -203,6 +203,8 @@ pub fn token_to_string(tok: &Token) -> String {
token::Dot => ".".to_string(),
token::DotDot => "..".to_string(),
token::DotDotDot => "...".to_string(),
token::DotDotEq => "..=".to_string(),
token::DotEq => ".=".to_string(),
token::Comma => ",".to_string(),
token::Semi => ";".to_string(),
token::Colon => ":".to_string(),
......@@ -2588,7 +2590,8 @@ pub fn print_pat(&mut self, pat: &ast::Pat) -> io::Result<()> {
self.print_expr(begin)?;
self.s.space()?;
match *end_kind {
RangeEnd::Included => self.s.word("...")?,
RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("...")?,
RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..=")?,
RangeEnd::Excluded => self.s.word("..")?,
}
self.print_expr(end)?;
......
......@@ -62,8 +62,8 @@ pub enum AssocOp {
As,
/// `..` range
DotDot,
/// `...` range
DotDotDot,
/// `..=` range
DotDotEq,
/// `:`
Colon,
}
......@@ -105,7 +105,8 @@ pub fn from_token(t: &Token) -> Option<AssocOp> {
Token::AndAnd => Some(LAnd),
Token::OrOr => Some(LOr),
Token::DotDot => Some(DotDot),
Token::DotDotDot => Some(DotDotDot),
Token::DotDotEq => Some(DotDotEq),
Token::DotDotDot => Some(DotDotEq), // remove this after SNAP
Token::Colon => Some(Colon),
_ if t.is_keyword(keywords::As) => Some(As),
_ => None
......@@ -151,7 +152,7 @@ pub fn precedence(&self) -> usize {
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
LAnd => 6,
LOr => 5,
DotDot | DotDotDot => 4,
DotDot | DotDotEq => 4,
Inplace => 3,
Assign | AssignOp(_) => 2,
}
......@@ -166,7 +167,7 @@ pub fn fixity(&self) -> Fixity {
As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
LAnd | LOr | Colon => Fixity::Left,
DotDot | DotDotDot => Fixity::None
DotDot | DotDotEq => Fixity::None
}
}
......@@ -176,7 +177,7 @@ pub fn is_comparison(&self) -> bool {
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract |
ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
DotDot | DotDotDot | Colon => false
DotDot | DotDotEq | Colon => false
}
}
......@@ -186,7 +187,7 @@ pub fn is_assign_like(&self) -> bool {
Assign | AssignOp(_) | Inplace => true,
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
LOr | DotDot | DotDotDot | Colon => false
LOr | DotDot | DotDotEq | Colon => false
}
}
......@@ -211,7 +212,7 @@ pub fn to_ast_binop(&self) -> Option<BinOpKind> {
BitOr => Some(BinOpKind::BitOr),
LAnd => Some(BinOpKind::And),
LOr => Some(BinOpKind::Or),
Inplace | Assign | AssignOp(_) | As | DotDot | DotDotDot | Colon => None
Inplace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
}
}
}
......
......@@ -10,5 +10,5 @@
fn main() {
let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
let x = &tmp[1...]; //~ ERROR E0586
let x = &tmp[1..=]; //~ ERROR E0586
}
// Copyright 2014 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.
pub fn main() {
match 22 {
0 ..= 3 => {} //~ ERROR `..=` syntax in patterns is experimental
_ => {}
}
}
......@@ -18,12 +18,12 @@ pub fn main() {
..1;
0..1;
...; //~ERROR inclusive range with no end
..=; //~ERROR inclusive range with no end
//~^HELP bounded at the end
0...; //~ERROR inclusive range with no end
0..=; //~ERROR inclusive range with no end
//~^HELP bounded at the end
...1;
0...1;
..=1;
0..=1;
}
......@@ -14,7 +14,7 @@
// #![feature(inclusive_range)]
pub fn main() {
let _: std::ops::RangeInclusive<_> = { use std::intrinsics; 1 } ... { use std::intrinsics; 2 };
let _: std::ops::RangeInclusive<_> = { use std::intrinsics; 1 } ..= { use std::intrinsics; 2 };
//~^ ERROR use of unstable library feature 'inclusive_range'
//~| ERROR core_intrinsics
//~| ERROR core_intrinsics
......
......@@ -153,5 +153,5 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
&slice[3...7]
&slice[3..=7]
}
......@@ -11,5 +11,5 @@
// Parsing of range patterns
fn main() {
let macropus!() ... 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `...`
let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `..=`
}
......@@ -11,5 +11,5 @@
// Parsing of range patterns
fn main() {
let 10 ... makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!`
let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!`
}
......@@ -11,5 +11,5 @@
// Parsing of range patterns
fn main() {
let 10 ... 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+`
let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+`
}
......@@ -11,5 +11,6 @@
// Parsing of range patterns
fn main() {
let 10 - 3 ... 10 = 8; //~ error: expected one of `...`, `..`, `:`, `;`, or `=`, found `-`
let 10 - 3 ..= 10 = 8;
//~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-`
}
......@@ -13,7 +13,7 @@
#![feature(inclusive_range_syntax, inclusive_range)]
pub fn main() {
for _ in 1... {} //~ERROR inclusive range with no end
for _ in 1..= {} //~ERROR inclusive range with no end
//~^HELP bounded at the end
}
......@@ -15,21 +15,21 @@
// #![feature(inclusive_range_syntax, inclusive_range)]
macro_rules! m {
() => { for _ in 1...10 {} } //~ ERROR inclusive range syntax is experimental
() => { for _ in 1..=10 {} } //~ ERROR inclusive range syntax is experimental
}
#[cfg(nope)]
fn f() {}
#[cfg(not(nope))]
fn f() {
for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental
for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental
}
#[cfg(nope)]
macro_rules! n { () => {} }
#[cfg(not(nope))]
macro_rules! n {
() => { for _ in 1...10 {} } //~ ERROR inclusive range syntax is experimental
() => { for _ in 1..=10 {} } //~ ERROR inclusive range syntax is experimental
}
macro_rules! o {
......@@ -38,7 +38,7 @@ fn f() {
fn g() {}
#[cfg(not(nope))]
fn g() {
for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental
for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental
}
g();
......@@ -54,7 +54,7 @@ fn g() {
fn h() {}
#[cfg(not(nope))]
fn h() {
for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental
for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental
}
h();
......@@ -62,8 +62,8 @@ fn h() {
}
pub fn main() {
for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental
for _ in ...10 {} //~ ERROR inclusive range syntax is experimental
for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental
for _ in ..=10 {} //~ ERROR inclusive range syntax is experimental
f(); // not allowed in cfg'ed functions
......
// 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.
// Test old and new syntax for inclusive range patterns.
#![feature(dotdoteq_in_patterns)]
fn main() {
assert!(match 42 { 0 ... 100 => true, _ => false });
assert!(match 42 { 0 ..= 100 => true, _ => false });
assert!(match 'x' { 'a' ... 'z' => true, _ => false });
assert!(match 'x' { 'a' ..= 'z' => true, _ => false });
}
......@@ -17,18 +17,18 @@
fn foo() -> isize { 42 }
// Test that range syntax works in return statements
fn return_range_to() -> RangeToInclusive<i32> { return ...1; }
fn return_range_to() -> RangeToInclusive<i32> { return ..=1; }
pub fn main() {
let mut count = 0;
for i in 0_usize...10 {
for i in 0_usize..=10 {
assert!(i >= 0 && i <= 10);
count += i;
}
assert_eq!(count, 55);
let mut count = 0;
let mut range = 0_usize...10;
let mut range = 0_usize..=10;
for i in range {
assert!(i >= 0 && i <= 10);
count += i;
......@@ -36,53 +36,53 @@ pub fn main() {
assert_eq!(count, 55);
let mut count = 0;
for i in (0_usize...10).step_by(2) {
for i in (0_usize..=10).step_by(2) {
assert!(i >= 0 && i <= 10 && i % 2 == 0);
count += i;
}
assert_eq!(count, 30);
let _ = 0_usize...4+4-3;
let _ = 0...foo();
let _ = 0_usize..=4+4-3;
let _ = 0..=foo();
let _ = { &42...&100 }; // references to literals are OK
let _ = ...42_usize;
let _ = { &42..=&100 }; // references to literals are OK
let _ = ..=42_usize;
// Test we can use two different types with a common supertype.
let x = &42;
{
let y = 42;
let _ = x...&y;
let _ = x..=&y;
}
// test collection indexing
let vec = (0...10).collect::<Vec<_>>();
let vec = (0..=10).collect::<Vec<_>>();
let slice: &[_] = &*vec;
let string = String::from("hello world");
let stir = "hello world";
assert_eq!(&vec[3...6], &[3, 4, 5, 6]);
assert_eq!(&vec[ ...6], &[0, 1, 2, 3, 4, 5, 6]);
assert_eq!(&vec[3..=6], &[3, 4, 5, 6]);
assert_eq!(&vec[ ..=6], &[0, 1, 2, 3, 4, 5, 6]);
assert_eq!(&slice[3...6], &[3, 4, 5, 6]);
assert_eq!(&slice[ ...6], &[0, 1, 2, 3, 4, 5, 6]);
assert_eq!(&slice[3..=6], &[3, 4, 5, 6]);
assert_eq!(&slice[ ..=6], &[0, 1, 2, 3, 4, 5, 6]);
assert_eq!(&string[3...6], "lo w");
assert_eq!(&string[ ...6], "hello w");
assert_eq!(&string[3..=6], "lo w");
assert_eq!(&string[ ..=6], "hello w");
assert_eq!(&stir[3...6], "lo w");
assert_eq!(&stir[ ...6], "hello w");
assert_eq!(&stir[3..=6], "lo w");
assert_eq!(&stir[ ..=6], "hello w");
// test the size hints and emptying
let mut long = 0...255u8;
let mut short = 42...42u8;
let mut long = 0..=255u8;
let mut short = 42..=42u8;
assert_eq!(long.size_hint(), (256, Some(256)));
assert_eq!(short.size_hint(), (1, Some(1)));
long.next();
short.next();
assert_eq!(long.size_hint(), (255, Some(255)));
assert_eq!(short.size_hint(), (0, Some(0)));
assert_eq!(short, 1...0);
assert_eq!(short, 1..=0);
assert_eq!(long.len(), 255);
assert_eq!(short.len(), 0);
......@@ -94,31 +94,31 @@ pub fn main() {
assert_eq!(long.next(), Some(1));
assert_eq!(long.next(), Some(2));
assert_eq!(long.next_back(), Some(252));
for i in 3...251 {
for i in 3..=251 {
assert_eq!(long.next(), Some(i));
}
assert_eq!(long, 1...0);
assert_eq!(long, 1..=0);
// check underflow
let mut narrow = 1...0;
let mut narrow = 1..=0;
assert_eq!(narrow.next_back(), None);
assert_eq!(narrow, 1...0);
let mut zero = 0u8...0;
assert_eq!(narrow, 1..=0);
let mut zero = 0u8..=0;
assert_eq!(zero.next_back(), Some(0));
assert_eq!(zero.next_back(), None);
assert_eq!(zero, 1...0);
let mut high = 255u8...255;
assert_eq!(zero, 1..=0);
let mut high = 255u8..=255;
assert_eq!(high.next_back(), Some(255));
assert_eq!(high.next_back(), None);
assert_eq!(high, 1...0);
assert_eq!(high, 1..=0);
// what happens if you have a nonsense range?
let mut nonsense = 10...5;
let mut nonsense = 10..=5;
assert_eq!(nonsense.next(), None);
assert_eq!(nonsense, 10...5);
assert_eq!(nonsense, 10..=5);
// output
assert_eq!(format!("{:?}", 0...10), "0...10");
assert_eq!(format!("{:?}", ...10), "...10");
assert_eq!(format!("{:?}", long), "1...0");
assert_eq!(format!("{:?}", 0..=10), "0..=10");
assert_eq!(format!("{:?}", ..=10), "..=10");
assert_eq!(format!("{:?}", long), "1..=0");
}
......@@ -14,7 +14,7 @@
fn main() {
let mut count = 0;
for i in 0_usize...10 {
for i in 0_usize..=10 {
assert!(i >= 0 && i <= 10);
count += i;
}
......
Subproject commit a1fd68da464fc51585f351c81fc2b867211c197e
Subproject commit 22eb5241c0ee5bb7eaf95e270a2b1500e82bf767
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册