Auto merge of #84147 - cuviper:array-method-dispatch, r=nikomatsakis,m-ou-se
Cautiously add IntoIterator for arrays by value Add the attribute described in #84133, `#[rustc_skip_array_during_method_dispatch]`, which effectively hides a trait from method dispatch when the receiver type is an array. Then cherry-pick `IntoIterator for [T; N]` from #65819 and gate it with that attribute. Arrays can now be used as `IntoIterator` normally, but `array.into_iter()` has edition-dependent behavior, returning `slice::Iter` for 2015 and 2018 editions, or `array::IntoIter` for 2021 and later. r? `@nikomatsakis` cc `@LukasKalbertodt` `@rust-lang/libs`
This commit is contained in:
commit
13a2615883
@ -544,6 +544,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_main, Normal, template!(Word),
|
||||
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_skip_array_during_method_dispatch, Normal, template!(Word),
|
||||
"the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
|
||||
from method dispatch when the receiver is an array, for compatibility in editions < 2021."
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes, Testing:
|
||||
|
@ -757,6 +757,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
data.paren_sugar,
|
||||
data.has_auto_impl,
|
||||
data.is_marker,
|
||||
data.skip_array_during_method_dispatch,
|
||||
data.specialization_kind,
|
||||
self.def_path_hash(item_id),
|
||||
)
|
||||
@ -767,6 +768,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
ty::trait_def::TraitSpecializationKind::None,
|
||||
self.def_path_hash(item_id),
|
||||
),
|
||||
|
@ -1422,6 +1422,7 @@ impl EncodeContext<'a, 'tcx> {
|
||||
paren_sugar: trait_def.paren_sugar,
|
||||
has_auto_impl: self.tcx.trait_is_auto(def_id),
|
||||
is_marker: trait_def.is_marker,
|
||||
skip_array_during_method_dispatch: trait_def.skip_array_during_method_dispatch,
|
||||
specialization_kind: trait_def.specialization_kind,
|
||||
};
|
||||
|
||||
|
@ -385,6 +385,7 @@ struct TraitData {
|
||||
paren_sugar: bool,
|
||||
has_auto_impl: bool,
|
||||
is_marker: bool,
|
||||
skip_array_during_method_dispatch: bool,
|
||||
specialization_kind: ty::trait_def::TraitSpecializationKind,
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,11 @@ pub struct TraitDef {
|
||||
/// and thus `impl`s of it are allowed to overlap.
|
||||
pub is_marker: bool,
|
||||
|
||||
/// If `true`, then this trait has the `#[rustc_skip_array_during_method_dispatch]`
|
||||
/// attribute, indicating that editions before 2021 should not consider this trait
|
||||
/// during method dispatch if the receiver is an array.
|
||||
pub skip_array_during_method_dispatch: bool,
|
||||
|
||||
/// Used to determine whether the standard library is allowed to specialize
|
||||
/// on this trait.
|
||||
pub specialization_kind: TraitSpecializationKind,
|
||||
@ -82,6 +87,7 @@ impl<'tcx> TraitDef {
|
||||
paren_sugar: bool,
|
||||
has_auto_impl: bool,
|
||||
is_marker: bool,
|
||||
skip_array_during_method_dispatch: bool,
|
||||
specialization_kind: TraitSpecializationKind,
|
||||
def_path_hash: DefPathHash,
|
||||
) -> TraitDef {
|
||||
@ -91,6 +97,7 @@ impl<'tcx> TraitDef {
|
||||
paren_sugar,
|
||||
has_auto_impl,
|
||||
is_marker,
|
||||
skip_array_during_method_dispatch,
|
||||
specialization_kind,
|
||||
def_path_hash,
|
||||
}
|
||||
|
@ -1033,6 +1033,7 @@ symbols! {
|
||||
rustc_regions,
|
||||
rustc_reservation_impl,
|
||||
rustc_serialize,
|
||||
rustc_skip_array_during_method_dispatch,
|
||||
rustc_specialization_trait,
|
||||
rustc_stable,
|
||||
rustc_std_internal_symbol,
|
||||
|
@ -1461,6 +1461,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
TraitCandidate(trait_ref) => {
|
||||
if let Some(method_name) = self.method_name {
|
||||
// Some trait methods are excluded for arrays before 2021.
|
||||
// (`array.into_iter()` wants a slice iterator for compatibility.)
|
||||
if self_ty.is_array() && !method_name.span.rust_2021() {
|
||||
let trait_def = self.tcx.trait_def(trait_ref.def_id);
|
||||
if trait_def.skip_array_during_method_dispatch {
|
||||
return ProbeResult::NoMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
let predicate = trait_ref.without_const().to_predicate(self.tcx);
|
||||
let obligation = traits::Obligation::new(cause, self.param_env, predicate);
|
||||
if !self.predicate_may_hold(&obligation) {
|
||||
|
@ -1191,6 +1191,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
|
||||
}
|
||||
|
||||
let is_marker = tcx.has_attr(def_id, sym::marker);
|
||||
let skip_array_during_method_dispatch =
|
||||
tcx.has_attr(def_id, sym::rustc_skip_array_during_method_dispatch);
|
||||
let spec_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
|
||||
ty::trait_def::TraitSpecializationKind::Marker
|
||||
} else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
|
||||
@ -1199,7 +1201,16 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
|
||||
ty::trait_def::TraitSpecializationKind::None
|
||||
};
|
||||
let def_path_hash = tcx.def_path_hash(def_id);
|
||||
ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, spec_kind, def_path_hash)
|
||||
ty::TraitDef::new(
|
||||
def_id,
|
||||
unsafety,
|
||||
paren_sugar,
|
||||
is_auto,
|
||||
is_marker,
|
||||
skip_array_during_method_dispatch,
|
||||
spec_kind,
|
||||
def_path_hash,
|
||||
)
|
||||
}
|
||||
|
||||
fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
|
||||
|
@ -155,6 +155,28 @@ impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N] {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
|
||||
// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
|
||||
// so those calls will still resolve to the slice implementation, by reference.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[stable(feature = "array_into_iter_impl", since = "1.53.0")]
|
||||
impl<T, const N: usize> IntoIterator for [T; N] {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T, N>;
|
||||
|
||||
/// Creates a consuming iterator, that is, one that moves each value out of
|
||||
/// the array (from start to end). The array cannot be used after calling
|
||||
/// this unless `T` implements `Copy`, so the whole array is copied.
|
||||
///
|
||||
/// Arrays have special behavior when calling `.into_iter()` prior to the
|
||||
/// 2021 edition -- see the [array] Editions section for more information.
|
||||
///
|
||||
/// [array]: prim@array
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T, const N: usize> IntoIterator for &'a [T; N] {
|
||||
type Item = &'a T;
|
||||
|
@ -198,6 +198,7 @@ pub trait FromIterator<A>: Sized {
|
||||
/// }
|
||||
/// ```
|
||||
#[rustc_diagnostic_item = "IntoIterator"]
|
||||
#[cfg_attr(not(bootstrap), rustc_skip_array_during_method_dispatch)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait IntoIterator {
|
||||
/// The type of the elements being iterated over.
|
||||
|
@ -498,7 +498,7 @@ mod prim_pointer {}
|
||||
/// - [`Copy`]
|
||||
/// - [`Clone`]
|
||||
/// - [`Debug`]
|
||||
/// - [`IntoIterator`] (implemented for `&[T; N]` and `&mut [T; N]`)
|
||||
/// - [`IntoIterator`] (implemented for `[T; N]`, `&[T; N]` and `&mut [T; N]`)
|
||||
/// - [`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`]
|
||||
/// - [`Hash`]
|
||||
/// - [`AsRef`], [`AsMut`]
|
||||
@ -517,7 +517,8 @@ mod prim_pointer {}
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
#[cfg_attr(bootstrap, doc = "```ignore")]
|
||||
#[cfg_attr(not(bootstrap), doc = "```")]
|
||||
/// let mut array: [i32; 3] = [0; 3];
|
||||
///
|
||||
/// array[1] = 1;
|
||||
@ -526,31 +527,16 @@ mod prim_pointer {}
|
||||
/// assert_eq!([1, 2], &array[1..]);
|
||||
///
|
||||
/// // This loop prints: 0 1 2
|
||||
/// for x in &array {
|
||||
/// for x in array {
|
||||
/// print!("{} ", x);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// An array itself is not iterable:
|
||||
/// You can also iterate over reference to the array's elements:
|
||||
///
|
||||
/// ```compile_fail,E0277
|
||||
/// ```
|
||||
/// let array: [i32; 3] = [0; 3];
|
||||
///
|
||||
/// for x in array { }
|
||||
/// // error: the trait bound `[i32; 3]: std::iter::Iterator` is not satisfied
|
||||
/// ```
|
||||
///
|
||||
/// The solution is to coerce the array to a slice by calling a slice method:
|
||||
///
|
||||
/// ```
|
||||
/// # let array: [i32; 3] = [0; 3];
|
||||
/// for x in array.iter() { }
|
||||
/// ```
|
||||
///
|
||||
/// You can also use the array reference's [`IntoIterator`] implementation:
|
||||
///
|
||||
/// ```
|
||||
/// # let array: [i32; 3] = [0; 3];
|
||||
/// for x in &array { }
|
||||
/// ```
|
||||
///
|
||||
@ -564,6 +550,57 @@ mod prim_pointer {}
|
||||
/// move_away(roa);
|
||||
/// ```
|
||||
///
|
||||
/// # Editions
|
||||
///
|
||||
/// Prior to Rust 1.53, arrays did not implement `IntoIterator` by value, so the method call
|
||||
/// `array.into_iter()` auto-referenced into a slice iterator. That behavior is preserved in the
|
||||
/// 2015 and 2018 editions of Rust for compatability, ignoring `IntoIterator` by value.
|
||||
///
|
||||
#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")]
|
||||
#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")]
|
||||
/// # #![allow(array_into_iter)] // override our `deny(warnings)`
|
||||
/// let array: [i32; 3] = [0; 3];
|
||||
///
|
||||
/// // This creates a slice iterator, producing references to each value.
|
||||
/// for item in array.into_iter().enumerate() {
|
||||
/// let (i, x): (usize, &i32) = item;
|
||||
/// println!("array[{}] = {}", i, x);
|
||||
/// }
|
||||
///
|
||||
/// // The `array_into_iter` lint suggests this change for future compatibility:
|
||||
/// for item in array.iter().enumerate() {
|
||||
/// let (i, x): (usize, &i32) = item;
|
||||
/// println!("array[{}] = {}", i, x);
|
||||
/// }
|
||||
///
|
||||
/// // You can explicitly iterate an array by value using
|
||||
/// // `IntoIterator::into_iter` or `std::array::IntoIter::new`:
|
||||
/// for item in IntoIterator::into_iter(array).enumerate() {
|
||||
/// let (i, x): (usize, i32) = item;
|
||||
/// println!("array[{}] = {}", i, x);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Starting in the 2021 edition, `array.into_iter()` will use `IntoIterator` normally to iterate
|
||||
/// by value, and `iter()` should be used to iterate by reference like previous editions.
|
||||
///
|
||||
/// ```rust,edition2021,ignore
|
||||
/// # // FIXME: ignored because 2021 testing is still unstable
|
||||
/// let array: [i32; 3] = [0; 3];
|
||||
///
|
||||
/// // This iterates by reference:
|
||||
/// for item in array.iter().enumerate() {
|
||||
/// let (i, x): (usize, &i32) = item;
|
||||
/// println!("array[{}] = {}", i, x);
|
||||
/// }
|
||||
///
|
||||
/// // This iterates by value:
|
||||
/// for item in array.into_iter().enumerate() {
|
||||
/// let (i, x): (usize, i32) = item;
|
||||
/// println!("array[{}] = {}", i, x);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [slice]: prim@slice
|
||||
/// [`Debug`]: fmt::Debug
|
||||
/// [`Hash`]: hash::Hash
|
||||
|
@ -1,23 +1,16 @@
|
||||
// check-pass
|
||||
|
||||
fn main() {
|
||||
for _ in [0..1] {}
|
||||
//~^ ERROR is not an iterator
|
||||
for _ in [0..=1] {}
|
||||
//~^ ERROR is not an iterator
|
||||
for _ in [0..] {}
|
||||
//~^ ERROR is not an iterator
|
||||
for _ in [..1] {}
|
||||
//~^ ERROR is not an iterator
|
||||
for _ in [..=1] {}
|
||||
//~^ ERROR is not an iterator
|
||||
let start = 0;
|
||||
let end = 0;
|
||||
for _ in [start..end] {}
|
||||
//~^ ERROR is not an iterator
|
||||
let array_of_range = [start..end];
|
||||
for _ in array_of_range {}
|
||||
//~^ ERROR is not an iterator
|
||||
for _ in [0..1, 2..3] {}
|
||||
//~^ ERROR is not an iterator
|
||||
for _ in [0..=1] {}
|
||||
//~^ ERROR is not an iterator
|
||||
}
|
||||
|
@ -1,102 +0,0 @@
|
||||
error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator
|
||||
--> $DIR/array-of-ranges.rs:2:14
|
||||
|
|
||||
LL | for _ in [0..1] {}
|
||||
| ^^^^^^ if you meant to iterate between two values, remove the square brackets
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]`
|
||||
= note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end`
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[std::ops::Range<{integer}>; 1]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator
|
||||
--> $DIR/array-of-ranges.rs:4:14
|
||||
|
|
||||
LL | for _ in [0..=1] {}
|
||||
| ^^^^^^^ if you meant to iterate between two values, remove the square brackets
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]`
|
||||
= note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end`
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[RangeInclusive<{integer}>; 1]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[RangeFrom<{integer}>; 1]` is not an iterator
|
||||
--> $DIR/array-of-ranges.rs:6:14
|
||||
|
|
||||
LL | for _ in [0..] {}
|
||||
| ^^^^^ if you meant to iterate from a value onwards, remove the square brackets
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[RangeFrom<{integer}>; 1]`
|
||||
= note: `[start..]` is an array of one `RangeFrom`; you might have meant to have a `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an unbounded iterator will run forever unless you `break` or `return` from within the loop
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[RangeFrom<{integer}>; 1]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[RangeTo<{integer}>; 1]` is not an iterator
|
||||
--> $DIR/array-of-ranges.rs:8:14
|
||||
|
|
||||
LL | for _ in [..1] {}
|
||||
| ^^^^^ if you meant to iterate until a value, remove the square brackets and add a starting value
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[RangeTo<{integer}>; 1]`
|
||||
= note: `[..end]` is an array of one `RangeTo`; you might have meant to have a bounded `Range` without the brackets: `0..end`
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[RangeTo<{integer}>; 1]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[RangeToInclusive<{integer}>; 1]` is not an iterator
|
||||
--> $DIR/array-of-ranges.rs:10:14
|
||||
|
|
||||
LL | for _ in [..=1] {}
|
||||
| ^^^^^^ if you meant to iterate until a value (including it), remove the square brackets and add a starting value
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[RangeToInclusive<{integer}>; 1]`
|
||||
= note: `[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a bounded `RangeInclusive` without the brackets: `0..=end`
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[RangeToInclusive<{integer}>; 1]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator
|
||||
--> $DIR/array-of-ranges.rs:14:14
|
||||
|
|
||||
LL | for _ in [start..end] {}
|
||||
| ^^^^^^^^^^^^ if you meant to iterate between two values, remove the square brackets
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]`
|
||||
= note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end`
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[std::ops::Range<{integer}>; 1]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator
|
||||
--> $DIR/array-of-ranges.rs:17:14
|
||||
|
|
||||
LL | for _ in array_of_range {}
|
||||
| ^^^^^^^^^^^^^^ if you meant to iterate between two values, remove the square brackets
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]`
|
||||
= note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end`
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[std::ops::Range<{integer}>; 1]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[std::ops::Range<{integer}>; 2]` is not an iterator
|
||||
--> $DIR/array-of-ranges.rs:19:14
|
||||
|
|
||||
LL | for _ in [0..1, 2..3] {}
|
||||
| ^^^^^^^^^^^^ arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 2]`
|
||||
= note: see <https://github.com/rust-lang/rust/pull/65819> for more details
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[std::ops::Range<{integer}>; 2]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator
|
||||
--> $DIR/array-of-ranges.rs:21:14
|
||||
|
|
||||
LL | for _ in [0..=1] {}
|
||||
| ^^^^^^^ if you meant to iterate between two values, remove the square brackets
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]`
|
||||
= note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end`
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[RangeInclusive<{integer}>; 1]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -1,9 +1,8 @@
|
||||
// check-pass
|
||||
|
||||
fn main() {
|
||||
for _ in [1, 2] {}
|
||||
//~^ ERROR is not an iterator
|
||||
let x = [1, 2];
|
||||
for _ in x {}
|
||||
//~^ ERROR is not an iterator
|
||||
for _ in [1.0, 2.0] {}
|
||||
//~^ ERROR is not an iterator
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
error[E0277]: `[{integer}; 2]` is not an iterator
|
||||
--> $DIR/array.rs:2:14
|
||||
|
|
||||
LL | for _ in [1, 2] {}
|
||||
| ^^^^^^ arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[{integer}; 2]`
|
||||
= note: see <https://github.com/rust-lang/rust/pull/65819> for more details
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[{integer}; 2]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[{integer}; 2]` is not an iterator
|
||||
--> $DIR/array.rs:5:14
|
||||
|
|
||||
LL | for _ in x {}
|
||||
| ^ arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[{integer}; 2]`
|
||||
= note: see <https://github.com/rust-lang/rust/pull/65819> for more details
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[{integer}; 2]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error[E0277]: `[{float}; 2]` is not an iterator
|
||||
--> $DIR/array.rs:7:14
|
||||
|
|
||||
LL | for _ in [1.0, 2.0] {}
|
||||
| ^^^^^^^^^^ arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `[{float}; 2]`
|
||||
= note: see <https://github.com/rust-lang/rust/pull/65819> for more details
|
||||
= note: required because of the requirements on the impl of `IntoIterator` for `[{float}; 2]`
|
||||
= note: required by `into_iter`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
39
src/test/ui/iterators/into-iter-on-arrays-2018.rs
Normal file
39
src/test/ui/iterators/into-iter-on-arrays-2018.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// check-pass
|
||||
// edition:2018
|
||||
|
||||
use std::array::IntoIter;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::slice::Iter;
|
||||
|
||||
fn main() {
|
||||
let array = [0; 10];
|
||||
|
||||
// Before 2021, the method dispatched to `IntoIterator for &[T; N]`,
|
||||
// which we continue to support for compatibility.
|
||||
let _: Iter<'_, i32> = array.into_iter();
|
||||
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
|
||||
//~| WARNING this was previously accepted by the compiler but is being phased out
|
||||
|
||||
let _: Iter<'_, i32> = Box::new(array).into_iter();
|
||||
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
|
||||
//~| WARNING this was previously accepted by the compiler but is being phased out
|
||||
|
||||
// The `array_into_iter` lint doesn't cover other wrappers that deref to an array.
|
||||
let _: Iter<'_, i32> = Rc::new(array).into_iter();
|
||||
let _: Iter<'_, i32> = Array(array).into_iter();
|
||||
|
||||
// But you can always use the trait method explicitly as an array.
|
||||
let _: IntoIter<i32, 10> = IntoIterator::into_iter(array);
|
||||
}
|
||||
|
||||
/// User type that dereferences to an array.
|
||||
struct Array([i32; 10]);
|
||||
|
||||
impl Deref for Array {
|
||||
type Target = [i32; 10];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
42
src/test/ui/iterators/into-iter-on-arrays-2018.stderr
Normal file
42
src/test/ui/iterators/into-iter-on-arrays-2018.stderr
Normal file
@ -0,0 +1,42 @@
|
||||
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||
--> $DIR/into-iter-on-arrays-2018.rs:14:34
|
||||
|
|
||||
LL | let _: Iter<'_, i32> = array.into_iter();
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= note: `#[warn(array_into_iter)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||
|
||||
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||
--> $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 was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||
|
||||
warning: 2 warnings emitted
|
||||
|
||||
Future incompatibility report: Future breakage date: None, diagnostic:
|
||||
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||
--> $DIR/into-iter-on-arrays-2018.rs:14:34
|
||||
|
|
||||
LL | let _: Iter<'_, i32> = array.into_iter();
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= note: `#[warn(array_into_iter)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||
|
||||
Future breakage date: None, diagnostic:
|
||||
warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
|
||||
--> $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 was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
|
||||
|
33
src/test/ui/iterators/into-iter-on-arrays-2021.rs
Normal file
33
src/test/ui/iterators/into-iter-on-arrays-2021.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// check-pass
|
||||
// edition:2021
|
||||
// compile-flags: -Zunstable-options
|
||||
|
||||
use std::array::IntoIter;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
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();
|
||||
|
||||
// The `array_into_iter` lint doesn't cover other wrappers that deref to an array.
|
||||
let _: IntoIter<i32, 10> = Rc::new(array).into_iter();
|
||||
let _: IntoIter<i32, 10> = Array(array).into_iter();
|
||||
|
||||
// You can always use the trait method explicitly as an array.
|
||||
let _: IntoIter<i32, 10> = IntoIterator::into_iter(array);
|
||||
}
|
||||
|
||||
/// User type that dereferences to an array.
|
||||
struct Array([i32; 10]);
|
||||
|
||||
impl Deref for Array {
|
||||
type Target = [i32; 10];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user