Skip to content

Commit 8484831

Browse files
committed
Auto merge of #30884 - durka:inclusive-ranges, r=aturon
This PR implements [RFC 1192](https://github.com/rust-lang/rfcs/blob/master/text/1192-inclusive-ranges.md), which is triple-dot syntax for inclusive range expressions. The new stuff is behind two feature gates (one for the syntax and one for the std::ops types). This replaces the deprecated functionality in std::iter. Along the way I simplified the desugaring for all ranges. This is my first contribution to rust which changes more than one character outside of a test or comment, so please review carefully! Some of the individual commit messages have more of my notes. Also thanks for putting up with my dumb questions in #rust-internals. - For implementing `std::ops::RangeInclusive`, I took @Stebalien's suggestion from rust-lang/rfcs#1192 (comment). It seemed to me to make the implementation easier and increase type safety. If that stands, the RFC should be amended to avoid confusion. - I also kind of like @glaebhoerl's [idea](rust-lang/rfcs#1254 (comment)), which is unified inclusive/exclusive range syntax something like `x>..=y`. We can experiment with this while everything is behind a feature gate. - There are a couple of FIXMEs left (see the last commit). I didn't know what to do about `RangeArgument` and I haven't added `Index` impls yet. Those should be discussed/finished before merging. cc @gankro since you [complained](https://www.reddit.com/r/rust/comments/3xkfro/what_happened_to_inclusive_ranges/cy5j0yq) cc #27777 #30877 #1192 rust-lang/rfcs#1254 relevant to #28237 (tracking issue)
2 parents 45f0ce7 + 430b3e1 commit 8484831

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+983
-390
lines changed

Diff for: src/doc/book/iterators.md

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ Now that you know more Rust, we can talk in detail about how this works.
1414
Ranges (the `0..10`) are 'iterators'. An iterator is something that we can
1515
call the `.next()` method on repeatedly, and it gives us a sequence of things.
1616

17+
(By the way, a range with two dots like `0..10` is inclusive on the left (so it
18+
starts at 0) and exclusive on the right (so it ends at 9). A mathematician
19+
would write "[0, 10)". To get a range that goes all the way up to 10 you can
20+
write `0...10`.)
21+
1722
Like this:
1823

1924
```rust

Diff for: src/doc/book/syntax-index.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@
6666
* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
6767
* `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)].
6868
* `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. See [Patterns (Ignoring bindings)].
69-
* `...` (`expr ... expr`): inclusive range pattern. See [Patterns (Ranges)].
69+
* `...` (`...expr`, `expr...expr`) *in an expression*: inclusive range expression. See [Iterators].
70+
* `...` (`expr...expr`) *in a pattern*: inclusive range pattern. See [Patterns (Ranges)].
7071
* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`).
7172
* `/=` (`var /= expr`): arithmetic division & assignment.
7273
* `:` (`pat: type`, `ident: type`): constraints. See [Variable Bindings], [Functions], [Structs], [Traits].
@@ -205,6 +206,7 @@
205206
[Functions (Early Returns)]: functions.html#early-returns
206207
[Functions]: functions.html
207208
[Generics]: generics.html
209+
[Iterators]: iterators.html
208210
[Lifetimes]: lifetimes.html
209211
[Loops (`for`)]: loops.html#for
210212
[Loops (`loop`)]: loops.html#loop

Diff for: src/doc/reference.md

+23
Original file line numberDiff line numberDiff line change
@@ -2277,6 +2277,10 @@ The currently implemented features of the reference compiler are:
22772277
`#[derive_Foo] #[derive_Bar]`, which can be user-defined syntax
22782278
extensions.
22792279

2280+
* `inclusive_range_syntax` - Allows use of the `a...b` and `...b` syntax for inclusive ranges.
2281+
2282+
* `inclusive_range` - Allows use of the types that represent desugared inclusive ranges.
2283+
22802284
* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
22812285
are inherently unstable and no promise about them is made.
22822286

@@ -2747,6 +2751,25 @@ let y = 0..10;
27472751
assert_eq!(x, y);
27482752
```
27492753

2754+
Similarly, the `...` operator will construct an object of one of the
2755+
`std::ops::RangeInclusive` variants.
2756+
2757+
```
2758+
# #![feature(inclusive_range_syntax)]
2759+
1...2; // std::ops::RangeInclusive
2760+
...4; // std::ops::RangeToInclusive
2761+
```
2762+
2763+
The following expressions are equivalent.
2764+
2765+
```
2766+
# #![feature(inclusive_range_syntax, inclusive_range)]
2767+
let x = std::ops::RangeInclusive::NonEmpty {start: 0, end: 10};
2768+
let y = 0...10;
2769+
2770+
assert_eq!(x, y);
2771+
```
2772+
27502773
### Unary operator expressions
27512774

27522775
Rust defines the following unary operators. They are all written as prefix operators,

Diff for: src/libcollections/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
#![feature(fmt_internals)]
4141
#![feature(fmt_radix)]
4242
#![feature(heap_api)]
43-
#![feature(iter_arith)]
43+
#![feature(inclusive_range)]
4444
#![feature(iter_arith)]
4545
#![feature(lang_items)]
4646
#![feature(nonzero)]

Diff for: src/libcollections/range.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub trait RangeArgument<T> {
3535
}
3636
}
3737

38+
// FIXME add inclusive ranges to RangeArgument
3839

3940
impl<T> RangeArgument<T> for RangeFull {}
4041

Diff for: src/libcollections/string.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ use core::fmt;
5959
use core::hash;
6060
use core::iter::FromIterator;
6161
use core::mem;
62-
use core::ops::{self, Add};
62+
use core::ops::{self, Add, Index, IndexMut};
6363
use core::ptr;
6464
use core::slice;
6565
use core::str::pattern::Pattern;
@@ -1606,6 +1606,24 @@ impl ops::Index<ops::RangeFull> for String {
16061606
unsafe { str::from_utf8_unchecked(&self.vec) }
16071607
}
16081608
}
1609+
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
1610+
impl ops::Index<ops::RangeInclusive<usize>> for String {
1611+
type Output = str;
1612+
1613+
#[inline]
1614+
fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
1615+
Index::index(&**self, index)
1616+
}
1617+
}
1618+
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
1619+
impl ops::Index<ops::RangeToInclusive<usize>> for String {
1620+
type Output = str;
1621+
1622+
#[inline]
1623+
fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
1624+
Index::index(&**self, index)
1625+
}
1626+
}
16091627

16101628
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
16111629
impl ops::IndexMut<ops::Range<usize>> for String {
@@ -1635,6 +1653,20 @@ impl ops::IndexMut<ops::RangeFull> for String {
16351653
unsafe { mem::transmute(&mut *self.vec) }
16361654
}
16371655
}
1656+
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
1657+
impl ops::IndexMut<ops::RangeInclusive<usize>> for String {
1658+
#[inline]
1659+
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
1660+
IndexMut::index_mut(&mut **self, index)
1661+
}
1662+
}
1663+
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
1664+
impl ops::IndexMut<ops::RangeToInclusive<usize>> for String {
1665+
#[inline]
1666+
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
1667+
IndexMut::index_mut(&mut **self, index)
1668+
}
1669+
}
16381670

16391671
#[stable(feature = "rust1", since = "1.0.0")]
16401672
impl ops::Deref for String {

Diff for: src/libcollections/vec.rs

+32
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,24 @@ impl<T> ops::Index<ops::RangeFull> for Vec<T> {
12261226
self
12271227
}
12281228
}
1229+
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
1230+
impl<T> ops::Index<ops::RangeInclusive<usize>> for Vec<T> {
1231+
type Output = [T];
1232+
1233+
#[inline]
1234+
fn index(&self, index: ops::RangeInclusive<usize>) -> &[T] {
1235+
Index::index(&**self, index)
1236+
}
1237+
}
1238+
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
1239+
impl<T> ops::Index<ops::RangeToInclusive<usize>> for Vec<T> {
1240+
type Output = [T];
1241+
1242+
#[inline]
1243+
fn index(&self, index: ops::RangeToInclusive<usize>) -> &[T] {
1244+
Index::index(&**self, index)
1245+
}
1246+
}
12291247

12301248
#[stable(feature = "rust1", since = "1.0.0")]
12311249
impl<T> ops::IndexMut<ops::Range<usize>> for Vec<T> {
@@ -1255,6 +1273,20 @@ impl<T> ops::IndexMut<ops::RangeFull> for Vec<T> {
12551273
self
12561274
}
12571275
}
1276+
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
1277+
impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for Vec<T> {
1278+
#[inline]
1279+
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] {
1280+
IndexMut::index_mut(&mut **self, index)
1281+
}
1282+
}
1283+
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
1284+
impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for Vec<T> {
1285+
#[inline]
1286+
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] {
1287+
IndexMut::index_mut(&mut **self, index)
1288+
}
1289+
}
12581290

12591291
#[stable(feature = "rust1", since = "1.0.0")]
12601292
impl<T> ops::Deref for Vec<T> {

0 commit comments

Comments
 (0)