Rollup merge of #62959 - LukasKalbertodt:array-value-iter, r=scottmcm

Add by-value iterator for arrays

This adds an iterator that can iterate over arrays by value, yielding all elements by value. However, **this PR does _not_ add a corresponding `IntoIterator` impl for arrays**. The `IntoIterator` impl needs some discussion about backwards-compatibility that should take place in a separate PR. With this patch, this code should work (but there is currently still a bug):

```rust
#![feature(array_value_iter)]
use std::array::IntoIter;

let arr = [1, 2, 3];
for x in IntoIter::new(arr) {
    println!("{}", x);
}
```

**TODO**:
- [x] Get initial feedback
- [x] Add tests
- [x] Figure out why stage1 produces weird bugs ([comment](https://github.com/rust-lang/rust/pull/62959#issuecomment-516016524))
- [x] Add UI tests as mentioned [here](https://github.com/rust-lang/rust/pull/62959#discussion_r307061894) (will do that soon-ish)
- [x] Fix [this new bug](https://github.com/rust-lang/rust/pull/62959#issuecomment-544732159)

**Notes for reviewers**
- Is the use of `MaybeUninit` correct here? I think it has to be used due to the `Clone` impl which has to fill the dead array elements with something, but cannot fill it with a correct instance.
- Are the unit tests sufficient?

CC #25725
This commit is contained in:
Mazdak Farrokhzad 2019-10-25 06:18:01 +02:00 committed by GitHub
commit a302155344
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 696 additions and 1 deletions

266
src/libcore/array/iter.rs Normal file
View file

@ -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<T, const N: usize>
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<T>; N],
/// The elements in `data` that have not been yielded yet.
///
/// Invariants:
/// - `alive.start <= alive.end`
/// - `alive.end <= N`
alive: Range<usize>,
}
impl<T, const N: usize> IntoIter<T, {N}>
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<T>` is guaranteed to have the same size and alignment
// > as `T`.
//
// The docs even show a transmute from an array of `MaybeUninit<T>` 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<T>; {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<T>; 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>], &[T]>(slice)
}
}
}
#[stable(feature = "array_value_iter_impls", since = "1.38.0")]
impl<T, const N: usize> Iterator for IntoIter<T, {N}>
where
[T; N]: LengthAtMost32,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
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<usize>) {
let len = self.len();
(len, Some(len))
}
fn count(self) -> usize {
self.len()
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
}
#[stable(feature = "array_value_iter_impls", since = "1.38.0")]
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, {N}>
where
[T; N]: LengthAtMost32,
{
fn next_back(&mut self) -> Option<Self::Item> {
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<T, const N: usize> Drop for IntoIter<T, {N}>
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<T, const N: usize> ExactSizeIterator for IntoIter<T, {N}>
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<T, const N: usize> FusedIterator for IntoIter<T, {N}>
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<T, const N: usize> TrustedLen for IntoIter<T, {N}>
where
[T; N]: LengthAtMost32,
{}
#[stable(feature = "array_value_iter_impls", since = "1.38.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, {N}>
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<T>; 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<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, {N}>
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()
}
}

View file

@ -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

View file

@ -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<usize>);
impl Drop for Foo<'_> {
fn drop(&mut self) {
self.0.set(self.0.get() + 1);
}
}
fn five(i: &Cell<usize>) -> [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);
}

View file

@ -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)]

View file

@ -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<Item = i32> {
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() {}

View file

@ -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<Item = i32> {
//~^ 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() {}

View file

@ -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::<T, N>::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<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ 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<i32, 33usize>`
= 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::<T, N>::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<i32, 33usize>`
= 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::<T, N>::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<i32, 33usize>`
= 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::<T, N>::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<i32, 33usize>`
= 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::<T, N>::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<i32, 33usize>`
= 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::<T, N>::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<i32, 33usize>`
= 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::<T, N>::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<i32, 33usize>`
= 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`.