From 9fba2622a018c69c9dcff378be1d47e63948e127 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 31 May 2022 22:15:50 +0400 Subject: [PATCH 1/5] implement tuple<->array convertions via `From` --- library/core/src/tuple.rs | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 75d7a3f40058e..da3384f517761 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -100,6 +100,26 @@ macro_rules! tuple_impls { } } } + + #[stable(feature = "array_tuple_conv", since = "1.63.0")] + impl From<[T; count!($($T)+)]> for ($(${ignore(T)} T,)+) { + #[inline] + #[allow(non_snake_case)] + fn from(array: [T; count!($($T)+)]) -> Self { + let [$($T,)+] = array; + ($($T,)+) + } + } + + #[stable(feature = "array_tuple_conv", since = "1.63.0")] + impl From<($(${ignore(T)} T,)+)> for [T; count!($($T)+)] { + #[inline] + #[allow(non_snake_case)] + fn from(tuple: ($(${ignore(T)} T,)+)) -> Self { + let ($($T,)+) = tuple; + [$($T,)+] + } + } } } @@ -179,3 +199,23 @@ macro_rules! last_type { } tuple_impls!(E D C B A Z Y X W V U T); + +macro_rules! count { + ($($a:ident)*) => { + 0 $(${ignore(a)} + 1)* + }; +} + +#[stable(feature = "array_tuple_conv", since = "1.63.0")] +impl From<()> for [T; 0] { + fn from((): ()) -> Self { + [] + } +} + +#[stable(feature = "array_tuple_conv", since = "1.63.0")] +impl From<[T; 0]> for () { + fn from([]: [T; 0]) -> Self { + () + } +} From 4d04a062c8660d0fbbceae27a78dba201b9477a1 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 2 Jun 2022 12:26:06 +0400 Subject: [PATCH 2/5] Use metavar `${count(x)}` instead of reimplementing it --- library/core/src/tuple.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index da3384f517761..ea52a1131fd93 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -102,17 +102,17 @@ macro_rules! tuple_impls { } #[stable(feature = "array_tuple_conv", since = "1.63.0")] - impl From<[T; count!($($T)+)]> for ($(${ignore(T)} T,)+) { + impl From<[T; ${count(T)}]> for ($(${ignore(T)} T,)+) { #[inline] #[allow(non_snake_case)] - fn from(array: [T; count!($($T)+)]) -> Self { + fn from(array: [T; ${count(T)}]) -> Self { let [$($T,)+] = array; ($($T,)+) } } #[stable(feature = "array_tuple_conv", since = "1.63.0")] - impl From<($(${ignore(T)} T,)+)> for [T; count!($($T)+)] { + impl From<($(${ignore(T)} T,)+)> for [T; ${count(T)}] { #[inline] #[allow(non_snake_case)] fn from(tuple: ($(${ignore(T)} T,)+)) -> Self { @@ -200,12 +200,6 @@ macro_rules! last_type { tuple_impls!(E D C B A Z Y X W V U T); -macro_rules! count { - ($($a:ident)*) => { - 0 $(${ignore(a)} + 1)* - }; -} - #[stable(feature = "array_tuple_conv", since = "1.63.0")] impl From<()> for [T; 0] { fn from((): ()) -> Self { From 04305c05d361feebbc133196f1f5eb43a01270e9 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 2 Jun 2022 13:12:15 +0400 Subject: [PATCH 3/5] Remove `[]` <-> `()` `From` convertions ... with this convertions some tests fail :( --- library/core/src/tuple.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index ea52a1131fd93..c46c49547f6d4 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -199,17 +199,3 @@ macro_rules! last_type { } tuple_impls!(E D C B A Z Y X W V U T); - -#[stable(feature = "array_tuple_conv", since = "1.63.0")] -impl From<()> for [T; 0] { - fn from((): ()) -> Self { - [] - } -} - -#[stable(feature = "array_tuple_conv", since = "1.63.0")] -impl From<[T; 0]> for () { - fn from([]: [T; 0]) -> Self { - () - } -} From 36f86936b2aef9ae9abba614037c3ab96c9a5af4 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 2 Jun 2022 13:14:43 +0400 Subject: [PATCH 4/5] --bless tests --- tests/ui/issues/issue-32709.stderr | 13 ++++++++++--- .../ui/suggestions/issue-71394-no-from-impl.stderr | 10 ++++++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/tests/ui/issues/issue-32709.stderr b/tests/ui/issues/issue-32709.stderr index 1d595ca5649b2..a4ba5da4d8724 100644 --- a/tests/ui/issues/issue-32709.stderr +++ b/tests/ui/issues/issue-32709.stderr @@ -7,9 +7,16 @@ LL | Err(5)?; | ^ the trait `From<{integer}>` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual>> + = help: the following other types implement trait `From`: + <(T, T) as From<[T; 2]>> + <(T, T, T) as From<[T; 3]>> + <(T, T, T, T) as From<[T; 4]>> + <(T, T, T, T, T) as From<[T; 5]>> + <(T, T, T, T, T, T) as From<[T; 6]>> + <(T, T, T, T, T, T, T) as From<[T; 7]>> + <(T, T, T, T, T, T, T, T) as From<[T; 8]>> + <(T, T, T, T, T, T, T, T, T) as From<[T; 9]>> + and 4 others = note: required for `Result` to implement `FromResidual>` error: aborting due to previous error diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index 5c36a385a4671..ea57992b48326 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -6,8 +6,14 @@ LL | let _: &[i8] = data.into(); | = help: the following other types implement trait `From`: <&'input [u8] as From>> - <[T; LANES] as From>> - <[bool; LANES] as From>> + <[T; 10] as From<(T, T, T, T, T, T, T, T, T, T)>> + <[T; 11] as From<(T, T, T, T, T, T, T, T, T, T, T)>> + <[T; 12] as From<(T, T, T, T, T, T, T, T, T, T, T, T)>> + <[T; 1] as From<(T,)>> + <[T; 2] as From<(T, T)>> + <[T; 3] as From<(T, T, T)>> + <[T; 4] as From<(T, T, T, T)>> + and 7 others = note: required for `&[u8]` to implement `Into<&[i8]>` error: aborting due to previous error From de105164ea8733b2cab14cf8920f859a17574715 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 3 May 2023 18:38:40 +0000 Subject: [PATCH 5/5] Mention array<->tuple convs in docs --- library/core/src/primitive_docs.rs | 20 ++++++++++++++++++++ library/std/src/primitive_docs.rs | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 08ffc407eadb1..e06ccb5b2870c 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -610,6 +610,9 @@ mod prim_pointer {} /// if the element type allows it. As a stopgap, trait implementations are /// statically generated up to size 32. /// +/// Arrays of sizes from 1 to 12 (inclusive) implement [`From`], where `Tuple` +/// is a homogenous [prim@tuple] of appropriate length. +/// /// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on /// an array. Indeed, this provides most of the API for working with arrays. /// @@ -672,6 +675,13 @@ mod prim_pointer {} /// move_away(roa); /// ``` /// +/// Arrays can be created from homogenous tuples of appropriate length: +/// +/// ``` +/// let tuple: (u32, u32, u32) = (1, 2, 3); +/// let array: [u32; 3] = tuple.into(); +/// ``` +/// /// # Editions /// /// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call @@ -774,6 +784,7 @@ mod prim_pointer {} /// [`Borrow`]: borrow::Borrow /// [`BorrowMut`]: borrow::BorrowMut /// [slice pattern]: ../reference/patterns.html#slice-patterns +/// [`From`]: convert::From #[stable(feature = "rust1", since = "1.0.0")] mod prim_array {} @@ -1000,7 +1011,9 @@ mod prim_str {} /// * [`Debug`] /// * [`Default`] /// * [`Hash`] +/// * [`From<[T; N]>`][from] /// +/// [from]: convert::From /// [`Debug`]: fmt::Debug /// [`Hash`]: hash::Hash /// @@ -1051,6 +1064,13 @@ mod prim_str {} /// assert_eq!(y, 5); /// ``` /// +/// Homogenous tuples can be created from arrays of appropriate length: +/// +/// ``` +/// let array: [u32; 3] = [1, 2, 3]; +/// let tuple: (u32, u32, u32) = array.into(); +/// ``` +/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_tuple {} diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 08ffc407eadb1..e06ccb5b2870c 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -610,6 +610,9 @@ mod prim_pointer {} /// if the element type allows it. As a stopgap, trait implementations are /// statically generated up to size 32. /// +/// Arrays of sizes from 1 to 12 (inclusive) implement [`From`], where `Tuple` +/// is a homogenous [prim@tuple] of appropriate length. +/// /// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on /// an array. Indeed, this provides most of the API for working with arrays. /// @@ -672,6 +675,13 @@ mod prim_pointer {} /// move_away(roa); /// ``` /// +/// Arrays can be created from homogenous tuples of appropriate length: +/// +/// ``` +/// let tuple: (u32, u32, u32) = (1, 2, 3); +/// let array: [u32; 3] = tuple.into(); +/// ``` +/// /// # Editions /// /// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call @@ -774,6 +784,7 @@ mod prim_pointer {} /// [`Borrow`]: borrow::Borrow /// [`BorrowMut`]: borrow::BorrowMut /// [slice pattern]: ../reference/patterns.html#slice-patterns +/// [`From`]: convert::From #[stable(feature = "rust1", since = "1.0.0")] mod prim_array {} @@ -1000,7 +1011,9 @@ mod prim_str {} /// * [`Debug`] /// * [`Default`] /// * [`Hash`] +/// * [`From<[T; N]>`][from] /// +/// [from]: convert::From /// [`Debug`]: fmt::Debug /// [`Hash`]: hash::Hash /// @@ -1051,6 +1064,13 @@ mod prim_str {} /// assert_eq!(y, 5); /// ``` /// +/// Homogenous tuples can be created from arrays of appropriate length: +/// +/// ``` +/// let array: [u32; 3] = [1, 2, 3]; +/// let tuple: (u32, u32, u32) = array.into(); +/// ``` +/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_tuple {}