diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f89cf812e970a..dca11b23fc1f5 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1192,7 +1192,13 @@ pub fn min(v1: T, v2: T) -> T { #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] -pub fn min_by Ordering>(v1: T, v2: T, compare: F) -> T { +#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] +pub const fn min_by(v1: T, v2: T, compare: F) -> T +where + F: ~const FnOnce(&T, &T) -> Ordering, + F: ~const Drop, + T: ~const Drop, +{ match compare(&v1, &v2) { Ordering::Less | Ordering::Equal => v1, Ordering::Greater => v2, @@ -1255,7 +1261,13 @@ pub fn max(v1: T, v2: T) -> T { #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] -pub fn max_by Ordering>(v1: T, v2: T, compare: F) -> T { +#[rustc_const_unstable(feature = "const_cmp", issue = "92391")] +pub const fn max_by(v1: T, v2: T, compare: F) -> T +where + F: ~const FnOnce(&T, &T) -> Ordering, + F: ~const Drop, + T: ~const Drop, +{ match compare(&v1, &v2) { Ordering::Less | Ordering::Equal => v2, Ordering::Greater => v1, diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs index 9c6acfb1e8c94..1ceb154ddb88c 100644 --- a/library/core/src/internal_macros.rs +++ b/library/core/src/internal_macros.rs @@ -187,3 +187,52 @@ macro_rules! impl_fn_for_zst { )+ } } + +macro_rules! impl_const_closure { + ( + impl$(<$( $tt : tt ),*>)? + const FnOnce for $Name: path $(where $($WhereTy:ty : $(~ $const:ident)? $Trait:path),+ $(,)?)? = + $(#[$meta:meta])* + |$mutorself:ident $($self:ident)?, $( $arg: tt: $ArgTy: ty ),*| $(-> $ReturnTy: ty)? + $body: block; + ) => { + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl $( < $( $tt ),* > )? const FnOnce<($( $ArgTy, )*)> for $Name + $(where $($WhereTy: $(~$const)? $Trait),+)? + { + #[allow(unused_parens)] + type Output = ( $( $ReturnTy )? ); + + #[allow(unused_mut)] + $(#[$meta])* + extern "rust-call" fn call_once($mutorself $($self)?, ($( $arg, )*): ($( $ArgTy, )*)) -> Self::Output { + $body + } + } + }; + ( + impl$(< $( $tt: tt ),* >)? + const FnMut for $Name: path $(where $($WhereTy:ty : $(~ $const:ident)? $Trait:path),+ $(,)?)? = + $(#[$meta:meta])* + |&mut $self:ident, $( $arg: tt: $ArgTy: ty ),*| $(-> $ReturnTy: ty)? + $body: block; + ) => { + impl_const_closure! { + impl$(< $( $tt ),* >)? + const FnOnce for $Name $(where $($WhereTy: $(~$const)? $Trait),+)? = + $(#[$meta])* + |mut $self, $( $arg: $ArgTy),*| $(-> $ReturnTy)? + $body; + } + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl $( < $( $tt ),* > )? const FnMut<($( $ArgTy, )*)> for $Name + $(where $($WhereTy: $(~$const)? $Trait),+)? + { + $(#[$meta])* + #[allow(unused_parens)] + extern "rust-call" fn call_mut(&mut $self, ($( $arg, )*): ($( $ArgTy, )*)) -> ( $($ReturnTy)? ) { + $body + } + } + } +} diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 53e48500e3b4d..c58c3b0fc11f5 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 71a5a4ea831ff..323e3f6c5ed69 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 e5f2886dcafad..f03dc364b69df 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -19,7 +19,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..63bb0a4495777 100644 --- a/library/core/src/iter/adapters/cycle.rs +++ b/library/core/src/iter/adapters/cycle.rs @@ -15,8 +15,12 @@ pub struct Cycle { iter: I, } -impl Cycle { - pub(in crate::iter) fn new(iter: I) -> Cycle { +impl Cycle { + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + 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 84e4618844a61..c3ea04ae8d898 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 351fd569d8acf..9387f7d5856a2 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -14,8 +14,9 @@ pub struct FlatMap { } impl U> FlatMap { - pub(in crate::iter) fn new(iter: I, f: F) -> FlatMap { - FlatMap { inner: FlattenCompat::new(iter.map(f)) } + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + pub(in crate::iter) const fn new(iter: I, f: F) -> FlatMap { + FlatMap { inner: FlattenCompat::new(Map::new(iter, f)) } } } @@ -152,7 +153,8 @@ pub struct Flatten> { } impl> Flatten { - pub(in super::super) fn new(iter: I) -> Flatten { + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + pub(in super::super) const fn new(iter: I) -> Flatten { Flatten { inner: FlattenCompat::new(iter) } } } @@ -270,13 +272,10 @@ 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 { - FlattenCompat { iter: iter.fuse(), frontiter: None, backiter: None } + const fn new(iter: I) -> FlattenCompat { + FlattenCompat { iter: super::Fuse::new(iter), frontiter: None, backiter: None } } } diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index fbf752c6f2024..80f36817d09f8 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..969e5d73daf9c 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -19,8 +19,9 @@ impl Intersperse where I::Item: Clone, { - pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self { - Self { iter: iter.peekable(), separator, needs_sep: false } + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + pub(in crate::iter) const fn new(iter: I, separator: I::Item) -> Self { + Self { iter: Peekable::new(iter), separator, needs_sep: false } } } @@ -108,8 +109,9 @@ where I: Iterator, G: FnMut() -> I::Item, { - pub(in crate::iter) fn new(iter: I, separator: G) -> Self { - Self { iter: iter.peekable(), separator, needs_sep: false } + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + pub(in crate::iter) const fn new(iter: I, separator: G) -> Self { + Self { iter: Peekable::new(iter), separator, needs_sep: false } } } diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index b2ed82508dd29..f4ed5ae6d3d88 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -3,7 +3,7 @@ use crate::iter::adapters::{ zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; -use crate::ops::Try; +use crate::ops::{FromResidual, Try}; /// An iterator that maps the values of `iter` with `f`. /// @@ -65,7 +65,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,6 +77,33 @@ impl fmt::Debug for Map { } } +struct MapFold(F, G); +struct MapTryFold(F, G); + +impl_const_closure! { + impl const FnMut for MapFold + where + F: ~const FnMut(T) -> B, + F: ~const Drop, + G: ~const FnMut(Acc, B) -> Acc, + G: ~const Drop, + = |&mut self, acc: Acc, elt: T| -> Acc { + self.1(acc, self.0(elt)) + }; +} + +impl_const_closure! { + impl const FnMut for MapTryFold + where + F: ~const FnMut(T) -> B, + F: ~const Drop, + G: ~const FnMut(Acc, B) -> R, + G: ~const Drop, + = |&mut self, acc: Acc, elt: T| -> R { + self.1(acc, self.0(elt)) + }; +} + fn map_fold( mut f: impl FnMut(T) -> B, mut g: impl FnMut(Acc, B) -> Acc, @@ -92,9 +119,10 @@ fn map_try_fold<'a, T, B, Acc, R>( } #[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 + ~const Drop, { type Item = B; @@ -111,17 +139,21 @@ 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, B) -> R, + G: ~const Drop, + R: ~const Try, + R: ~const FromResidual, { - self.iter.try_fold(init, map_try_fold(&mut self.f, g)) + self.iter.try_fold(init, MapTryFold(&mut self.f, g)) } fn fold(self, init: Acc, g: G) -> Acc where - G: FnMut(Acc, Self::Item) -> Acc, + I: ~const Drop, + G: ~const FnMut(Acc, B) -> Acc, + G: ~const Drop, { - self.iter.fold(init, map_fold(self.f, g)) + self.iter.fold(init, MapFold(self.f, g)) } #[doc(hidden)] diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs index 1e8d6bf3e00e1..061a6d5a5a77a 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/peekable.rs b/library/core/src/iter/adapters/peekable.rs index 20aca323bab79..783977ab1b37c 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -19,7 +19,8 @@ pub struct Peekable { } impl Peekable { - pub(in crate::iter) fn new(iter: I) -> Peekable { + #[rustc_allow_const_fn_unstable(const_fn_trait_bound)] + 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 80bfd2231241b..c8eeafbda2931 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 ea1da8ba434ed..21134a207c6d8 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..b62eee8b7f432 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -17,8 +17,9 @@ pub struct StepBy { } impl StepBy { - pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy { - assert!(step != 0); + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + pub(in crate::iter) const fn new(iter: I, step: usize) -> StepBy { + assert!(step != 0, "Step must be non-zero"); 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 2962e0104d11d..598eb1691c18f 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 ded216da952a3..00618e0033447 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 f50e71da20f16..2cc8c3407953f 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -18,9 +18,11 @@ pub struct Zip { len: usize, a_len: usize, } + impl Zip { - pub(in crate::iter) fn new(a: A, b: B) -> Zip { - ZipImpl::new(a, b) + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + pub(in crate::iter) const fn new(a: A, b: B) -> Zip { + ZipNewImpl::new(a, b) } fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> { while let Some(x) = Iterator::next(self) { @@ -68,7 +70,7 @@ where A: IntoIterator, B: IntoIterator, { - ZipImpl::new(a.into_iter(), b.into_iter()) + ZipNewImpl::new(a.into_iter(), b.into_iter()) } #[stable(feature = "rust1", since = "1.0.0")] @@ -118,11 +120,16 @@ where } } +// Zip::new specialization trait +#[doc(hidden)] +trait ZipNewImpl { + fn new(a: A, b: B) -> Self; +} + // Zip specialization trait #[doc(hidden)] 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; @@ -140,16 +147,6 @@ trait ZipImpl { // 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] default fn next(&mut self) -> Option<(A::Item, B::Item)> { let x = self.a.next()?; @@ -195,6 +192,24 @@ macro_rules! zip_impl_general_defaults { }; } +#[doc(hidden)] +#[rustc_const_unstable(feature = "iter_internals", issue = "none")] +impl const ZipNewImpl for Zip +where + A: Iterator, + B: Iterator, +{ + default fn new(a: A, b: B) -> Self { + Zip { + a, + b, + index: 0, // unused + len: 0, // unused + a_len: 0, // unused + } + } +} + // General Zip impl #[doc(hidden)] impl ZipImpl for Zip @@ -255,7 +270,7 @@ where } #[doc(hidden)] -impl ZipImpl for Zip +impl ZipNewImpl for Zip where A: TrustedRandomAccess + Iterator, B: TrustedRandomAccess + Iterator, @@ -265,7 +280,14 @@ where let len = cmp::min(a_len, b.size()); Zip { a, b, index: 0, len, a_len } } +} +#[doc(hidden)] +impl ZipImpl for Zip +where + A: TrustedRandomAccess + Iterator, + B: TrustedRandomAccess + Iterator, +{ #[inline] fn next(&mut self) -> Option<(A::Item, B::Item)> { if self.index < self.len { @@ -554,9 +576,13 @@ pub unsafe trait TrustedRandomAccessNoCoerce: Sized { /// /// Same requirements calling `get_unchecked` directly. #[doc(hidden)] -pub(in crate::iter::adapters) unsafe fn try_get_unchecked(it: &mut I, idx: usize) -> I::Item +#[rustc_const_unstable(feature = "iter_internals", issue = "none")] +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`. @@ -569,13 +595,15 @@ unsafe trait SpecTrustedRandomAccess: Iterator { unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item; } -unsafe impl SpecTrustedRandomAccess for I { +#[rustc_const_unstable(feature = "iter_internals", issue = "none")] +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 { +#[rustc_const_unstable(feature = "iter_internals", issue = "none")] +unsafe impl const SpecTrustedRandomAccess for I { unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index fc14620a2df84..7fe79b6f46793 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -229,7 +229,8 @@ pub trait IntoIterator { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for I { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const IntoIterator for I { type Item = I::Item; type IntoIter = I; @@ -330,7 +331,10 @@ 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) + where + T::IntoIter: ~const Iterator, + T::IntoIter: ~const Drop; /// Extends a collection with exactly one element. #[unstable(feature = "extend_one", issue = "72631")] @@ -342,24 +346,32 @@ pub trait Extend { /// /// The default implementation does nothing. #[unstable(feature = "extend_one", issue = "72631")] + #[default_method_body_is_const] fn extend_reserve(&mut self, additional: usize) { let _ = additional; } } #[stable(feature = "extend_for_unit", since = "1.28.0")] -impl Extend<()> for () { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each(drop) +#[rustc_const_unstable(feature = "const_extend", issue = "92475")] +impl const Extend<()> for () { + fn extend>(&mut self, iter: T) + where + T::IntoIter: ~const Iterator, + T::IntoIter: ~const Drop, + { + let mut iter = iter.into_iter(); + while let Some(()) = iter.next() {} } fn extend_one(&mut self, _item: ()) {} } #[stable(feature = "extend_for_tuple", since = "1.56.0")] -impl Extend<(A, B)> for (ExtendA, ExtendB) +#[rustc_const_unstable(feature = "const_extend", issue = "92475")] +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`. /// @@ -381,18 +393,29 @@ 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 Iterator, + T::IntoIter: ~const Drop, + { 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); - } + pub struct Ext<'a, FromA, FromB> { + a: &'a mut FromA, + b: &'a mut FromB, + } + + impl_const_closure! { + impl<'a, FromA, FromB, A, B> const FnMut for Ext<'a, FromA, FromB> + where + FromA: ~const Extend, + FromB: ~const Extend, + = |&mut self, _: (), tuple: (A, B)| { + let (t, u) = tuple; + self.a.extend_one(t); + self.b.extend_one(u); + }; } let (lower_bound, _) = iter.size_hint(); @@ -401,7 +424,7 @@ where b.extend_reserve(lower_bound); } - iter.fold((), extend(a, b)); + iter.fold((), Ext { a, b }); } fn extend_one(&mut self, item: (A, B)) { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 1d947297463d9..866578dd59b3b 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -157,6 +157,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn size_hint(&self) -> (usize, Option) { (0, None) } @@ -194,15 +195,21 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn count(self) -> usize where Self: Sized, + Self: ~const Drop, + Self::Item: ~const Drop, { - self.fold( - 0, - #[rustc_inherit_overflow_checks] - |count, _| count + 1, - ) + #[rustc_inherit_overflow_checks] + #[rustc_allow_const_fn_unstable(const_fn_trait_bound)] + #[inline] + const fn counter(count: usize, _: T) -> usize { + count + 1 + } + + self.fold(0, counter) } /// Consumes the iterator, returning the last element. @@ -224,12 +231,18 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn last(self) -> Option where Self: Sized, + Self: ~const Drop, + Self::Item: ~const Drop, { #[inline] - fn some(_: Option, x: T) -> Option { + const fn some(_: Option, x: T) -> Option + where + Option: ~const Drop, + { Some(x) } @@ -270,9 +283,18 @@ 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 { - self.next().ok_or(i)?; + #[default_method_body_is_const] + fn advance_by(&mut self, n: usize) -> Result<(), usize> + where + Self::Item: ~const Drop, + { + let mut i = 0; + while i < n { + match self.next() { + Some(_) => {} + None => return Err(i), + } + i += 1; } Ok(()) } @@ -318,9 +340,15 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn nth(&mut self, n: usize) -> Option { - self.advance_by(n).ok()?; - self.next() + #[default_method_body_is_const] + fn nth(&mut self, n: usize) -> Option + where + Self::Item: ~const Drop, + { + match self.advance_by(n) { + Ok(_) => self.next(), + Err(_) => None, + } } /// Creates an iterator starting at the same point, but stepping by @@ -370,6 +398,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_step_by", since = "1.28.0")] + #[default_method_body_is_const] fn step_by(self, step: usize) -> StepBy where Self: Sized, @@ -441,10 +470,11 @@ pub trait Iterator { /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn chain(self, other: U) -> Chain where Self: Sized, - U: IntoIterator, + U: ~const IntoIterator, { Chain::new(self, other.into_iter()) } @@ -519,10 +549,11 @@ pub trait Iterator { /// [`next`]: Iterator::next #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn zip(self, other: U) -> Zip where Self: Sized, - U: IntoIterator, + U: ~const IntoIterator, { Zip::new(self, other.into_iter()) } @@ -561,6 +592,7 @@ pub trait Iterator { /// [`intersperse_with`]: Iterator::intersperse_with #[inline] #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] + #[default_method_body_is_const] fn intersperse(self, separator: Self::Item) -> Intersperse where Self: Sized, @@ -619,6 +651,7 @@ pub trait Iterator { /// [`intersperse`]: Iterator::intersperse #[inline] #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] + #[default_method_body_is_const] fn intersperse_with(self, separator: G) -> IntersperseWith where Self: Sized, @@ -678,6 +711,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn map(self, f: F) -> Map where Self: Sized, @@ -723,17 +757,26 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_for_each", since = "1.21.0")] + #[default_method_body_is_const] fn for_each(self, f: F) where Self: Sized, - F: FnMut(Self::Item), - { - #[inline] - fn call(mut f: impl FnMut(T)) -> impl FnMut((), T) { - move |(), item| f(item) + Self: ~const Drop, + F: ~const FnMut(Self::Item) + ~const Drop, + { + struct ForEach(F); + + impl_const_closure! { + impl const FnMut for ForEach + where + F: ~const FnMut(T), + F: ~const Drop, + = |&mut self, _: (), t: T| -> () { + self.0(t) + }; } - self.fold((), call(f)); + self.fold((), ForEach(f)); } /// Creates an iterator which uses a closure to determine if an element @@ -798,6 +841,7 @@ pub trait Iterator { /// Note that `iter.filter(f).next()` is equivalent to `iter.find(f)`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn filter

(self, predicate: P) -> Filter where Self: Sized, @@ -843,6 +887,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn filter_map(self, f: F) -> FilterMap where Self: Sized, @@ -889,6 +934,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn enumerate(self) -> Enumerate where Self: Sized, @@ -960,6 +1006,7 @@ pub trait Iterator { /// [`next`]: Iterator::next #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn peekable(self) -> Peekable where Self: Sized, @@ -1025,6 +1072,7 @@ pub trait Iterator { #[inline] #[doc(alias = "drop_while")] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn skip_while

(self, predicate: P) -> SkipWhile where Self: Sized, @@ -1106,6 +1154,7 @@ pub trait Iterator { /// the iteration should stop, but wasn't placed back into the iterator. #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn take_while

(self, predicate: P) -> TakeWhile where Self: Sized, @@ -1194,6 +1243,7 @@ pub trait Iterator { /// [`fuse`]: Iterator::fuse #[inline] #[stable(feature = "iter_map_while", since = "1.57.0")] + #[default_method_body_is_const] fn map_while(self, predicate: P) -> MapWhile where Self: Sized, @@ -1225,6 +1275,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn skip(self, n: usize) -> Skip where Self: Sized, @@ -1278,6 +1329,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn take(self, n: usize) -> Take where Self: Sized, @@ -1322,6 +1374,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn scan(self, initial_state: St, f: F) -> Scan where Self: Sized, @@ -1362,6 +1415,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn flat_map(self, f: F) -> FlatMap where Self: Sized, @@ -1434,6 +1488,7 @@ pub trait Iterator { /// [`flat_map()`]: Iterator::flat_map #[inline] #[stable(feature = "iterator_flatten", since = "1.29.0")] + #[default_method_body_is_const] fn flatten(self) -> Flatten where Self: Sized, @@ -1502,6 +1557,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn fuse(self) -> Fuse where Self: Sized, @@ -1586,6 +1642,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn inspect(self, f: F) -> Inspect where Self: Sized, @@ -1616,6 +1673,7 @@ pub trait Iterator { /// assert_eq!(of_rust, vec!["of", "Rust"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn by_ref(&mut self) -> &mut Self where Self: Sized, @@ -1734,7 +1792,8 @@ 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 + #[default_method_body_is_const] + fn collect>(self) -> B where Self: Sized, { @@ -1767,31 +1826,41 @@ pub trait Iterator { /// assert_eq!(odd, vec![1, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn partition(self, f: F) -> (B, B) where Self: Sized, - B: Default + Extend, - F: FnMut(&Self::Item) -> bool, - { - #[inline] - fn extend<'a, T, B: Extend>( - mut f: impl FnMut(&T) -> bool + 'a, + Self: ~const Drop, + B: ~const Default, + B: ~const Extend, + F: ~const FnMut(&Self::Item) -> bool, + F: ~const Drop, + { + struct Partition<'a, F, B> { + f: F, left: &'a mut B, right: &'a mut B, - ) -> impl FnMut((), T) + 'a { - move |(), x| { - if f(&x) { - left.extend_one(x); + } + + impl_const_closure! { + impl<'a, F, T, B> const FnMut for Partition<'a, F, B> + where + F: ~const FnMut(&T) -> bool, + F: ~const Drop, + B: ~const Extend, + = |&mut self, _: (), t: T| -> () { + if (self.f)(&t) { + self.left.extend_one(t); } else { - right.extend_one(x); + self.right.extend_one(t); } - } + }; } let mut left: B = Default::default(); let mut right: B = Default::default(); - self.fold((), extend(f, &mut left, &mut right)); + self.fold((), Partition { f, left: &mut left, right: &mut right }); (left, right) } @@ -1829,37 +1898,53 @@ pub trait Iterator { /// assert!(a[i..].iter().all(|&n| n % 2 == 1)); // odds /// ``` #[unstable(feature = "iter_partition_in_place", reason = "new API", issue = "62543")] + #[default_method_body_is_const] 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, + Self: ~const DoubleEndedIterator, + Self: ~const Drop, + P: ~const FnMut(&T) -> bool, + P: ~const Drop, { // 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... // These closure "factory" functions exist to avoid genericity in `Self`. - #[inline] - fn is_false<'a, T>( - predicate: &'a mut impl FnMut(&T) -> bool, + struct IsFalse<'a, F> { + predicate: &'a mut F, true_count: &'a mut usize, - ) -> impl FnMut(&&mut T) -> bool + 'a { - move |x| { - let p = predicate(&**x); - *true_count += p as usize; + } + + impl_const_closure! { + impl<'a, F, T> const FnMut for IsFalse<'a, F> + where + F: ~const FnMut(&T) -> bool, + F: ~const Drop, + = |&mut self, x: &&mut T| -> bool { + let p = (self.predicate)(&**x); + *self.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) + struct IsTrue<'a, F>(&'a mut F); + + impl_const_closure! { + impl<'a, F, T> const FnMut for IsTrue<'a, F> + where + F: ~const FnMut(&T) -> bool, + F: ~const Drop, + = |&mut self, x: &&mut T| -> bool { + self.0(&**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)) { + while let Some(head) = self.find(IsFalse { predicate, true_count: &mut true_count }) { + if let Some(tail) = self.rfind(IsTrue(predicate)) { crate::mem::swap(head, tail); true_count += 1; } else { @@ -1886,10 +1971,14 @@ pub trait Iterator { /// assert!(!"IntoIterator".chars().is_partitioned(char::is_uppercase)); /// ``` #[unstable(feature = "iter_is_partitioned", reason = "new API", issue = "62544")] + #[default_method_body_is_const] fn is_partitioned

(mut self, mut predicate: P) -> bool where Self: Sized, - P: FnMut(Self::Item) -> bool, + Self: ~const Drop, + Self::Item: ~const Drop, + P: ~const FnMut(Self::Item) -> bool, + P: ~const Drop, { // Either all items test `true`, or the first clause stops at `false` // and we check that there are no more `true` items after that. @@ -1980,15 +2069,21 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] + #[default_method_body_is_const] 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, + F: ~const Drop, + R: ~const Try, + R: ~const FromResidual, { 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 } } @@ -2038,18 +2133,28 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] + #[default_method_body_is_const] fn try_for_each(&mut self, f: F) -> R where Self: Sized, - F: FnMut(Self::Item) -> R, - R: Try, - { - #[inline] - fn call(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R { - move |(), x| f(x) + F: ~const FnMut(Self::Item) -> R, + F: ~const Drop, + R: ~const Try, + R: ~const FromResidual, + { + struct Call(F); + + impl_const_closure! { + impl const FnMut for Call + where + F: ~const FnMut(T) -> R, + F: ~const Drop, + = |&mut self, _: (), x: T| -> R { + self.0(x) + }; } - self.try_fold((), call(f)) + self.try_fold((), Call(f)) } /// Folds every element into an accumulator by applying an operation, @@ -2157,13 +2262,16 @@ pub trait Iterator { #[doc(alias = "inject", alias = "foldl")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn fold(mut self, init: B, mut f: F) -> B + #[default_method_body_is_const] + fn fold(self, init: B, mut f: F) -> B where Self: Sized, - F: FnMut(B, Self::Item) -> B, + Self: ~const Drop, + F: ~const FnMut(B, Self::Item) -> B, + F: ~const Drop, { let mut accum = init; - while let Some(x) = self.next() { + for x in self { accum = f(accum, x); } accum @@ -2203,10 +2311,13 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_fold_self", since = "1.51.0")] + #[default_method_body_is_const] fn reduce(mut self, f: F) -> Option where Self: Sized, - F: FnMut(Self::Item, Self::Item) -> Self::Item, + Self: ~const Drop, + F: ~const FnMut(Self::Item, Self::Item) -> Self::Item, + F: ~const Drop, { let first = self.next()?; Some(self.fold(first, f)) @@ -2274,12 +2385,18 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")] + #[default_method_body_is_const] fn try_reduce(&mut self, f: F) -> ChangeOutputType> where Self: Sized, - F: FnMut(Self::Item, Self::Item) -> R, - R: Try, + F: ~const FnMut(Self::Item, Self::Item) -> R, + F: ~const Drop, + R: ~const Try, + R: ~const FromResidual, R::Residual: Residual>, + >>::TryType: + ~const Try>, + >>::TryType: ~const FromResidual, { let first = match self.next() { Some(i) => i, @@ -2331,18 +2448,31 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn all(&mut self, f: F) -> bool where Self: Sized, - F: FnMut(Self::Item) -> bool, - { - #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> { - move |(), x| { - if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } - } + F: ~const FnMut(Self::Item) -> bool, + F: ~const Drop, + Self::Item: ~const Drop, + { + struct Check(F); + impl_const_closure! { + impl const FnMut for Check + where + F: ~const FnMut(T) -> bool, + F: ~const Drop, + T: ~const Drop, + = |&mut self, _: (), x: T| -> ControlFlow<()> { + if self.0(x) { + ControlFlow::CONTINUE + } else { + ControlFlow::BREAK + } + }; } - self.try_fold((), check(f)) == ControlFlow::CONTINUE + + matches!(self.try_fold((), Check(f)), ControlFlow::Continue(())) } /// Tests if any element of the iterator matches a predicate. @@ -2384,19 +2514,31 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn any(&mut self, f: F) -> bool where Self: Sized, - F: FnMut(Self::Item) -> bool, - { - #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<()> { - move |(), x| { - if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } - } + F: ~const FnMut(Self::Item) -> bool, + F: ~const Drop, + Self::Item: ~const Drop, + { + struct Check(F); + impl_const_closure! { + impl const FnMut for Check + where + F: ~const FnMut(T) -> bool, + F: ~const Drop, + T: ~const Drop, + = |&mut self, _: (), x: T| -> ControlFlow<()> { + if self.0(x) { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } + }; } - self.try_fold((), check(f)) == ControlFlow::BREAK + matches!(self.try_fold((), Check(f)), ControlFlow::Break(())) } /// Searches for an element of an iterator that satisfies a predicate. @@ -2444,19 +2586,31 @@ pub trait Iterator { /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn find

(&mut self, predicate: P) -> Option where Self: Sized, - P: FnMut(&Self::Item) -> bool, - { - #[inline] - fn check(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut((), T) -> ControlFlow { - move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } - } + Self::Item: ~const Drop, + P: ~const FnMut(&Self::Item) -> bool, + P: ~const Drop, + { + struct Check(F); + + impl_const_closure! { + impl const FnMut for Check + where + F: ~const FnMut(&T) -> bool, + F: ~const Drop, + T: ~const Drop, + = |&mut self, _: (), x: T| -> ControlFlow { + if self.0(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } + }; } - self.try_fold((), check(predicate)).break_value() + match self.try_fold((), Check(predicate)) { + ControlFlow::Break(b) => Some(b), + _ => None, + } } /// Applies function to the elements of iterator and returns @@ -2475,20 +2629,30 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_find_map", since = "1.30.0")] + #[default_method_body_is_const] fn find_map(&mut self, f: F) -> Option where Self: Sized, - F: FnMut(Self::Item) -> Option, - { - #[inline] - fn check(mut f: impl FnMut(T) -> Option) -> impl FnMut((), T) -> ControlFlow { - move |(), x| match f(x) { - Some(x) => ControlFlow::Break(x), - None => ControlFlow::CONTINUE, - } + F: ~const FnMut(Self::Item) -> Option, + F: ~const Drop, + Self::Item: ~const Drop, + { + struct Check(F); + impl_const_closure! { + impl const FnMut for Check + where + F: ~const FnMut(T) -> Option, + F: ~const Drop, + T: ~const Drop, + = |&mut self, _: (), x: T| -> ControlFlow { + match self.0(x) { + Some(x) => ControlFlow::Break(x), + None => ControlFlow::CONTINUE, + } + }; } - self.try_fold((), check(f)).break_value() + self.try_fold((), Check(f)).break_value() } /// Applies function to the elements of iterator and returns @@ -2531,29 +2695,41 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] + #[default_method_body_is_const] fn try_find(&mut self, f: F) -> ChangeOutputType> where Self: Sized, - F: FnMut(&Self::Item) -> R, - R: Try, + F: ~const FnMut(&Self::Item) -> R, + F: ~const Drop, + R: ~const Try, R::Residual: Residual>, - { - #[inline] - fn check( - mut f: impl FnMut(&I) -> V, - ) -> impl FnMut((), I) -> ControlFlow - where - V: Try, - R: Residual>, - { - move |(), x| 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)), - } + <::Residual as Residual>>::TryType: + ~const Try>, + <::Residual as Residual>>::TryType: ~const FromResidual, + Self::Item: ~const Drop, + { + pub struct Check(F); + + impl_const_closure! { + impl const FnMut for Check + where + F: ~const FnMut(&I) -> V, + F: ~const Drop, + I: ~const Drop, + V: ~const Try, + R: Residual>, + R::TryType: ~const Try>, + R::TryType: ~const FromResidual, + = |&mut self, _: (), x: I| -> ControlFlow { + match self.0(&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((), Check(f)) { ControlFlow::Break(x) => x, ControlFlow::Continue(()) => Try::from_output(None), } @@ -2613,22 +2789,28 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn position

(&mut self, predicate: P) -> Option where Self: Sized, - P: FnMut(Self::Item) -> bool, - { - #[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) } - } + P: ~const FnMut(Self::Item) -> bool, + P: ~const Drop, + Self::Item: ~const Drop, + { + pub struct Check(F); + + impl_const_closure! { + impl const FnMut for Check + where + F: ~const FnMut(T) -> bool, + F: ~const Drop, + T: ~const Drop, + = #[rustc_inherit_overflow_checks] |&mut self, i: usize, x: T| -> ControlFlow { + if self.0(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i + 1) } + }; } - self.try_fold(0, check(predicate)).break_value() + self.try_fold(0, Check(predicate)).break_value() } /// Searches for an element in an iterator from the right, returning its @@ -2670,25 +2852,32 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn rposition

(self) -> P where Self: Sized, - P: Product, + P: ~const Product, { Product::product(self) } @@ -3126,13 +3386,22 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[default_method_body_is_const] fn cmp(self, other: I) -> Ordering where - I: IntoIterator, - Self::Item: Ord, - Self: Sized, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator, + I::IntoIter: ~const Drop, + Self::Item: ~const Ord + ~const Drop, + Self: Sized + ~const Drop, { - self.cmp_by(other, |x, y| x.cmp(&y)) + #[inline] + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + 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 @@ -3155,11 +3424,18 @@ 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")] + #[default_method_body_is_const] fn cmp_by(mut self, other: I, mut cmp: F) -> Ordering where Self: Sized, - I: IntoIterator, - F: FnMut(Self::Item, I::Item) -> Ordering, + Self: ~const Drop, + Self::Item: ~const Drop, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator, + I::IntoIter: ~const Drop, + <::IntoIter as Iterator>::Item: ~const Drop, + F: ~const FnMut(Self::Item, <::IntoIter as Iterator>::Item) -> Ordering, + F: ~const Drop, { let mut other = other.into_iter(); @@ -3202,13 +3478,26 @@ pub trait Iterator { /// assert_eq!([f64::NAN].iter().partial_cmp([1.].iter()), None); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[default_method_body_is_const] fn partial_cmp(self, other: I) -> Option where - I: IntoIterator, - Self::Item: PartialOrd, - Self: Sized, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator + ~const Drop, + <::IntoIter as Iterator>::Item: ~const Drop, + Self::Item: ~const PartialOrd<<::IntoIter as Iterator>::Item>, + Self::Item: ~const Drop, + Self: Sized + ~const Drop, { - self.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) + #[inline] + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + const fn partial_cmp + ~const Drop, B: ~const Drop>( + x: A, + y: B, + ) -> Option { + x.partial_cmp(&y) + } + + self.partial_cmp_by(other, partial_cmp) } /// [Lexicographically](Ord#lexicographical-comparison) compares the elements of this [`Iterator`] with those @@ -3240,11 +3529,18 @@ pub trait Iterator { /// ); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] + #[default_method_body_is_const] fn partial_cmp_by(mut self, other: I, mut partial_cmp: F) -> Option where Self: Sized, - I: IntoIterator, - F: FnMut(Self::Item, I::Item) -> Option, + Self: ~const Drop, + Self::Item: ~const Drop, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator, + I::IntoIter: ~const Drop, + I::Item: ~const Drop, + F: ~const FnMut(Self::Item, I::Item) -> Option, + F: ~const Drop, { let mut other = other.into_iter(); @@ -3282,13 +3578,22 @@ pub trait Iterator { /// assert_eq!([1].iter().eq([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[default_method_body_is_const] fn eq(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialEq, - Self: Sized, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator + ~const Drop, + <::IntoIter as Iterator>::Item: ~const Drop, + Self::Item: ~const PartialEq<<::IntoIter as Iterator>::Item>, + Self::Item: ~const Drop, + Self: Sized + ~const Drop, { - self.eq_by(other, |x, y| x == y) + #[inline] + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + const fn eq + ~const Drop, B: ~const Drop>(x: A, y: B) -> bool { + x == y + } + self.eq_by(other, eq) } /// Determines if the elements of this [`Iterator`] are equal to those of @@ -3307,11 +3612,18 @@ pub trait Iterator { /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y)); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] + #[default_method_body_is_const] fn eq_by(mut self, other: I, mut eq: F) -> bool where Self: Sized, - I: IntoIterator, - F: FnMut(Self::Item, I::Item) -> bool, + Self: ~const Drop, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator, + I::IntoIter: ~const Drop, + <::IntoIter as Iterator>::Item: ~const Drop, + Self::Item: ~const Drop, + F: ~const FnMut(Self::Item, <::IntoIter as Iterator>::Item) -> bool, + F: ~const Drop, { let mut other = other.into_iter(); @@ -3342,11 +3654,15 @@ pub trait Iterator { /// assert_eq!([1].iter().ne([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[default_method_body_is_const] fn ne(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialEq, - Self: Sized, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator + ~const Drop, + <::IntoIter as Iterator>::Item: ~const Drop, + Self::Item: ~const PartialEq<<::IntoIter as Iterator>::Item>, + Self::Item: ~const Drop, + Self: Sized + ~const Drop, { !self.eq(other) } @@ -3363,13 +3679,17 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().lt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[default_method_body_is_const] fn lt(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialOrd, - Self: Sized, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator + ~const Drop, + <::IntoIter as Iterator>::Item: ~const Drop, + Self::Item: ~const PartialOrd<<::IntoIter as Iterator>::Item>, + Self::Item: ~const Drop, + Self: Sized + ~const Drop, { - 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) @@ -3384,11 +3704,15 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().le([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[default_method_body_is_const] fn le(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialOrd, - Self: Sized, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator + ~const Drop, + <::IntoIter as Iterator>::Item: ~const Drop, + Self::Item: ~const PartialOrd<<::IntoIter as Iterator>::Item>, + Self::Item: ~const Drop, + Self: Sized + ~const Drop, { matches!(self.partial_cmp(other), Some(Ordering::Less | Ordering::Equal)) } @@ -3405,13 +3729,17 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().gt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[default_method_body_is_const] fn gt(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialOrd, - Self: Sized, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator + ~const Drop, + <::IntoIter as Iterator>::Item: ~const Drop, + Self::Item: ~const PartialOrd<<::IntoIter as Iterator>::Item>, + Self::Item: ~const Drop, + Self: Sized + ~const Drop, { - 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) @@ -3426,11 +3754,15 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().ge([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[default_method_body_is_const] fn ge(self, other: I) -> bool where - I: IntoIterator, - Self::Item: PartialOrd, - Self: Sized, + I: ~const IntoIterator, + I::IntoIter: ~const Iterator + ~const Drop, + <::IntoIter as Iterator>::Item: ~const Drop, + Self::Item: ~const PartialOrd<<::IntoIter as Iterator>::Item>, + Self::Item: ~const Drop, + Self: Sized + ~const Drop, { matches!(self.partial_cmp(other), Some(Ordering::Greater | Ordering::Equal)) } @@ -3457,12 +3789,18 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[default_method_body_is_const] fn is_sorted(self) -> bool where Self: Sized, - Self::Item: PartialOrd, + Self: ~const Drop, + Self::Item: ~const PartialOrd, + Self::Item: ~const Drop, { - self.is_sorted_by(PartialOrd::partial_cmp) + const fn partial_cmp(a: &T, b: &T) -> Option { + a.partial_cmp(b) + } + self.is_sorted_by(partial_cmp) } /// Checks if the elements of this iterator are sorted using the given comparator function. @@ -3485,23 +3823,30 @@ pub trait Iterator { /// /// [`is_sorted`]: Iterator::is_sorted #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[default_method_body_is_const] fn is_sorted_by(mut self, compare: F) -> bool where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Option, - { - #[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) { + Self: ~const Drop, + F: ~const FnMut(&Self::Item, &Self::Item) -> Option, + F: ~const Drop, + Self::Item: ~const Drop, + { + struct Check<'a, T, F>(&'a mut T, F); + + impl_const_closure! { + impl<'a, T, F> const FnMut for Check<'a, T, F> + where + F: ~const FnMut(&T, &T) -> Option, + F: ~const Drop, + T: ~const Drop, + = |&mut self, curr: T| -> bool { + if let Some(Ordering::Greater) | None = self.1(&self.0, &curr) { return false; } - *last = curr; + *self.0 = curr; true - } + }; } let mut last = match self.next() { @@ -3509,7 +3854,7 @@ pub trait Iterator { None => return true, }; - self.all(check(&mut last, compare)) + self.all(Check(&mut last, compare)) } /// Checks if the elements of this iterator are sorted using the given key extraction @@ -3531,11 +3876,15 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[default_method_body_is_const] fn is_sorted_by_key(self, f: F) -> bool where Self: Sized, + Self: ~const Drop, F: FnMut(Self::Item) -> K, - K: PartialOrd, + F: ~const Drop, + K: ~const PartialOrd, + K: ~const Drop, { self.map(f).is_sorted() } @@ -3546,16 +3895,18 @@ pub trait Iterator { #[inline] #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] + #[default_method_body_is_const] unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, { - unreachable!("Always specialized"); + panic!("internal error: entered unreachable code: Always specialized"); } } #[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 { @@ -3564,10 +3915,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 Drop, + { (**self).advance_by(n) } - fn nth(&mut self, n: usize) -> Option { + fn nth(&mut self, n: usize) -> Option + where + I::Item: ~const Drop, + { (**self).nth(n) } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d8ac816fb15a0..46cafb9be5a4c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -107,17 +107,21 @@ #![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_char_convert)] +#![feature(const_cmp)] #![feature(const_discriminant)] #![feature(const_eval_select)] +#![feature(const_extend)] #![feature(const_float_bits_conv)] #![feature(const_float_classify)] #![feature(const_fmt_arguments_new)] +#![feature(const_for)] #![feature(const_heap)] #![feature(const_convert)] #![feature(const_inherent_unchecked_arith)] #![feature(const_int_unchecked_arith)] #![feature(const_intrinsic_copy)] #![feature(const_intrinsic_forget)] +#![feature(const_iter)] #![feature(const_likely)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init)] @@ -151,6 +155,8 @@ #![feature(variant_count)] #![feature(const_array_from_ref)] #![feature(const_slice_from_ref)] +#![feature(iter_internals)] +#![feature(const_try)] // // Language features: #![feature(abi_unadjusted)] diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 10a24a545d329..53e565d5aed42 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -95,7 +95,8 @@ pub enum ControlFlow { } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl ops::Try for ControlFlow { +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +impl const ops::Try for ControlFlow { type Output = C; type Residual = ControlFlow; @@ -114,7 +115,7 @@ impl ops::Try for ControlFlow { } #[unstable(feature = "try_trait_v2", issue = "84277")] -impl ops::FromResidual for ControlFlow { +impl const ops::FromResidual for ControlFlow { #[inline] fn from_residual(residual: ControlFlow) -> Self { match residual { @@ -177,9 +178,12 @@ impl ControlFlow { /// ``` #[inline] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub fn break_value(self) -> Option { + pub const fn break_value(self) -> Option + where + C: ~const Drop, + { match self { - ControlFlow::Continue(..) => None, + ControlFlow::Continue(_x) => None, ControlFlow::Break(x) => Some(x), } } diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index e5c4798afcbff..a127b2b2b8892 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -229,9 +229,10 @@ pub trait FnOnce { mod impls { #[stable(feature = "rust1", since = "1.0.0")] - impl Fn for &F + #[rustc_const_unstable(feature = "const_closure_impls", issue = "92474")] + impl const Fn for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call(&self, args: A) -> F::Output { (**self).call(args) @@ -239,9 +240,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &F + #[rustc_const_unstable(feature = "const_closure_impls", issue = "92474")] + impl const FnMut for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (**self).call(args) @@ -249,9 +251,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &F + #[rustc_const_unstable(feature = "const_closure_impls", issue = "92474")] + impl const FnOnce for &F where - F: Fn, + F: ~const Fn, { type Output = F::Output; @@ -261,9 +264,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &mut F + #[rustc_const_unstable(feature = "const_closure_impls", issue = "92474")] + impl const FnMut for &mut F where - F: FnMut, + F: ~const FnMut, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (*self).call_mut(args) @@ -271,9 +275,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &mut F + #[rustc_const_unstable(feature = "const_closure_impls", issue = "92474")] + impl const FnOnce for &mut F where - F: FnMut, + F: ~const FnMut, { type Output = F::Output; extern "rust-call" fn call_once(self, args: A) -> F::Output { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 8adfb6f4bcf52..941eced985f56 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1133,7 +1133,8 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut<'_, T> { + #[rustc_const_unstable(feature = "const_iter", issue = "92476")] + pub const fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { inner: Item { opt: self.as_mut() } } } @@ -1858,7 +1859,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; @@ -1882,7 +1884,8 @@ impl IntoIterator for Option { } #[stable(since = "1.4.0", feature = "option_iter")] -impl<'a, T> IntoIterator for &'a Option { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl<'a, T> const IntoIterator for &'a Option { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1892,7 +1895,8 @@ impl<'a, T> IntoIterator for &'a Option { } #[stable(since = "1.4.0", feature = "option_iter")] -impl<'a, T> IntoIterator for &'a mut Option { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl<'a, T> const IntoIterator for &'a mut Option { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; @@ -1978,7 +1982,8 @@ struct Item { opt: Option, } -impl Iterator for Item { +#[rustc_const_unstable(feature = "iter_internals", issue = "none")] +impl const Iterator for Item { type Item = A; #[inline] @@ -2018,7 +2023,8 @@ pub struct Iter<'a, A: 'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, A> Iterator for Iter<'a, A> { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl<'a, A> const Iterator for Iter<'a, A> { type Item = &'a A; #[inline] @@ -2068,7 +2074,8 @@ pub struct IterMut<'a, A: 'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, A> Iterator for IterMut<'a, A> { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl<'a, A> const Iterator for IterMut<'a, A> { type Item = &'a mut A; #[inline] @@ -2109,7 +2116,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/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs index 770b6f7601fa2..b0f031bd6ada7 100644 --- a/library/core/tests/iter/mod.rs +++ b/library/core/tests/iter/mod.rs @@ -100,3 +100,16 @@ pub fn extend_for_unit() { } assert_eq!(x, 5); } + +#[test] +pub fn test_const_iter() { + const IT: core::option::IntoIter<()> = { + let mut it = Some(()).into_iter(); + for _ in &mut it {} + it + }; + + let mut iter = IT; + + assert_eq!(iter.next(), None); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 841c114063dc1..93ff6f37c9517 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -13,6 +13,8 @@ #![feature(const_bool_to_option)] #![feature(const_cell_into_inner)] #![feature(const_convert)] +#![feature(const_for)] +#![feature(const_iter)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init)] #![feature(const_maybe_uninit_assume_init_read)] diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 8571a6a137f51..3f77de08a3e2b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -126,11 +126,14 @@ impl Buffer { } } -fn comma_sep(items: impl Iterator) -> impl fmt::Display { +fn comma_sep( + items: impl Iterator, + space_after_comma: bool, +) -> impl fmt::Display { display_fn(move |f| { for (i, item) in items.enumerate() { if i != 0 { - write!(f, ", ")?; + write!(f, ",{}", if space_after_comma { " " } else { "" })?; } fmt::Display::fmt(&item, f)?; } @@ -231,9 +234,9 @@ impl clean::Generics { } if f.alternate() { - write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx)))) + write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx)), true)) } else { - write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx)))) + write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx)), true)) } }) } @@ -249,10 +252,80 @@ crate fn print_where_clause<'a, 'tcx: 'a>( end_newline: bool, ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { - if gens.where_predicates.is_empty() { + let mut where_predicates = gens.where_predicates.iter().filter(|pred| { + !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty()) + }).map(|pred| { + display_fn(move |f| { + if f.alternate() { + f.write_str(" ")?; + } else { + f.write_str("
")?; + } + + match pred { + clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => { + let bounds = bounds; + let for_prefix = match bound_params.len() { + 0 => String::new(), + _ if f.alternate() => { + format!( + "for<{:#}> ", + comma_sep(bound_params.iter().map(|lt| lt.print()), true) + ) + } + _ => format!( + "for<{}> ", + comma_sep(bound_params.iter().map(|lt| lt.print()), true) + ), + }; + + if f.alternate() { + write!( + f, + "{}{:#}: {:#}", + for_prefix, + ty.print(cx), + print_generic_bounds(bounds, cx) + ) + } else { + write!( + f, + "{}{}: {}", + for_prefix, + ty.print(cx), + print_generic_bounds(bounds, cx) + ) + } + } + clean::WherePredicate::RegionPredicate { lifetime, bounds } => { + write!( + f, + "{}: {}", + lifetime.print(), + bounds + .iter() + .map(|b| b.print(cx).to_string()) + .collect::>() + .join(" + ") + ) + } + clean::WherePredicate::EqPredicate { lhs, rhs } => { + if f.alternate() { + write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx),) + } else { + write!(f, "{} == {}", lhs.print(cx), rhs.print(cx),) + } + } + } + }) + }).peekable(); + + if where_predicates.peek().is_none() { return Ok(()); } + let mut clause = String::new(); + if f.alternate() { clause.push_str(" where"); } else { @@ -262,72 +335,11 @@ crate fn print_where_clause<'a, 'tcx: 'a>( clause.push_str(" where"); } } - for (i, pred) in gens.where_predicates.iter().enumerate() { - if f.alternate() { - clause.push(' '); - } else { - clause.push_str("
"); - } - - match pred { - clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => { - let bounds = bounds; - let for_prefix = match bound_params.len() { - 0 => String::new(), - _ if f.alternate() => { - format!( - "for<{:#}> ", - comma_sep(bound_params.iter().map(|lt| lt.print())) - ) - } - _ => format!( - "for<{}> ", - comma_sep(bound_params.iter().map(|lt| lt.print())) - ), - }; - if f.alternate() { - clause.push_str(&format!( - "{}{:#}: {:#}", - for_prefix, - ty.print(cx), - print_generic_bounds(bounds, cx) - )); - } else { - clause.push_str(&format!( - "{}{}: {}", - for_prefix, - ty.print(cx), - print_generic_bounds(bounds, cx) - )); - } - } - clean::WherePredicate::RegionPredicate { lifetime, bounds } => { - clause.push_str(&format!( - "{}: {}", - lifetime.print(), - bounds - .iter() - .map(|b| b.print(cx).to_string()) - .collect::>() - .join(" + ") - )); - } - clean::WherePredicate::EqPredicate { lhs, rhs } => { - if f.alternate() { - clause.push_str(&format!("{:#} == {:#}", lhs.print(cx), rhs.print(cx),)); - } else { - clause.push_str(&format!("{} == {}", lhs.print(cx), rhs.print(cx),)); - } - } - } - - if i < gens.where_predicates.len() - 1 || end_newline { - clause.push(','); - } - } + clause.push_str(&comma_sep(where_predicates, false).to_string()); if end_newline { + clause.push(','); // add a space so stripping
tags and breaking spaces still renders properly if f.alternate() { clause.push(' '); @@ -377,13 +389,13 @@ impl clean::PolyTrait { write!( f, "for<{:#}> ", - comma_sep(self.generic_params.iter().map(|g| g.print(cx))) + comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true) )?; } else { write!( f, "for<{}> ", - comma_sep(self.generic_params.iter().map(|g| g.print(cx))) + comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true) )?; } } @@ -407,7 +419,8 @@ impl clean::GenericBound { let modifier_str = match modifier { hir::TraitBoundModifier::None => "", hir::TraitBoundModifier::Maybe => "?", - hir::TraitBoundModifier::MaybeConst => "~const", + // ~const is experimental; do not display those bounds in rustdoc + hir::TraitBoundModifier::MaybeConst => "", }; if f.alternate() { write!(f, "{}{:#}", modifier_str, ty.print(cx)) @@ -1093,7 +1106,7 @@ impl clean::BareFunctionDecl { write!( f, "for<{}> ", - comma_sep(self.generic_params.iter().map(|g| g.print(cx))) + comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true) ) } else { Ok(()) diff --git a/src/test/rustdoc/const-generics/generic_const_exprs.rs b/src/test/rustdoc/const-generics/generic_const_exprs.rs index 35036a89360e2..215ee228eb857 100644 --- a/src/test/rustdoc/const-generics/generic_const_exprs.rs +++ b/src/test/rustdoc/const-generics/generic_const_exprs.rs @@ -3,5 +3,5 @@ #![allow(incomplete_features)] // make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647 // @has foo/struct.Ice.html '//pre[@class="rust struct"]' \ -// 'pub struct Ice where [(); N + 1]: ;' +// 'pub struct Ice;' pub struct Ice where [(); N + 1]:; diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr index df24585e5551a..1193c5268387c 100644 --- a/src/test/ui/consts/const-fn-error.stderr +++ b/src/test/ui/consts/const-fn-error.stderr @@ -40,7 +40,7 @@ error[E0080]: evaluation of constant value failed LL | for i in 0..x { | ^^^^ | | - | calling non-const function ` as IntoIterator>::into_iter` + | calling non-const function `iter::range::>::next` | inside `f` at $DIR/const-fn-error.rs:5:14 ... LL | let a : [i32; f(X)]; diff --git a/src/test/ui/issues/issue-23966.stderr b/src/test/ui/issues/issue-23966.stderr index ae8233d5c76e6..87996c54ebc4d 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, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `fold` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3044.stderr b/src/test/ui/issues/issue-3044.stderr index b93aeade95e42..4cd5b4ea6826b 100644 --- a/src/test/ui/issues/issue-3044.stderr +++ b/src/test/ui/issues/issue-3044.stderr @@ -11,7 +11,7 @@ LL | | }); note: associated function defined here --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | fn fold(mut self, init: B, mut f: F) -> B +LL | fn fold(self, init: B, mut f: F) -> B | ^^^^ 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 49d6709a86017..b01f418d5d01e 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -17,8 +17,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 6a96709cbacdb..e2ea4791fbe77 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 @@ -8,8 +8,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:29 @@ -21,8 +21,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/suggestions/imm-ref-trait-object.stderr b/src/test/ui/suggestions/imm-ref-trait-object.stderr index 42ca3a78d8f9f..a6201d0335411 100644 --- a/src/test/ui/suggestions/imm-ref-trait-object.stderr +++ b/src/test/ui/suggestions/imm-ref-trait-object.stderr @@ -6,7 +6,7 @@ LL | t.min().unwrap() | ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | Self: Sized, +LL | Self: Sized + ~const Drop, | ----- this has a `Sized` requirement | = note: you need `&mut dyn Iterator` instead of `&dyn Iterator`

(&mut self, predicate: P) -> Option where P: FnMut(Self::Item) -> bool, - Self: Sized + ExactSizeIterator + DoubleEndedIterator, + Self: Sized, + Self: ~const ExactSizeIterator, + Self: ~const DoubleEndedIterator, { + pub struct Check(F); + // 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| { + impl_const_closure! { + impl const FnMut for Check + where + F: ~const FnMut(T) -> bool, + F: ~const Drop, + T: ~const Drop, + = |&mut self, i: usize, x: T| -> ControlFlow { let i = i - 1; - if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i) } - } + if self.0(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i) } + }; } - let n = self.len(); - self.try_rfold(n, check(predicate)).break_value() + let n = Self::len(self); + self.try_rfold(n, Check(predicate)).break_value() } /// Returns the maximum element of an iterator. @@ -2721,12 +2910,19 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn max(self) -> Option where - Self: Sized, - Self::Item: Ord, + Self: Sized + ~const Drop, + Self::Item: ~const Ord + ~const Drop, { - self.max_by(Ord::cmp) + #[inline] + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + const fn cmp(a: &T, b: &T) -> Ordering { + a.cmp(b) + } + + self.max_by(cmp) } /// Returns the minimum element of an iterator. @@ -2759,12 +2955,19 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn min(self) -> Option where - Self: Sized, - Self::Item: Ord, + Self: Sized + ~const Drop, + Self::Item: ~const Ord + ~const Drop, { - self.min_by(Ord::cmp) + #[inline] + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + const fn cmp(a: &T, b: &T) -> Ordering { + a.cmp(b) + } + + self.min_by(cmp) } /// Returns the element that gives the maximum value from the @@ -2781,22 +2984,35 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - fn max_by_key(self, f: F) -> Option + #[default_method_body_is_const] + fn max_by_key(self, f: F) -> Option where Self: Sized, - F: FnMut(&Self::Item) -> B, - { - #[inline] - fn key(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) { - move |x| (f(&x), x) + Self: ~const Drop, + Self::Item: ~const Drop, + B: ~const Drop, + F: ~const FnMut(&Self::Item) -> B, + F: ~const Drop, + { + struct Key(F); + + impl_const_closure! { + impl const FnMut for Key + where + F: ~const FnMut(&T) -> B, + F: ~const Drop, + = |&mut self, x: T| -> (B, T) { + (self.0(&x), x) + }; } #[inline] - fn compare((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering { + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + 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(Key(f)).max_by(compare)?; Some(x) } @@ -2814,17 +3030,29 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_max_by", since = "1.15.0")] + #[default_method_body_is_const] fn max_by(self, compare: F) -> Option where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - #[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) + Self: ~const Drop, + F: ~const FnMut(&Self::Item, &Self::Item) -> Ordering, + F: ~const Drop, + Self::Item: ~const Drop, + { + pub struct Fold(F); + + impl_const_closure! { + impl const FnMut for Fold + where + F: ~const FnMut(&T, &T) -> Ordering, + F: ~const Drop, + T: ~const Drop, + = |&mut self, x: T, y: T| -> T { + cmp::max_by(x, y, &mut self.0) + }; } - self.reduce(fold(compare)) + self.reduce(Fold(compare)) } /// Returns the element that gives the minimum value from the @@ -2841,22 +3069,35 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - fn min_by_key(self, f: F) -> Option + #[default_method_body_is_const] + fn min_by_key(self, f: F) -> Option where Self: Sized, - F: FnMut(&Self::Item) -> B, - { - #[inline] - fn key(mut f: impl FnMut(&T) -> B) -> impl FnMut(T) -> (B, T) { - move |x| (f(&x), x) + Self: ~const Drop, + Self::Item: ~const Drop, + B: ~const Drop, + F: ~const FnMut(&Self::Item) -> B, + F: ~const Drop, + { + struct Key(F); + + impl_const_closure! { + impl const FnMut for Key + where + F: ~const FnMut(&T) -> B, + F: ~const Drop, + = |&mut self, x: T| -> (B, T) { + (self.0(&x), x) + }; } #[inline] - fn compare((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering { + #[rustc_const_unstable(feature = "iter_internals", issue = "none")] + 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(Key(f)).min_by(compare)?; Some(x) } @@ -2874,17 +3115,29 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_min_by", since = "1.15.0")] + #[default_method_body_is_const] fn min_by(self, compare: F) -> Option where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - #[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) + Self: ~const Drop, + F: ~const FnMut(&Self::Item, &Self::Item) -> Ordering, + F: ~const Drop, + Self::Item: ~const Drop, + { + pub struct Fold(F); + + impl_const_closure! { + impl const FnMut for Fold + where + F: ~const FnMut(&T, &T) -> Ordering, + F: ~const Drop, + T: ~const Drop, + = |&mut self, x: T, y: T| -> T { + cmp::min_by(x, y, &mut self.0) + }; } - self.reduce(fold(compare)) + self.reduce(Fold(compare)) } /// Reverses an iterator's direction. @@ -2911,6 +3164,7 @@ pub trait Iterator { #[inline] #[doc(alias = "reverse")] #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn rev(self) -> Rev where Self: Sized + DoubleEndedIterator, @@ -2949,13 +3203,14 @@ pub trait Iterator { /// assert_eq!(z, [3, 6]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] 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 + ~const Drop, { - let mut unzipped: (FromA, FromB) = Default::default(); + let mut unzipped: (FromA, FromB) = (FromA::default(), FromB::default()); unzipped.extend(self); unzipped } @@ -2981,6 +3236,7 @@ pub trait Iterator { /// assert_eq!(v_map, vec![1, 2, 3]); /// ``` #[stable(feature = "iter_copied", since = "1.36.0")] + #[default_method_body_is_const] fn copied<'a, T: 'a>(self) -> Copied where Self: Sized + Iterator, @@ -3012,6 +3268,7 @@ pub trait Iterator { /// assert_eq!(v_map, vec![1, 2, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[default_method_body_is_const] fn cloned<'a, T: 'a>(self) -> Cloned where Self: Sized + Iterator, @@ -3046,9 +3303,10 @@ pub trait Iterator { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[default_method_body_is_const] fn cycle(self) -> Cycle where - Self: Sized + Clone, + Self: Sized + ~const Clone, { Cycle::new(self) } @@ -3076,10 +3334,11 @@ pub trait Iterator { /// assert_eq!(sum, 6); /// ``` #[stable(feature = "iter_arith", since = "1.11.0")] + #[default_method_body_is_const] fn sum(self) -> S where Self: Sized, - S: Sum, + S: ~const Sum, { Sum::sum(self) } @@ -3105,10 +3364,11 @@ pub trait Iterator { /// assert_eq!(factorial(5), 120); /// ``` #[stable(feature = "iter_arith", since = "1.11.0")] + #[default_method_body_is_const] fn product