From f0dec8bc8ddec7a959db5a789ea01655a89a15fe Mon Sep 17 00:00:00 2001 From: Lars Schumann Date: Wed, 8 Apr 2026 22:37:12 +0000 Subject: [PATCH] constify (DoubleEnded)Iterator for RepeatN --- library/core/src/iter/sources/repeat_n.rs | 36 ++++++++++++---- library/core/src/iter/traits/double_ended.rs | 17 +++++--- library/core/src/iter/traits/exact_size.rs | 9 +++- library/core/src/iter/traits/iterator.rs | 42 +++++++++++++++---- .../item-collection/opaque-return-impls.rs | 5 ++- 5 files changed, 82 insertions(+), 27 deletions(-) diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index c29ab24a08357..de98d73faf4a8 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -1,5 +1,6 @@ use crate::fmt; use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator}; +use crate::marker::Destruct; use crate::num::NonZero; use crate::ops::Try; @@ -85,9 +86,18 @@ pub struct RepeatN { impl RepeatN { /// If we haven't already dropped the element, return it in an option. + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] #[inline] - fn take_element(&mut self) -> Option { - self.inner.take().map(|inner| inner.element) + const fn take_element(&mut self) -> Option + where + A: [const] Destruct, + { + //FIXME(const-hack): revert this to a const closure when they are fine to use + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + const fn inner_element(inner: RepeatNInner) -> T { + inner.element + } + self.inner.take().map(inner_element) } } @@ -103,7 +113,8 @@ impl fmt::Debug for RepeatN { } #[stable(feature = "iter_repeat_n", since = "1.82.0")] -impl Iterator for RepeatN { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Iterator for RepeatN { type Item = A; #[inline] @@ -156,14 +167,21 @@ impl Iterator for RepeatN { } #[stable(feature = "iter_repeat_n", since = "1.82.0")] -impl ExactSizeIterator for RepeatN { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const ExactSizeIterator for RepeatN { fn len(&self) -> usize { - self.inner.as_ref().map(|inner| inner.count.get()).unwrap_or(0) + //FIXME(const-hack): revert this to a const closure when they are fine to use + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + const fn inner_count(inner: &RepeatNInner) -> usize { + inner.count.get() + } + self.inner.as_ref().map(inner_count).unwrap_or(0) } } #[stable(feature = "iter_repeat_n", since = "1.82.0")] -impl DoubleEndedIterator for RepeatN { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const DoubleEndedIterator for RepeatN { #[inline] fn next_back(&mut self) -> Option { self.next() @@ -182,8 +200,8 @@ impl DoubleEndedIterator for RepeatN { #[inline] fn try_rfold(&mut self, init: B, f: F) -> R where - F: FnMut(B, A) -> R, - R: Try, + F: [const] FnMut(B, A) -> R + [const] Destruct, + R: [const] Try, { self.try_fold(init, f) } @@ -191,7 +209,7 @@ impl DoubleEndedIterator for RepeatN { #[inline] fn rfold(self, init: B, f: F) -> B where - F: FnMut(B, A) -> B, + F: [const] FnMut(B, A) -> B + [const] Destruct, { self.fold(init, f) } diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index ce80874a23897..f522a2c3e8d29 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -137,13 +137,18 @@ pub const trait DoubleEndedIterator: [const] Iterator { /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", issue = "77404")] - #[rustc_non_const_trait_method] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - for i in 0..n { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> + where + Self::Item: [const] Destruct, + { + //FIXME(const-hack): revert this to `for i in 0..n` when possible + let mut i: usize = 0; + while i < n { if self.next_back().is_none() { // SAFETY: `i` is always less than `n`. return Err(unsafe { NonZero::new_unchecked(n - i) }); } + i += 1; } Ok(()) } @@ -191,8 +196,10 @@ pub const trait DoubleEndedIterator: [const] Iterator { /// ``` #[inline] #[stable(feature = "iter_nth_back", since = "1.37.0")] - #[rustc_non_const_trait_method] - fn nth_back(&mut self, n: usize) -> Option { + fn nth_back(&mut self, n: usize) -> Option + where + Self::Item: [const] Destruct, + { if self.advance_back_by(n).is_err() { return None; } diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs index 908830d8a9514..2a2f5e715cf11 100644 --- a/library/core/src/iter/traits/exact_size.rs +++ b/library/core/src/iter/traits/exact_size.rs @@ -83,7 +83,8 @@ /// assert_eq!(4, counter.len()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub trait ExactSizeIterator: Iterator { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +pub const trait ExactSizeIterator: [const] Iterator { /// Returns the exact remaining length of the iterator. /// /// The implementation ensures that the iterator will return exactly `len()` @@ -119,7 +120,11 @@ pub trait ExactSizeIterator: Iterator { // guaranteed by the trait. If this trait were rust-internal, // we could use debug_assert!; assert_eq! will check all Rust user // implementations too. - assert_eq!(upper, Some(lower)); + //assert_eq!(upper, Some(lower)); + //FIXME(review) assert_eq! is not const, what to put here? + if upper != Some(lower) { + panic!() + } lower } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index c6a06c133a156..73f23da08758b 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -308,32 +308,54 @@ pub const trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_advance_by", issue = "77404")] - #[rustc_non_const_trait_method] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> + where + Self::Item: [const] Destruct, + { /// Helper trait to specialize `advance_by` via `try_fold` for `Sized` iterators. - trait SpecAdvanceBy { + const trait SpecAdvanceBy { fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero>; } - impl SpecAdvanceBy for I { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const SpecAdvanceBy for I + where + I::Item: [const] Destruct, + { default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero> { - for i in 0..n { + //FIXME(const-hack): revert this to `for i in 0..n` when possible + let mut i: usize = 0; + while i < n { if self.next().is_none() { // SAFETY: `i` is always less than `n`. return Err(unsafe { NonZero::new_unchecked(n - i) }); } + i += 1; } Ok(()) } } - impl SpecAdvanceBy for I { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + impl const SpecAdvanceBy for I + where + I::Item: [const] Destruct, + { fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero> { + //FIXME(const-hack): revert this to a const closure when they are fine to use + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + const fn try_minus_one( + n: NonZero, + _: T, + ) -> Option> { + NonZero::new(n.get() - 1) + } + let Some(n) = NonZero::new(n) else { return Ok(()); }; - let res = self.try_fold(n, |n, _| NonZero::new(n.get() - 1)); + let res = self.try_fold(n, try_minus_one); match res { None => Ok(()), @@ -386,8 +408,10 @@ pub const trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_non_const_trait_method] - fn nth(&mut self, n: usize) -> Option { + fn nth(&mut self, n: usize) -> Option + where + Self::Item: [const] Destruct, + { self.advance_by(n).ok()?; self.next() } diff --git a/tests/codegen-units/item-collection/opaque-return-impls.rs b/tests/codegen-units/item-collection/opaque-return-impls.rs index 484fbe7fe62f1..af79d75d4b6da 100644 --- a/tests/codegen-units/item-collection/opaque-return-impls.rs +++ b/tests/codegen-units/item-collection/opaque-return-impls.rs @@ -73,12 +73,13 @@ pub fn foo3() -> Box> { } //~ MONO_ITEM fn ::spec_advance_by -//~ MONO_ITEM fn ::spec_advance_by::{closure#0} +//~ MONO_ITEM fn ::spec_advance_by::try_minus_one:: //~ MONO_ITEM fn ::advance_by //~ MONO_ITEM fn ::next //~ MONO_ITEM fn ::nth //~ MONO_ITEM fn ::size_hint -//~ MONO_ITEM fn ::try_fold::, {closure@::spec_advance_by::{closure#0}}, std::option::Option>> +//~ MONO_ITEM fn ::try_fold::, fn(std::num::NonZero, usize) -> std::option::Option> {::spec_advance_by::try_minus_one::}, std::option::Option>> +//~ MONO_ITEM fn , usize) -> std::option::Option> {::spec_advance_by::try_minus_one::} as std::ops::FnMut<(std::num::NonZero, usize)>>::call_mut - shim(fn(std::num::NonZero, usize) -> std::option::Option> {::spec_advance_by::try_minus_one::}) //~ MONO_ITEM fn > as std::ops::FromResidual>>::from_residual //~ MONO_ITEM fn > as std::ops::Try>::branch //~ MONO_ITEM fn > as std::ops::Try>::from_output