From 1a8109253196064e26a427d9184874ae14c55f6e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 17 Apr 2024 16:35:48 -0400 Subject: [PATCH] Add the impls for Box<[T]>: IntoIterator Co-authored-by: ltdk --- library/alloc/src/boxed.rs | 86 ++++++++++++++++++++++++++++++++++ library/core/src/slice/iter.rs | 3 ++ 2 files changed, 89 insertions(+) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index f1a6df94e11..21d00503001 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -135,6 +135,45 @@ //! is not allowed. For more guidance on working with box from unsafe code, see //! [rust-lang/unsafe-code-guidelines#326][ucg#326]. //! +//! # Editions +//! +//! A special case exists for the implementation of `IntoIterator` for arrays on the Rust 2021 +//! edition, as documented [here][array]. Unfortunately, it was later found that a similar +//! workaround should be added for boxed slices, and this was applied in the 2024 edition. +//! +//! Specifically, `IntoIterator` is implemented for `Box<[T]>` on all editions, but specific calls +//! to `into_iter()` for boxed slices will defer to the slice implementation on editions before +//! 2024: +//! +#![cfg_attr(bootstrap, doc = "```rust,edition2021,ignore")] +#![cfg_attr(not(bootstrap), doc = "```rust,edition2021")] +//! // Rust 2015, 2018, and 2021: +//! +//! # #![allow(boxed_slice_into_iter)] // override our `deny(warnings)` +//! let boxed_slice: Box<[i32]> = vec![0; 3].into_boxed_slice(); +//! +//! // This creates a slice iterator, producing references to each value. +//! for item in boxed_slice.into_iter().enumerate() { +//! let (i, x): (usize, &i32) = item; +//! println!("boxed_slice[{i}] = {x}"); +//! } +//! +//! // The `boxed_slice_into_iter` lint suggests this change for future compatibility: +//! for item in boxed_slice.iter().enumerate() { +//! let (i, x): (usize, &i32) = item; +//! println!("boxed_slice[{i}] = {x}"); +//! } +//! +//! // You can explicitly iterate a boxed slice by value using `IntoIterator::into_iter` +//! for item in IntoIterator::into_iter(boxed_slice).enumerate() { +//! let (i, x): (usize, i32) = item; +//! println!("boxed_slice[{i}] = {x}"); +//! } +//! ``` +//! +//! Similar to the array implementation, this may be modified in the future to remove this override, +//! and it's best to avoid relying on this edition-dependent behavior if you wish to preserve +//! compatibility with future versions of the compiler. //! //! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198 //! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326 @@ -165,6 +204,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))] @@ -177,6 +217,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; @@ -2080,6 +2121,51 @@ impl FromIterator for Box<[I]> { } } +/// This implementation is required to make sure that the `Box<[I]>: IntoIterator` +/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. +#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")] +impl !Iterator for Box<[I], A> {} + +/// This implementation is required to make sure that the `&Box<[I]>: 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, I, A: Allocator> !Iterator for &'a Box<[I], A> {} + +/// This implementation is required to make sure that the `&mut Box<[I]>: 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, I, A: Allocator> !Iterator for &'a mut Box<[I], 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 IntoIterator for Box<[I], A> { + type IntoIter = vec::IntoIter; + type Item = I; + fn into_iter(self) -> vec::IntoIter { + self.into_vec().into_iter() + } +} + +#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")] +impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], 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, A: Allocator> IntoIterator for &'a mut Box<[I], 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 = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")] impl FromIterator for Box { diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index d7d4f90c1a5..96fc87ab2e9 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -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 !Iterator for [T] {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a [T] { type Item = &'a T;