From a2e94ca1ee21f46eb18cd4392fa8e621ebaea20a Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Thu, 25 Jul 2019 00:39:39 +0200 Subject: [PATCH 1/3] Add `array::IntoIter` as a consuming/by-value array iterator The iterator is implemented using const generics. It implements the traits `Iterator`, `DoubleEndedIterator`, `ExactSizeIterator`, `FusedIterator` and `TrustedLen`. It also contains a public method `new` to create it from an array. `IntoIterator` was not implemented for arrays yet, as there are still some open questions regarding backwards compatibility. This commit only adds the iterator impl and does not yet offer a convenient way to obtain that iterator. --- src/libcore/array/iter.rs | 266 +++++++++++++++++++++++++ src/libcore/{array.rs => array/mod.rs} | 7 + 2 files changed, 273 insertions(+) create mode 100644 src/libcore/array/iter.rs rename src/libcore/{array.rs => array/mod.rs} (98%) diff --git a/src/libcore/array/iter.rs b/src/libcore/array/iter.rs new file mode 100644 index 0000000000000..850a599c6599f --- /dev/null +++ b/src/libcore/array/iter.rs @@ -0,0 +1,266 @@ +//! Defines the `IntoIter` owned iterator for arrays. + +use crate::{ + fmt, + iter::{ExactSizeIterator, FusedIterator, TrustedLen}, + mem::{self, MaybeUninit}, + ops::Range, + ptr, +}; +use super::LengthAtMost32; + + +/// A by-value [array] iterator. +/// +/// [array]: ../../std/primitive.array.html +#[unstable(feature = "array_value_iter", issue = "0")] +pub struct IntoIter +where + [T; N]: LengthAtMost32, +{ + /// This is the array we are iterating over. + /// + /// Elements with index `i` where `alive.start <= i < alive.end` have not + /// been yielded yet and are valid array entries. Elements with indices `i + /// < alive.start` or `i >= alive.end` have been yielded already and must + /// not be accessed anymore! Those dead elements might even be in a + /// completely uninitialized state! + /// + /// So the invariants are: + /// - `data[alive]` is alive (i.e. contains valid elements) + /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the + /// elements were already read and must not be touched anymore!) + data: [MaybeUninit; N], + + /// The elements in `data` that have not been yielded yet. + /// + /// Invariants: + /// - `alive.start <= alive.end` + /// - `alive.end <= N` + alive: Range, +} + +impl IntoIter +where + [T; N]: LengthAtMost32, +{ + /// Creates a new iterator over the given `array`. + /// + /// *Note*: this method might never get stabilized and/or removed in the + /// future as there will likely be another, preferred way of obtaining this + /// iterator (either via `IntoIterator` for arrays or via another way). + #[unstable(feature = "array_value_iter", issue = "0")] + pub fn new(array: [T; N]) -> Self { + // The transmute here is actually safe. The docs of `MaybeUninit` + // promise: + // + // > `MaybeUninit` is guaranteed to have the same size and alignment + // > as `T`. + // + // The docs even show a transmute from an array of `MaybeUninit` to + // an array of `T`. + // + // With that, this initialization satisfies the invariants. + + // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it + // works with const generics: + // `mem::transmute::<[T; {N}], [MaybeUninit; {N}]>(array)` + // + // Until then, we do it manually here. We first create a bitwise copy + // but cast the pointer so that it is treated as a different type. Then + // we forget `array` so that it is not dropped. + let data = unsafe { + let data = ptr::read(&array as *const [T; N] as *const [MaybeUninit; N]); + mem::forget(array); + data + }; + + Self { + data, + alive: 0..N, + } + } + + /// Returns an immutable slice of all elements that have not been yielded + /// yet. + fn as_slice(&self) -> &[T] { + // This transmute is safe. As mentioned in `new`, `MaybeUninit` retains + // the size and alignment of `T`. Furthermore, we know that all + // elements within `alive` are properly initialized. + let slice = &self.data[self.alive.clone()]; + unsafe { + mem::transmute::<&[MaybeUninit], &[T]>(slice) + } + } +} + + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl Iterator for IntoIter +where + [T; N]: LengthAtMost32, +{ + type Item = T; + fn next(&mut self) -> Option { + if self.alive.start == self.alive.end { + return None; + } + + // Bump start index. + // + // From the check above we know that `alive.start != alive.end`. + // Combine this with the invariant `alive.start <= alive.end`, we know + // that `alive.start < alive.end`. Increasing `alive.start` by 1 + // maintains the invariant regarding `alive`. However, due to this + // change, for a short time, the alive zone is not `data[alive]` + // anymore, but `data[idx..alive.end]`. + let idx = self.alive.start; + self.alive.start += 1; + + // Read the element from the array. This is safe: `idx` is an index + // into the "alive" region of the array. Reading this element means + // that `data[idx]` is regarded as dead now (i.e. do not touch). As + // `idx` was the start of the alive-zone, the alive zone is now + // `data[alive]` again, restoring all invariants. + let out = unsafe { self.data.get_unchecked(idx).read() }; + + Some(out) + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } + + fn count(self) -> usize { + self.len() + } + + fn last(mut self) -> Option { + self.next_back() + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl DoubleEndedIterator for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn next_back(&mut self) -> Option { + if self.alive.start == self.alive.end { + return None; + } + + // Decrease end index. + // + // From the check above we know that `alive.start != alive.end`. + // Combine this with the invariant `alive.start <= alive.end`, we know + // that `alive.start < alive.end`. As `alive.start` cannot be negative, + // `alive.end` is at least 1, meaning that we can safely decrement it + // by one. This also maintains the invariant `alive.start <= + // alive.end`. However, due to this change, for a short time, the alive + // zone is not `data[alive]` anymore, but `data[alive.start..alive.end + // + 1]`. + self.alive.end -= 1; + + // Read the element from the array. This is safe: `alive.end` is an + // index into the "alive" region of the array. Compare the previous + // comment that states that the alive region is + // `data[alive.start..alive.end + 1]`. Reading this element means that + // `data[alive.end]` is regarded as dead now (i.e. do not touch). As + // `alive.end` was the end of the alive-zone, the alive zone is now + // `data[alive]` again, restoring all invariants. + let out = unsafe { self.data.get_unchecked(self.alive.end).read() }; + + Some(out) + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl Drop for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn drop(&mut self) { + // We simply drop each element via `for_each`. This should not incur + // any significant runtime overhead and avoids adding another `unsafe` + // block. + self.by_ref().for_each(drop); + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl ExactSizeIterator for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn len(&self) -> usize { + // Will never underflow due to the invariant `alive.start <= + // alive.end`. + self.alive.end - self.alive.start + } + fn is_empty(&self) -> bool { + self.alive.is_empty() + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl FusedIterator for IntoIter +where + [T; N]: LengthAtMost32, +{} + +// The iterator indeed reports the correct length. The number of "alive" +// elements (that will still be yielded) is the length of the range `alive`. +// This range is decremented in length in either `next` or `next_back`. It is +// always decremented by 1 in those methods, but only if `Some(_)` is returned. +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +unsafe impl TrustedLen for IntoIter +where + [T; N]: LengthAtMost32, +{} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl Clone for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn clone(&self) -> Self { + unsafe { + // This creates a new uninitialized array. Note that the `assume_init` + // refers to the array, not the individual elements. And it is Ok if + // the array is in an uninitialized state as all elements may be + // uninitialized (all bit patterns are valid). Compare the + // `MaybeUninit` docs for more information. + let mut new_data: [MaybeUninit; N] = MaybeUninit::uninit().assume_init(); + + // Clone all alive elements. + for idx in self.alive.clone() { + // The element at `idx` in the old array is alive, so we can + // safely call `get_ref()`. We then clone it, and write the + // clone into the new array. + let clone = self.data.get_unchecked(idx).get_ref().clone(); + new_data.get_unchecked_mut(idx).write(clone); + } + + Self { + data: new_data, + alive: self.alive.clone(), + } + } + } +} + +#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +impl fmt::Debug for IntoIter +where + [T; N]: LengthAtMost32, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Only print the elements that were not yielded yet: we cannot + // access the yielded elements anymore. + f.debug_tuple("IntoIter") + .field(&self.as_slice()) + .finish() + } +} diff --git a/src/libcore/array.rs b/src/libcore/array/mod.rs similarity index 98% rename from src/libcore/array.rs rename to src/libcore/array/mod.rs index b5614010e5c2f..120658e9a4343 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array/mod.rs @@ -14,6 +14,13 @@ use crate::hash::{Hash, self}; use crate::marker::Unsize; use crate::slice::{Iter, IterMut}; +#[cfg(not(bootstrap))] +mod iter; + +#[cfg(not(bootstrap))] +#[unstable(feature = "array_value_iter", issue = "0")] +pub use iter::IntoIter; + /// Utility trait implemented only on arrays of fixed size /// /// This trait can be used to implement other traits on fixed-size arrays From 5334a307d551e5affaef253f1c83141495db46f0 Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Fri, 26 Jul 2019 13:27:13 +0200 Subject: [PATCH 2/3] Add unit tests for `array::IntoIter` Many tests are based on tests by Josh Stone --- src/libcore/tests/array.rs | 207 ++++++++++++++++++++++++++++++++++++- src/libcore/tests/lib.rs | 1 + 2 files changed, 207 insertions(+), 1 deletion(-) diff --git a/src/libcore/tests/array.rs b/src/libcore/tests/array.rs index 9e133ac568811..4f3b79c78b66c 100644 --- a/src/libcore/tests/array.rs +++ b/src/libcore/tests/array.rs @@ -1,4 +1,4 @@ -use core::array::FixedSizeArray; +use core::array::{FixedSizeArray, IntoIter}; use core::convert::TryFrom; #[test] @@ -40,3 +40,208 @@ fn array_try_from() { 30 31 32 } } + + +#[test] +fn iterator_collect() { + let arr = [0, 1, 2, 5, 9]; + let v: Vec<_> = IntoIter::new(arr.clone()).collect(); + assert_eq!(&arr[..], &v[..]); +} + +#[test] +fn iterator_rev_collect() { + let arr = [0, 1, 2, 5, 9]; + let v: Vec<_> = IntoIter::new(arr.clone()).rev().collect(); + assert_eq!(&v[..], &[9, 5, 2, 1, 0]); +} + +#[test] +fn iterator_nth() { + let v = [0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(IntoIter::new(v.clone()).nth(i).unwrap(), v[i]); + } + assert_eq!(IntoIter::new(v.clone()).nth(v.len()), None); + + let mut iter = IntoIter::new(v); + assert_eq!(iter.nth(2).unwrap(), v[2]); + assert_eq!(iter.nth(1).unwrap(), v[4]); +} + +#[test] +fn iterator_last() { + let v = [0, 1, 2, 3, 4]; + assert_eq!(IntoIter::new(v).last().unwrap(), 4); + assert_eq!(IntoIter::new([0]).last().unwrap(), 0); + + let mut it = IntoIter::new([0, 9, 2, 4]); + assert_eq!(it.next_back(), Some(4)); + assert_eq!(it.last(), Some(2)); +} + +#[test] +fn iterator_clone() { + let mut it = IntoIter::new([0, 2, 4, 6, 8]); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let mut clone = it.clone(); + assert_eq!(it.next_back(), Some(6)); + assert_eq!(clone.next_back(), Some(6)); + assert_eq!(it.next_back(), Some(4)); + assert_eq!(clone.next_back(), Some(4)); + assert_eq!(it.next(), Some(2)); + assert_eq!(clone.next(), Some(2)); +} + +#[test] +fn iterator_fused() { + let mut it = IntoIter::new([0, 9, 2]); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(9)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); +} + +#[test] +fn iterator_len() { + let mut it = IntoIter::new([0, 1, 2, 5, 9]); + assert_eq!(it.size_hint(), (5, Some(5))); + assert_eq!(it.len(), 5); + assert_eq!(it.is_empty(), false); + + assert_eq!(it.next(), Some(0)); + assert_eq!(it.size_hint(), (4, Some(4))); + assert_eq!(it.len(), 4); + assert_eq!(it.is_empty(), false); + + assert_eq!(it.next_back(), Some(9)); + assert_eq!(it.size_hint(), (3, Some(3))); + assert_eq!(it.len(), 3); + assert_eq!(it.is_empty(), false); + + // Empty + let it = IntoIter::new([] as [String; 0]); + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.len(), 0); + assert_eq!(it.is_empty(), true); +} + +#[test] +fn iterator_count() { + let v = [0, 1, 2, 3, 4]; + assert_eq!(IntoIter::new(v.clone()).count(), 5); + + let mut iter2 = IntoIter::new(v); + iter2.next(); + iter2.next(); + assert_eq!(iter2.count(), 3); +} + +#[test] +fn iterator_flat_map() { + assert!((0..5).flat_map(|i| IntoIter::new([2 * i, 2 * i + 1])).eq(0..10)); +} + +#[test] +fn iterator_debug() { + let arr = [0, 1, 2, 5, 9]; + assert_eq!( + format!("{:?}", IntoIter::new(arr)), + "IntoIter([0, 1, 2, 5, 9])", + ); +} + +#[test] +fn iterator_drops() { + use core::cell::Cell; + + // This test makes sure the correct number of elements are dropped. The `R` + // type is just a reference to a `Cell` that is incremented when an `R` is + // dropped. + + #[derive(Clone)] + struct Foo<'a>(&'a Cell); + + impl Drop for Foo<'_> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + fn five(i: &Cell) -> [Foo<'_>; 5] { + // This is somewhat verbose because `Foo` does not implement `Copy` + // since it implements `Drop`. Consequently, we cannot write + // `[Foo(i); 5]`. + [Foo(i), Foo(i), Foo(i), Foo(i), Foo(i)] + } + + // Simple: drop new iterator. + let i = Cell::new(0); + { + IntoIter::new(five(&i)); + } + assert_eq!(i.get(), 5); + + // Call `next()` once. + let i = Cell::new(0); + { + let mut iter = IntoIter::new(five(&i)); + let _x = iter.next(); + assert_eq!(i.get(), 0); + assert_eq!(iter.count(), 4); + assert_eq!(i.get(), 4); + } + assert_eq!(i.get(), 5); + + // Check `clone` and calling `next`/`next_back`. + let i = Cell::new(0); + { + let mut iter = IntoIter::new(five(&i)); + iter.next(); + assert_eq!(i.get(), 1); + iter.next_back(); + assert_eq!(i.get(), 2); + + let mut clone = iter.clone(); + assert_eq!(i.get(), 2); + + iter.next(); + assert_eq!(i.get(), 3); + + clone.next(); + assert_eq!(i.get(), 4); + + assert_eq!(clone.count(), 2); + assert_eq!(i.get(), 6); + } + assert_eq!(i.get(), 8); + + // Check via `nth`. + let i = Cell::new(0); + { + let mut iter = IntoIter::new(five(&i)); + let _x = iter.nth(2); + assert_eq!(i.get(), 2); + let _y = iter.last(); + assert_eq!(i.get(), 3); + } + assert_eq!(i.get(), 5); + + // Check every element. + let i = Cell::new(0); + for (index, _x) in IntoIter::new(five(&i)).enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + for (index, _x) in IntoIter::new(five(&i)).rev().enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 35661356028cb..b28ed2eaa0876 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -31,6 +31,7 @@ #![feature(slice_partition_dedup)] #![feature(int_error_matching)] #![feature(const_fn)] +#![feature(array_value_iter)] #![feature(iter_partition_in_place)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] From c36b9ddcb40b81642cef2d1dd17bcd45f54c70da Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Mon, 21 Oct 2019 13:47:02 +0200 Subject: [PATCH 3/3] Add UI tests for `array::IntoIter` impls This it to make sure traits are implemented for arrays with length 32 and below, while they are not implemented for >= 33. --- .../array-impls/into-iter-impls-length-32.rs | 41 ++++++ .../into-iter-no-impls-length-33.rs | 53 ++++++++ .../into-iter-no-impls-length-33.stderr | 122 ++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs create mode 100644 src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.rs create mode 100644 src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr diff --git a/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs b/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs new file mode 100644 index 0000000000000..0aeba8607e818 --- /dev/null +++ b/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs @@ -0,0 +1,41 @@ +// check-pass + +#![feature(array_value_iter)] +#![feature(trusted_len)] + +use std::{ + array::IntoIter, + fmt::Debug, + iter::{ExactSizeIterator, FusedIterator, TrustedLen}, +}; + +pub fn yes_iterator() -> impl Iterator { + IntoIter::new([0i32; 32]) +} + +pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator { + IntoIter::new([0i32; 32]) +} + +pub fn yes_exact_size_iterator() -> impl ExactSizeIterator { + IntoIter::new([0i32; 32]) +} + +pub fn yes_fused_iterator() -> impl FusedIterator { + IntoIter::new([0i32; 32]) +} + +pub fn yes_trusted_len() -> impl TrustedLen { + IntoIter::new([0i32; 32]) +} + +pub fn yes_clone() -> impl Clone { + IntoIter::new([0i32; 32]) +} + +pub fn yes_debug() -> impl Debug { + IntoIter::new([0i32; 32]) +} + + +fn main() {} diff --git a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.rs b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.rs new file mode 100644 index 0000000000000..a0bbd2ce64add --- /dev/null +++ b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.rs @@ -0,0 +1,53 @@ +#![feature(array_value_iter)] +#![feature(trusted_len)] + +use std::{ + array::IntoIter, + fmt::Debug, + iter::{ExactSizeIterator, FusedIterator, TrustedLen}, +}; + +pub fn no_iterator() -> impl Iterator { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_double_ended_iterator() -> impl DoubleEndedIterator { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_exact_size_iterator() -> impl ExactSizeIterator { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_fused_iterator() -> impl FusedIterator { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_trusted_len() -> impl TrustedLen { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_clone() -> impl Clone { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_debug() -> impl Debug { + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 + IntoIter::new([0i32; 33]) + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + + +fn main() {} diff --git a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr new file mode 100644 index 0000000000000..bfdff8e3bbe61 --- /dev/null +++ b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr @@ -0,0 +1,122 @@ +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:12:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:10:25 + | +LL | pub fn no_iterator() -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:18:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:16:38 + | +LL | pub fn no_double_ended_iterator() -> impl DoubleEndedIterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:24:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:22:36 + | +LL | pub fn no_exact_size_iterator() -> impl ExactSizeIterator { + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:30:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:28:31 + | +LL | pub fn no_fused_iterator() -> impl FusedIterator { + | ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:36:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:34:28 + | +LL | pub fn no_trusted_len() -> impl TrustedLen { + | ^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:42:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:40:22 + | +LL | pub fn no_clone() -> impl Clone { + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:48:5 + | +LL | IntoIter::new([0i32; 33]) + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required by `std::array::IntoIter::::new` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/into-iter-no-impls-length-33.rs:46:22 + | +LL | pub fn no_debug() -> impl Debug { + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | + = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter` + = note: the return type of a function must have a statically known size + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0277`.