Skip to content

Commit 45acd46

Browse files
committed
Auto merge of rust-lang#124097 - compiler-errors:box-into-iter, r=WaffleLapkin
Add `IntoIterator` for `Box<[T]>` + edition 2024-specific lints * Adds a similar method probe opt-out mechanism to the `[T;N]: IntoIterator` implementation for edition 2021. * Adjusts the relevant lints (shadowed `.into_iter()` calls, new source of method ambiguity). * Adds some tests. * Took the liberty to rework the logic in the `ARRAY_INTO_ITER` lint, since it was kind of confusing. Based mostly off of rust-lang#116607. ACP: rust-lang/libs-team#263 References rust-lang#59878 Tracking for Rust 2024: rust-lang#123759 Crater run was done here: rust-lang#116607 (comment) Consensus afaict was that there is too much breakage, so let's do this in an edition-dependent way much like `[T; N]: IntoIterator`.
2 parents dc3424e + fd9af8b commit 45acd46

File tree

4 files changed

+92
-2
lines changed

4 files changed

+92
-2
lines changed

alloc/src/boxed.rs

+86
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,45 @@
135135
//! is not allowed. For more guidance on working with box from unsafe code, see
136136
//! [rust-lang/unsafe-code-guidelines#326][ucg#326].
137137
//!
138+
//! # Editions
139+
//!
140+
//! A special case exists for the implementation of `IntoIterator` for arrays on the Rust 2021
141+
//! edition, as documented [here][array]. Unfortunately, it was later found that a similar
142+
//! workaround should be added for boxed slices, and this was applied in the 2024 edition.
143+
//!
144+
//! Specifically, `IntoIterator` is implemented for `Box<[T]>` on all editions, but specific calls
145+
//! to `into_iter()` for boxed slices will defer to the slice implementation on editions before
146+
//! 2024:
147+
//!
148+
#![cfg_attr(bootstrap, doc = "```rust,edition2021,ignore")]
149+
#![cfg_attr(not(bootstrap), doc = "```rust,edition2021")]
150+
//! // Rust 2015, 2018, and 2021:
151+
//!
152+
//! # #![allow(boxed_slice_into_iter)] // override our `deny(warnings)`
153+
//! let boxed_slice: Box<[i32]> = vec![0; 3].into_boxed_slice();
154+
//!
155+
//! // This creates a slice iterator, producing references to each value.
156+
//! for item in boxed_slice.into_iter().enumerate() {
157+
//! let (i, x): (usize, &i32) = item;
158+
//! println!("boxed_slice[{i}] = {x}");
159+
//! }
160+
//!
161+
//! // The `boxed_slice_into_iter` lint suggests this change for future compatibility:
162+
//! for item in boxed_slice.iter().enumerate() {
163+
//! let (i, x): (usize, &i32) = item;
164+
//! println!("boxed_slice[{i}] = {x}");
165+
//! }
166+
//!
167+
//! // You can explicitly iterate a boxed slice by value using `IntoIterator::into_iter`
168+
//! for item in IntoIterator::into_iter(boxed_slice).enumerate() {
169+
//! let (i, x): (usize, i32) = item;
170+
//! println!("boxed_slice[{i}] = {x}");
171+
//! }
172+
//! ```
173+
//!
174+
//! Similar to the array implementation, this may be modified in the future to remove this override,
175+
//! and it's best to avoid relying on this edition-dependent behavior if you wish to preserve
176+
//! compatibility with future versions of the compiler.
138177
//!
139178
//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
140179
//! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326
@@ -165,6 +204,7 @@ use core::ops::{
165204
};
166205
use core::pin::Pin;
167206
use core::ptr::{self, addr_of_mut, NonNull, Unique};
207+
use core::slice;
168208
use core::task::{Context, Poll};
169209

170210
#[cfg(not(no_global_oom_handling))]
@@ -177,6 +217,7 @@ use crate::raw_vec::RawVec;
177217
use crate::str::from_boxed_utf8_unchecked;
178218
#[cfg(not(no_global_oom_handling))]
179219
use crate::string::String;
220+
use crate::vec;
180221
#[cfg(not(no_global_oom_handling))]
181222
use crate::vec::Vec;
182223

@@ -2080,6 +2121,51 @@ impl<I> FromIterator<I> for Box<[I]> {
20802121
}
20812122
}
20822123

2124+
/// This implementation is required to make sure that the `Box<[I]>: IntoIterator`
2125+
/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
2126+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2127+
impl<I, A: Allocator> !Iterator for Box<[I], A> {}
2128+
2129+
/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator`
2130+
/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
2131+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2132+
impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {}
2133+
2134+
/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator`
2135+
/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
2136+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2137+
impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {}
2138+
2139+
// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator`
2140+
// hides this implementation from explicit `.into_iter()` calls on editions < 2024,
2141+
// so those calls will still resolve to the slice implementation, by reference.
2142+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2143+
impl<I, A: Allocator> IntoIterator for Box<[I], A> {
2144+
type IntoIter = vec::IntoIter<I, A>;
2145+
type Item = I;
2146+
fn into_iter(self) -> vec::IntoIter<I, A> {
2147+
self.into_vec().into_iter()
2148+
}
2149+
}
2150+
2151+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2152+
impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> {
2153+
type IntoIter = slice::Iter<'a, I>;
2154+
type Item = &'a I;
2155+
fn into_iter(self) -> slice::Iter<'a, I> {
2156+
self.iter()
2157+
}
2158+
}
2159+
2160+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
2161+
impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> {
2162+
type IntoIter = slice::IterMut<'a, I>;
2163+
type Item = &'a mut I;
2164+
fn into_iter(self) -> slice::IterMut<'a, I> {
2165+
self.iter_mut()
2166+
}
2167+
}
2168+
20832169
#[cfg(not(no_global_oom_handling))]
20842170
#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
20852171
impl FromIterator<char> for Box<str> {

core/src/array/iter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub struct IntoIter<T, const N: usize> {
3838
alive: IndexRange,
3939
}
4040

41-
// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
41+
// Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator`
4242
// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
4343
// so those calls will still resolve to the slice implementation, by reference.
4444
#[stable(feature = "array_into_iter_impl", since = "1.53.0")]

core/src/iter/traits/collect.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,6 @@ where
268268
/// }
269269
/// ```
270270
#[rustc_diagnostic_item = "IntoIterator"]
271-
#[rustc_skip_array_during_method_dispatch]
272271
#[rustc_on_unimplemented(
273272
on(
274273
_Self = "core::ops::range::RangeTo<Idx>",
@@ -312,6 +311,8 @@ where
312311
label = "`{Self}` is not an iterator",
313312
message = "`{Self}` is not an iterator"
314313
)]
314+
#[cfg_attr(bootstrap, rustc_skip_array_during_method_dispatch)]
315+
#[cfg_attr(not(bootstrap), rustc_skip_during_method_dispatch(array, boxed_slice))]
315316
#[stable(feature = "rust1", since = "1.0.0")]
316317
pub trait IntoIterator {
317318
/// The type of the elements being iterated over.

core/src/slice/iter.rs

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ use crate::ptr::{self, without_provenance, without_provenance_mut, NonNull};
1616

1717
use super::{from_raw_parts, from_raw_parts_mut};
1818

19+
#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
20+
impl<T> !Iterator for [T] {}
21+
1922
#[stable(feature = "rust1", since = "1.0.0")]
2023
impl<'a, T> IntoIterator for &'a [T] {
2124
type Item = &'a T;

0 commit comments

Comments
 (0)