From c06bda67dfc1c3f7f6b38c5228f4496445e317ef Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Fri, 17 Apr 2026 20:23:19 +0100 Subject: [PATCH] Add a new type parameter to new `Range` types --- library/core/src/ops/range.rs | 32 ++-- library/core/src/range.rs | 168 +++++++++--------- .../crates/hir-ty/src/infer/expr.rs | 17 +- .../crates/test-utils/src/minicore.rs | 12 +- 4 files changed, 127 insertions(+), 102 deletions(-) diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index c15c8f20c16be..6962265c06886 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -817,7 +817,11 @@ impl Bound<&T> { #[stable(feature = "collections_range", since = "1.28.0")] #[rustc_diagnostic_item = "RangeBounds"] #[rustc_const_unstable(feature = "const_range", issue = "none")] -pub const trait RangeBounds { +pub const trait RangeBounds< + Start: ?Sized, + #[unstable(feature = "new_range_end_bound", issue = "155456")] End: ?Sized = Start, +> +{ /// Start index bound. /// /// Returns the start value as a `Bound`. @@ -832,7 +836,7 @@ pub const trait RangeBounds { /// assert_eq!((3..10).start_bound(), Included(&3)); /// ``` #[stable(feature = "collections_range", since = "1.28.0")] - fn start_bound(&self) -> Bound<&T>; + fn start_bound(&self) -> Bound<&Start>; /// End index bound. /// @@ -848,7 +852,7 @@ pub const trait RangeBounds { /// assert_eq!((3..10).end_bound(), Excluded(&10)); /// ``` #[stable(feature = "collections_range", since = "1.28.0")] - fn end_bound(&self) -> Bound<&T>; + fn end_bound(&self) -> Bound<&End>; /// Returns `true` if `item` is contained in the range. /// @@ -867,8 +871,9 @@ pub const trait RangeBounds { #[stable(feature = "range_contains", since = "1.35.0")] fn contains(&self, item: &U) -> bool where - T: [const] PartialOrd, - U: ?Sized + [const] PartialOrd, + Start: [const] PartialOrd, + End: [const] PartialOrd, + U: ?Sized + [const] PartialOrd + [const] PartialOrd, { (match self.start_bound() { Included(start) => start <= item, @@ -935,7 +940,7 @@ pub const trait RangeBounds { #[unstable(feature = "range_bounds_is_empty", issue = "137300")] fn is_empty(&self) -> bool where - T: [const] PartialOrd, + Start: [const] PartialOrd, { !match (self.start_bound(), self.end_bound()) { (Unbounded, _) | (_, Unbounded) => true, @@ -954,7 +959,11 @@ pub const trait RangeBounds { /// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`. #[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -pub const trait IntoBounds: [const] RangeBounds { +pub const trait IntoBounds< + Start, + #[unstable(feature = "new_range_end_bound", issue = "155456")] End = Start, +>: [const] RangeBounds +{ /// Convert this range into the start and end bounds. /// Returns `(start_bound, end_bound)`. /// @@ -968,7 +977,7 @@ pub const trait IntoBounds: [const] RangeBounds { /// assert_eq!((0..5).into_bounds(), (Included(0), Excluded(5))); /// assert_eq!((..=7).into_bounds(), (Unbounded, Included(7))); /// ``` - fn into_bounds(self) -> (Bound, Bound); + fn into_bounds(self) -> (Bound, Bound); /// Compute the intersection of `self` and `other`. /// @@ -997,11 +1006,12 @@ pub const trait IntoBounds: [const] RangeBounds { /// assert!(!(-12..387).intersect(0..256).is_empty()); /// assert!((1..5).intersect(6..).is_empty()); /// ``` - fn intersect(self, other: R) -> (Bound, Bound) + fn intersect(self, other: R) -> (Bound, Bound) where Self: Sized, - T: [const] Ord + [const] Destruct, - R: Sized + [const] IntoBounds, + Start: [const] Ord + [const] Destruct, + End: [const] Ord + [const] Destruct, + R: Sized + [const] IntoBounds, { let (self_start, self_end) = IntoBounds::into_bounds(self); let (other_start, other_end) = IntoBounds::into_bounds(other); diff --git a/library/core/src/range.rs b/library/core/src/range.rs index ade9a35b0ab33..8b957a031973b 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -69,17 +69,18 @@ use crate::ops::{IntoBounds, OneSidedRange, OneSidedRangeBound, RangeBounds}; #[derive(Copy, Hash)] #[derive_const(Clone, Default, PartialEq, Eq)] #[stable(feature = "new_range_api", since = "1.96.0")] -pub struct Range { +pub struct Range +{ /// The lower bound of the range (inclusive). #[stable(feature = "new_range_api", since = "1.96.0")] - pub start: Idx, + pub start: Start, /// The upper bound of the range (exclusive). #[stable(feature = "new_range_api", since = "1.96.0")] - pub end: Idx, + pub end: End, } #[stable(feature = "new_range_api", since = "1.96.0")] -impl fmt::Debug for Range { +impl fmt::Debug for Range { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.start.fmt(fmt)?; write!(fmt, "..")?; @@ -88,7 +89,7 @@ impl fmt::Debug for Range { } } -impl Range { +impl Range { /// Creates an iterator over the elements within this range. /// /// Shorthand for `.clone().into_iter()` @@ -105,12 +106,12 @@ impl Range { /// ``` #[stable(feature = "new_range_api", since = "1.96.0")] #[inline] - pub fn iter(&self) -> RangeIter { + pub fn iter(&self) -> RangeIter { self.clone().into_iter() } } -impl> Range { +impl Range { /// Returns `true` if `item` is contained in the range. /// /// # Examples @@ -136,10 +137,11 @@ impl> Range { #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn contains(&self, item: &U) -> bool where - Idx: [const] PartialOrd, - U: ?Sized + [const] PartialOrd, + Start: [const] PartialOrd, + End: [const] PartialOrd, + U: ?Sized + [const] PartialOrd + [const] PartialOrd, { - >::contains(self, item) + >::contains(self, item) } /// Returns `true` if the range contains no items. @@ -168,7 +170,7 @@ impl> Range { #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn is_empty(&self) -> bool where - Idx: [const] PartialOrd, + Start: [const] PartialOrd, { !(self.start < self.end) } @@ -176,11 +178,11 @@ impl> Range { #[stable(feature = "new_range_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const RangeBounds for Range { - fn start_bound(&self) -> Bound<&T> { +impl const RangeBounds for Range { + fn start_bound(&self) -> Bound<&Start> { Included(&self.start) } - fn end_bound(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&End> { Excluded(&self.end) } } @@ -193,26 +195,26 @@ impl const RangeBounds for Range { /// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`. #[stable(feature = "new_range_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const RangeBounds for Range<&T> { - fn start_bound(&self) -> Bound<&T> { +impl const RangeBounds for Range<&Start, &End> { + fn start_bound(&self) -> Bound<&Start> { Included(self.start) } - fn end_bound(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&End> { Excluded(self.end) } } #[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const IntoBounds for Range { - fn into_bounds(self) -> (Bound, Bound) { +impl const IntoBounds for Range { + fn into_bounds(self) -> (Bound, Bound) { (Included(self.start), Excluded(self.end)) } } #[stable(feature = "new_range_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] -impl const From> for legacy::Range { +impl const From> for legacy::Range { #[inline] fn from(value: Range) -> Self { Self { start: value.start, end: value.end } @@ -220,7 +222,7 @@ impl const From> for legacy::Range { } #[stable(feature = "new_range_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] -impl const From> for Range { +impl const From> for Range { #[inline] fn from(value: legacy::Range) -> Self { Self { start: value.start, end: value.end } @@ -248,17 +250,20 @@ impl const From> for Range { #[lang = "RangeInclusiveCopy"] #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] -pub struct RangeInclusive { +pub struct RangeInclusive< + Start, + #[unstable(feature = "new_range_end_bound", issue = "155456")] End = Start, +> { /// The lower bound of the range (inclusive). #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] - pub start: Idx, + pub start: Start, /// The upper bound of the range (inclusive). #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] - pub last: Idx, + pub last: End, } #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] -impl fmt::Debug for RangeInclusive { +impl fmt::Debug for RangeInclusive { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.start.fmt(fmt)?; write!(fmt, "..=")?; @@ -267,7 +272,7 @@ impl fmt::Debug for RangeInclusive { } } -impl> RangeInclusive { +impl RangeInclusive { /// Returns `true` if `item` is contained in the range. /// /// # Examples @@ -294,10 +299,11 @@ impl> RangeInclusive { #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn contains(&self, item: &U) -> bool where - Idx: [const] PartialOrd, - U: ?Sized + [const] PartialOrd, + Start: [const] PartialOrd, + End: [const] PartialOrd, + U: ?Sized + [const] PartialOrd + [const] PartialOrd, { - >::contains(self, item) + >::contains(self, item) } /// Returns `true` if the range contains no items. @@ -326,13 +332,13 @@ impl> RangeInclusive { #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn is_empty(&self) -> bool where - Idx: [const] PartialOrd, + Start: [const] PartialOrd, { !(self.start <= self.last) } } -impl RangeInclusive { +impl RangeInclusive { /// Creates an iterator over the elements within this range. /// /// Shorthand for `.clone().into_iter()` @@ -349,18 +355,18 @@ impl RangeInclusive { /// ``` #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] #[inline] - pub fn iter(&self) -> RangeInclusiveIter { + pub fn iter(&self) -> RangeInclusiveIter { self.clone().into_iter() } } #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const RangeBounds for RangeInclusive { - fn start_bound(&self) -> Bound<&T> { +impl const RangeBounds for RangeInclusive { + fn start_bound(&self) -> Bound<&Start> { Included(&self.start) } - fn end_bound(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&End> { Included(&self.last) } } @@ -373,11 +379,11 @@ impl const RangeBounds for RangeInclusive { /// i.e. replace `start..=end` with `(Bound::Included(start), Bound::Included(end))`. #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const RangeBounds for RangeInclusive<&T> { - fn start_bound(&self) -> Bound<&T> { +impl const RangeBounds for RangeInclusive<&Start, &End> { + fn start_bound(&self) -> Bound<&Start> { Included(self.start) } - fn end_bound(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&End> { Included(self.last) } } @@ -385,8 +391,8 @@ impl const RangeBounds for RangeInclusive<&T> { // #[stable(feature = "new_range_inclusive_api", since = "1.95.0")] #[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const IntoBounds for RangeInclusive { - fn into_bounds(self) -> (Bound, Bound) { +impl const IntoBounds for RangeInclusive { + fn into_bounds(self) -> (Bound, Bound) { (Included(self.start), Included(self.last)) } } @@ -445,14 +451,14 @@ impl const From> for RangeInclusive { #[derive(Copy, Hash)] #[derive_const(Clone, PartialEq, Eq)] #[stable(feature = "new_range_from_api", since = "1.96.0")] -pub struct RangeFrom { +pub struct RangeFrom { /// The lower bound of the range (inclusive). #[stable(feature = "new_range_from_api", since = "1.96.0")] - pub start: Idx, + pub start: Start, } #[stable(feature = "new_range_from_api", since = "1.96.0")] -impl fmt::Debug for RangeFrom { +impl fmt::Debug for RangeFrom { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.start.fmt(fmt)?; write!(fmt, "..")?; @@ -460,7 +466,7 @@ impl fmt::Debug for RangeFrom { } } -impl RangeFrom { +impl RangeFrom { /// Creates an iterator over the elements within this range. /// /// Shorthand for `.clone().into_iter()` @@ -477,12 +483,12 @@ impl RangeFrom { /// ``` #[stable(feature = "new_range_from_api", since = "1.96.0")] #[inline] - pub fn iter(&self) -> RangeFromIter { + pub fn iter(&self) -> RangeFromIter { self.clone().into_iter() } } -impl> RangeFrom { +impl RangeFrom { /// Returns `true` if `item` is contained in the range. /// /// # Examples @@ -503,20 +509,20 @@ impl> RangeFrom { #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn contains(&self, item: &U) -> bool where - Idx: [const] PartialOrd, - U: ?Sized + [const] PartialOrd, + Start: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { - >::contains(self, item) + >::contains(self, item) } } #[stable(feature = "new_range_from_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const RangeBounds for RangeFrom { - fn start_bound(&self) -> Bound<&T> { +impl const RangeBounds for RangeFrom { + fn start_bound(&self) -> Bound<&Start> { Included(&self.start) } - fn end_bound(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&End> { Unbounded } } @@ -529,11 +535,11 @@ impl const RangeBounds for RangeFrom { /// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`. #[stable(feature = "new_range_from_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const RangeBounds for RangeFrom<&T> { - fn start_bound(&self) -> Bound<&T> { +impl const RangeBounds for RangeFrom<&Start> { + fn start_bound(&self) -> Bound<&Start> { Included(self.start) } - fn end_bound(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&End> { Unbounded } } @@ -548,28 +554,28 @@ impl const IntoBounds for RangeFrom { #[unstable(feature = "one_sided_range", issue = "69780")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const OneSidedRange for RangeFrom +impl const OneSidedRange for RangeFrom where - Self: RangeBounds, + Self: RangeBounds, { - fn bound(self) -> (OneSidedRangeBound, T) { + fn bound(self) -> (OneSidedRangeBound, Start) { (OneSidedRangeBound::StartInclusive, self.start) } } #[stable(feature = "new_range_from_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] -impl const From> for legacy::RangeFrom { +impl const From> for legacy::RangeFrom { #[inline] - fn from(value: RangeFrom) -> Self { + fn from(value: RangeFrom) -> Self { Self { start: value.start } } } #[stable(feature = "new_range_from_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] -impl const From> for RangeFrom { +impl const From> for RangeFrom { #[inline] - fn from(value: legacy::RangeFrom) -> Self { + fn from(value: legacy::RangeFrom) -> Self { Self { start: value.start } } } @@ -620,14 +626,14 @@ impl const From> for RangeFrom { #[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")] -pub struct RangeToInclusive { +pub struct RangeToInclusive { /// The upper bound of the range (inclusive) #[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")] - pub last: Idx, + pub last: End, } #[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")] -impl fmt::Debug for RangeToInclusive { +impl fmt::Debug for RangeToInclusive { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "..=")?; self.last.fmt(fmt)?; @@ -635,7 +641,7 @@ impl fmt::Debug for RangeToInclusive { } } -impl> RangeToInclusive { +impl RangeToInclusive { /// Returns `true` if `item` is contained in the range. /// /// # Examples @@ -654,10 +660,10 @@ impl> RangeToInclusive { #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn contains(&self, item: &U) -> bool where - Idx: [const] PartialOrd, - U: ?Sized + [const] PartialOrd, + End: [const] PartialOrd, + U: ?Sized + [const] PartialOrd, { - >::contains(self, item) + >::contains(self, item) } } @@ -674,46 +680,46 @@ impl From> for legacy::RangeToInclusive { } } -// RangeToInclusive cannot impl From> +// RangeToInclusive cannot impl From> // because underflow would be possible with (..0).into() #[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const RangeBounds for RangeToInclusive { - fn start_bound(&self) -> Bound<&T> { +impl const RangeBounds for RangeToInclusive { + fn start_bound(&self) -> Bound<&Start> { Unbounded } - fn end_bound(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&End> { Included(&self.last) } } #[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const RangeBounds for RangeToInclusive<&T> { - fn start_bound(&self) -> Bound<&T> { +impl const RangeBounds for RangeToInclusive<&End> { + fn start_bound(&self) -> Bound<&Start> { Unbounded } - fn end_bound(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&End> { Included(self.last) } } #[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const IntoBounds for RangeToInclusive { - fn into_bounds(self) -> (Bound, Bound) { +impl const IntoBounds for RangeToInclusive { + fn into_bounds(self) -> (Bound, Bound) { (Unbounded, Included(self.last)) } } #[unstable(feature = "one_sided_range", issue = "69780")] #[rustc_const_unstable(feature = "const_range", issue = "none")] -impl const OneSidedRange for RangeToInclusive +impl const OneSidedRange for RangeToInclusive where - Self: RangeBounds, + Self: RangeBounds, { - fn bound(self) -> (OneSidedRangeBound, T) { + fn bound(self) -> (OneSidedRangeBound, End) { (OneSidedRangeBound::EndInclusive, self.last) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index ee34a30ebaaf0..120c4a1e02e89 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -784,6 +784,13 @@ impl<'db> InferenceContext<'_, 'db> { GenericArgs::new_from_slice(&[GenericArg::from(ty)]), ) }; + let two_arg_adt = |adt, ty: Ty<'db>, ty2: Ty<'db>| { + Ty::new_adt( + self.interner(), + adt, + GenericArgs::new_from_slice(&[GenericArg::from(ty), GenericArg::from(ty2)]), + ) + }; match (range_type, lhs_ty, rhs_ty) { (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { Some(adt) => { @@ -801,13 +808,15 @@ impl<'db> InferenceContext<'_, 'db> { None => self.err_ty(), } } - (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { - Some(adt) => single_arg_adt(adt, ty), + (RangeOp::Exclusive, Some(ty), Some(ty2)) => match self.resolve_range() { + Some(adt) if self.has_new_range_feature() => two_arg_adt(adt, ty, ty2), + Some(adt) => single_arg_adt(adt, ty2), None => self.err_ty(), }, - (RangeOp::Inclusive, Some(_), Some(ty)) => { + (RangeOp::Inclusive, Some(ty), Some(ty2)) => { match self.resolve_range_inclusive() { - Some(adt) => single_arg_adt(adt, ty), + Some(adt) if self.has_new_range_feature() => two_arg_adt(adt, ty, ty2), + Some(adt) => single_arg_adt(adt, ty2), None => self.err_ty(), } } diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 86fb08073253c..01de6d0113723 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -1156,9 +1156,9 @@ pub mod ops { // region:new_range pub mod range { #[lang = "RangeCopy"] - pub struct Range { - pub start: Idx, - pub end: Idx, + pub struct Range { + pub start: Start, + pub end: End, } #[lang = "RangeFromCopy"] @@ -1167,9 +1167,9 @@ pub mod range { } #[lang = "RangeInclusiveCopy"] - pub struct RangeInclusive { - pub start: Idx, - pub end: Idx, + pub struct RangeInclusive { + pub start: Start, + pub end: End, } #[lang = "RangeToInclusiveCopy"]