Skip to content

Commit 0207008

Browse files
committed
std::range instead of std::ops::range
1 parent 2e54cff commit 0207008

File tree

1 file changed

+61
-60
lines changed

1 file changed

+61
-60
lines changed

text/3550-new-range.md

Lines changed: 61 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# Summary
77
[summary]: #summary
88

9-
Change the range operators `a..b`, `a..`, and `a..=b` to resolve to new types `ops::range::Range`, `ops::range::RangeFrom`, and `ops::range::RangeInclusive` in Edition 2024. These new types will not implement `Iterator`, instead implementing `Copy` and `IntoIterator`.
9+
Change the range operators `a..b`, `a..`, and `a..=b` to resolve to new types `std::range::Range`, `std::range::RangeFrom`, and `std::range::RangeInclusive` in Edition 2024. These new types will not implement `Iterator`, instead implementing `Copy` and `IntoIterator`.
1010

1111
# Motivation
1212
[motivation]: #motivation
@@ -38,13 +38,13 @@ Another primary motivation is the extra size of `RangeInclusive`. It uses an ext
3838

3939
Rust has several different types of "range" syntax, including the following:
4040

41-
- `a..b` denotes a range from `a` (inclusive) to `b` (exclusive). It resolves to the type `std::ops::range::Range`.
41+
- `a..b` denotes a range from `a` (inclusive) to `b` (exclusive). It resolves to the type `std::range::Range`.
4242
The iterator for `Range` will yield values from `a` (inclusive) to `b` (exclusive) in steps of one.
4343

44-
- `a..=b` denotes a range from `a` (inclusive) to `b` (inclusive). It resolve to the type `std::ops::range::RangeInclusive`.
44+
- `a..=b` denotes a range from `a` (inclusive) to `b` (inclusive). It resolve to the type `std::range::RangeInclusive`.
4545
The iterator for `RangeInclusive` will yield values from `a` (inclusive) to `b` (inclusive) in steps of one.
4646

47-
- `a..` denotes a range from `a` (inclusive) with no upper bound. It resolves to the type `std::ops::range::RangeFrom`.
47+
- `a..` denotes a range from `a` (inclusive) with no upper bound. It resolves to the type `std::range::RangeFrom`.
4848
The iterator for `RangeFrom` will yield values starting with `a` and increasing in steps of one.
4949

5050
These types implement the `IntoIterator` trait, enabling their use directly in a `for` loop:
@@ -78,7 +78,7 @@ for n in (0..5).rev() {
7878

7979
## Legacy Range Types
8080

81-
In Rust editions prior to 2024, `a..b`, `a..=b`, and `a..` resolved to a different set of types (now found in `std::ops::range::legacy`). These legacy range types did not implement `Copy`, and implemented `Iterator` directly (rather than `IntoIterator`).
81+
In Rust editions prior to 2024, `a..b`, `a..=b`, and `a..` resolved to a different set of types (now found in `std::range::legacy`). These legacy range types did not implement `Copy`, and implemented `Iterator` directly (rather than `IntoIterator`).
8282

8383
This meant that any `Iterator` method could be called on those range types:
8484
```rust
@@ -128,7 +128,7 @@ Or fall back to converting to the legacy types:
128128
pub fn takes_range(range: std::ops::Range<usize>) { ... }
129129
takes_range(0..5);
130130
// After
131-
pub fn takes_range(range: std::ops::range::legacy::Range<usize>) { ... }
131+
pub fn takes_range(range: std::range::legacy::Range<usize>) { ... }
132132
takes_range((0..5).to_legacy());
133133
```
134134

@@ -144,7 +144,7 @@ To reduce the need for the above conversions, we recommend making the following
144144
pub fn takes_range(range: std::ops::Range<usize>) { ... }
145145

146146
// After
147-
pub fn takes_range(range: impl Into<std::ops::range::legacy::Range<usize>>) { ... }
147+
pub fn takes_range(range: impl Into<std::range::legacy::Range<usize>>) { ... }
148148
// Or
149149
pub fn takes_range(range: impl std::ops::RangeBounds<usize>) { ... }
150150
```
@@ -207,9 +207,9 @@ use std::ops::{Index, Range};
207207
impl Index<Range<usize>> for Bar { ... }
208208

209209
// After
210-
use std::ops::{Index, range::Range, range::legacy};
211-
impl Index<legacy::Range<usize>> for Bar { ... }
210+
use std::ops::{Index, Range};
212211
impl Index<Range<usize>> for Bar { ... }
212+
impl Index<std::range::Range<usize>> for Bar { ... }
213213
```
214214

215215
## Diagnostics
@@ -240,108 +240,109 @@ The [**Range Expressions** page in the Reference](https://doc.rust-lang.org/refe
240240

241241
> ## Edition 2024 and later
242242
>
243-
> The `..` and `..=` operators will construct an object of one of the `std::ops::range::Range` (or `core::ops::range::Range`) variants, according to the following table:
243+
> The `..` and `..=` operators will construct an object of one of the `std::range::Range` (or `core::range::Range`) variants, according to the following table:
244244
>
245245
> | Production | Syntax | Type | Range |
246246
> |------------------------|---------------|------------------------------|-----------------------|
247-
> | _RangeExpr_ | start`..`end | std::ops::range::Range | start &le; x &lt; end |
248-
> | _RangeFromExpr_ | start`..` | std::ops::range::RangeFrom | start &le; x |
249-
> | _RangeToExpr_ | `..`end | std::ops::range::RangeTo | x &lt; end |
250-
> | _RangeFullExpr_ | `..` | std::ops::range::RangeFull | - |
251-
> | _RangeInclusiveExpr_ | start`..=`end | std::ops::range::RangeInclusive | start &le; x &le; end |
252-
> | _RangeToInclusiveExpr_ | `..=`end | std::ops::range::RangeToInclusive | x &le; end |
247+
> | _RangeExpr_ | start`..`end | std::range::Range | start &le; x &lt; end |
248+
> | _RangeFromExpr_ | start`..` | std::range::RangeFrom | start &le; x |
249+
> | _RangeToExpr_ | `..`end | std::range::RangeTo | x &lt; end |
250+
> | _RangeFullExpr_ | `..` | std::range::RangeFull | - |
251+
> | _RangeInclusiveExpr_ | start`..=`end | std::range::RangeInclusive | start &le; x &le; end |
252+
> | _RangeToInclusiveExpr_ | `..=`end | std::range::RangeToInclusive | x &le; end |
253253
>
254-
> **Note:** While `std::ops::RangeTo`, `std::ops::RangeFull`, and `std::ops::RangeToInclusive` are re-exports of `std::ops::range::RangeTo`, `std::ops::range::RangeFull`, and `std::ops::Range::RangeToInclusive` respectively, `std::ops::Range`, `std::ops::RangeFrom`, and `std::ops::RangeInclusive` are re-exports of the types under `std::ops::range::legacy::` (NOT those directly under `std::ops::range::`) for backwards-compatibility reasons.
254+
> **Note:** While `std::ops::RangeTo`, `std::ops::RangeFull`, and `std::ops::RangeToInclusive` are re-exports of `std::range::RangeTo`, `std::range::RangeFull`, and `std::ops::Range::RangeToInclusive` respectively, `std::ops::Range`, `std::ops::RangeFrom`, and `std::ops::RangeInclusive` are re-exports of the types under `std::range::legacy::` (NOT those directly under `std::range::`) for backwards-compatibility reasons.
255255
>
256256
> Examples:
257257
>
258258
> ```rust
259-
> 1..2; // std::ops::range::Range
260-
> 3..; // std::ops::range::RangeFrom
261-
> ..4; // std::ops::range::RangeTo
262-
> ..; // std::ops::range::RangeFull
263-
> 5..=6; // std::ops::range::RangeInclusive
264-
> ..=7; // std::ops::range::RangeToInclusive
259+
> 1..2; // std::range::Range
260+
> 3..; // std::range::RangeFrom
261+
> ..4; // std::range::RangeTo
262+
> ..; // std::range::RangeFull
263+
> 5..=6; // std::range::RangeInclusive
264+
> ..=7; // std::range::RangeToInclusive
265265
> ```
266266
>
267267
> The following expressions are equivalent.
268268
>
269269
> ```rust
270-
> let x = std::ops::range::Range {start: 0, end: 10};
270+
> let x = std::range::Range {start: 0, end: 10};
271271
> let y = 0..10;
272272
>
273273
> assert_eq!(x, y);
274274
> ```
275275
>
276276
> ## Prior to Edition 2024
277277
>
278-
> The `..` and `..=` operators will construct an object of one of the `std::ops::range::legacy::Range` (or `core::ops::range::legacy::Range`) variants, according to the following table:
278+
> The `..` and `..=` operators will construct an object of one of the `std::range::legacy::Range` (or `core::range::legacy::Range`) variants, according to the following table:
279279
>
280280
> | Production | Syntax | Type | Range |
281281
> |------------------------|---------------|------------------------------|-----------------------|
282-
> | _RangeExpr_ | start`..`end | std::ops::range::legacy::Range | start &le; x &lt; end |
283-
> | _RangeFromExpr_ | start`..` | std::ops::range::legacy::RangeFrom | start &le; x |
284-
> | _RangeToExpr_ | `..`end | std::ops::range::RangeTo | x &lt; end |
285-
> | _RangeFullExpr_ | `..` | std::ops::range::RangeFull | - |
286-
> | _RangeInclusiveExpr_ | start`..=`end | std::ops::range::legacy::RangeInclusive | start &le; x &le; end |
287-
> | _RangeToInclusiveExpr_ | `..=`end | std::ops::range::RangeToInclusive | x &le; end |
282+
> | _RangeExpr_ | start`..`end | std::range::legacy::Range | start &le; x &lt; end |
283+
> | _RangeFromExpr_ | start`..` | std::range::legacy::RangeFrom | start &le; x |
284+
> | _RangeToExpr_ | `..`end | std::range::RangeTo | x &lt; end |
285+
> | _RangeFullExpr_ | `..` | std::range::RangeFull | - |
286+
> | _RangeInclusiveExpr_ | start`..=`end | std::range::legacy::RangeInclusive | start &le; x &le; end |
287+
> | _RangeToInclusiveExpr_ | `..=`end | std::range::RangeToInclusive | x &le; end |
288288
>
289-
> **Note:** `std::ops::Range`, `std::ops::RangeFrom`, and `std::ops::RangeInclusive` are re-exports of the respective types under `std::ops::range::legacy::`. `std::ops::RangeTo`, `std::ops::RangeFull`, and `std::ops::RangeToInclusive` are re-exports of the respective types under `std::ops::range::`.
289+
> **Note:** `std::ops::Range`, `std::ops::RangeFrom`, and `std::ops::RangeInclusive` are re-exports of the respective types under `std::range::legacy::`. `std::ops::RangeTo`, `std::ops::RangeFull`, and `std::ops::RangeToInclusive` are re-exports of the respective types under `std::range::`.
290290
>
291291
> Examples:
292292
>
293293
> ```rust
294-
> 1..2; // std::ops::range::legacy::Range
295-
> 3..; // std::ops::range::legacy::RangeFrom
296-
> ..4; // std::ops::range::RangeTo
297-
> ..; // std::ops::range::RangeFull
298-
> 5..=6; // std::ops::range::legacy::RangeInclusive
299-
> ..=7; // std::ops::range::RangeToInclusive
294+
> 1..2; // std::range::legacy::Range
295+
> 3..; // std::range::legacy::RangeFrom
296+
> ..4; // std::range::RangeTo
297+
> ..; // std::range::RangeFull
298+
> 5..=6; // std::range::legacy::RangeInclusive
299+
> ..=7; // std::range::RangeToInclusive
300300
> ```
301301
>
302302
> The following expressions are equivalent.
303303
>
304304
> ```rust
305-
> let x = std::ops::range::legacy::Range {start: 0, end: 10};
306-
> // Or: let x = std::ops::Range {start: 0, end: 10};
307-
> let y = 0..10;
305+
> let x = std::range::legacy::Range {start: 0, end: 10};
306+
> let y = std::ops::Range {start: 0, end: 10};
307+
> let z = 0..10;
308308
>
309309
> assert_eq!(x, y);
310+
> assert_eq!(x, z);
310311
> ```
311312
312313
## New paths
313314
314-
There is no language support for edition-dependent path resolution, so these types must continue to be accessible under their current paths. However, their canonical paths will change to live under `ops::range::legacy`:
315+
There is no language support for edition-dependent path resolution, so these types must continue to be accessible under their current paths. However, their canonical paths will change to live under `std::range::legacy`:
315316
316-
- `ops::Range` will be a re-export of `ops::range::legacy::Range`
317-
- `ops::RangeFrom` will be a re-export of `ops::range::legacy::RangeFrom`
318-
- `ops::RangeInclusive` will be a re-export of `ops::range::legacy::RangeFrom`
317+
- `std::ops::Range` will be a re-export of `std::range::legacy::Range`
318+
- `std::ops::RangeFrom` will be a re-export of `std::range::legacy::RangeFrom`
319+
- `std::ops::RangeInclusive` will be a re-export of `std::range::legacy::RangeFrom`
319320
320321
In order to not break existing links to the documentation for these types, the re-exports must remain `doc(inline)`.
321322
322-
The replacement types will live under `ops::range`:
323+
The replacement types will live under `range`:
323324
324-
- `ops::range::Range` will be the Edition 2024 replacement for `ops::range::legacy::Range`
325-
- `ops::range::RangeFrom` will be the Edition 2024 replacement for `ops::range::legacy::RangeFrom`
326-
- `ops::range::RangeInclusive` will be the Edition 2024 replacement for `ops::range::legacy::RangeFrom`
325+
- `std::range::Range` will be the Edition 2024 replacement for `std::range::legacy::Range`
326+
- `std::range::RangeFrom` will be the Edition 2024 replacement for `std::range::legacy::RangeFrom`
327+
- `std::range::RangeInclusive` will be the Edition 2024 replacement for `std::range::legacy::RangeFrom`
327328
328-
The `RangeFull`, `RangeTo`, and `RangeToInclusive` types will remain unchanged. But for consistency, their canonical paths will be changed to live under `ops::range`:
329+
The `RangeFull`, `RangeTo`, and `RangeToInclusive` types will remain unchanged. But for consistency, their canonical paths will be changed to live under `range`:
329330
330-
- `ops::RangeFull` will be a re-export of `ops::range::RangeFull`
331-
- `ops::RangeTo` will be a re-export of `ops::range::RangeTo`
332-
- `ops::RangeToInclusive` will be a re-export of `ops::range::RangeToInclusive`
331+
- `std::ops::RangeFull` will be a re-export of `std::range::RangeFull`
332+
- `std::ops::RangeTo` will be a re-export of `std::range::RangeTo`
333+
- `std::ops::RangeToInclusive` will be a re-export of `std::range::RangeToInclusive`
333334
334335
## Iterator types
335336
336337
Because the three new types will implement `IntoIterator` directly, they need three new respective `IntoIter` types:
337338
338-
- `ops::range::IterRange` will be `<ops::range::Range<_> as IntoIterator>::IntoIter`
339-
- `ops::range::IterRangeFrom` will be `<ops::range::RangeFrom<_> as IntoIterator>::IntoIter`
340-
- `ops::range::IterRangeInclusive` will be `<ops::range::RangeInclusive<_> as IntoIterator>::IntoIter`
339+
- `std::range::IterRange` will be `<range::Range<_> as IntoIterator>::IntoIter`
340+
- `std::range::IterRangeFrom` will be `<range::RangeFrom<_> as IntoIterator>::IntoIter`
341+
- `std::range::IterRangeInclusive` will be `<range::RangeInclusive<_> as IntoIterator>::IntoIter`
341342
342343
These iterator types will implement the same iterator traits (`DoubleEndedIterator`, `FusedIterator`, etc) as the legacy range types, with the following exceptions:
343-
- `ops::range::IterRange` will not implement `ExactSizeIterator` for `u32` or `i32`
344-
- `ops::range::IterRangeInclusive` will not implement `ExactSizeIterator` for `u16` or `i16`
344+
- `std::range::IterRange` will not implement `ExactSizeIterator` for `u32` or `i32`
345+
- `std::range::IterRangeInclusive` will not implement `ExactSizeIterator` for `u16` or `i16`
345346
346347
Those `ExactSizeIterator` impls on the legacy range types are [known to be incorrect](https://github.com/rust-lang/rust/blob/495203bf61efabecc2c460be38e1eb0f9952601b/library/core/src/iter/range.rs#L903-L936).
347348
@@ -362,7 +363,7 @@ impl<Idx> IterRangeInclusive<Idx> {
362363
363364
## Changed structure and API
364365

365-
`ops::range::Range` and `ops::range::RangeFrom` will have identical structure to the existing types, with public fields for the bounds. However, `ops::range::RangeInclusive` will be changed:
366+
`std::range::Range` and `std::range::RangeFrom` will have identical structure to the existing types, with public fields for the bounds. However, `std::range::RangeInclusive` will be changed:
366367
- `start` and `end` will be changed to public fields
367368
- `exhausted` field will be removed entirely
368369

@@ -543,7 +544,7 @@ We leave the following items to be decided by the **libs-api** team after this p
543544

544545
- The set of inherent methods copied from `Iterator` present on the new range types
545546
- The exact module paths and type names
546-
+ `std::ops::range::` is long and heavily nested, perhaps `std::range::` would be better?
547+
+ Should the new types live at `std::ops::range::` instead?
547548
+ `IterRange`, `IterRangeInclusive` or just `Iter`, `IterInclusive`?
548549
- Should other range-related items (like `RangeBounds`) also be moved under the `range` module?
549550
- Should `RangeFrom` even implement `IntoIterator`, or should it require an explicit `.iter()` call? Using it as an iterator [can be a footgun](https://github.com/rust-lang/libs-team/issues/304), usually people want `start..=MAX` instead. Also, it is inconsistent with `RangeTo`, which doesn't implement `IntoIterator` either.

0 commit comments

Comments
 (0)