Skip to content

Commit

Permalink
Auto merge of #30884 - durka:inclusive-ranges, r=aturon
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
bors committed Mar 6, 2016
2 parents 45f0ce7 + 430b3e1 commit 8484831
Show file tree
Hide file tree
Showing 46 changed files with 983 additions and 390 deletions.
5 changes: 5 additions & 0 deletions src/doc/book/iterators.md
Expand Up @@ -14,6 +14,11 @@ Now that you know more Rust, we can talk in detail about how this works.
Ranges (the `0..10`) are 'iterators'. An iterator is something that we can
call the `.next()` method on repeatedly, and it gives us a sequence of things.

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

Like this:

```rust
Expand Down
4 changes: 3 additions & 1 deletion src/doc/book/syntax-index.md
Expand Up @@ -66,7 +66,8 @@
* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
* `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)].
* `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. See [Patterns (Ignoring bindings)].
* `...` (`expr ... expr`): inclusive range pattern. See [Patterns (Ranges)].
* `...` (`...expr`, `expr...expr`) *in an expression*: inclusive range expression. See [Iterators].
* `...` (`expr...expr`) *in a pattern*: inclusive range pattern. See [Patterns (Ranges)].
* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`).
* `/=` (`var /= expr`): arithmetic division & assignment.
* `:` (`pat: type`, `ident: type`): constraints. See [Variable Bindings], [Functions], [Structs], [Traits].
Expand Down Expand Up @@ -205,6 +206,7 @@
[Functions (Early Returns)]: functions.html#early-returns
[Functions]: functions.html
[Generics]: generics.html
[Iterators]: iterators.html
[Lifetimes]: lifetimes.html
[Loops (`for`)]: loops.html#for
[Loops (`loop`)]: loops.html#loop
Expand Down
23 changes: 23 additions & 0 deletions src/doc/reference.md
Expand Up @@ -2277,6 +2277,10 @@ The currently implemented features of the reference compiler are:
`#[derive_Foo] #[derive_Bar]`, which can be user-defined syntax
extensions.

* `inclusive_range_syntax` - Allows use of the `a...b` and `...b` syntax for inclusive ranges.

* `inclusive_range` - Allows use of the types that represent desugared inclusive ranges.

* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
are inherently unstable and no promise about them is made.

Expand Down Expand Up @@ -2747,6 +2751,25 @@ let y = 0..10;
assert_eq!(x, y);
```

Similarly, the `...` operator will construct an object of one of the
`std::ops::RangeInclusive` variants.

```
# #![feature(inclusive_range_syntax)]
1...2; // std::ops::RangeInclusive
...4; // std::ops::RangeToInclusive
```

The following expressions are equivalent.

```
# #![feature(inclusive_range_syntax, inclusive_range)]
let x = std::ops::RangeInclusive::NonEmpty {start: 0, end: 10};
let y = 0...10;
assert_eq!(x, y);
```

### Unary operator expressions

Rust defines the following unary operators. They are all written as prefix operators,
Expand Down
2 changes: 1 addition & 1 deletion src/libcollections/lib.rs
Expand Up @@ -40,7 +40,7 @@
#![feature(fmt_internals)]
#![feature(fmt_radix)]
#![feature(heap_api)]
#![feature(iter_arith)]
#![feature(inclusive_range)]
#![feature(iter_arith)]
#![feature(lang_items)]
#![feature(nonzero)]
Expand Down
1 change: 1 addition & 0 deletions src/libcollections/range.rs
Expand Up @@ -35,6 +35,7 @@ pub trait RangeArgument<T> {
}
}

// FIXME add inclusive ranges to RangeArgument

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

Expand Down
34 changes: 33 additions & 1 deletion src/libcollections/string.rs
Expand Up @@ -59,7 +59,7 @@ use core::fmt;
use core::hash;
use core::iter::FromIterator;
use core::mem;
use core::ops::{self, Add};
use core::ops::{self, Add, Index, IndexMut};
use core::ptr;
use core::slice;
use core::str::pattern::Pattern;
Expand Down Expand Up @@ -1606,6 +1606,24 @@ impl ops::Index<ops::RangeFull> for String {
unsafe { str::from_utf8_unchecked(&self.vec) }
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl ops::Index<ops::RangeInclusive<usize>> for String {
type Output = str;

#[inline]
fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
Index::index(&**self, index)
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl ops::Index<ops::RangeToInclusive<usize>> for String {
type Output = str;

#[inline]
fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
Index::index(&**self, index)
}
}

#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::Range<usize>> for String {
Expand Down Expand Up @@ -1635,6 +1653,20 @@ impl ops::IndexMut<ops::RangeFull> for String {
unsafe { mem::transmute(&mut *self.vec) }
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl ops::IndexMut<ops::RangeInclusive<usize>> for String {
#[inline]
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
IndexMut::index_mut(&mut **self, index)
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl ops::IndexMut<ops::RangeToInclusive<usize>> for String {
#[inline]
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
IndexMut::index_mut(&mut **self, index)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Deref for String {
Expand Down
32 changes: 32 additions & 0 deletions src/libcollections/vec.rs
Expand Up @@ -1226,6 +1226,24 @@ impl<T> ops::Index<ops::RangeFull> for Vec<T> {
self
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<T> ops::Index<ops::RangeInclusive<usize>> for Vec<T> {
type Output = [T];

#[inline]
fn index(&self, index: ops::RangeInclusive<usize>) -> &[T] {
Index::index(&**self, index)
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<T> ops::Index<ops::RangeToInclusive<usize>> for Vec<T> {
type Output = [T];

#[inline]
fn index(&self, index: ops::RangeToInclusive<usize>) -> &[T] {
Index::index(&**self, index)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ops::IndexMut<ops::Range<usize>> for Vec<T> {
Expand Down Expand Up @@ -1255,6 +1273,20 @@ impl<T> ops::IndexMut<ops::RangeFull> for Vec<T> {
self
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for Vec<T> {
#[inline]
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] {
IndexMut::index_mut(&mut **self, index)
}
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for Vec<T> {
#[inline]
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] {
IndexMut::index_mut(&mut **self, index)
}
}

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

0 comments on commit 8484831

Please sign in to comment.