diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 03094bfd333..144543be7c4 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -81,6 +81,7 @@ impl From for TryFromSliceError { } } +#[cfg(bootstrap)] macro_rules! __impl_slice_eq1 { ($Lhs: ty, $Rhs: ty) => { __impl_slice_eq1! { $Lhs, $Rhs, Sized } @@ -96,6 +97,7 @@ macro_rules! __impl_slice_eq1 { } } +#[cfg(bootstrap)] macro_rules! __impl_slice_eq2 { ($Lhs: ty, $Rhs: ty) => { __impl_slice_eq2! { $Lhs, $Rhs, Sized } @@ -114,6 +116,7 @@ macro_rules! __impl_slice_eq2 { } // macro for implementing n-element array functions and operations +#[cfg(bootstrap)] macro_rules! array_impls { ($($N:expr)+) => { $( @@ -264,6 +267,323 @@ macro_rules! array_impls { } } +#[cfg(not(bootstrap))] +mod impls_using_const_generics { + use super::*; + + #[stable(feature = "rust1", since = "1.0.0")] + impl AsRef<[T]> for [T; N] + where + [T; N]: LengthAtMost32, + { + #[inline] + fn as_ref(&self) -> &[T] { + &self[..] + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl AsMut<[T]> for [T; N] + where + [T; N]: LengthAtMost32, + { + #[inline] + fn as_mut(&mut self) -> &mut [T] { + &mut self[..] + } + } + + #[stable(feature = "array_borrow", since = "1.4.0")] + impl Borrow<[T]> for [T; N] + where + [T; N]: LengthAtMost32, + { + fn borrow(&self) -> &[T] { + self + } + } + + #[stable(feature = "array_borrow", since = "1.4.0")] + impl BorrowMut<[T]> for [T; N] + where + [T; N]: LengthAtMost32, + { + fn borrow_mut(&mut self) -> &mut [T] { + self + } + } + + #[stable(feature = "try_from", since = "1.34.0")] + impl TryFrom<&[T]> for [T; N] + where + T: Copy, + [T; N]: LengthAtMost32, + { + type Error = TryFromSliceError; + + fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> { + <&Self>::try_from(slice).map(|r| *r) + } + } + + #[stable(feature = "try_from", since = "1.34.0")] + impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] + where + [T; N]: LengthAtMost32, + { + type Error = TryFromSliceError; + + fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> { + if slice.len() == N { + let ptr = slice.as_ptr() as *const [T; N]; + unsafe { Ok(&*ptr) } + } else { + Err(TryFromSliceError(())) + } + } + } + + #[stable(feature = "try_from", since = "1.34.0")] + impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] + where + [T; N]: LengthAtMost32, + { + type Error = TryFromSliceError; + + fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> { + if slice.len() == N { + let ptr = slice.as_mut_ptr() as *mut [T; N]; + unsafe { Ok(&mut *ptr) } + } else { + Err(TryFromSliceError(())) + } + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl Hash for [T; N] + where + [T; N]: LengthAtMost32, + { + fn hash(&self, state: &mut H) { + Hash::hash(&self[..], state) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl fmt::Debug for [T; N] + where + [T; N]: LengthAtMost32, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&&self[..], f) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T, const N: usize> IntoIterator for &'a [T; N] + where + [T; N]: LengthAtMost32, + { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] + where + [T; N]: LengthAtMost32, + { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A, B, const N: usize> PartialEq<[B; N]> for [A; N] + where + A: PartialEq, + [A; N]: LengthAtMost32, + [B; N]: LengthAtMost32, + { + #[inline] + fn eq(&self, other: &[B; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[B; N]) -> bool { + self[..] != other[..] + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A, B, const N: usize> PartialEq<[B]> for [A; N] + where + A: PartialEq, + [A; N]: LengthAtMost32, + { + #[inline] + fn eq(&self, other: &[B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[B]) -> bool { + self[..] != other[..] + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for [B] + where + B: PartialEq, + [A; N]: LengthAtMost32, + { + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A, B, const N: usize> PartialEq<&'b [B]> for [A; N] + where + A: PartialEq, + [A; N]: LengthAtMost32, + { + #[inline] + fn eq(&self, other: &&'b [B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &&'b [B]) -> bool { + self[..] != other[..] + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for &'b [B] + where + B: PartialEq, + [A; N]: LengthAtMost32, + { + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A, B, const N: usize> PartialEq<&'b mut [B]> for [A; N] + where + A: PartialEq, + [A; N]: LengthAtMost32, + { + #[inline] + fn eq(&self, other: &&'b mut [B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &&'b mut [B]) -> bool { + self[..] != other[..] + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for &'b mut [B] + where + B: PartialEq, + [A; N]: LengthAtMost32, + { + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] + } + } + + // NOTE: some less important impls are omitted to reduce code bloat + // __impl_slice_eq2! { [A; $N], &'b [B; $N] } + // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } + + #[stable(feature = "rust1", since = "1.0.0")] + impl Eq for [T; N] where [T; N]: LengthAtMost32 {} + + #[stable(feature = "rust1", since = "1.0.0")] + impl PartialOrd for [T; N] + where + [T; N]: LengthAtMost32, + { + #[inline] + fn partial_cmp(&self, other: &[T; N]) -> Option { + PartialOrd::partial_cmp(&&self[..], &&other[..]) + } + #[inline] + fn lt(&self, other: &[T; N]) -> bool { + PartialOrd::lt(&&self[..], &&other[..]) + } + #[inline] + fn le(&self, other: &[T; N]) -> bool { + PartialOrd::le(&&self[..], &&other[..]) + } + #[inline] + fn ge(&self, other: &[T; N]) -> bool { + PartialOrd::ge(&&self[..], &&other[..]) + } + #[inline] + fn gt(&self, other: &[T; N]) -> bool { + PartialOrd::gt(&&self[..], &&other[..]) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl Ord for [T; N] + where + [T; N]: LengthAtMost32, + { + #[inline] + fn cmp(&self, other: &[T; N]) -> Ordering { + Ord::cmp(&&self[..], &&other[..]) + } + } +} + +/// Implemented for lengths where trait impls are allowed on arrays in core/std +#[rustc_on_unimplemented( + message="arrays only have std trait implementations for lengths 0..=32", +)] +#[unstable(feature = "const_generic_impls_guard", issue = "0", + reason = "will never be stable, just a temporary step until const generics are stable")] +#[cfg(not(bootstrap))] +pub trait LengthAtMost32 {} + +#[cfg(not(bootstrap))] +macro_rules! array_impls { + ($($N:literal)+) => { + $( + #[unstable(feature = "const_generic_impls_guard", issue = "0")] + impl LengthAtMost32 for [T; $N] {} + )+ + } +} + array_impls! { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 6ab64a11237..278a63081a1 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -74,6 +74,7 @@ #![feature(concat_idents)] #![feature(const_fn)] #![feature(const_fn_union)] +#![cfg_attr(not(bootstrap), feature(const_generics))] #![feature(custom_inner_attributes)] #![feature(doc_cfg)] #![feature(doc_spotlight)] diff --git a/src/test/ui/const-generics/array-impls/core-traits-impls-length-32.rs b/src/test/ui/const-generics/array-impls/core-traits-impls-length-32.rs new file mode 100644 index 00000000000..9998bb84ca0 --- /dev/null +++ b/src/test/ui/const-generics/array-impls/core-traits-impls-length-32.rs @@ -0,0 +1,66 @@ +// check-pass + +pub fn yes_as_ref() -> impl AsRef<[u8]> { + [0; 32] +} + +pub fn yes_as_mut() -> impl AsMut<[u8]> { + [0; 32] +} + +pub fn yes_borrow() -> impl std::borrow::Borrow<[u8]> { + [0; 32] +} + +pub fn yes_borrow_mut() -> impl std::borrow::BorrowMut<[u8]> { + [0; 32] +} + +pub fn yes_try_from_slice() -> impl std::convert::TryFrom<&'static [u8]> { + [0; 32] +} + +pub fn yes_ref_try_from_slice() -> impl std::convert::TryFrom<&'static [u8]> { + let a: &'static _ = &[0; 32]; + a +} + +pub fn yes_hash() -> impl std::hash::Hash { + [0; 32] +} + +pub fn yes_debug() -> impl std::fmt::Debug { + [0; 32] +} + +pub fn yes_ref_into_iterator() -> impl IntoIterator { + let a: &'static _ = &[0; 32]; + a +} + +pub fn yes_partial_eq() -> impl PartialEq<[u8; 32]> { + [0; 32] +} + +pub fn yes_partial_eq_slice() -> impl PartialEq<[u8]> { + [0; 32] +} + +pub fn yes_slice_partial_eq() -> impl PartialEq<[u8; 32]> { + let a: &'static _ = &[0; 32]; + &a[..] +} + +pub fn yes_eq() -> impl Eq { + [0; 32] +} + +pub fn yes_partial_ord() -> impl PartialOrd<[u8; 32]> { + [0; 32] +} + +pub fn yes_ord() -> impl Ord { + [0; 32] +} + +fn main() {} diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs new file mode 100644 index 00000000000..8397d204f35 --- /dev/null +++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs @@ -0,0 +1,29 @@ +pub fn no_debug() { + println!("{:?}", [0_usize; 33]); + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_hash() { + use std::collections::HashSet; + let mut set = HashSet::new(); + set.insert([0_usize; 33]); + //~^ ERROR arrays only have std trait implementations for lengths 0..=32 +} + +pub fn no_partial_eq() -> bool { + [0_usize; 33] == [1_usize; 33] + //~^ ERROR binary operation `==` cannot be applied to type `[usize; 33]` +} + +pub fn no_partial_ord() -> bool { + [0_usize; 33] < [1_usize; 33] + //~^ ERROR binary operation `<` cannot be applied to type `[usize; 33]` +} + +pub fn no_into_iterator() { + for _ in &[0_usize; 33] { + //~^ ERROR the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr new file mode 100644 index 00000000000..09652d99e8e --- /dev/null +++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr @@ -0,0 +1,54 @@ +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/core-traits-no-impls-length-33.rs:2:22 + | +LL | println!("{:?}", [0_usize; 33]); + | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]` + | + = note: required because of the requirements on the impl of `std::fmt::Debug` for `[usize; 33]` + = note: required by `std::fmt::Debug::fmt` + +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/core-traits-no-impls-length-33.rs:9:9 + | +LL | set.insert([0_usize; 33]); + | ^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]` + | + = note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]` + +error[E0369]: binary operation `==` cannot be applied to type `[usize; 33]` + --> $DIR/core-traits-no-impls-length-33.rs:14:19 + | +LL | [0_usize; 33] == [1_usize; 33] + | ------------- ^^ ------------- [usize; 33] + | | + | [usize; 33] + | + = note: an implementation of `std::cmp::PartialEq` might be missing for `[usize; 33]` + +error[E0369]: binary operation `<` cannot be applied to type `[usize; 33]` + --> $DIR/core-traits-no-impls-length-33.rs:19:19 + | +LL | [0_usize; 33] < [1_usize; 33] + | ------------- ^ ------------- [usize; 33] + | | + | [usize; 33] + | + = note: an implementation of `std::cmp::PartialOrd` might be missing for `[usize; 33]` + +error[E0277]: the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied + --> $DIR/core-traits-no-impls-length-33.rs:24:14 + | +LL | for _ in &[0_usize; 33] { + | ^^^^^^^^^^^^^^ the trait `std::iter::IntoIterator` is not implemented for `&[usize; 33]` + | + = help: the following implementations were found: + <&'a [T; _] as std::iter::IntoIterator> + <&'a [T] as std::iter::IntoIterator> + <&'a mut [T; _] as std::iter::IntoIterator> + <&'a mut [T] as std::iter::IntoIterator> + = note: required by `std::iter::IntoIterator::into_iter` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/broken-mir-2.rs b/src/test/ui/const-generics/broken-mir-2.rs index fb9a63ea738..d9a4411b4f9 100644 --- a/src/test/ui/const-generics/broken-mir-2.rs +++ b/src/test/ui/const-generics/broken-mir-2.rs @@ -4,6 +4,7 @@ use std::fmt::Debug; #[derive(Debug)] -struct S([T; N]); //~ ERROR `[T; _]` doesn't implement `std::fmt::Debug` +struct S([T; N]); +//~^ ERROR arrays only have std trait implementations for lengths 0..=32 fn main() {} diff --git a/src/test/ui/const-generics/broken-mir-2.stderr b/src/test/ui/const-generics/broken-mir-2.stderr index fb9b88bde0a..7cad4017712 100644 --- a/src/test/ui/const-generics/broken-mir-2.stderr +++ b/src/test/ui/const-generics/broken-mir-2.stderr @@ -4,13 +4,13 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error[E0277]: `[T; _]` doesn't implement `std::fmt::Debug` +error[E0277]: arrays only have std trait implementations for lengths 0..=32 --> $DIR/broken-mir-2.rs:7:36 | LL | struct S([T; N]); - | ^^^^^^ `[T; _]` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[T; _]` | - = help: the trait `std::fmt::Debug` is not implemented for `[T; _]` + = note: required because of the requirements on the impl of `std::fmt::Debug` for `[T; _]` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[T; _]` = note: required for the cast to the object type `dyn std::fmt::Debug` diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.rs b/src/test/ui/const-generics/derive-debug-array-wrapper.rs index a29cb90ebb7..eee634c1564 100644 --- a/src/test/ui/const-generics/derive-debug-array-wrapper.rs +++ b/src/test/ui/const-generics/derive-debug-array-wrapper.rs @@ -3,7 +3,7 @@ #[derive(Debug)] struct X { - a: [u32; N], //~ ERROR `[u32; _]` doesn't implement `std::fmt::Debug` + a: [u32; N], //~ ERROR arrays only have std trait implementations for lengths 0..=32 } fn main() {} diff --git a/src/test/ui/const-generics/derive-debug-array-wrapper.stderr b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr index 5bab1d1b54a..799ab145edf 100644 --- a/src/test/ui/const-generics/derive-debug-array-wrapper.stderr +++ b/src/test/ui/const-generics/derive-debug-array-wrapper.stderr @@ -4,13 +4,13 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error[E0277]: `[u32; _]` doesn't implement `std::fmt::Debug` +error[E0277]: arrays only have std trait implementations for lengths 0..=32 --> $DIR/derive-debug-array-wrapper.rs:6:5 | LL | a: [u32; N], - | ^^^^^^^^^^^ `[u32; _]` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[u32; _]` | - = help: the trait `std::fmt::Debug` is not implemented for `[u32; _]` + = note: required because of the requirements on the impl of `std::fmt::Debug` for `[u32; _]` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u32; _]` = note: required for the cast to the object type `dyn std::fmt::Debug`