stabilize new Range type and iterator

stabilizes `core::range::Range`
stabilizes `core::range::RangeIter`
stabilizes `std::range` which was missed in prior PRs

Updates docs to reflect stabilization (removed "experimental")

`RangeIter::remainder` is excluded from stabilization
This commit is contained in:
Peter Jaszkowiak
2026-03-03 18:49:37 -07:00
parent cf7da0b727
commit 620e92f016
13 changed files with 76 additions and 83 deletions
+5 -1
View File
@@ -2,9 +2,13 @@
#![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))]
#![cfg_attr(all(feature = "nightly", test), feature(test))]
#![cfg_attr(feature = "nightly", feature(extend_one, step_trait))]
#![cfg_attr(feature = "nightly", feature(new_range_api))]
// tidy-alphabetical-end
// FIXME(#125687): new_range_api recently stabilized
// Remove this when it hits stable. cfg(bootstrap)
#![allow(stable_features)]
#![cfg_attr(feature = "nightly", feature(new_range_api))]
pub mod bit_set;
#[cfg(feature = "nightly")]
pub mod interval;
+24 -32
View File
@@ -1,19 +1,18 @@
//! # Experimental replacement range types
//! # Replacement range types
//!
//! The types within this module are meant to replace the existing
//! `Range`, `RangeInclusive`, and `RangeFrom` types in a future edition.
//! The types within this module are meant to replace the legacy `Range`,
//! `RangeInclusive`, `RangeToInclusive` and `RangeFrom` types in a future edition.
//!
//! ```
//! #![feature(new_range_api)]
//! use core::range::{Range, RangeFrom, RangeInclusive};
//! use core::range::{Range, RangeFrom, RangeInclusive, RangeToInclusive};
//!
//! let arr = [0, 1, 2, 3, 4];
//! assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]);
//! assert_eq!(arr[ .. 3 ], [0, 1, 2 ]);
//! assert_eq!(arr[ ..=3 ], [0, 1, 2, 3 ]);
//! assert_eq!(arr[ RangeFrom::from(1.. )], [ 1, 2, 3, 4]);
//! assert_eq!(arr[ Range::from(1..3 )], [ 1, 2 ]);
//! assert_eq!(arr[RangeInclusive::from(1..=3)], [ 1, 2, 3 ]);
//! assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]);
//! assert_eq!(arr[ .. 3 ], [0, 1, 2 ]);
//! assert_eq!(arr[RangeToInclusive::from( ..=3)], [0, 1, 2, 3 ]);
//! assert_eq!(arr[ RangeFrom::from(1.. )], [ 1, 2, 3, 4]);
//! assert_eq!(arr[ Range::from(1..3 )], [ 1, 2 ]);
//! assert_eq!(arr[ RangeInclusive::from(1..=3)], [ 1, 2, 3 ]);
//! ```
use crate::fmt;
@@ -21,7 +20,7 @@
mod iter;
#[unstable(feature = "new_range_api", issue = "125687")]
#[unstable(feature = "new_range_api_legacy", issue = "125687")]
pub mod legacy;
#[doc(inline)]
@@ -31,7 +30,7 @@
#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
pub use iter::RangeInclusiveIter;
#[doc(inline)]
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
pub use iter::RangeIter;
// FIXME(#125687): re-exports temporarily removed
@@ -57,7 +56,6 @@
/// # Examples
///
/// ```
/// #![feature(new_range_api)]
/// use core::range::Range;
///
/// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 });
@@ -66,17 +64,17 @@
#[lang = "RangeCopy"]
#[derive(Copy, Hash)]
#[derive_const(Clone, Default, PartialEq, Eq)]
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
pub struct Range<Idx> {
/// The lower bound of the range (inclusive).
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
pub start: Idx,
/// The upper bound of the range (exclusive).
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
pub end: Idx,
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.start.fmt(fmt)?;
@@ -94,7 +92,6 @@ impl<Idx: Step> Range<Idx> {
/// # Examples
///
/// ```
/// #![feature(new_range_api)]
/// use core::range::Range;
///
/// let mut i = Range::from(3..9).iter().map(|n| n*n);
@@ -102,7 +99,7 @@ impl<Idx: Step> Range<Idx> {
/// assert_eq!(i.next(), Some(16));
/// assert_eq!(i.next(), Some(25));
/// ```
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub fn iter(&self) -> RangeIter<Idx> {
self.clone().into_iter()
@@ -115,7 +112,6 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
/// # Examples
///
/// ```
/// #![feature(new_range_api)]
/// use core::range::Range;
///
/// assert!(!Range::from(3..5).contains(&2));
@@ -132,7 +128,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
/// assert!(!Range::from(f32::NAN..1.0).contains(&0.5));
/// ```
#[inline]
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
pub const fn contains<U>(&self, item: &U) -> bool
where
@@ -147,7 +143,6 @@ pub const fn contains<U>(&self, item: &U) -> bool
/// # Examples
///
/// ```
/// #![feature(new_range_api)]
/// use core::range::Range;
///
/// assert!(!Range::from(3..5).is_empty());
@@ -158,7 +153,6 @@ pub const fn contains<U>(&self, item: &U) -> bool
/// The range is empty if either side is incomparable:
///
/// ```
/// #![feature(new_range_api)]
/// use core::range::Range;
///
/// assert!(!Range::from(3.0..5.0).is_empty());
@@ -166,7 +160,7 @@ pub const fn contains<U>(&self, item: &U) -> bool
/// assert!( Range::from(f32::NAN..5.0).is_empty());
/// ```
#[inline]
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
pub const fn is_empty(&self) -> bool
where
@@ -176,7 +170,7 @@ pub const fn is_empty(&self) -> bool
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
impl<T> const RangeBounds<T> for Range<T> {
fn start_bound(&self) -> Bound<&T> {
@@ -193,7 +187,7 @@ fn end_bound(&self) -> Bound<&T> {
/// If you need to use this implementation where `T` is unsized,
/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
/// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`.
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
impl<T> const RangeBounds<T> for Range<&T> {
fn start_bound(&self) -> Bound<&T> {
@@ -204,8 +198,7 @@ fn end_bound(&self) -> Bound<&T> {
}
}
// #[unstable(feature = "range_into_bounds", issue = "136903")]
#[unstable(feature = "new_range_api", issue = "125687")]
#[unstable(feature = "range_into_bounds", issue = "136903")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
impl<T> const IntoBounds<T> for Range<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
@@ -213,7 +206,7 @@ fn into_bounds(self) -> (Bound<T>, Bound<T>) {
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl<T> const From<Range<T>> for legacy::Range<T> {
#[inline]
@@ -221,8 +214,7 @@ fn from(value: Range<T>) -> Self {
Self { start: value.start, end: value.end }
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl<T> const From<legacy::Range<T>> for Range<T> {
#[inline]
+6 -7
View File
@@ -6,7 +6,7 @@
use crate::{intrinsics, mem};
/// By-value [`Range`] iterator.
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[derive(Debug, Clone)]
pub struct RangeIter<A>(legacy::Range<A>);
@@ -17,7 +17,6 @@ impl<A> RangeIter<A> {
/// # Examples
///
/// ```
/// #![feature(new_range_api)]
/// #![feature(new_range_remainder)]
///
/// let range = core::range::Range::from(3..11);
@@ -65,7 +64,7 @@ unsafe impl TrustedRandomAccessNoCoerce for RangeIter<$t> {
u64 i64
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
impl<A: Step> Iterator for RangeIter<A> {
type Item = A;
@@ -133,7 +132,7 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
impl<A: Step> DoubleEndedIterator for RangeIter<A> {
#[inline]
fn next_back(&mut self) -> Option<A> {
@@ -154,10 +153,10 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A: TrustedStep> TrustedLen for RangeIter<A> {}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
impl<A: Step> FusedIterator for RangeIter<A> {}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
impl<A: Step> IntoIterator for Range<A> {
type Item = A;
type IntoIter = RangeIter<A>;
@@ -300,7 +299,7 @@ fn into_iter(self) -> Self::IntoIter {
// since e.g. `(0..=u64::MAX).len()` would be `u64::MAX + 1`.
macro_rules! range_exact_iter_impl {
($($t:ty)*) => ($(
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
impl ExactSizeIterator for RangeIter<$t> { }
)*)
}
+2 -2
View File
@@ -125,7 +125,7 @@ impl Sealed for ops::RangeToInclusive<usize> {}
#[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")]
impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
impl Sealed for range::Range<usize> {}
#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
impl Sealed for range::RangeInclusive<usize> {}
@@ -458,7 +458,7 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
unsafe impl<T> const SliceIndex<[T]> for range::Range<usize> {
type Output = [T];
+1 -1
View File
@@ -258,7 +258,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_index", issue = "143775")]
unsafe impl const SliceIndex<str> for range::Range<usize> {
type Output = str;
-1
View File
@@ -85,7 +85,6 @@
#![feature(maybe_uninit_uninit_array_transpose)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(new_range_api)]
#![feature(next_index)]
#![feature(non_exhaustive_omitted_patterns_lint)]
#![feature(nonzero_from_str_radix)]
+1 -1
View File
@@ -537,7 +537,7 @@
pub use core::pin;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::ptr;
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_api", since = "CURRENT_RUSTC_VERSION")]
pub use core::range;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::result;
@@ -1,5 +1,3 @@
#![feature(new_range_api)]
fn main() {
let a: core::range::RangeFrom<u8> = 1..;
//~^ ERROR mismatched types
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/feature-gate-new_range.rs:4:41
--> $DIR/feature-gate-new_range.rs:2:41
|
LL | let a: core::range::RangeFrom<u8> = 1..;
| -------------------------- ^^^ expected `RangeFrom<u8>`, found `RangeFrom<{integer}>`
@@ -14,7 +14,7 @@ LL | let a: core::range::RangeFrom<u8> = (1..).into();
| + ++++++++
error[E0308]: mismatched types
--> $DIR/feature-gate-new_range.rs:6:37
--> $DIR/feature-gate-new_range.rs:4:37
|
LL | let b: core::range::Range<u8> = 2..3;
| ---------------------- ^^^^ expected `Range<u8>`, found `Range<{integer}>`
@@ -29,7 +29,7 @@ LL | let b: core::range::Range<u8> = (2..3).into();
| + ++++++++
error[E0308]: mismatched types
--> $DIR/feature-gate-new_range.rs:8:46
--> $DIR/feature-gate-new_range.rs:6:46
|
LL | let c: core::range::RangeInclusive<u8> = 4..=5;
| ------------------------------- ^^^^^ expected `RangeInclusive<u8>`, found `RangeInclusive<{integer}>`
+1 -1
View File
@@ -1,6 +1,6 @@
//@ check-pass
#![feature(new_range_api)]
#![feature(new_range_api_legacy)]
fn main() {
// Unchanged
-1
View File
@@ -1,6 +1,5 @@
//@ check-pass
#![feature(new_range_api)]
#![feature(new_range)]
fn main() {
+17 -5
View File
@@ -6,6 +6,7 @@
RangeToInclusive,
RangeFrom,
RangeFromIter,
Range,
};
fn range_inclusive(mut r: RangeInclusive<usize>) {
@@ -43,13 +44,24 @@ fn range_from(mut r: RangeFrom<usize>) {
i.remainder(); //~ ERROR unstable
}
fn range(mut r: Range<usize>) {
&[1, 2, 3][r];
r.start;
r.end;
r.contains(&5);
r.is_empty();
r.iter();
let mut i = r.into_iter();
i.next();
// Left unstable
i.remainder(); //~ ERROR unstable
}
// Unstable module
use std::range::legacy; //~ ERROR unstable
// Unstable types
use std::range::Range; //~ ERROR unstable
use std::range::RangeIter; //~ ERROR unstable
fn main() {}
+16 -26
View File
@@ -1,35 +1,15 @@
error[E0658]: use of unstable library feature `new_range_api`
--> $DIR/new_range_stability.rs:48:5
error[E0658]: use of unstable library feature `new_range_api_legacy`
--> $DIR/new_range_stability.rs:65:5
|
LL | use std::range::legacy;
| ^^^^^^^^^^^^^^^^^^
|
= note: see issue #125687 <https://github.com/rust-lang/rust/issues/125687> for more information
= help: add `#![feature(new_range_api)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable library feature `new_range_api`
--> $DIR/new_range_stability.rs:52:5
|
LL | use std::range::Range;
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #125687 <https://github.com/rust-lang/rust/issues/125687> for more information
= help: add `#![feature(new_range_api)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable library feature `new_range_api`
--> $DIR/new_range_stability.rs:53:5
|
LL | use std::range::RangeIter;
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #125687 <https://github.com/rust-lang/rust/issues/125687> for more information
= help: add `#![feature(new_range_api)]` to the crate attributes to enable
= help: add `#![feature(new_range_api_legacy)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable library feature `new_range_remainder`
--> $DIR/new_range_stability.rs:22:7
--> $DIR/new_range_stability.rs:23:7
|
LL | i.remainder();
| ^^^^^^^^^
@@ -39,7 +19,7 @@ LL | i.remainder();
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable library feature `new_range_remainder`
--> $DIR/new_range_stability.rs:43:7
--> $DIR/new_range_stability.rs:44:7
|
LL | i.remainder();
| ^^^^^^^^^
@@ -48,6 +28,16 @@ LL | i.remainder();
= help: add `#![feature(new_range_remainder)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 5 previous errors
error[E0658]: use of unstable library feature `new_range_remainder`
--> $DIR/new_range_stability.rs:60:7
|
LL | i.remainder();
| ^^^^^^^^^
|
= note: see issue #154458 <https://github.com/rust-lang/rust/issues/154458> for more information
= help: add `#![feature(new_range_remainder)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0658`.