-
Notifications
You must be signed in to change notification settings - Fork 13.3k
RangeInclusive cannot be used in const generics. #70155
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Labels
A-const-generics
Area: const generics (parameters and arguments)
C-feature-request
Category: A feature request, i.e: not implemented / a PR.
F-const_generics
`#![feature(const_generics)]`
T-libs-api
Relevant to the library API team, which will review and decide on the PR/issue.
Comments
Dylan-DPC-zz
pushed a commit
to Dylan-DPC-zz/rust
that referenced
this issue
Mar 20, 2020
…ramertj Derive PartialEq, Eq and Hash for RangeInclusive The manual implementation of `PartialEq`, `Eq` and `Hash` for `RangeInclusive` was functionally equivalent to a derived implementation. This change removes the manual implementation and adds the respective derives. A side effect of this change is that the derives also add implementations for `StructuralPartialEq` and `StructuralEq`, which enables `RangeInclusive` to be used in const generics, closing rust-lang#70155. This change is enabled by rust-lang#68835, which changed the field `is_empty: Option<bool>` to `exhausted: bool` removing the need for *semantic* equality instead of *structural* equality. ## PartialEq original [`PartialEq`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L353-L359) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> { #[inline] fn eq(&self, other: &Self) -> bool { self.start == other.start && self.end == other.end && self.exhausted == other.exhausted } } ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx> crate::marker::StructuralPartialEq for RangeInclusive<Idx> {} #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::cmp::PartialEq> crate::cmp::PartialEq for RangeInclusive<Idx> { #[inline] fn eq(&self, other: &RangeInclusive<Idx>) -> bool { match *other { RangeInclusive { start: ref __self_1_0,end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => { (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1) && (*__self_0_2) == (*__self_1_2) } }, } } #[inline] fn ne(&self, other: &RangeInclusive<Idx>) -> bool { match *other { RangeInclusive { start: ref __self_1_0, end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1exhausted: ref __self_0_2 } => { (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1) || (*__self_0_2) != (*__self_1_2) } }, } } } ``` These implementations both test for *structural* equality, with the same order of field comparisons, and the bound `Idx: PartialEq` is the same. ## Eq original [`Eq`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L361-L362) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: Eq> Eq for RangeInclusive<Idx> {} ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx> crate::marker::StructuralEq for RangeInclusive<Idx> {} #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::cmp::Eq> crate::cmp::Eq for RangeInclusive<Idx> { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { let _: crate::cmp::AssertParamIsEq<Idx>; let _: crate::cmp::AssertParamIsEq<Idx>; let _: crate::cmp::AssertParamIsEq<bool>; } } } ``` These implementations are equivalent since `Eq` is just a marker trait and the bound `Idx: Eq` is the same. ## Hash original [`Hash`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L364-L371) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: Hash> Hash for RangeInclusive<Idx> { fn hash<H: Hasher>(&self, state: &mut H) { self.start.hash(state); self.end.hash(state); self.exhausted.hash(state); } } ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::hash::Hash> crate::hash::Hash for RangeInclusive<Idx> { fn hash<__H: crate::hash::Hasher>(&self, state: &mut __H) -> () { match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => { crate::hash::Hash::hash(&(*__self_0_0), state); crate::hash::Hash::hash(&(*__self_0_1), state); crate::hash::Hash::hash(&(*__self_0_2), state) } } } } ``` These implementations are functionally equivalent, with the same order of field hashing, and the bound `Idx: Hash` is the same.
Dylan-DPC-zz
pushed a commit
to Dylan-DPC-zz/rust
that referenced
this issue
Mar 21, 2020
…ramertj Derive PartialEq, Eq and Hash for RangeInclusive The manual implementation of `PartialEq`, `Eq` and `Hash` for `RangeInclusive` was functionally equivalent to a derived implementation. This change removes the manual implementation and adds the respective derives. A side effect of this change is that the derives also add implementations for `StructuralPartialEq` and `StructuralEq`, which enables `RangeInclusive` to be used in const generics, closing rust-lang#70155. This change is enabled by rust-lang#68835, which changed the field `is_empty: Option<bool>` to `exhausted: bool` removing the need for *semantic* equality instead of *structural* equality. ## PartialEq original [`PartialEq`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L353-L359) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> { #[inline] fn eq(&self, other: &Self) -> bool { self.start == other.start && self.end == other.end && self.exhausted == other.exhausted } } ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx> crate::marker::StructuralPartialEq for RangeInclusive<Idx> {} #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::cmp::PartialEq> crate::cmp::PartialEq for RangeInclusive<Idx> { #[inline] fn eq(&self, other: &RangeInclusive<Idx>) -> bool { match *other { RangeInclusive { start: ref __self_1_0,end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => { (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1) && (*__self_0_2) == (*__self_1_2) } }, } } #[inline] fn ne(&self, other: &RangeInclusive<Idx>) -> bool { match *other { RangeInclusive { start: ref __self_1_0, end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1exhausted: ref __self_0_2 } => { (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1) || (*__self_0_2) != (*__self_1_2) } }, } } } ``` These implementations both test for *structural* equality, with the same order of field comparisons, and the bound `Idx: PartialEq` is the same. ## Eq original [`Eq`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L361-L362) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: Eq> Eq for RangeInclusive<Idx> {} ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx> crate::marker::StructuralEq for RangeInclusive<Idx> {} #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::cmp::Eq> crate::cmp::Eq for RangeInclusive<Idx> { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { let _: crate::cmp::AssertParamIsEq<Idx>; let _: crate::cmp::AssertParamIsEq<Idx>; let _: crate::cmp::AssertParamIsEq<bool>; } } } ``` These implementations are equivalent since `Eq` is just a marker trait and the bound `Idx: Eq` is the same. ## Hash original [`Hash`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L364-L371) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: Hash> Hash for RangeInclusive<Idx> { fn hash<H: Hasher>(&self, state: &mut H) { self.start.hash(state); self.end.hash(state); self.exhausted.hash(state); } } ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::hash::Hash> crate::hash::Hash for RangeInclusive<Idx> { fn hash<__H: crate::hash::Hasher>(&self, state: &mut __H) -> () { match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => { crate::hash::Hash::hash(&(*__self_0_0), state); crate::hash::Hash::hash(&(*__self_0_1), state); crate::hash::Hash::hash(&(*__self_0_2), state) } } } } ``` These implementations are functionally equivalent, with the same order of field hashing, and the bound `Idx: Hash` is the same.
Centril
added a commit
to Centril/rust
that referenced
this issue
Mar 21, 2020
…ramertj Derive PartialEq, Eq and Hash for RangeInclusive The manual implementation of `PartialEq`, `Eq` and `Hash` for `RangeInclusive` was functionally equivalent to a derived implementation. This change removes the manual implementation and adds the respective derives. A side effect of this change is that the derives also add implementations for `StructuralPartialEq` and `StructuralEq`, which enables `RangeInclusive` to be used in const generics, closing rust-lang#70155. This change is enabled by rust-lang#68835, which changed the field `is_empty: Option<bool>` to `exhausted: bool` removing the need for *semantic* equality instead of *structural* equality. ## PartialEq original [`PartialEq`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L353-L359) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> { #[inline] fn eq(&self, other: &Self) -> bool { self.start == other.start && self.end == other.end && self.exhausted == other.exhausted } } ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx> crate::marker::StructuralPartialEq for RangeInclusive<Idx> {} #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::cmp::PartialEq> crate::cmp::PartialEq for RangeInclusive<Idx> { #[inline] fn eq(&self, other: &RangeInclusive<Idx>) -> bool { match *other { RangeInclusive { start: ref __self_1_0,end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => { (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1) && (*__self_0_2) == (*__self_1_2) } }, } } #[inline] fn ne(&self, other: &RangeInclusive<Idx>) -> bool { match *other { RangeInclusive { start: ref __self_1_0, end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1exhausted: ref __self_0_2 } => { (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1) || (*__self_0_2) != (*__self_1_2) } }, } } } ``` These implementations both test for *structural* equality, with the same order of field comparisons, and the bound `Idx: PartialEq` is the same. ## Eq original [`Eq`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L361-L362) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: Eq> Eq for RangeInclusive<Idx> {} ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx> crate::marker::StructuralEq for RangeInclusive<Idx> {} #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::cmp::Eq> crate::cmp::Eq for RangeInclusive<Idx> { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { let _: crate::cmp::AssertParamIsEq<Idx>; let _: crate::cmp::AssertParamIsEq<Idx>; let _: crate::cmp::AssertParamIsEq<bool>; } } } ``` These implementations are equivalent since `Eq` is just a marker trait and the bound `Idx: Eq` is the same. ## Hash original [`Hash`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L364-L371) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: Hash> Hash for RangeInclusive<Idx> { fn hash<H: Hasher>(&self, state: &mut H) { self.start.hash(state); self.end.hash(state); self.exhausted.hash(state); } } ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::hash::Hash> crate::hash::Hash for RangeInclusive<Idx> { fn hash<__H: crate::hash::Hasher>(&self, state: &mut __H) -> () { match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => { crate::hash::Hash::hash(&(*__self_0_0), state); crate::hash::Hash::hash(&(*__self_0_1), state); crate::hash::Hash::hash(&(*__self_0_2), state) } } } } ``` These implementations are functionally equivalent, with the same order of field hashing, and the bound `Idx: Hash` is the same.
Centril
added a commit
to Centril/rust
that referenced
this issue
Mar 21, 2020
…ramertj Derive PartialEq, Eq and Hash for RangeInclusive The manual implementation of `PartialEq`, `Eq` and `Hash` for `RangeInclusive` was functionally equivalent to a derived implementation. This change removes the manual implementation and adds the respective derives. A side effect of this change is that the derives also add implementations for `StructuralPartialEq` and `StructuralEq`, which enables `RangeInclusive` to be used in const generics, closing rust-lang#70155. This change is enabled by rust-lang#68835, which changed the field `is_empty: Option<bool>` to `exhausted: bool` removing the need for *semantic* equality instead of *structural* equality. ## PartialEq original [`PartialEq`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L353-L359) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> { #[inline] fn eq(&self, other: &Self) -> bool { self.start == other.start && self.end == other.end && self.exhausted == other.exhausted } } ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx> crate::marker::StructuralPartialEq for RangeInclusive<Idx> {} #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::cmp::PartialEq> crate::cmp::PartialEq for RangeInclusive<Idx> { #[inline] fn eq(&self, other: &RangeInclusive<Idx>) -> bool { match *other { RangeInclusive { start: ref __self_1_0,end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => { (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1) && (*__self_0_2) == (*__self_1_2) } }, } } #[inline] fn ne(&self, other: &RangeInclusive<Idx>) -> bool { match *other { RangeInclusive { start: ref __self_1_0, end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1exhausted: ref __self_0_2 } => { (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1) || (*__self_0_2) != (*__self_1_2) } }, } } } ``` These implementations both test for *structural* equality, with the same order of field comparisons, and the bound `Idx: PartialEq` is the same. ## Eq original [`Eq`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L361-L362) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: Eq> Eq for RangeInclusive<Idx> {} ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx> crate::marker::StructuralEq for RangeInclusive<Idx> {} #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::cmp::Eq> crate::cmp::Eq for RangeInclusive<Idx> { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { let _: crate::cmp::AssertParamIsEq<Idx>; let _: crate::cmp::AssertParamIsEq<Idx>; let _: crate::cmp::AssertParamIsEq<bool>; } } } ``` These implementations are equivalent since `Eq` is just a marker trait and the bound `Idx: Eq` is the same. ## Hash original [`Hash`](https://github.com/rust-lang/rust/blob/f4c675c476c18b1a11041193f2f59d695b126bc8/src/libcore/ops/range.rs#L364-L371) implementation: ```rust #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: Hash> Hash for RangeInclusive<Idx> { fn hash<H: Hasher>(&self, state: &mut H) { self.start.hash(state); self.end.hash(state); self.exhausted.hash(state); } } ``` expanded derive implementation (using `cargo expand ops::range`): ```rust #[automatically_derived] #[allow(unused_qualifications)] #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: crate::hash::Hash> crate::hash::Hash for RangeInclusive<Idx> { fn hash<__H: crate::hash::Hasher>(&self, state: &mut __H) -> () { match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => { crate::hash::Hash::hash(&(*__self_0_0), state); crate::hash::Hash::hash(&(*__self_0_1), state); crate::hash::Hash::hash(&(*__self_0_2), state) } } } } ``` These implementations are functionally equivalent, with the same order of field hashing, and the bound `Idx: Hash` is the same.
CDirkx
pushed a commit
to CDirkx/rust
that referenced
this issue
Mar 22, 2020
With rust-lang#70166 merged, `RangeInclusive` now derives `PartialEq` and `Eq`, implementing structural equality and as a side effect the range is now usable with const generics, closing rust-lang#70155. A test is added to avoid a change to the private fields or the equality implementation of the range from subtly reverting rust-lang#70155.
CDirkx
pushed a commit
to CDirkx/rust
that referenced
this issue
Mar 23, 2020
In addition to the regression test of `RangeInclusive` for rust-lang#70155, now all range types are checked for usability within const generics: - `RangeFrom` - `RangeFull` - `RangeToInclusive` - `RangeTo` - `Range` The test are moved from `test\ui\const-generics\issues\issue-70155` to `test\ui\const-generics\std\range` in anticipation of future similar tests for std types.
Centril
added a commit
to Centril/rust
that referenced
this issue
Mar 23, 2020
…-obk Add regression test for rust-lang#70155. With rust-lang#70166 merged, `RangeInclusive` now derives `PartialEq` and `Eq`, implementing structural equality and as a side effect the range is now usable with const generics, closing rust-lang#70155. As per [rust-lang#70166 (comment)](rust-lang#70166 (comment)) a test is added to avoid a change to the private fields or the equality implementation of the range from subtly reverting rust-lang#70155.
bors
added a commit
to rust-lang-ci/rust
that referenced
this issue
Mar 24, 2020
Rollup of 11 pull requests Successful merges: - rust-lang#67761 (Move the dep_graph construction to a dedicated crate.) - rust-lang#69740 (Replace some desc logic in librustc_lint with article_and_desc) - rust-lang#69981 (Evaluate repeat expression lengths as late as possible) - rust-lang#70087 (Remove const eval loop detector) - rust-lang#70242 (Improve E0308 error message wording) - rust-lang#70264 (Fix invalid suggestion on `&mut` iterators yielding `&` references) - rust-lang#70267 (get rid of ConstPropUnsupported; use ZST marker structs instead) - rust-lang#70277 (Remove `ReClosureBound`) - rust-lang#70283 (Add regression test for rust-lang#70155.) - rust-lang#70294 (Account for bad placeholder types in where clauses) - rust-lang#70309 (Clean up E0452 explanation) Failed merges: r? @ghost
# for free
to join this conversation on GitHub.
Already have an account?
# to comment
Labels
A-const-generics
Area: const generics (parameters and arguments)
C-feature-request
Category: A feature request, i.e: not implemented / a PR.
F-const_generics
`#![feature(const_generics)]`
T-libs-api
Relevant to the library API team, which will review and decide on the PR/issue.
All range types except
RangeInclusive
can be used in const generics:This compiles (on nightly), while the following does not:
This is because
RangeInclusive
does not implementStructuralPartialEq
andStructuralEq
(#63438).RangeInclusive
has fieldsstart
andend
similar to the other range types, but also has an extra field:exhausted: bool
(#68835). This was recently changed from a fieldis_empty: Option<bool>
. This extra field tracks state for iteration and was added to address performance issues (#45222).The old implementation with
is_empty
had semantic equality, however the new implementation withexhausted
has structural equality:from range.rs
I believe this means we can either manually add implementations for
StructuralPartialEq
andStructuralEq
, or just derivePartialEq
andEq
, which will allowRangeInclusive
to also be used in const generics and remove the inconsistency with other range types.The text was updated successfully, but these errors were encountered: