From 9e7656cea24c7889342655f90aa3d4c365c1777d Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 24 Sep 2022 06:24:37 +0000 Subject: [PATCH 1/4] Allow const iterator implementations --- library/core/src/array/mod.rs | 28 +- library/core/src/cmp.rs | 31 +- .../core/src/iter/adapters/array_chunks.rs | 2 +- .../core/src/iter/adapters/by_ref_sized.rs | 25 +- library/core/src/iter/adapters/chain.rs | 2 +- library/core/src/iter/adapters/cloned.rs | 2 +- library/core/src/iter/adapters/copied.rs | 2 +- library/core/src/iter/adapters/cycle.rs | 5 +- library/core/src/iter/adapters/enumerate.rs | 2 +- library/core/src/iter/adapters/filter.rs | 2 +- library/core/src/iter/adapters/filter_map.rs | 2 +- library/core/src/iter/adapters/flatten.rs | 24 +- library/core/src/iter/adapters/fuse.rs | 2 +- library/core/src/iter/adapters/inspect.rs | 2 +- library/core/src/iter/adapters/intersperse.rs | 13 +- library/core/src/iter/adapters/map.rs | 55 +- library/core/src/iter/adapters/map_while.rs | 2 +- library/core/src/iter/adapters/mod.rs | 45 +- library/core/src/iter/adapters/peekable.rs | 2 +- library/core/src/iter/adapters/rev.rs | 2 +- library/core/src/iter/adapters/scan.rs | 2 +- library/core/src/iter/adapters/skip.rs | 2 +- library/core/src/iter/adapters/skip_while.rs | 2 +- library/core/src/iter/adapters/step_by.rs | 2 +- library/core/src/iter/adapters/take.rs | 2 +- library/core/src/iter/adapters/take_while.rs | 2 +- library/core/src/iter/adapters/zip.rs | 114 +++- library/core/src/iter/traits/collect.rs | 38 +- library/core/src/iter/traits/exact_size.rs | 24 +- library/core/src/iter/traits/iterator.rs | 583 +++++++++++------- library/core/src/iter/traits/marker.rs | 3 +- library/core/src/lib.rs | 13 +- library/core/src/ops/control_flow.rs | 19 +- library/core/src/option.rs | 9 +- src/test/ui/issues/issue-23966.stderr | 4 +- src/test/ui/issues/issue-34334.stderr | 4 +- ...e-66923-show-error-for-correct-call.stderr | 8 +- .../ui/iterators/collect-into-array.stderr | 4 +- .../ui/iterators/collect-into-slice.stderr | 6 +- .../branches.stderr | 4 +- .../recursion4.stderr | 8 +- .../ui/suggestions/derive-clone-for-eq.stderr | 4 +- src/test/ui/traits/alias/object-fail.stderr | 4 +- 43 files changed, 705 insertions(+), 406 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 2090756d7a3ec..be11cd0fd2de3 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -11,6 +11,7 @@ use crate::error::Error; use crate::fmt; use crate::hash::{self, Hash}; use crate::iter::TrustedLen; +use crate::marker::Destruct; use crate::mem::{self, MaybeUninit}; use crate::ops::{ ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try, @@ -852,23 +853,26 @@ where /// If `iter.next()` panicks, all items already yielded by the iterator are /// dropped. #[inline] -fn try_collect_into_array( +const fn try_collect_into_array( iter: &mut I, ) -> Result> where - I: Iterator, - I::Item: Try, - R: Residual<[T; N]>, + I: ~const Iterator, + I::Item: ~const Try, + R: ~const Residual<[T; N]>, + T: ~const Destruct, { if N == 0 { // SAFETY: An empty array is always inhabited and has no validity invariants. - return Ok(Try::from_output(unsafe { mem::zeroed() })); + return Ok(Try::from_output(unsafe { MaybeUninit::zeroed().assume_init() })); } let mut array = MaybeUninit::uninit_array::(); let mut guard = Guard { array_mut: &mut array, initialized: 0 }; - for _ in 0..N { + let mut i = 0; + // FIXME(const_trait_impl): replace with `for` loop + while i < N { match iter.next() { Some(item_rslt) => { let item = match item_rslt.branch() { @@ -892,6 +896,7 @@ where return Err(unsafe { IntoIter::new_unchecked(array, alive) }); } } + i += 1; } mem::forget(guard); @@ -952,12 +957,17 @@ impl Drop for Guard<'_, T, N> { /// Returns the next chunk of `N` items from the iterator or errors with an /// iterator over the remainder. Used for `Iterator::next_chunk`. #[inline] -pub(crate) fn iter_next_chunk( +pub(crate) const fn iter_next_chunk( iter: &mut I, ) -> Result<[I::Item; N], IntoIter> where - I: Iterator, + I: ~const Iterator, + I::Item: ~const Destruct, { let mut map = iter.map(NeverShortCircuit); - try_collect_into_array(&mut map).map(|NeverShortCircuit(arr)| arr) + + match try_collect_into_array(&mut map) { + Ok(NeverShortCircuit(x)) => Ok(x), + Err(e) => Err(e), + } } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 5db5cbfc3dfdd..6da9f745399e1 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -281,7 +281,8 @@ pub macro PartialEq($item:item) { #[doc(alias = "!=")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Eq"] -pub trait Eq: PartialEq { +#[const_trait] +pub trait Eq: ~const PartialEq { // this method is used solely by #[deriving] to assert // that every component of a type implements #[deriving] // itself, the current deriving infrastructure means doing this @@ -331,8 +332,9 @@ pub struct AssertParamIsEq { /// let result = 2.cmp(&1); /// assert_eq!(Ordering::Greater, result); /// ``` -#[derive(Clone, Copy, Eq, Debug, Hash)] -#[cfg_attr(not(bootstrap), derive_const(PartialOrd, Ord, PartialEq))] +#[derive(Clone, Copy, Debug, Hash)] +#[cfg_attr(bootstrap, derive(Ord, Eq))] +#[cfg_attr(not(bootstrap), derive_const(PartialOrd, Ord, PartialEq, Eq))] #[stable(feature = "rust1", since = "1.0.0")] #[repr(i8)] pub enum Ordering { @@ -762,7 +764,7 @@ impl Clone for Reverse { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Ord"] #[const_trait] -pub trait Ord: Eq + PartialOrd { +pub trait Ord: ~const Eq + ~const PartialOrd { /// This method returns an [`Ordering`] between `self` and `other`. /// /// By convention, `self.cmp(&other)` returns the ordering matching the expression @@ -892,16 +894,6 @@ impl const PartialEq for Ordering { } } -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] -#[cfg(bootstrap)] -impl const Ord for Ordering { - #[inline] - fn cmp(&self, other: &Ordering) -> Ordering { - (*self as i32).cmp(&(*other as i32)) - } -} - #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] #[cfg(bootstrap)] @@ -1231,9 +1223,8 @@ pub const fn min(v1: T, v2: T) -> T { #[stable(feature = "cmp_min_max_by", since = "1.53.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] pub const fn min_by Ordering>(v1: T, v2: T, compare: F) -> T -where +where T: ~const Destruct, - F: ~const Destruct, { match compare(&v1, &v2) { Ordering::Less | Ordering::Equal => v1, @@ -1318,8 +1309,6 @@ pub const fn max(v1: T, v2: T) -> T { pub const fn max_by Ordering>(v1: T, v2: T, compare: F) -> T where T: ~const Destruct, - F: ~const Destruct, -{ match compare(&v1, &v2) { Ordering::Less | Ordering::Equal => v2, Ordering::Greater => v1, @@ -1399,7 +1388,8 @@ mod impls { macro_rules! eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl Eq for $t {} + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl const Eq for $t {} )*) } @@ -1523,7 +1513,8 @@ mod impls { } #[unstable(feature = "never_type", issue = "35121")] - impl Eq for ! {} + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl const Eq for ! {} #[unstable(feature = "never_type", issue = "35121")] #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs index 5e4211058aa6f..1f431f7ce0005 100644 --- a/library/core/src/iter/adapters/array_chunks.rs +++ b/library/core/src/iter/adapters/array_chunks.rs @@ -24,7 +24,7 @@ where I: Iterator, { #[track_caller] - pub(in crate::iter) fn new(iter: I) -> Self { + pub(in crate::iter) const fn new(iter: I) -> Self { assert!(N != 0, "chunk size must be non-zero"); Self { iter, remainder: None } } diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs index 1945e402ff50e..f9efa970ed93c 100644 --- a/library/core/src/iter/adapters/by_ref_sized.rs +++ b/library/core/src/iter/adapters/by_ref_sized.rs @@ -1,7 +1,6 @@ -use crate::{ - const_closure::ConstFnMutClosure, - ops::{NeverShortCircuit, Try}, -}; +use crate::const_closure::ConstFnMutClosure; +use crate::marker::Destruct; +use crate::ops::{NeverShortCircuit, Try}; /// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics. /// @@ -15,7 +14,7 @@ pub struct ByRefSized<'a, I>(pub &'a mut I); // to avoid accidentally calling the `&mut Iterator` implementations. #[unstable(feature = "std_internals", issue = "none")] -impl Iterator for ByRefSized<'_, I> { +impl const Iterator for ByRefSized<'_, I> { type Item = I::Item; #[inline] @@ -29,19 +28,25 @@ impl Iterator for ByRefSized<'_, I> { } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> Result<(), usize> + where + I::Item: ~const Destruct, + { I::advance_by(self.0, n) } #[inline] - fn nth(&mut self, n: usize) -> Option { + fn nth(&mut self, n: usize) -> Option + where + I::Item: ~const Destruct, + { I::nth(self.0, n) } #[inline] fn fold(self, init: B, mut f: F) -> B where - F: FnMut(B, Self::Item) -> B, + F: ~const FnMut(B, Self::Item) -> B + ~const Destruct, { // `fold` needs ownership, so this can't forward directly. I::try_fold(self.0, init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp)) @@ -51,8 +56,8 @@ impl Iterator for ByRefSized<'_, I> { #[inline] fn try_fold(&mut self, init: B, f: F) -> R where - F: FnMut(B, Self::Item) -> R, - R: Try, + F: ~const FnMut(B, Self::Item) -> R + ~const Destruct, + R: ~const Try, { I::try_fold(self.0, init, f) } diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 60eb3a6da3a4b..f5fcf49bb2da5 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -32,7 +32,7 @@ pub struct Chain { b: Option, } impl Chain { - pub(in super::super) fn new(a: A, b: B) -> Chain { + pub(in super::super) const fn new(a: A, b: B) -> Chain { Chain { a: Some(a), b: Some(b) } } } diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index aba24a79dcf79..8d79729b6c975 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -19,7 +19,7 @@ pub struct Cloned { } impl Cloned { - pub(in crate::iter) fn new(it: I) -> Cloned { + pub(in crate::iter) const fn new(it: I) -> Cloned { Cloned { it } } } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 62d3afb81603d..ea6dd32529fde 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -22,7 +22,7 @@ pub struct Copied { } impl Copied { - pub(in crate::iter) fn new(it: I) -> Copied { + pub(in crate::iter) const fn new(it: I) -> Copied { Copied { it } } } diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs index 02b5939072ef0..a4ede289572e8 100644 --- a/library/core/src/iter/adapters/cycle.rs +++ b/library/core/src/iter/adapters/cycle.rs @@ -16,7 +16,10 @@ pub struct Cycle { } impl Cycle { - pub(in crate::iter) fn new(iter: I) -> Cycle { + pub(in crate::iter) const fn new(iter: I) -> Cycle + where + I: ~const Clone, + { Cycle { orig: iter.clone(), iter } } } diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 14a126951115c..f696fd808be1e 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -19,7 +19,7 @@ pub struct Enumerate { count: usize, } impl Enumerate { - pub(in crate::iter) fn new(iter: I) -> Enumerate { + pub(in crate::iter) const fn new(iter: I) -> Enumerate { Enumerate { iter, count: 0 } } } diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index a0afaa326ad63..c46893250c087 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -18,7 +18,7 @@ pub struct Filter { predicate: P, } impl Filter { - pub(in crate::iter) fn new(iter: I, predicate: P) -> Filter { + pub(in crate::iter) const fn new(iter: I, predicate: P) -> Filter { Filter { iter, predicate } } } diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index e0d665c9e12ba..bbe5e8b5c1a0f 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -17,7 +17,7 @@ pub struct FilterMap { f: F, } impl FilterMap { - pub(in crate::iter) fn new(iter: I, f: F) -> FilterMap { + pub(in crate::iter) const fn new(iter: I, f: F) -> FilterMap { FilterMap { iter, f } } } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 307016c269099..31386efe4c0d2 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -1,5 +1,6 @@ use crate::fmt; use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen}; +use crate::marker::Destruct; use crate::ops::{ControlFlow, Try}; /// An iterator that maps each element to an iterator, and yields the elements @@ -13,8 +14,12 @@ pub struct FlatMap { inner: FlattenCompat, ::IntoIter>, } -impl U> FlatMap { - pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap { +impl FlatMap { + pub(in crate::iter) const fn new(iter: I, f: F) -> FlatMap + where + I: ~const Iterator + ~const Destruct, + F: ~const FnMut(I::Item) -> U + ~const Destruct, + { FlatMap { inner: FlattenCompat::new(iter.map(f)) } } } @@ -172,7 +177,10 @@ pub struct Flatten> { } impl> Flatten { - pub(in super::super) fn new(iter: I) -> Flatten { + pub(in super::super) const fn new(iter: I) -> Flatten + where + I: ~const Iterator, + { Flatten { inner: FlattenCompat::new(iter) } } } @@ -310,12 +318,12 @@ struct FlattenCompat { frontiter: Option, backiter: Option, } -impl FlattenCompat -where - I: Iterator, -{ +impl FlattenCompat { /// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`. - fn new(iter: I) -> FlattenCompat { + const fn new(iter: I) -> FlattenCompat + where + I: ~const Iterator, + { FlattenCompat { iter: iter.fuse(), frontiter: None, backiter: None } } } diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index c931445420342..e779eead02e57 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -21,7 +21,7 @@ pub struct Fuse { iter: Option, } impl Fuse { - pub(in crate::iter) fn new(iter: I) -> Fuse { + pub(in crate::iter) const fn new(iter: I) -> Fuse { Fuse { iter: Some(iter) } } } diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs index 19839fdfe5bc3..4ed0ce2e2d4d7 100644 --- a/library/core/src/iter/adapters/inspect.rs +++ b/library/core/src/iter/adapters/inspect.rs @@ -18,7 +18,7 @@ pub struct Inspect { f: F, } impl Inspect { - pub(in crate::iter) fn new(iter: I, f: F) -> Inspect { + pub(in crate::iter) const fn new(iter: I, f: F) -> Inspect { Inspect { iter, f } } } diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index d8bbd424cf258..7915b67341a78 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -19,7 +19,10 @@ impl Intersperse where I::Item: Clone, { - pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self { + pub(in crate::iter) const fn new(iter: I, separator: I::Item) -> Self + where + I: ~const Iterator, + { Self { iter: iter.peekable(), separator, needs_sep: false } } } @@ -103,12 +106,14 @@ where } } -impl IntersperseWith +impl IntersperseWith where - I: Iterator, G: FnMut() -> I::Item, { - pub(in crate::iter) fn new(iter: I, separator: G) -> Self { + pub(in crate::iter) const fn new(iter: I, separator: G) -> Self + where + I: ~const Iterator, + { Self { iter: iter.peekable(), separator, needs_sep: false } } } diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 9e25dbe462c91..9a99cf274645f 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -3,6 +3,7 @@ use crate::iter::adapters::{ zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; +use crate::marker::Destruct; use crate::ops::Try; /// An iterator that maps the values of `iter` with `f`. @@ -65,7 +66,7 @@ pub struct Map { } impl Map { - pub(in crate::iter) fn new(iter: I, f: F) -> Map { + pub(in crate::iter) const fn new(iter: I, f: F) -> Map { Map { iter, f } } } @@ -77,24 +78,29 @@ impl fmt::Debug for Map { } } -fn map_fold( - mut f: impl FnMut(T) -> B, - mut g: impl FnMut(Acc, B) -> Acc, -) -> impl FnMut(Acc, T) -> Acc { - move |acc, elt| g(acc, f(elt)) +const fn map_fold(x: &mut (F, G), (acc, elt): (Acc, T)) -> Acc +where + F: ~const FnMut(T) -> B, + G: ~const FnMut(Acc, B) -> Acc, +{ + x.1(acc, x.0(elt)) } -fn map_try_fold<'a, T, B, Acc, R>( - f: &'a mut impl FnMut(T) -> B, - mut g: impl FnMut(Acc, B) -> R + 'a, -) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, elt| g(acc, f(elt)) +const fn map_try_fold(x: &mut (F, G), (acc, elt): (Acc, T)) -> R +where + F: ~const FnMut(T) -> B, + G: ~const FnMut(Acc, B) -> R, +{ + x.1(acc, x.0(elt)) } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Map +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Iterator for Map where - F: FnMut(I::Item) -> B, + F: ~const FnMut(I::Item) -> B, + F: ~const Destruct, + I: ~const Destruct, { type Item = B; @@ -111,17 +117,20 @@ where fn try_fold(&mut self, init: Acc, g: G) -> R where Self: Sized, - G: FnMut(Acc, Self::Item) -> R, - R: Try, + G: ~const FnMut(Acc, Self::Item) -> R + ~const Destruct, + R: ~const Try, { - self.iter.try_fold(init, map_try_fold(&mut self.f, g)) + let mut tup = (&mut self.f, g); + self.iter.try_fold(init, ConstFnMutClosure::new(&mut tup, map_try_fold)) } - fn fold(self, init: Acc, g: G) -> Acc + fn fold(mut self, init: Acc, g: G) -> Acc where - G: FnMut(Acc, Self::Item) -> Acc, + G: ~const FnMut(Acc, Self::Item) -> Acc + ~const Destruct, + Self: ~const Destruct, { - self.iter.fold(init, map_fold(self.f, g)) + let mut tup = (&mut self.f, g); + self.iter.fold(init, ConstFnMutClosure::new(&mut tup, map_fold)) } #[inline] @@ -151,14 +160,16 @@ where G: FnMut(Acc, Self::Item) -> R, R: Try, { - self.iter.try_rfold(init, map_try_fold(&mut self.f, g)) + let mut tup = (&mut self.f, g); + self.iter.try_rfold(init, ConstFnMutClosure::new(&mut tup, map_try_fold)) } - fn rfold(self, init: Acc, g: G) -> Acc + fn rfold(mut self, init: Acc, g: G) -> Acc where G: FnMut(Acc, Self::Item) -> Acc, { - self.iter.rfold(init, map_fold(self.f, g)) + let mut tup = (&mut self.f, g); + self.iter.rfold(init, ConstFnMutClosure::new(&mut tup, map_fold)) } } diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs index fbdeca4d4ee4f..31eb84b570e6f 100644 --- a/library/core/src/iter/adapters/map_while.rs +++ b/library/core/src/iter/adapters/map_while.rs @@ -18,7 +18,7 @@ pub struct MapWhile { } impl MapWhile { - pub(in crate::iter) fn new(iter: I, predicate: P) -> MapWhile { + pub(in crate::iter) const fn new(iter: I, predicate: P) -> MapWhile { MapWhile { iter, predicate } } } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 8cc2b7cec4165..0c20b35613835 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,4 +1,5 @@ use crate::iter::{InPlaceIterable, Iterator}; +use crate::marker::Destruct; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; mod array_chunks; @@ -153,11 +154,14 @@ pub(crate) struct GenericShunt<'a, I, R> { /// Process the given iterator as if it yielded a the item's `Try::Output` /// type instead. Any `Try::Residual`s encountered will stop the inner iterator /// and be propagated back to the overall result. -pub(crate) fn try_process(iter: I, mut f: F) -> ChangeOutputType +pub(crate) const fn try_process(iter: I, mut f: F) -> ChangeOutputType where - I: Iterator>, - for<'a> F: FnMut(GenericShunt<'a, I, R>) -> U, - R: Residual, + I: ~const Iterator, + I::Item: ~const Try, + for<'a> F: ~const FnMut(GenericShunt<'a, I, R>) -> U, + F: ~const Destruct, + R: ~const Residual, + U: ~const Destruct, { let mut residual = None; let shunt = GenericShunt { iter, residual: &mut residual }; @@ -168,9 +172,11 @@ where } } -impl Iterator for GenericShunt<'_, I, R> +impl const Iterator for GenericShunt<'_, I, R> where - I: Iterator>, + I: ~const Iterator, + I::Item: ~const Try, + R: ~const Destruct, { type Item = ::Output; @@ -187,20 +193,31 @@ where } } - fn try_fold(&mut self, init: B, mut f: F) -> T + fn try_fold(&mut self, init: B, f: F) -> T where - F: FnMut(B, Self::Item) -> T, - T: Try, + F: ~const FnMut(B, Self::Item) -> T + ~const Destruct, + T: ~const Try, { - self.iter - .try_fold(init, |acc, x| match Try::branch(x) { + const fn try_fold_impl( + (f, residual): &mut (F, &mut Option), + (acc, x): (B, Item), + ) -> ControlFlow + where + F: ~const FnMut(B, Item::Output) -> T, + Item: ~const Try, + T: ~const Try, + Item::Residual: ~const Destruct, + { + match Try::branch(x) { ControlFlow::Continue(x) => ControlFlow::from_try(f(acc, x)), ControlFlow::Break(r) => { - *self.residual = Some(r); + **residual = Some(r); ControlFlow::Break(try { acc }) } - }) - .into_try() + } + } + let mut tuple = (f, &mut *self.residual); + self.iter.try_fold(init, ConstFnMutClosure::new(&mut tuple, try_fold_impl)).into_try() } impl_fold_via_try_fold! { fold -> try_fold } diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index 20aca323bab79..a3e957efbb73d 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -19,7 +19,7 @@ pub struct Peekable { } impl Peekable { - pub(in crate::iter) fn new(iter: I) -> Peekable { + pub(in crate::iter) const fn new(iter: I) -> Peekable { Peekable { iter, peeked: None } } } diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs index 139fb7bbdd996..b048d8246777b 100644 --- a/library/core/src/iter/adapters/rev.rs +++ b/library/core/src/iter/adapters/rev.rs @@ -16,7 +16,7 @@ pub struct Rev { } impl Rev { - pub(in crate::iter) fn new(iter: T) -> Rev { + pub(in crate::iter) const fn new(iter: T) -> Rev { Rev { iter } } } diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs index 62470512cc747..631da4894231a 100644 --- a/library/core/src/iter/adapters/scan.rs +++ b/library/core/src/iter/adapters/scan.rs @@ -19,7 +19,7 @@ pub struct Scan { } impl Scan { - pub(in crate::iter) fn new(iter: I, state: St, f: F) -> Scan { + pub(in crate::iter) const fn new(iter: I, state: St, f: F) -> Scan { Scan { iter, state, f } } } diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index c6334880db57c..c62ba7b9be946 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -18,7 +18,7 @@ pub struct Skip { } impl Skip { - pub(in crate::iter) fn new(iter: I, n: usize) -> Skip { + pub(in crate::iter) const fn new(iter: I, n: usize) -> Skip { Skip { iter, n } } } diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs index f29661779c056..0103123be7d2c 100644 --- a/library/core/src/iter/adapters/skip_while.rs +++ b/library/core/src/iter/adapters/skip_while.rs @@ -19,7 +19,7 @@ pub struct SkipWhile { } impl SkipWhile { - pub(in crate::iter) fn new(iter: I, predicate: P) -> SkipWhile { + pub(in crate::iter) const fn new(iter: I, predicate: P) -> SkipWhile { SkipWhile { iter, flag: false, predicate } } } diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 4252c34a0e0fc..9ce84343efcbb 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -17,7 +17,7 @@ pub struct StepBy { } impl StepBy { - pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy { + pub(in crate::iter) const fn new(iter: I, step: usize) -> StepBy { assert!(step != 0); StepBy { iter, step: step - 1, first_take: true } } diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index 58a0b9d7bbe99..36244e3dfcf79 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -18,7 +18,7 @@ pub struct Take { } impl Take { - pub(in crate::iter) fn new(iter: I, n: usize) -> Take { + pub(in crate::iter) const fn new(iter: I, n: usize) -> Take { Take { iter, n } } } diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs index ec66dc3aec360..fdef2dc44ae02 100644 --- a/library/core/src/iter/adapters/take_while.rs +++ b/library/core/src/iter/adapters/take_while.rs @@ -19,7 +19,7 @@ pub struct TakeWhile { } impl TakeWhile { - pub(in crate::iter) fn new(iter: I, predicate: P) -> TakeWhile { + pub(in crate::iter) const fn new(iter: I, predicate: P) -> TakeWhile { TakeWhile { iter, flag: false, predicate } } } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 8153c8cfef133..9f6e86ba2d9b4 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -1,7 +1,9 @@ use crate::cmp; use crate::fmt::{self, Debug}; +use crate::intrinsics::const_eval_select; use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; use crate::iter::{InPlaceIterable, SourceIter, TrustedLen}; +use crate::marker::Destruct; /// An iterator that iterates two other iterators simultaneously. /// @@ -19,10 +21,23 @@ pub struct Zip { a_len: usize, } impl Zip { - pub(in crate::iter) fn new(a: A, b: B) -> Zip { + pub(in crate::iter) const fn new(a: A, b: B) -> Zip + where + A: ~const Iterator, + B: ~const Iterator, + A::Item: ~const Destruct, + B::Item: ~const Destruct, + { ZipImpl::new(a, b) } - fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> { + + const fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> + where + A: ~const Iterator, + B: ~const Iterator, + A::Item: ~const Destruct, + B::Item: ~const Destruct, + { while let Some(x) = Iterator::next(self) { if n == 0 { return Some(x); @@ -72,10 +87,13 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Zip +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Iterator for Zip where - A: Iterator, - B: Iterator, + A: ~const Iterator, + B: ~const Iterator, + A::Item: ~const Destruct, + B::Item: ~const Destruct, { type Item = (A::Item, B::Item); @@ -119,6 +137,7 @@ where // Zip specialization trait #[doc(hidden)] +#[const_trait] trait ZipImpl { type Item; fn new(a: A, b: B) -> Self; @@ -150,6 +169,7 @@ macro_rules! zip_impl_general_defaults { } #[inline] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_try, const_for))] default fn next(&mut self) -> Option<(A::Item, B::Item)> { let x = self.a.next()?; let y = self.b.next()?; @@ -164,8 +184,8 @@ macro_rules! zip_impl_general_defaults { #[inline] default fn next_back(&mut self) -> Option<(A::Item, B::Item)> where - A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator, + A: ~const DoubleEndedIterator + ~const ExactSizeIterator, + B: ~const DoubleEndedIterator + ~const ExactSizeIterator, { // The function body below only uses `self.a/b.len()` and `self.a/b.next_back()` // and doesn’t call `next_back` too often, so this implementation is safe in @@ -176,12 +196,17 @@ macro_rules! zip_impl_general_defaults { if a_sz != b_sz { // Adjust a, b to equal length if a_sz > b_sz { - for _ in 0..a_sz - b_sz { + // FIXME(const_trait_impl): replace with `for` + let mut i = 0; + while i < a_sz - b_sz { self.a.next_back(); + i += 1; } } else { - for _ in 0..b_sz - a_sz { + let mut i = 0; + while i < b_sz - a_sz { self.b.next_back(); + i += 1; } } } @@ -195,11 +220,14 @@ macro_rules! zip_impl_general_defaults { } // General Zip impl + #[doc(hidden)] -impl ZipImpl for Zip +impl const ZipImpl for Zip where - A: Iterator, - B: Iterator, + A: ~const Iterator, + B: ~const Iterator, + A::Item: ~const Destruct, + B::Item: ~const Destruct, { type Item = (A::Item, B::Item); @@ -226,15 +254,17 @@ where where Self: TrustedRandomAccessNoCoerce, { - unreachable!("Always specialized"); + panic!("internal error: entered unreachable code: Always specialized"); } } #[doc(hidden)] -impl ZipImpl for Zip +impl const ZipImpl for Zip where - A: TrustedRandomAccessNoCoerce + Iterator, - B: TrustedRandomAccessNoCoerce + Iterator, + A: ~const TrustedRandomAccessNoCoerce + ~const Iterator, + B: ~const TrustedRandomAccessNoCoerce + ~const Iterator, + A::Item: ~const Destruct, + B::Item: ~const Destruct, { zip_impl_general_defaults! {} @@ -254,10 +284,12 @@ where } #[doc(hidden)] -impl ZipImpl for Zip +impl const ZipImpl for Zip where - A: TrustedRandomAccess + Iterator, - B: TrustedRandomAccess + Iterator, + A: ~const TrustedRandomAccess + ~const Iterator, + B: ~const TrustedRandomAccess + ~const Iterator, + A::Item: ~const Destruct, + B::Item: ~const Destruct, { fn new(a: A, b: B) -> Self { let a_len = a.size(); @@ -329,8 +361,8 @@ where #[inline] fn next_back(&mut self) -> Option<(A::Item, B::Item)> where - A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator, + A: ~const DoubleEndedIterator + ~const ExactSizeIterator, + B: ~const DoubleEndedIterator + ~const ExactSizeIterator, { if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT { let sz_a = self.a.size(); @@ -341,18 +373,37 @@ where if sz_a != sz_b { let sz_a = self.a.size(); if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len { - for _ in 0..sz_a - self.len { + // FIXME(const_trait_impl): replace with `for` + let mut i = 0; + while i < sz_a - self.len { // since next_back() may panic we increment the counters beforehand // to keep Zip's state in sync with the underlying iterator source self.a_len -= 1; self.a.next_back(); + i += 1; + } + #[track_caller] + fn assert_rt(a: usize, b: usize) { + debug_assert_eq!(a, b); + } + const fn assert_ct(a: usize, b: usize) { + if a == b { + return; + } + panic!("assertion failed") + } + // SAFETY: only panicking + unsafe { + const_eval_select((self.a_len, self.len), assert_ct, assert_rt); } - debug_assert_eq!(self.a_len, self.len); } let sz_b = self.b.size(); if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len { - for _ in 0..sz_b - self.len { + // FIXME(const_trait_impl): replace with `for` + let mut i = 0; + while i < sz_a - self.len { self.b.next_back(); + i += 1; } } } @@ -520,7 +571,8 @@ impl(it: &mut I, idx: usize) -> I::Item +pub(in crate::iter::adapters) const unsafe fn try_get_unchecked( + it: &mut I, + idx: usize, +) -> I::Item where - I: Iterator, + I: ~const Iterator, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. unsafe { it.try_get_unchecked(idx) } } +#[const_trait] unsafe trait SpecTrustedRandomAccess: Iterator { /// If `Self: TrustedRandomAccess`, it must be safe to call /// `Iterator::__iterator_get_unchecked(self, index)`. unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item; } -unsafe impl SpecTrustedRandomAccess for I { +unsafe impl const SpecTrustedRandomAccess for I { default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item { panic!("Should only be called on TrustedRandomAccess iterators"); } } -unsafe impl SpecTrustedRandomAccess for I { +unsafe impl const SpecTrustedRandomAccess for I { #[inline] unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { // SAFETY: the caller must uphold the contract for diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index e099700e3e7c8..3b7c06f238b4d 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -1,3 +1,6 @@ +use crate::const_closure::ConstFnMutClosure; +use crate::marker::Destruct; + /// Conversion from an [`Iterator`]. /// /// By implementing `FromIterator` for a type, you define how it will be @@ -236,7 +239,7 @@ pub trait IntoIterator { /// Which kind of iterator are we turning this into? #[stable(feature = "rust1", since = "1.0.0")] - type IntoIter: Iterator; + type IntoIter: ~const Iterator; /// Creates an iterator from a value. /// @@ -344,6 +347,7 @@ impl const IntoIterator for I { /// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{c:?}")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[const_trait] pub trait Extend { /// Extends a collection with the contents of an iterator. /// @@ -365,7 +369,7 @@ pub trait Extend { /// assert_eq!("abcdef", &message); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn extend>(&mut self, iter: T); + fn extend>(&mut self, iter: T); /// Extends a collection with exactly one element. #[unstable(feature = "extend_one", issue = "72631")] @@ -391,10 +395,11 @@ impl Extend<()> for () { } #[stable(feature = "extend_for_tuple", since = "1.56.0")] -impl Extend<(A, B)> for (ExtendA, ExtendB) +#[rustc_const_unstable(feature = "const_extend", issue = "none")] +impl const Extend<(A, B)> for (ExtendA, ExtendB) where - ExtendA: Extend, - ExtendB: Extend, + ExtendA: ~const Extend, + ExtendB: ~const Extend, { /// Allows to `extend` a tuple of collections that also implement `Extend`. /// @@ -416,18 +421,20 @@ where /// assert_eq!(b, [2, 5, 8]); /// assert_eq!(c, [3, 6, 9]); /// ``` - fn extend>(&mut self, into_iter: T) { + fn extend>(&mut self, into_iter: T) + where + T::IntoIter: ~const Destruct, + { let (a, b) = self; let iter = into_iter.into_iter(); - fn extend<'a, A, B>( - a: &'a mut impl Extend, - b: &'a mut impl Extend, - ) -> impl FnMut((), (A, B)) + 'a { - move |(), (t, u)| { - a.extend_one(t); - b.extend_one(u); - } + const fn extend((a, b): &mut (&mut EA, &mut EB), ((), (t, u)): ((), (A, B))) + where + EA: ~const Extend, + EB: ~const Extend, + { + a.extend_one(t); + b.extend_one(u); } let (lower_bound, _) = iter.size_hint(); @@ -435,8 +442,7 @@ where a.extend_reserve(lower_bound); b.extend_reserve(lower_bound); } - - iter.fold((), extend(a, b)); + iter.fold((), ConstFnMutClosure::new(&mut (a, b), extend)); } fn extend_one(&mut self, item: (A, B)) { diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs index 1757e37ec0e2f..195965e8ee806 100644 --- a/library/core/src/iter/traits/exact_size.rs +++ b/library/core/src/iter/traits/exact_size.rs @@ -1,3 +1,5 @@ +use crate::intrinsics::const_eval_select; + /// An iterator that knows its exact length. /// /// Many [`Iterator`]s don't know how many times they will iterate, but some do. @@ -73,7 +75,8 @@ /// assert_eq!(4, counter.len()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub trait ExactSizeIterator: Iterator { +#[const_trait] +pub trait ExactSizeIterator: ~const Iterator { /// Returns the exact remaining length of the iterator. /// /// The implementation ensures that the iterator will return exactly `len()` @@ -105,11 +108,25 @@ pub trait ExactSizeIterator: Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn len(&self) -> usize { let (lower, upper) = self.size_hint(); + #[track_caller] + #[inline] + fn assert_rt(lower: usize, upper: Option) { + assert_eq!(upper, Some(lower)); + } + const fn assert_ct(lower: usize, upper: Option) { + match upper { + Some(upper) if upper == lower => {} + _ => panic!("expected `upper` to be equal to `Some(lower)`"), + } + } // Note: This assertion is overly defensive, but it checks the invariant // 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)); + // SAFETY: only using because compile time functions do not get formatted panic messages + unsafe { + const_eval_select((lower, upper), assert_ct, assert_rt); + } lower } @@ -141,7 +158,8 @@ pub trait ExactSizeIterator: Iterator { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for &mut I { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const ExactSizeIterator for &mut I { fn len(&self) -> usize { (**self).len() } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 83c7e8977e9f3..193e3294be98d 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,5 +1,8 @@ use crate::array; use crate::cmp::{self, Ordering}; +use crate::const_closure::ConstFnMutClosure; +use crate::iter::adapters::GenericShunt; +use crate::marker::Destruct; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; @@ -64,6 +67,7 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} #[doc(notable_trait)] #[rustc_diagnostic_item = "Iterator"] #[must_use = "iterators are lazy and do nothing unless consumed"] +#[const_trait] pub trait Iterator { /// The type of the elements being iterated over. #[stable(feature = "rust1", since = "1.0.0")] @@ -140,6 +144,7 @@ pub trait Iterator { ) -> Result<[Self::Item; N], array::IntoIter> where Self: Sized, + Self::Item: ~const Destruct, { array::iter_next_chunk(self) } @@ -252,12 +257,14 @@ pub trait Iterator { fn count(self) -> usize where Self: Sized, + Self: ~const Destruct, + Self::Item: ~const Destruct, { - self.fold( - 0, - #[rustc_inherit_overflow_checks] - |count, _| count + 1, - ) + #[rustc_inherit_overflow_checks] + const fn fold(count: usize, _: T) -> usize { + count + 1 + } + self.fold(0, fold) } /// Consumes the iterator, returning the last element. @@ -282,9 +289,11 @@ pub trait Iterator { fn last(self) -> Option where Self: Sized, + Self::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] - fn some(_: Option, x: T) -> Option { + const fn some(_: Option, x: T) -> Option { Some(x) } @@ -325,9 +334,15 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - for i in 0..n { + fn advance_by(&mut self, n: usize) -> Result<(), usize> + where + Self::Item: ~const Destruct, + { + let mut i = 0; + // FIXME(const_trait_impl) use a for loop once `Range` can implement iterator. + while i < n { self.next().ok_or(i)?; + i += 1; } Ok(()) } @@ -373,7 +388,10 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - 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() } @@ -499,7 +517,7 @@ pub trait Iterator { fn chain(self, other: U) -> Chain where Self: Sized, - U: IntoIterator, + U: ~const IntoIterator, { Chain::new(self, other.into_iter()) } @@ -617,7 +635,9 @@ pub trait Iterator { fn zip(self, other: U) -> Zip where Self: Sized, - U: IntoIterator, + U: ~const IntoIterator, + U::Item: ~const Destruct, + Self::Item: ~const Destruct, { Zip::new(self, other.into_iter()) } @@ -818,17 +838,18 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_for_each", since = "1.21.0")] - fn for_each(self, f: F) + fn for_each(self, mut f: F) where Self: Sized, - F: FnMut(Self::Item), + F: ~const FnMut(Self::Item) + ~const Destruct, + Self: ~const Destruct, { #[inline] - fn call(mut f: impl FnMut(T)) -> impl FnMut((), T) { - move |(), item| f(item) + const fn call(f: &mut F, ((), item): ((), T)) { + f(item) } - self.fold((), call(f)); + self.fold((), ConstFnMutClosure::new(&mut f, call)); } /// Creates an iterator which uses a closure to determine if an element @@ -1461,7 +1482,8 @@ pub trait Iterator { where Self: Sized, U: IntoIterator, - F: FnMut(Self::Item) -> U, + F: ~const FnMut(Self::Item) -> U + ~const Destruct, + Self: ~const Destruct, { FlatMap::new(self, f) } @@ -1829,7 +1851,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] - fn collect>(self) -> B + fn collect>(self) -> B where Self: Sized, { @@ -1910,11 +1932,21 @@ pub trait Iterator { fn try_collect(&mut self) -> ChangeOutputType where Self: Sized, - ::Item: Try, - <::Item as Try>::Residual: Residual, - B: FromIterator<::Output>, + ::Item: ~const Try, + <::Item as Try>::Residual: ~const Residual + ~const Destruct, + B: ~const FromIterator<::Output> + ~const Destruct, { - try_process(ByRefSized(self), |i| i.collect()) + const fn collect<'a, T, R, O>(x: GenericShunt<'a, T, R>) -> O + where + T: ~const Iterator, + T::Item: ~const Try, + R: ~const Destruct, + O: ~const FromIterator<<::Item as Try>::Output>, + { + x.collect() + } + + try_process(ByRefSized(self), collect) } /// Collects all the items from an iterator into a collection. @@ -1980,7 +2012,7 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")] - fn collect_into>(self, collection: &mut E) -> &mut E + fn collect_into>(self, collection: &mut E) -> &mut E where Self: Sized, { @@ -2017,30 +2049,29 @@ pub trait Iterator { fn partition(self, f: F) -> (B, B) where Self: Sized, - B: Default + Extend, - F: FnMut(&Self::Item) -> bool, + B: ~const Default + ~const Extend + ~const Destruct, + F: ~const FnMut(&Self::Item) -> bool + ~const Destruct, + Self: ~const Destruct, { #[inline] - fn extend<'a, T, B: Extend>( - mut f: impl FnMut(&T) -> bool + 'a, - left: &'a mut B, - right: &'a mut B, - ) -> impl FnMut((), T) + 'a { - move |(), x| { - if f(&x) { - left.extend_one(x); - } else { - right.extend_one(x); - } + const fn extend bool, T, B: ~const Extend>( + (f, left, right): &mut (F, B, B), + ((), x): ((), T), + ) { + if f(&x) { + left.extend_one(x); + } else { + right.extend_one(x); } } - let mut left: B = Default::default(); - let mut right: B = Default::default(); + let left: B = Default::default(); + let right: B = Default::default(); + let mut tuple = (f, left, right); - self.fold((), extend(f, &mut left, &mut right)); + self.fold((), ConstFnMutClosure::new(&mut tuple, extend)); - (left, right) + (tuple.1, tuple.2) } /// Reorders the elements of this iterator *in-place* according to the given predicate, @@ -2078,8 +2109,9 @@ pub trait Iterator { #[unstable(feature = "iter_partition_in_place", reason = "new API", issue = "62543")] fn partition_in_place<'a, T: 'a, P>(mut self, ref mut predicate: P) -> usize where - Self: Sized + DoubleEndedIterator, - P: FnMut(&T) -> bool, + Self: Sized + ~const DoubleEndedIterator, + P: ~const FnMut(&T) -> bool + ~const Destruct, + Self: ~const Destruct, { // FIXME: should we worry about the count overflowing? The only way to have more than // `usize::MAX` mutable references is with ZSTs, which aren't useful to partition... @@ -2087,33 +2119,35 @@ pub trait Iterator { // These closure "factory" functions exist to avoid genericity in `Self`. #[inline] - fn is_false<'a, T>( - predicate: &'a mut impl FnMut(&T) -> bool, - true_count: &'a mut usize, - ) -> impl FnMut(&&mut T) -> bool + 'a { - move |x| { - let p = predicate(&**x); - *true_count += p as usize; - !p - } + const fn is_false bool, T>( + (predicate, true_count): &mut (F, usize), + (x,): (&&mut T,), + ) -> bool { + let p = predicate(&**x); + *true_count += p as usize; + !p } #[inline] - fn is_true(predicate: &mut impl FnMut(&T) -> bool) -> impl FnMut(&&mut T) -> bool + '_ { - move |x| predicate(&**x) + const fn is_true bool, T>( + predicate: &mut F, + (x,): (&&mut T,), + ) -> bool { + predicate(&**x) } // Repeatedly find the first `false` and swap it with the last `true`. - let mut true_count = 0; - while let Some(head) = self.find(is_false(predicate, &mut true_count)) { - if let Some(tail) = self.rfind(is_true(predicate)) { + let mut tuple = (predicate, 0); + let mut f = ConstFnMutClosure::new(&mut tuple, is_false); + while let Some(head) = self.find(&mut f) { + if let Some(tail) = self.rfind(ConstFnMutClosure::new(&mut f.data.0, is_true)) { crate::mem::swap(head, tail); - true_count += 1; + f.data.1 += 1; } else { break; } } - true_count + tuple.1 } /// Checks if the elements of this iterator are partitioned according to the given predicate, @@ -2136,7 +2170,9 @@ pub trait Iterator { fn is_partitioned

(mut self, mut predicate: P) -> bool where Self: Sized, - P: FnMut(Self::Item) -> bool, + P: ~const FnMut(Self::Item) -> bool + ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, { // Either all items test `true`, or the first clause stops at `false` // and we check that there are no more `true` items after that. @@ -2230,12 +2266,15 @@ pub trait Iterator { fn try_fold(&mut self, init: B, mut f: F) -> R where Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, + F: ~const FnMut(B, Self::Item) -> R + ~const Destruct, + R: ~const Try, { let mut accum = init; - while let Some(x) = self.next() { - accum = f(accum, x)?; + loop { + match self.next() { + Some(x) => accum = f(accum, x)?, + None => break, + } } try { accum } } @@ -2285,18 +2324,21 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] - fn try_for_each(&mut self, f: F) -> R + fn try_for_each(&mut self, mut f: F) -> R where Self: Sized, - F: FnMut(Self::Item) -> R, - R: Try, + F: ~const FnMut(Self::Item) -> R + ~const Destruct, + R: ~const Try, { #[inline] - fn call(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R { - move |(), x| f(x) + const fn call(f: &mut F, ((), x): ((), T)) -> R + where + F: ~const FnMut(T) -> R, + { + f(x) } - self.try_fold((), call(f)) + self.try_fold((), ConstFnMutClosure::new(&mut f, call)) } /// Folds every element into an accumulator by applying an operation, @@ -2407,11 +2449,15 @@ pub trait Iterator { fn fold(mut self, init: B, mut f: F) -> B where Self: Sized, - F: FnMut(B, Self::Item) -> B, + F: ~const FnMut(B, Self::Item) -> B + ~const Destruct, + Self: ~const Destruct, { let mut accum = init; - while let Some(x) = self.next() { - accum = f(accum, x); + loop { + match self.next() { + Some(x) => accum = f(accum, x), + None => break, + } } accum } @@ -2444,7 +2490,8 @@ pub trait Iterator { fn reduce(mut self, f: F) -> Option where Self: Sized, - F: FnMut(Self::Item, Self::Item) -> Self::Item, + F: ~const FnMut(Self::Item, Self::Item) -> Self::Item + ~const Destruct, + Self: ~const Destruct, { let first = self.next()?; Some(self.fold(first, f)) @@ -2515,9 +2562,9 @@ pub trait Iterator { fn try_reduce(&mut self, f: F) -> ChangeOutputType> where Self: Sized, - F: FnMut(Self::Item, Self::Item) -> R, - R: Try, - R::Residual: Residual>, + F: ~const FnMut(Self::Item, Self::Item) -> R + ~const Destruct, + R: ~const Try, + R::Residual: ~const Residual>, { let first = match self.next() { Some(i) => i, @@ -2569,18 +2616,19 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn all(&mut self, f: F) -> bool + fn all(&mut self, mut f: F) -> bool where Self: Sized, - F: FnMut(Self::Item) -> bool, + F: ~const FnMut(Self::Item) -> bool + ~const Destruct, { #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> { - move |(), x| { - if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } - } + const fn check bool, T>( + f: &mut F, + ((), x): ((), T), + ) -> ControlFlow<()> { + if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } } - self.try_fold((), check(f)) == ControlFlow::CONTINUE + matches!(self.try_fold((), ConstFnMutClosure::new(&mut f, check)), ControlFlow::CONTINUE) } /// Tests if any element of the iterator matches a predicate. @@ -2622,19 +2670,20 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn any(&mut self, f: F) -> bool + fn any(&mut self, mut f: F) -> bool where Self: Sized, - F: FnMut(Self::Item) -> bool, + F: ~const FnMut(Self::Item) -> bool + ~const Destruct, { #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> { - move |(), x| { - if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } - } + const fn check bool, T>( + f: &mut F, + ((), x): ((), T), + ) -> ControlFlow<()> { + if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } - self.try_fold((), check(f)) == ControlFlow::BREAK + matches!(self.try_fold((), ConstFnMutClosure::new(&mut f, check)), ControlFlow::BREAK) } /// Searches for an element of an iterator that satisfies a predicate. @@ -2682,19 +2731,22 @@ pub trait Iterator { /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn find

(&mut self, predicate: P) -> Option + fn find

(&mut self, mut predicate: P) -> Option where Self: Sized, - P: FnMut(&Self::Item) -> bool, + P: ~const FnMut(&Self::Item) -> bool + ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] - fn check(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow { - move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } - } + const fn check bool, T: ~const Destruct>( + predicate: &mut F, + ((), x): ((), T), + ) -> ControlFlow { + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } - self.try_fold((), check(predicate)).break_value() + self.try_fold((), ConstFnMutClosure::new(&mut predicate, check)).break_value() } /// Applies function to the elements of iterator and returns @@ -2713,20 +2765,23 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_find_map", since = "1.30.0")] - fn find_map(&mut self, f: F) -> Option + fn find_map(&mut self, mut f: F) -> Option where Self: Sized, - F: FnMut(Self::Item) -> Option, + F: ~const FnMut(Self::Item) -> Option + ~const Destruct, { #[inline] - fn check(mut f: impl FnMut(T) -> Option) -> impl FnMut((), T) -> ControlFlow { - move |(), x| match f(x) { + const fn check(f: &mut F, ((), x): ((), T)) -> ControlFlow + where + F: ~const FnMut(T) -> Option, + { + match f(x) { Some(x) => ControlFlow::Break(x), None => ControlFlow::CONTINUE, } } - self.try_fold((), check(f)).break_value() + self.try_fold((), ConstFnMutClosure::new(&mut f, check)).break_value() } /// Applies function to the elements of iterator and returns @@ -2769,29 +2824,30 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] - fn try_find(&mut self, f: F) -> ChangeOutputType> + fn try_find(&mut self, mut f: F) -> ChangeOutputType> where Self: Sized, - F: FnMut(&Self::Item) -> R, - R: Try, - R::Residual: Residual>, + F: ~const FnMut(&Self::Item) -> R + ~const Destruct, + R: ~const Try, + R::Residual: ~const Residual>, + Self::Item: ~const Destruct, { #[inline] - fn check( - mut f: impl FnMut(&I) -> V, - ) -> impl FnMut((), I) -> ControlFlow + const fn check(f: &mut F, ((), x): ((), I)) -> ControlFlow where - V: Try, - R: Residual>, + F: ~const FnMut(&I) -> V, + V: ~const Try, + R: ~const Residual>, + I: ~const Destruct, { - move |(), x| match f(&x).branch() { + match f(&x).branch() { ControlFlow::Continue(false) => ControlFlow::CONTINUE, ControlFlow::Continue(true) => ControlFlow::Break(Try::from_output(Some(x))), ControlFlow::Break(r) => ControlFlow::Break(FromResidual::from_residual(r)), } } - match self.try_fold((), check(f)) { + match self.try_fold((), ConstFnMutClosure::new(&mut f, check)) { ControlFlow::Break(x) => x, ControlFlow::Continue(()) => Try::from_output(None), } @@ -2851,22 +2907,22 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn position

(&mut self, predicate: P) -> Option + fn position

(&mut self, mut predicate: P) -> Option where Self: Sized, - P: FnMut(Self::Item) -> bool, + P: ~const FnMut(Self::Item) -> bool + ~const Destruct, + Self::Item: ~const Destruct, { #[inline] - fn check( - mut predicate: impl FnMut(T) -> bool, - ) -> impl FnMut(usize, T) -> ControlFlow { - #[rustc_inherit_overflow_checks] - move |i, x| { - if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i + 1) } - } + #[rustc_inherit_overflow_checks] + const fn check bool, T>( + predicate: &mut F, + (i, x): (usize, T), + ) -> ControlFlow { + if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i + 1) } } - self.try_fold(0, check(predicate)).break_value() + self.try_fold(0, ConstFnMutClosure::new(&mut predicate, check)).break_value() } /// Searches for an element in an iterator from the right, returning its @@ -2908,25 +2964,25 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn rposition

(&mut self, predicate: P) -> Option + fn rposition

(self) -> P where Self: Sized, - P: Product, + P: ~const Product, { Product::product(self) } @@ -3425,11 +3506,18 @@ pub trait Iterator { #[stable(feature = "iter_order", since = "1.5.0")] fn cmp(self, other: I) -> Ordering where - I: IntoIterator, - Self::Item: Ord, + I: ~const IntoIterator, + Self::Item: ~const Ord + ~const Destruct, + I::IntoIter: ~const Destruct, + I::Item: ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, Self: Sized, { - self.cmp_by(other, |x, y| x.cmp(&y)) + const fn cmp(x: T, y: T) -> Ordering { + x.cmp(&y) + } + self.cmp_by(other, cmp) } /// [Lexicographically](Ord#lexicographical-comparison) compares the elements of this [`Iterator`] with those @@ -3455,8 +3543,12 @@ pub trait Iterator { fn cmp_by(self, other: I, cmp: F) -> Ordering where Self: Sized, - I: IntoIterator, - F: FnMut(Self::Item, I::Item) -> Ordering, + I: ~const IntoIterator, + F: ~const FnMut(Self::Item, I::Item) -> Ordering + ~const Destruct, + I::IntoIter: ~const Destruct, + I::Item: ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] fn compare(mut cmp: F) -> impl FnMut(X, Y) -> ControlFlow @@ -3492,11 +3584,19 @@ pub trait Iterator { #[stable(feature = "iter_order", since = "1.5.0")] fn partial_cmp(self, other: I) -> Option where - I: IntoIterator, - Self::Item: PartialOrd, - Self: Sized, - { - self.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + I: ~const IntoIterator, + Self::Item: ~const PartialOrd + ~const Destruct, + I::Item: ~const Destruct, + I::IntoIter: ~const Destruct, + Self: ~const Destruct + Sized, + { + const fn partial_cmp + ~const Destruct, B: ~const Destruct>( + a: A, + b: B, + ) -> Option { + a.partial_cmp(&b) + } + self.partial_cmp_by(other, partial_cmp) } /// [Lexicographically](Ord#lexicographical-comparison) compares the elements of this [`Iterator`] with those @@ -3531,8 +3631,12 @@ pub trait Iterator { fn partial_cmp_by(self, other: I, partial_cmp: F) -> Option where Self: Sized, - I: IntoIterator, - F: FnMut(Self::Item, I::Item) -> Option, + I: ~const IntoIterator, + F: ~const FnMut(Self::Item, I::Item) -> Option + ~const Destruct, + I::IntoIter: ~const Destruct, + I::Item: ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] fn compare(mut partial_cmp: F) -> impl FnMut(X, Y) -> ControlFlow> @@ -3563,11 +3667,21 @@ pub trait Iterator { #[stable(feature = "iter_order", since = "1.5.0")] fn eq(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialEq, + I: ~const IntoIterator, + Self::Item: ~const PartialEq + ~const Destruct, + I::IntoIter: ~const Destruct, + I::Item: ~const Destruct, + Self: ~const Destruct, Self: Sized, { - self.eq_by(other, |x, y| x == y) + const fn eq + ~const Destruct, B: ~const Destruct>( + a: A, + b: B, + ) -> bool { + a == b + } + + self.eq_by(other, eq) } /// Determines if the elements of this [`Iterator`] are equal to those of @@ -3589,8 +3703,12 @@ pub trait Iterator { fn eq_by(self, other: I, eq: F) -> bool where Self: Sized, - I: IntoIterator, - F: FnMut(Self::Item, I::Item) -> bool, + I: ~const IntoIterator, + I::IntoIter: ~const Destruct, + F: ~const FnMut(Self::Item, I::Item) -> bool + ~const Destruct, + Self::Item: ~const Destruct, + I::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] fn compare(mut eq: F) -> impl FnMut(X, Y) -> ControlFlow<()> @@ -3620,8 +3738,11 @@ pub trait Iterator { #[stable(feature = "iter_order", since = "1.5.0")] fn ne(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialEq, + I: ~const IntoIterator, + Self::Item: ~const PartialEq + ~const Destruct, + I::Item: ~const Destruct, + I::IntoIter: ~const Destruct, + Self: ~const Destruct, Self: Sized, { !self.eq(other) @@ -3641,11 +3762,14 @@ pub trait Iterator { #[stable(feature = "iter_order", since = "1.5.0")] fn lt(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialOrd, + I: ~const IntoIterator, + Self::Item: ~const PartialOrd + ~const Destruct, + I::Item: ~const Destruct, + I::IntoIter: ~const Destruct, + Self: ~const Destruct, Self: Sized, { - self.partial_cmp(other) == Some(Ordering::Less) + matches!(self.partial_cmp(other), Some(Ordering::Less)) } /// Determines if the elements of this [`Iterator`] are [lexicographically](Ord#lexicographical-comparison) @@ -3662,8 +3786,11 @@ pub trait Iterator { #[stable(feature = "iter_order", since = "1.5.0")] fn le(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialOrd, + I: ~const IntoIterator, + Self::Item: ~const PartialOrd + ~const Destruct, + I::Item: ~const Destruct, + I::IntoIter: ~const Destruct, + Self: ~const Destruct, Self: Sized, { matches!(self.partial_cmp(other), Some(Ordering::Less | Ordering::Equal)) @@ -3683,11 +3810,14 @@ pub trait Iterator { #[stable(feature = "iter_order", since = "1.5.0")] fn gt(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialOrd, + I: ~const IntoIterator, + Self::Item: ~const PartialOrd + ~const Destruct, + I::Item: ~const Destruct, + I::IntoIter: ~const Destruct, + Self: ~const Destruct, Self: Sized, { - self.partial_cmp(other) == Some(Ordering::Greater) + matches!(self.partial_cmp(other), Some(Ordering::Greater)) } /// Determines if the elements of this [`Iterator`] are [lexicographically](Ord#lexicographical-comparison) @@ -3704,9 +3834,11 @@ pub trait Iterator { #[stable(feature = "iter_order", since = "1.5.0")] fn ge(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialOrd, - Self: Sized, + I: ~const IntoIterator, + Self::Item: ~const PartialOrd + ~const Destruct, + I::Item: ~const Destruct, + I::IntoIter: ~const Destruct, + Self: ~const Destruct + Sized, { matches!(self.partial_cmp(other), Some(Ordering::Greater | Ordering::Equal)) } @@ -3736,9 +3868,13 @@ pub trait Iterator { fn is_sorted(self) -> bool where Self: Sized, - Self::Item: PartialOrd, + Self::Item: ~const PartialOrd + ~const Destruct, + Self: ~const Destruct, { - self.is_sorted_by(PartialOrd::partial_cmp) + const fn partial_cmp(x: &T, y: &T) -> Option { + x.partial_cmp(y) + } + self.is_sorted_by(partial_cmp) } /// Checks if the elements of this iterator are sorted using the given comparator function. @@ -3764,28 +3900,30 @@ pub trait Iterator { fn is_sorted_by(mut self, compare: F) -> bool where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Option, + F: ~const FnMut(&Self::Item, &Self::Item) -> Option + ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] - fn check<'a, T>( - last: &'a mut T, - mut compare: impl FnMut(&T, &T) -> Option + 'a, - ) -> impl FnMut(T) -> bool + 'a { - move |curr| { - if let Some(Ordering::Greater) | None = compare(&last, &curr) { - return false; - } - *last = curr; - true + const fn check Option>( + (last, compare): &mut (T, F), + (curr,): (T,), + ) -> bool { + if let Some(Ordering::Greater) | None = compare(&last, &curr) { + return false; } + *last = curr; + true } - let mut last = match self.next() { + let last = match self.next() { Some(e) => e, None => return true, }; - self.all(check(&mut last, compare)) + let mut tupled = (last, compare); + + self.all(ConstFnMutClosure::new(&mut tupled, check)) } /// Checks if the elements of this iterator are sorted using the given key extraction @@ -3810,8 +3948,9 @@ pub trait Iterator { fn is_sorted_by_key(self, f: F) -> bool where Self: Sized, - F: FnMut(Self::Item) -> K, - K: PartialOrd, + F: ~const FnMut(Self::Item) -> K + ~const Destruct, + K: ~const PartialOrd + ~const Destruct, + Self: ~const Destruct, { self.map(f).is_sorted() } @@ -3826,7 +3965,8 @@ pub trait Iterator { where Self: TrustedRandomAccessNoCoerce, { - unreachable!("Always specialized"); + // FIXME(const_trait_impl): replace with unreachable when formatting is const + panic!("internal error: entered unreachable code: Always specialized"); } } @@ -3871,7 +4011,8 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for &mut I { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Iterator for &mut I { type Item = I::Item; #[inline] fn next(&mut self) -> Option { @@ -3880,10 +4021,16 @@ impl Iterator for &mut I { fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> Result<(), usize> + where + I::Item: ~const Destruct, + { (**self).advance_by(n) } - fn nth(&mut self, n: usize) -> Option { + fn nth(&mut self, n: usize) -> Option + where + I::Item: ~const Destruct, + { (**self).nth(n) } } diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index da753745740d7..dd25794039733 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -75,4 +75,5 @@ pub unsafe trait InPlaceIterable: Iterator {} /// for details. Consumers are free to rely on the invariants in unsafe code. #[unstable(feature = "trusted_step", issue = "85731")] #[rustc_specialization_trait] -pub unsafe trait TrustedStep: Step {} +#[const_trait] +pub unsafe trait TrustedStep: ~const Step {} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 848eccd7f2908..727aed856c3b5 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -107,23 +107,30 @@ #![feature(const_char_from_u32_unchecked)] #![feature(const_clone)] #![feature(const_cmp)] +#![feature(const_control_flow)] #![feature(const_discriminant)] #![feature(const_eval_select)] #![feature(const_exact_div)] +#![feature(const_extend)] +#![feature(const_for)] #![feature(const_float_bits_conv)] #![feature(const_float_classify)] #![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] #![feature(const_convert)] +#![feature(const_iter)] #![feature(const_index_range_slice_index)] #![feature(const_inherent_unchecked_arith)] #![feature(const_int_unchecked_arith)] #![feature(const_intrinsic_forget)] #![feature(const_likely)] -#![feature(const_maybe_uninit_uninit_array)] +#![feature(const_maybe_uninit_array_assume_init)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init)] +#![feature(const_maybe_uninit_uninit_array)] +#![feature(const_maybe_uninit_write)] +#![feature(const_maybe_uninit_zeroed)] #![feature(const_nonnull_new)] #![feature(const_num_from_num)] #![feature(const_ops)] @@ -132,13 +139,13 @@ #![feature(const_pin)] #![feature(const_pointer_is_aligned)] #![feature(const_ptr_sub_ptr)] -#![feature(const_replace)] -#![feature(const_result_drop)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_is_null)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_raw_ptr_comparison)] +#![feature(const_replace)] +#![feature(const_result_drop)] #![feature(const_size_of_val)] #![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_ptr_len)] diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index cd183540cd5e9..d4b835ee2d216 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -1,3 +1,4 @@ +use crate::marker::Destruct; use crate::{convert, ops}; /// Used to tell an operation whether it should exit early or go on as usual. @@ -180,9 +181,13 @@ impl ControlFlow { /// ``` #[inline] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub fn break_value(self) -> Option { + #[rustc_const_unstable(feature = "const_control_flow", issue = "none")] + pub const fn break_value(self) -> Option + where + C: ~const Destruct, + { match self { - ControlFlow::Continue(..) => None, + ControlFlow::Continue(_x) => None, ControlFlow::Break(x) => Some(x), } } @@ -243,7 +248,10 @@ impl ControlFlow { impl ControlFlow { /// Create a `ControlFlow` from any type implementing `Try`. #[inline] - pub(crate) fn from_try(r: R) -> Self { + pub(crate) const fn from_try(r: R) -> Self + where + R: ~const ops::Try, + { match R::branch(r) { ControlFlow::Continue(v) => ControlFlow::Continue(v), ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)), @@ -252,7 +260,10 @@ impl ControlFlow { /// Convert a `ControlFlow` into any type implementing `Try`; #[inline] - pub(crate) fn into_try(self) -> R { + pub(crate) const fn into_try(self) -> R + where + R: ~const ops::Try, + { match self { ControlFlow::Continue(v) => R::from_output(v), ControlFlow::Break(v) => v, diff --git a/library/core/src/option.rs b/library/core/src/option.rs index f284b43595576..dbc8dde200342 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1924,7 +1924,8 @@ impl const Default for Option { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for Option { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const IntoIterator for Option { type Item = T; type IntoIter = IntoIter; @@ -2044,7 +2045,8 @@ struct Item { opt: Option, } -impl Iterator for Item { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Iterator for Item { type Item = A; #[inline] @@ -2175,7 +2177,8 @@ pub struct IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Iterator for IntoIter { type Item = A; #[inline] diff --git a/src/test/ui/issues/issue-23966.stderr b/src/test/ui/issues/issue-23966.stderr index ae8233d5c76e6..3f48c93603ee9 100644 --- a/src/test/ui/issues/issue-23966.stderr +++ b/src/test/ui/issues/issue-23966.stderr @@ -10,8 +10,8 @@ LL | "".chars().fold(|_, _| (), ()); note: required by a bound in `fold` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | F: FnMut(B, Self::Item) -> B, - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `fold` +LL | F: ~const FnMut(B, Self::Item) -> B + ~const Destruct, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `fold` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index 72082f0cd1728..9bbe55c814a5a 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -25,8 +25,8 @@ LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_rece note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn collect>(self) -> B - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` +LL | fn collect>(self) -> B + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr index 2de1503765082..b769b50787538 100644 --- a/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr +++ b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr @@ -11,8 +11,8 @@ LL | let x2: Vec = x1.into_iter().collect(); note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn collect>(self) -> B - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` +LL | fn collect>(self) -> B + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` error[E0277]: a value of type `Vec` cannot be built from an iterator over elements of type `&f64` --> $DIR/issue-66923-show-error-for-correct-call.rs:12:14 @@ -27,8 +27,8 @@ LL | let x3 = x1.into_iter().collect::>(); note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn collect>(self) -> B - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` +LL | fn collect>(self) -> B + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` error: aborting due to 2 previous errors diff --git a/src/test/ui/iterators/collect-into-array.stderr b/src/test/ui/iterators/collect-into-array.stderr index a23a36a88abb3..8324c0a9e1dc4 100644 --- a/src/test/ui/iterators/collect-into-array.stderr +++ b/src/test/ui/iterators/collect-into-array.stderr @@ -10,8 +10,8 @@ LL | let whatever: [u32; 10] = (0..10).collect(); note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn collect>(self) -> B - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` +LL | fn collect>(self) -> B + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` error: aborting due to previous error diff --git a/src/test/ui/iterators/collect-into-slice.stderr b/src/test/ui/iterators/collect-into-slice.stderr index bc152467ce3a5..376479df61940 100644 --- a/src/test/ui/iterators/collect-into-slice.stderr +++ b/src/test/ui/iterators/collect-into-slice.stderr @@ -18,7 +18,7 @@ LL | let some_generated_vec = (0..10).collect(); note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn collect>(self) -> B +LL | fn collect>(self) -> B | ^ required by this bound in `collect` error[E0277]: a slice of type `[i32]` cannot be built since `[i32]` has no definite size @@ -33,8 +33,8 @@ LL | let some_generated_vec = (0..10).collect(); note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn collect>(self) -> B - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` +LL | fn collect>(self) -> B + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` error: aborting due to 3 previous errors diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches.stderr b/src/test/ui/lazy-type-alias-impl-trait/branches.stderr index 33f82448dd2ac..acc73d149b7df 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/branches.stderr +++ b/src/test/ui/lazy-type-alias-impl-trait/branches.stderr @@ -10,8 +10,8 @@ LL | std::iter::empty().collect() note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn collect>(self) -> B - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` +LL | fn collect>(self) -> B + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` error: aborting due to previous error diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion4.stderr b/src/test/ui/lazy-type-alias-impl-trait/recursion4.stderr index 57978edf2bf05..b8f6582a7b2b6 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/recursion4.stderr +++ b/src/test/ui/lazy-type-alias-impl-trait/recursion4.stderr @@ -10,8 +10,8 @@ LL | x = std::iter::empty().collect(); note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn collect>(self) -> B - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` +LL | fn collect>(self) -> B + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` error[E0277]: a value of type `impl Debug` cannot be built from an iterator over elements of type `_` --> $DIR/recursion4.rs:19:9 @@ -25,8 +25,8 @@ LL | x = std::iter::empty().collect(); note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn collect>(self) -> B - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` +LL | fn collect>(self) -> B + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/derive-clone-for-eq.stderr b/src/test/ui/suggestions/derive-clone-for-eq.stderr index 0645f0cdde7c0..e5c244692bb28 100644 --- a/src/test/ui/suggestions/derive-clone-for-eq.stderr +++ b/src/test/ui/suggestions/derive-clone-for-eq.stderr @@ -12,8 +12,8 @@ LL | impl PartialEq for Struct note: required by a bound in `Eq` --> $SRC_DIR/core/src/cmp.rs:LL:COL | -LL | pub trait Eq: PartialEq { - | ^^^^^^^^^^^^^^^ required by this bound in `Eq` +LL | pub trait Eq: ~const PartialEq { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Eq` = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | diff --git a/src/test/ui/traits/alias/object-fail.stderr b/src/test/ui/traits/alias/object-fail.stderr index 325bc6d280859..a2ed0948b6862 100644 --- a/src/test/ui/traits/alias/object-fail.stderr +++ b/src/test/ui/traits/alias/object-fail.stderr @@ -7,8 +7,8 @@ LL | let _: &dyn EqAlias = &123; note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/cmp.rs:LL:COL | -LL | pub trait Eq: PartialEq { - | ^^^^^^^^^^^^^^^ the trait cannot be made into an object because it uses `Self` as a type parameter +LL | pub trait Eq: ~const PartialEq { + | ^^^^^^^^^^^^^^^^^^^^^^ the trait cannot be made into an object because it uses `Self` as a type parameter error[E0191]: the value of the associated type `Item` (from trait `Iterator`) must be specified --> $DIR/object-fail.rs:9:17 From 7d2c911596d0c68c9d45087cdd9c8583e0d927fa Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 24 Sep 2022 06:48:17 +0000 Subject: [PATCH 2/4] Add libcore test --- library/core/src/iter/adapters/zip.rs | 5 +++-- library/core/tests/iter/mod.rs | 15 +++++++++++++++ library/core/tests/lib.rs | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 9f6e86ba2d9b4..6bcd2eea57e01 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -375,7 +375,8 @@ where if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len { // FIXME(const_trait_impl): replace with `for` let mut i = 0; - while i < sz_a - self.len { + let upper_bound = sz_a - self.len; + while i < upper_bound { // since next_back() may panic we increment the counters beforehand // to keep Zip's state in sync with the underlying iterator source self.a_len -= 1; @@ -401,7 +402,7 @@ where if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len { // FIXME(const_trait_impl): replace with `for` let mut i = 0; - while i < sz_a - self.len { + while i < sz_b - self.len { self.b.next_back(); i += 1; } diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs index 770b6f7601fa2..959fcbd887c3a 100644 --- a/library/core/tests/iter/mod.rs +++ b/library/core/tests/iter/mod.rs @@ -100,3 +100,18 @@ pub fn extend_for_unit() { } assert_eq!(x, 5); } + +#[test] +fn test_const_iter() { + const X: usize = { + let mut n = 0; + #[allow(for_loops_over_fallibles)] + for a in Some(1) { + n = a; + } + n + }; + + const _: () = assert!(X == 1); + assert_eq!(1, X); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 4c0c0da652f95..a895a63363214 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -13,7 +13,9 @@ #![feature(const_cell_into_inner)] #![feature(const_convert)] #![feature(const_hash)] +#![feature(const_for)] #![feature(const_heap)] +#![feature(const_iter)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] From 8249c6cc2615cf07c9827df571a04936736781a3 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 25 Sep 2022 13:15:22 +0000 Subject: [PATCH 3/4] rebased --- library/core/src/array/mod.rs | 30 ++++++-- library/core/src/cmp.rs | 3 +- library/core/src/const_closure.rs | 1 + library/core/src/iter/adapters/map.rs | 1 + library/core/src/iter/adapters/mod.rs | 1 + library/core/src/iter/adapters/zip.rs | 8 ++- library/core/src/iter/mod.rs | 3 +- library/core/src/iter/range.rs | 1 + library/core/src/iter/traits/accum.rs | 2 + library/core/src/iter/traits/collect.rs | 3 +- library/core/src/iter/traits/double_ended.rs | 44 ++++++++---- library/core/src/iter/traits/iterator.rs | 75 ++++++++++++-------- library/core/src/lib.rs | 1 + library/core/src/tuple.rs | 3 +- src/test/ui/consts/const-fn-error.stderr | 4 +- src/test/ui/consts/const-for.stderr | 4 +- src/test/ui/never_type/issue-52443.stderr | 4 +- 17 files changed, 125 insertions(+), 63 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index be11cd0fd2de3..4513cf55ed83d 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -916,7 +916,7 @@ where /// /// To minimize indirection fields are still pub but callers should at least use /// `push_unchecked` to signal that something unsafe is going on. -pub(crate) struct Guard<'a, T, const N: usize> { +pub(crate) struct Guard<'a, T: ~const Destruct, const N: usize> { /// The array to be initialized. pub array_mut: &'a mut [MaybeUninit; N], /// The number of items that have been initialized so far. @@ -930,7 +930,7 @@ impl Guard<'_, T, N> { /// /// No more than N elements must be initialized. #[inline] - pub unsafe fn push_unchecked(&mut self, item: T) { + pub const unsafe fn push_unchecked(&mut self, item: T) { // SAFETY: If `initialized` was correct before and the caller does not // invoke this method more than N times then writes will be in-bounds // and slots will not be initialized more than once. @@ -941,15 +941,33 @@ impl Guard<'_, T, N> { } } -impl Drop for Guard<'_, T, N> { +impl const Drop for Guard<'_, T, N> { fn drop(&mut self) { debug_assert!(self.initialized <= N); + #[inline] + const fn drop_ct(x: &mut [T]) { + let mut i = 0; + while i < x.len() { + // SAFETY: dropping the value, contains initialized objects + unsafe { + crate::ptr::read(&mut x[i]); + } + i += 1; + } + } + #[inline] + fn drop_rt(x: &mut [T]) { + // SAFETY: slice contains initialized objects + unsafe { crate::ptr::drop_in_place(x) } + } + // SAFETY: this slice will contain only initialized objects. unsafe { - crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( - &mut self.array_mut.get_unchecked_mut(..self.initialized), - )); + let to_drop = MaybeUninit::slice_assume_init_mut( + self.array_mut.get_unchecked_mut(..self.initialized), + ); + crate::intrinsics::const_eval_select((to_drop,), drop_ct, drop_rt); } } } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 6da9f745399e1..aa198cbbd1c63 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1223,7 +1223,7 @@ pub const fn min(v1: T, v2: T) -> T { #[stable(feature = "cmp_min_max_by", since = "1.53.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] pub const fn min_by Ordering>(v1: T, v2: T, compare: F) -> T -where +where T: ~const Destruct, { match compare(&v1, &v2) { @@ -1309,6 +1309,7 @@ pub const fn max(v1: T, v2: T) -> T { pub const fn max_by Ordering>(v1: T, v2: T, compare: F) -> T where T: ~const Destruct, +{ match compare(&v1, &v2) { Ordering::Less | Ordering::Equal => v2, Ordering::Greater => v1, diff --git a/library/core/src/const_closure.rs b/library/core/src/const_closure.rs index 151c8e6d8986a..541198624f1a3 100644 --- a/library/core/src/const_closure.rs +++ b/library/core/src/const_closure.rs @@ -25,6 +25,7 @@ pub(crate) struct ConstFnMutClosure { /// The Function of the Closure, must be: Fn(CapturedData, ClosureArgs) -> ClosureReturn pub func: Function, } + impl<'a, CapturedData: ?Sized, Function> ConstFnMutClosure<&'a mut CapturedData, Function> { /// Function for creating a new closure. /// diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 9a99cf274645f..8e06d332cdef1 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -1,3 +1,4 @@ +use crate::const_closure::ConstFnMutClosure; use crate::fmt; use crate::iter::adapters::{ zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 0c20b35613835..a707d96eae464 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,3 +1,4 @@ +use crate::const_closure::ConstFnMutClosure; use crate::iter::{InPlaceIterable, Iterator}; use crate::marker::Destruct; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 6bcd2eea57e01..2a6faf4df9257 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -171,8 +171,9 @@ macro_rules! zip_impl_general_defaults { #[inline] #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_try, const_for))] default fn next(&mut self) -> Option<(A::Item, B::Item)> { - let x = self.a.next()?; - let y = self.b.next()?; + // FIXME(const_trait_impl): revert to `?` when we can + let Some(x) = self.a.next() else { return None }; + let Some(y) = self.b.next() else { return None }; Some((x, y)) } @@ -586,11 +587,12 @@ pub unsafe trait TrustedRandomAccess: ~const TrustedRandomAccessNoCoerce {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] #[rustc_specialization_trait] +#[const_trait] pub unsafe trait TrustedRandomAccessNoCoerce: Sized { // Convenience method. fn size(&self) -> usize where - Self: Iterator, + Self: ~const Iterator, { self.size_hint().0 } diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index bb35d50b4bfda..84b6712d7c1ab 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -364,7 +364,8 @@ macro_rules! impl_fold_via_try_fold { #[inline] fn $fold(mut self, init: AAA, mut fold: FFF) -> AAA where - FFF: FnMut(AAA, Self::Item) -> AAA, + FFF: ~const FnMut(AAA, Self::Item) -> AAA + ~const crate::marker::Destruct, + Self: ~const crate::marker::Destruct, { use crate::const_closure::ConstFnMutClosure; use crate::ops::NeverShortCircuit; diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index ac7b389b15b4d..a52753f5753eb 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -21,6 +21,7 @@ unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usi /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +#[const_trait] pub trait Step: Clone + PartialOrd + Sized { /// Returns the number of *successor* steps required to get from `start` to `end`. /// diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 84d83ee39699f..9d71ae02837fc 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -10,6 +10,7 @@ use crate::num::Wrapping; /// [`sum()`]: Iterator::sum /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] +#[const_trait] pub trait Sum: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// "summing up" the items. @@ -27,6 +28,7 @@ pub trait Sum: Sized { /// [`product()`]: Iterator::product /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] +#[const_trait] pub trait Product: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// multiplying the items. diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 3b7c06f238b4d..10331c0c301f5 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -122,6 +122,7 @@ use crate::marker::Destruct; label = "value of type `{Self}` cannot be built from `std::iter::Iterator`" )] #[rustc_diagnostic_item = "FromIterator"] +#[const_trait] pub trait FromIterator: Sized { /// Creates a value from an iterator. /// @@ -267,7 +268,7 @@ pub trait IntoIterator { #[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")] #[stable(feature = "rust1", since = "1.0.0")] -impl const IntoIterator for I { +impl const IntoIterator for I { type Item = I::Item; type IntoIter = I; diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index bdf94c792c27c..3f2d9a5733bfc 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,3 +1,5 @@ +use crate::const_closure::ConstFnMutClosure; +use crate::marker::Destruct; use crate::ops::{ControlFlow, Try}; /// An iterator able to yield elements from both ends. @@ -37,6 +39,7 @@ use crate::ops::{ControlFlow, Try}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")] +#[const_trait] pub trait DoubleEndedIterator: Iterator { /// Removes and returns an element from the end of the iterator. /// @@ -131,9 +134,15 @@ pub trait DoubleEndedIterator: Iterator { /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - for i in 0..n { + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> + where + Self::Item: ~const Destruct, + { + // FIXME(const_trait_impl): revert back to for loop + let mut i = 0; + while i < n { self.next_back().ok_or(i)?; + i += 1; } Ok(()) } @@ -181,7 +190,10 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_nth_back", since = "1.37.0")] - fn nth_back(&mut self, n: usize) -> Option { + fn nth_back(&mut self, n: usize) -> Option + where + Self::Item: ~const Destruct, + { self.advance_back_by(n).ok()?; self.next_back() } @@ -221,8 +233,9 @@ pub trait DoubleEndedIterator: Iterator { fn try_rfold(&mut self, init: B, mut f: F) -> R where Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, + F: ~const FnMut(B, Self::Item) -> R + ~const Destruct, + R: ~const Try, + Self::Item: ~const Destruct, { let mut accum = init; while let Some(x) = self.next_back() { @@ -291,8 +304,9 @@ pub trait DoubleEndedIterator: Iterator { #[stable(feature = "iter_rfold", since = "1.27.0")] fn rfold(mut self, init: B, mut f: F) -> B where - Self: Sized, - F: FnMut(B, Self::Item) -> B, + Self: Sized + ~const Destruct, + F: ~const FnMut(B, Self::Item) -> B + ~const Destruct, + Self::Item: ~const Destruct, { let mut accum = init; while let Some(x) = self.next_back() { @@ -344,19 +358,21 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_rfind", since = "1.27.0")] - fn rfind

(&mut self, predicate: P) -> Option + fn rfind

(&mut self, mut predicate: P) -> Option where Self: Sized, - P: FnMut(&Self::Item) -> bool, + P: ~const FnMut(&Self::Item) -> bool + ~const Destruct, + Self::Item: ~const Destruct, { #[inline] - fn check(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow { - move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } - } + const fn check bool>( + predicate: &mut F, + ((), x): ((), T), + ) -> ControlFlow { + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } - self.try_rfold((), check(predicate)).break_value() + self.try_rfold((), ConstFnMutClosure::new(&mut predicate, check)).break_value() } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 193e3294be98d..84c6ce2565a6b 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3540,7 +3540,7 @@ pub trait Iterator { /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] - fn cmp_by(self, other: I, cmp: F) -> Ordering + fn cmp_by(self, other: I, mut cmp: F) -> Ordering where Self: Sized, I: ~const IntoIterator, @@ -3551,17 +3551,17 @@ pub trait Iterator { Self: ~const Destruct, { #[inline] - fn compare(mut cmp: F) -> impl FnMut(X, Y) -> ControlFlow + const fn compare(cmp: &mut F, (x, y): (X, Y)) -> ControlFlow where - F: FnMut(X, Y) -> Ordering, + F: ~const FnMut(X, Y) -> Ordering, { - move |x, y| match cmp(x, y) { + match cmp(x, y) { Ordering::Equal => ControlFlow::CONTINUE, non_eq => ControlFlow::Break(non_eq), } } - match iter_compare(self, other.into_iter(), compare(cmp)) { + match iter_compare(self, other.into_iter(), ConstFnMutClosure::new(&mut cmp, compare)) { ControlFlow::Continue(ord) => ord, ControlFlow::Break(ord) => ord, } @@ -3628,7 +3628,7 @@ pub trait Iterator { /// ); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] - fn partial_cmp_by(self, other: I, partial_cmp: F) -> Option + fn partial_cmp_by(self, other: I, mut partial_cmp: F) -> Option where Self: Sized, I: ~const IntoIterator, @@ -3639,17 +3639,24 @@ pub trait Iterator { Self: ~const Destruct, { #[inline] - fn compare(mut partial_cmp: F) -> impl FnMut(X, Y) -> ControlFlow> + const fn compare( + partial_cmp: &mut F, + (x, y): (X, Y), + ) -> ControlFlow> where - F: FnMut(X, Y) -> Option, + F: ~const FnMut(X, Y) -> Option, { - move |x, y| match partial_cmp(x, y) { + match partial_cmp(x, y) { Some(Ordering::Equal) => ControlFlow::CONTINUE, non_eq => ControlFlow::Break(non_eq), } } - match iter_compare(self, other.into_iter(), compare(partial_cmp)) { + match iter_compare( + self, + other.into_iter(), + ConstFnMutClosure::new(&mut partial_cmp, compare), + ) { ControlFlow::Continue(ord) => Some(ord), ControlFlow::Break(ord) => ord, } @@ -3700,7 +3707,7 @@ pub trait Iterator { /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y)); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] - fn eq_by(self, other: I, eq: F) -> bool + fn eq_by(self, other: I, mut eq: F) -> bool where Self: Sized, I: ~const IntoIterator, @@ -3711,16 +3718,14 @@ pub trait Iterator { Self: ~const Destruct, { #[inline] - fn compare(mut eq: F) -> impl FnMut(X, Y) -> ControlFlow<()> + const fn compare(eq: &mut F, (x, y): (X, Y)) -> ControlFlow<()> where - F: FnMut(X, Y) -> bool, + F: ~const FnMut(X, Y) -> bool, { - move |x, y| { - if eq(x, y) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } - } + if eq(x, y) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } } - match iter_compare(self, other.into_iter(), compare(eq)) { + match iter_compare(self, other.into_iter(), ConstFnMutClosure::new(&mut eq, compare)) { ControlFlow::Continue(ord) => ord == Ordering::Equal, ControlFlow::Break(()) => false, } @@ -3981,28 +3986,38 @@ pub trait Iterator { /// Isolates the logic shared by ['cmp_by'](Iterator::cmp_by), /// ['partial_cmp_by'](Iterator::partial_cmp_by), and ['eq_by'](Iterator::eq_by). #[inline] -fn iter_compare(mut a: A, mut b: B, f: F) -> ControlFlow +const fn iter_compare(mut a: A, b: B, f: F) -> ControlFlow where - A: Iterator, - B: Iterator, - F: FnMut(A::Item, B::Item) -> ControlFlow, + A: ~const Iterator + ~const Destruct, + B: ~const Iterator + ~const Destruct, + A::Item: ~const Destruct, + B::Item: ~const Destruct, + F: ~const FnMut(A::Item, B::Item) -> ControlFlow + ~const Destruct, { #[inline] - fn compare<'a, B, X, T>( - b: &'a mut B, - mut f: impl FnMut(X, B::Item) -> ControlFlow + 'a, - ) -> impl FnMut(X) -> ControlFlow> + 'a + const fn compare<'a, B, F, X, T>( + (b, f): &'a mut (B, F), + (x,): (X,), + ) -> ControlFlow> where - B: Iterator, + B: ~const Iterator, + F: ~const FnMut(X, B::Item) -> ControlFlow, + X: ~const Destruct, { - move |x| match b.next() { + match b.next() { None => ControlFlow::Break(ControlFlow::Continue(Ordering::Greater)), - Some(y) => f(x, y).map_break(ControlFlow::Break), + Some(y) => match f(x, y) { + ControlFlow::Break(x) => ControlFlow::Break(ControlFlow::Break(x)), + ControlFlow::Continue(x) => ControlFlow::Continue(x), + }, } } - match a.try_for_each(compare(&mut b, f)) { - ControlFlow::Continue(()) => ControlFlow::Continue(match b.next() { + let mut tuple = (b, f); + let mut f = ConstFnMutClosure::new(&mut tuple, compare); + + match a.try_for_each(&mut f) { + ControlFlow::Continue(()) => ControlFlow::Continue(match f.data.0.next() { None => Ordering::Equal, Some(_) => Ordering::Less, }), diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 727aed856c3b5..75858e2e2ec09 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -123,6 +123,7 @@ #![feature(const_index_range_slice_index)] #![feature(const_inherent_unchecked_arith)] #![feature(const_int_unchecked_arith)] +#![feature(const_intoiterator_identity)] #![feature(const_intrinsic_forget)] #![feature(const_likely)] #![feature(const_maybe_uninit_array_assume_init)] diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 28275798f751e..b0889ed2284d9 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -41,7 +41,8 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($T: Eq),+> Eq for ($($T,)+) + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl<$($T: ~const Eq),+> const Eq for ($($T,)+) where last_type!($($T,)+): ?Sized {} diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr index 02960b363e78f..e36324f0b3eea 100644 --- a/src/test/ui/consts/const-fn-error.stderr +++ b/src/test/ui/consts/const-fn-error.stderr @@ -22,8 +22,8 @@ LL | for i in 0..x { note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | -LL | impl const IntoIterator for I { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl const IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0658]: mutable references are not allowed in constant functions diff --git a/src/test/ui/consts/const-for.stderr b/src/test/ui/consts/const-for.stderr index 11e4ae309c01f..f2e1c8a4991a3 100644 --- a/src/test/ui/consts/const-for.stderr +++ b/src/test/ui/consts/const-for.stderr @@ -7,8 +7,8 @@ LL | for _ in 0..5 {} note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | -LL | impl const IntoIterator for I { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl const IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr index 0910e9ad77a84..3c0daa4c55f01 100644 --- a/src/test/ui/never_type/issue-52443.stderr +++ b/src/test/ui/never_type/issue-52443.stderr @@ -47,8 +47,8 @@ LL | [(); { for _ in 0usize.. {}; 0}]; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL | -LL | impl const IntoIterator for I { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl const IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0658]: mutable references are not allowed in constants From 070a4e3f62c486acd15a4b5aa3df761bc4ff134b Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 23 Nov 2022 00:59:58 +0000 Subject: [PATCH 4/4] Simplified iterator constructor functions --- library/core/src/iter/adapters/cycle.rs | 7 +- library/core/src/iter/adapters/flatten.rs | 12 +- library/core/src/iter/adapters/intersperse.rs | 14 +-- library/core/src/iter/adapters/zip.rs | 112 +++++++++--------- 4 files changed, 68 insertions(+), 77 deletions(-) diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs index a4ede289572e8..2fea46dd33bbe 100644 --- a/library/core/src/iter/adapters/cycle.rs +++ b/library/core/src/iter/adapters/cycle.rs @@ -15,11 +15,8 @@ pub struct Cycle { iter: I, } -impl Cycle { - pub(in crate::iter) const fn new(iter: I) -> Cycle - where - I: ~const Clone, - { +impl Cycle { + pub(in crate::iter) const fn new(iter: I) -> Cycle { Cycle { orig: iter.clone(), iter } } } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 31386efe4c0d2..5ec2cac1b6cef 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -14,12 +14,12 @@ pub struct FlatMap { inner: FlattenCompat, ::IntoIter>, } -impl FlatMap { - pub(in crate::iter) const fn new(iter: I, f: F) -> FlatMap - where - I: ~const Iterator + ~const Destruct, - F: ~const FnMut(I::Item) -> U + ~const Destruct, - { +impl FlatMap +where + I: ~const Iterator + ~const Destruct, + F: ~const FnMut(I::Item) -> U + ~const Destruct, +{ + pub(in crate::iter) const fn new(iter: I, f: F) -> FlatMap { FlatMap { inner: FlattenCompat::new(iter.map(f)) } } } diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index 7915b67341a78..8e0468f540526 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -15,14 +15,11 @@ where needs_sep: bool, } -impl Intersperse +impl Intersperse where I::Item: Clone, { - pub(in crate::iter) const fn new(iter: I, separator: I::Item) -> Self - where - I: ~const Iterator, - { + pub(in crate::iter) const fn new(iter: I, separator: I::Item) -> Self { Self { iter: iter.peekable(), separator, needs_sep: false } } } @@ -106,14 +103,11 @@ where } } -impl IntersperseWith +impl IntersperseWith where G: FnMut() -> I::Item, { - pub(in crate::iter) const fn new(iter: I, separator: G) -> Self - where - I: ~const Iterator, - { + pub(in crate::iter) const fn new(iter: I, separator: G) -> Self { Self { iter: iter.peekable(), separator, needs_sep: false } } } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 2a6faf4df9257..174e5506ff186 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -20,24 +20,16 @@ pub struct Zip { len: usize, a_len: usize, } -impl Zip { - pub(in crate::iter) const fn new(a: A, b: B) -> Zip - where - A: ~const Iterator, - B: ~const Iterator, - A::Item: ~const Destruct, - B::Item: ~const Destruct, - { - ZipImpl::new(a, b) +impl Zip +where + A::Item: ~const Destruct, + B::Item: ~const Destruct, +{ + pub(in crate::iter) const fn new(a: A, b: B) -> Zip { + NewZip::new(a, b) } - const fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> - where - A: ~const Iterator, - B: ~const Iterator, - A::Item: ~const Destruct, - B::Item: ~const Destruct, - { + fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> { while let Some(x) = Iterator::next(self) { if n == 0 { return Some(x); @@ -83,17 +75,14 @@ where A: IntoIterator, B: IntoIterator, { - ZipImpl::new(a.into_iter(), b.into_iter()) + NewZip::new(a.into_iter(), b.into_iter()) } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_iter", issue = "92476")] -impl const Iterator for Zip +impl Iterator for Zip where - A: ~const Iterator, - B: ~const Iterator, - A::Item: ~const Destruct, - B::Item: ~const Destruct, + A: Iterator, + B: Iterator, { type Item = (A::Item, B::Item); @@ -137,10 +126,8 @@ where // Zip specialization trait #[doc(hidden)] -#[const_trait] trait ZipImpl { type Item; - fn new(a: A, b: B) -> Self; fn next(&mut self) -> Option; fn size_hint(&self) -> (usize, Option); fn nth(&mut self, n: usize) -> Option; @@ -154,20 +141,45 @@ trait ZipImpl { Self: Iterator + TrustedRandomAccessNoCoerce; } +// Zip creation specialization trait +#[const_trait] +#[doc(hidden)] +trait NewZip { + fn new(a: A, b: B) -> Self; +} + +impl const NewZip for Zip +where + A: ~const Iterator, + B: ~const Iterator, +{ + default fn new(a: A, b: B) -> Self { + Zip { + a, + b, + index: 0, // unused + len: 0, // unused + a_len: 0, // unused + } + } +} + +impl const NewZip for Zip +where + A: ~const TrustedRandomAccess + ~const Iterator, + B: ~const TrustedRandomAccess + ~const Iterator, +{ + fn new(a: A, b: B) -> Self { + let a_len = a.size(); + let len = cmp::min(a_len, b.size()); + Zip { a, b, index: 0, len, a_len } + } +} + // Work around limitations of specialization, requiring `default` impls to be repeated // in intermediary impls. macro_rules! zip_impl_general_defaults { () => { - default fn new(a: A, b: B) -> Self { - Zip { - a, - b, - index: 0, // unused - len: 0, // unused - a_len: 0, // unused - } - } - #[inline] #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_try, const_for))] default fn next(&mut self) -> Option<(A::Item, B::Item)> { @@ -223,12 +235,10 @@ macro_rules! zip_impl_general_defaults { // General Zip impl #[doc(hidden)] -impl const ZipImpl for Zip +impl ZipImpl for Zip where - A: ~const Iterator, - B: ~const Iterator, - A::Item: ~const Destruct, - B::Item: ~const Destruct, + A: Iterator, + B: Iterator, { type Item = (A::Item, B::Item); @@ -260,12 +270,10 @@ where } #[doc(hidden)] -impl const ZipImpl for Zip +impl ZipImpl for Zip where - A: ~const TrustedRandomAccessNoCoerce + ~const Iterator, - B: ~const TrustedRandomAccessNoCoerce + ~const Iterator, - A::Item: ~const Destruct, - B::Item: ~const Destruct, + A: TrustedRandomAccessNoCoerce + Iterator, + B: TrustedRandomAccessNoCoerce + Iterator, { zip_impl_general_defaults! {} @@ -285,19 +293,11 @@ where } #[doc(hidden)] -impl const ZipImpl for Zip +impl ZipImpl for Zip where - A: ~const TrustedRandomAccess + ~const Iterator, - B: ~const TrustedRandomAccess + ~const Iterator, - A::Item: ~const Destruct, - B::Item: ~const Destruct, + A: TrustedRandomAccess + Iterator, + B: TrustedRandomAccess + Iterator, { - fn new(a: A, b: B) -> Self { - let a_len = a.size(); - let len = cmp::min(a_len, b.size()); - Zip { a, b, index: 0, len, a_len } - } - #[inline] fn next(&mut self) -> Option<(A::Item, B::Item)> { if self.index < self.len {

(&mut self, mut predicate: P) -> Option where - P: FnMut(Self::Item) -> bool, - Self: Sized + ExactSizeIterator + DoubleEndedIterator, + P: ~const FnMut(Self::Item) -> bool + ~const Destruct, + Self::Item: ~const Destruct, + Self: Sized + ~const ExactSizeIterator + ~const DoubleEndedIterator, { // No need for an overflow check here, because `ExactSizeIterator` // implies that the number of elements fits into a `usize`. #[inline] - fn check( - mut predicate: impl FnMut(T) -> bool, - ) -> impl FnMut(usize, T) -> ControlFlow { - move |i, x| { - let i = i - 1; - if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i) } - } + const fn check(predicate: &mut F, (i, x): (usize, T)) -> ControlFlow + where + F: ~const FnMut(T) -> bool, + { + let i = i - 1; + if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i) } } let n = self.len(); - self.try_rfold(n, check(predicate)).break_value() + self.try_rfold(n, ConstFnMutClosure::new(&mut predicate, check)).break_value() } /// Returns the maximum element of an iterator. @@ -2962,9 +3018,13 @@ pub trait Iterator { fn max(self) -> Option where Self: Sized, - Self::Item: Ord, + Self::Item: ~const Ord + ~const Destruct, + Self: ~const Destruct, { - self.max_by(Ord::cmp) + const fn cmp(x: &T, y: &T) -> Ordering { + x.cmp(y) + } + self.max_by(cmp) } /// Returns the minimum element of an iterator. @@ -3000,9 +3060,14 @@ pub trait Iterator { fn min(self) -> Option where Self: Sized, - Self::Item: Ord, + Self::Item: ~const Ord, + Self::Item: ~const Destruct, + Self: ~const Destruct, { - self.min_by(Ord::cmp) + const fn cmp(x: &T, y: &T) -> Ordering { + x.cmp(y) + } + self.min_by(cmp) } /// Returns the element that gives the maximum value from the @@ -3019,22 +3084,25 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - fn max_by_key(self, f: F) -> Option + fn max_by_key(self, mut f: F) -> Option where Self: Sized, - F: FnMut(&Self::Item) -> B, + F: ~const FnMut(&Self::Item) -> B + ~const Destruct, + B: ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] - fn key(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) { - move |x| (f(&x), x) + const fn key B, T, B>(f: &mut F, (x,): (T,)) -> (B, T) { + (f(&x), x) } #[inline] - fn compare((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering { + const fn compare((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering { x_p.cmp(y_p) } - let (_, x) = self.map(key(f)).max_by(compare)?; + let (_, x) = self.map(ConstFnMutClosure::new(&mut f, key)).max_by(compare)?; Some(x) } @@ -3052,17 +3120,22 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_max_by", since = "1.15.0")] - fn max_by(self, compare: F) -> Option + fn max_by(self, mut compare: F) -> Option where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Ordering, + F: ~const FnMut(&Self::Item, &Self::Item) -> Ordering + ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] - fn fold(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(T, T) -> T { - move |x, y| cmp::max_by(x, y, &mut compare) + const fn fold Ordering, T: ~const Destruct>( + compare: &mut F, + (x, y): (T, T), + ) -> T { + cmp::max_by(x, y, compare) } - self.reduce(fold(compare)) + self.reduce(ConstFnMutClosure::new(&mut compare, fold)) } /// Returns the element that gives the minimum value from the @@ -3079,22 +3152,25 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - fn min_by_key(self, f: F) -> Option + fn min_by_key(self, mut f: F) -> Option where Self: Sized, - F: FnMut(&Self::Item) -> B, + F: ~const FnMut(&Self::Item) -> B + ~const Destruct, + B: ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] - fn key(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) { - move |x| (f(&x), x) + const fn key B, T, B>(f: &mut F, (x,): (T,)) -> (B, T) { + (f(&x), x) } #[inline] - fn compare((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering { + const fn compare((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering { x_p.cmp(y_p) } - let (_, x) = self.map(key(f)).min_by(compare)?; + let (_, x) = self.map(ConstFnMutClosure::new(&mut f, key)).min_by(compare)?; Some(x) } @@ -3112,17 +3188,22 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_min_by", since = "1.15.0")] - fn min_by(self, compare: F) -> Option + fn min_by(self, mut compare: F) -> Option where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Ordering, + F: ~const FnMut(&Self::Item, &Self::Item) -> Ordering + ~const Destruct, + Self::Item: ~const Destruct, + Self: ~const Destruct, { #[inline] - fn fold(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(T, T) -> T { - move |x, y| cmp::min_by(x, y, &mut compare) + const fn fold Ordering, T: ~const Destruct>( + compare: &mut F, + (x, y): (T, T), + ) -> T { + cmp::min_by(x, y, compare) } - self.reduce(fold(compare)) + self.reduce(ConstFnMutClosure::new(&mut compare, fold)) } /// Reverses an iterator's direction. @@ -3189,9 +3270,9 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn unzip(self) -> (FromA, FromB) where - FromA: Default + Extend, - FromB: Default + Extend, - Self: Sized + Iterator, + FromA: ~const Default + ~const Extend, + FromB: ~const Default + ~const Extend, + Self: Sized + ~const Iterator, { let mut unzipped: (FromA, FromB) = Default::default(); unzipped.extend(self); @@ -3221,7 +3302,7 @@ pub trait Iterator { #[stable(feature = "iter_copied", since = "1.36.0")] fn copied<'a, T: 'a>(self) -> Copied where - Self: Sized + Iterator, + Self: Sized + ~const Iterator, T: Copy, { Copied::new(self) @@ -3302,7 +3383,7 @@ pub trait Iterator { #[inline] fn cycle(self) -> Cycle where - Self: Sized + Clone, + Self: Sized + ~const Clone, { Cycle::new(self) } @@ -3376,7 +3457,7 @@ pub trait Iterator { fn sum(self) -> S where Self: Sized, - S: Sum, + S: ~const Sum, { Sum::sum(self) } @@ -3405,7 +3486,7 @@ pub trait Iterator { fn product