Skip to content

Add Box<[T; N]>: IntoIterator without any method dispatch hacks #124108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ use core::ops::{
};
use core::pin::Pin;
use core::ptr::{self, addr_of_mut, NonNull, Unique};
use core::slice;
use core::task::{Context, Poll};

#[cfg(not(no_global_oom_handling))]
Expand All @@ -177,6 +178,7 @@ use crate::raw_vec::RawVec;
use crate::str::from_boxed_utf8_unchecked;
#[cfg(not(no_global_oom_handling))]
use crate::string::String;
use crate::vec;
#[cfg(not(no_global_oom_handling))]
use crate::vec::Vec;

Expand Down Expand Up @@ -2080,6 +2082,51 @@ impl<I> FromIterator<I> for Box<[I]> {
}
}

/// This implementation is required to make sure that the `Box<[I; N]>: IntoIterator`
/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
impl<I, const N: usize, A: Allocator> !Iterator for Box<[I; N], A> {}

/// This implementation is required to make sure that the `&Box<[I; N]>: IntoIterator`
/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
impl<'a, const N: usize, I, A: Allocator> !Iterator for &'a Box<[I; N], A> {}

/// This implementation is required to make sure that the `&mut Box<[I; N]>: IntoIterator`
/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
impl<'a, const N: usize, I, A: Allocator> !Iterator for &'a mut Box<[I; N], A> {}

// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator`
// hides this implementation from explicit `.into_iter()` calls on editions < 2024,
// so those calls will still resolve to the slice implementation, by reference.
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
impl<I, const N: usize, A: Allocator> IntoIterator for Box<[I; N], A> {
type IntoIter = vec::IntoIter<I, A>;
type Item = I;
fn into_iter(self) -> vec::IntoIter<I, A> {
(self as Box<[I], A>).into_vec().into_iter()
}
}

#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
impl<'a, I, const N: usize, A: Allocator> IntoIterator for &'a Box<[I; N], A> {
type IntoIter = slice::Iter<'a, I>;
type Item = &'a I;
fn into_iter(self) -> slice::Iter<'a, I> {
self.iter()
}
}

#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
impl<'a, I, const N: usize, A: Allocator> IntoIterator for &'a mut Box<[I; N], A> {
type IntoIter = slice::IterMut<'a, I>;
type Item = &'a mut I;
fn into_iter(self) -> slice::IterMut<'a, I> {
self.iter_mut()
}
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "box_slice_clone", since = "1.3.0")]
impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/slice/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ use crate::ptr::{self, without_provenance, without_provenance_mut, NonNull};

use super::{from_raw_parts, from_raw_parts_mut};

#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
impl<T, const N: usize> !Iterator for [T; N] {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> IntoIterator for &'a [T] {
type Item = &'a T;
Expand Down
5 changes: 1 addition & 4 deletions tests/ui/iterators/into-iter-on-arrays-2018.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::array::IntoIter;
use std::ops::Deref;
use std::rc::Rc;
use std::slice::Iter;
use std::vec;

fn main() {
let array = [0; 10];
Expand All @@ -15,10 +16,6 @@ fn main() {
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

let _: Iter<'_, i32> = Box::new(array).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

let _: Iter<'_, i32> = Rc::new(array).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Expand Down
19 changes: 5 additions & 14 deletions tests/ui/iterators/into-iter-on-arrays-2018.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:14:34
--> $DIR/into-iter-on-arrays-2018.rs:15:34
|
LL | let _: Iter<'_, i32> = array.into_iter();
| ^^^^^^^^^
Expand All @@ -17,16 +17,7 @@ LL | let _: Iter<'_, i32> = IntoIterator::into_iter(array);
| ++++++++++++++++++++++++ ~

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:18:44
|
LL | let _: Iter<'_, i32> = Box::new(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:22:43
--> $DIR/into-iter-on-arrays-2018.rs:19:43
|
LL | let _: Iter<'_, i32> = Rc::new(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
Expand All @@ -35,7 +26,7 @@ LL | let _: Iter<'_, i32> = Rc::new(array).into_iter();
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:25:41
--> $DIR/into-iter-on-arrays-2018.rs:22:41
|
LL | let _: Iter<'_, i32> = Array(array).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
Expand All @@ -44,7 +35,7 @@ LL | let _: Iter<'_, i32> = Array(array).into_iter();
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-2018.rs:32:24
--> $DIR/into-iter-on-arrays-2018.rs:29:24
|
LL | for _ in [1, 2, 3].into_iter() {}
| ^^^^^^^^^
Expand All @@ -61,5 +52,5 @@ LL - for _ in [1, 2, 3].into_iter() {}
LL + for _ in [1, 2, 3] {}
|

warning: 5 warnings emitted
warning: 4 warnings emitted

4 changes: 3 additions & 1 deletion tests/ui/iterators/into-iter-on-arrays-2021.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
use std::array::IntoIter;
use std::ops::Deref;
use std::rc::Rc;
use std::vec;

fn main() {
let array = [0; 10];

// In 2021, the method dispatches to `IntoIterator for [T; N]`.
let _: IntoIter<i32, 10> = array.into_iter();
let _: IntoIter<i32, 10> = Box::new(array).into_iter();
// and for `Box<[T; N]>`, we use `vec::IntoIter`, since #124108.
let _: vec::IntoIter<i32> = Box::new(array).into_iter();

// The `array_into_iter` lint doesn't cover other wrappers that deref to an array.
let _: IntoIter<i32, 10> = Rc::new(array).into_iter();
Expand Down
26 changes: 0 additions & 26 deletions tests/ui/iterators/into-iter-on-arrays-lint.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,6 @@ fn main() {
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

Box::new(small).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new([1, 2]).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(big).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new([0u8; 33]).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

Box::new(Box::new(small)).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new([1, 2])).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new(big)).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new([0u8; 33])).iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

// Expressions that should not
(&[1, 2]).into_iter();
(&small).into_iter();
Expand Down
26 changes: 0 additions & 26 deletions tests/ui/iterators/into-iter-on-arrays-lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,6 @@ fn main() {
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

Box::new(small).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new([1, 2]).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(big).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new([0u8; 33]).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

Box::new(Box::new(small)).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new([1, 2])).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new(big)).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning
Box::new(Box::new([0u8; 33])).into_iter();
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this changes meaning

// Expressions that should not
(&[1, 2]).into_iter();
(&small).into_iter();
Expand Down
74 changes: 1 addition & 73 deletions tests/ui/iterators/into-iter-on-arrays-lint.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -67,77 +67,5 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit
LL | IntoIterator::into_iter([0u8; 33]);
| ++++++++++++++++++++++++ ~

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:24:21
|
LL | Box::new(small).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:27:22
|
LL | Box::new([1, 2]).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:30:19
|
LL | Box::new(big).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:33:25
|
LL | Box::new([0u8; 33]).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:37:31
|
LL | Box::new(Box::new(small)).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:40:32
|
LL | Box::new(Box::new([1, 2])).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:43:29
|
LL | Box::new(Box::new(big)).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
--> $DIR/into-iter-on-arrays-lint.rs:46:35
|
LL | Box::new(Box::new([0u8; 33])).into_iter();
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
= warning: this changes meaning in Rust 2021
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>

warning: 12 warnings emitted
warning: 4 warnings emitted

4 changes: 2 additions & 2 deletions tests/ui/traits/method-on-unbounded-type-param.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ LL | x.cmp(&x);
which is required by `&mut dyn T: Iterator`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following traits define an item `cmp`, perhaps you need to implement one of them:
candidate #1: `Iterator`
candidate #2: `Ord`
candidate #1: `Ord`
= note: the trait `Iterator` defines an item `cmp`, but is explicitly unimplemented

error: aborting due to 4 previous errors

Expand Down
Loading