From ea0f5053de311b8929783288dd0982b50a4578f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 16 Aug 2019 09:57:38 +0200 Subject: [PATCH 01/51] Create base rfc --- text/0000-variadic_tuples.md | 95 ++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 text/0000-variadic_tuples.md diff --git a/text/0000-variadic_tuples.md b/text/0000-variadic_tuples.md new file mode 100644 index 00000000000..8e48d0048d2 --- /dev/null +++ b/text/0000-variadic_tuples.md @@ -0,0 +1,95 @@ +- Feature Name: (fill me in with a unique ident, `my_awesome_feature`) +- Start Date: (fill me in with today's date, YYYY-MM-DD) +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +One paragraph explanation of the feature. + +# Motivation +[motivation]: #motivation + +Why are we doing this? What use cases does it support? What is the expected outcome? + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: + +- Introducing new named concepts. +- Explaining the feature largely in terms of examples. +- Explaining how Rust programmers should *think* about the feature, and how it should impact the way they use Rust. It should explain the impact as concretely as possible. +- If applicable, provide sample error messages, deprecation warnings, or migration guidance. +- If applicable, describe the differences between teaching this to existing Rust programmers and new Rust programmers. + +For implementation-oriented RFCs (e.g. for compiler internals), this section should focus on how compiler contributors should think about the change, and give examples of its concrete impact. For policy RFCs, this section should provide an example-driven introduction to the policy, and explain its impact in concrete terms. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +This is the technical portion of the RFC. Explain the design in sufficient detail that: + +- Its interaction with other features is clear. +- It is reasonably clear how the feature would be implemented. +- Corner cases are dissected by example. + +The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work. + +# Drawbacks +[drawbacks]: #drawbacks + +Why should we *not* do this? + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +- Why is this design the best in the space of possible designs? +- What other designs have been considered and what is the rationale for not choosing them? +- What is the impact of not doing this? + +# Prior art +[prior-art]: #prior-art + +Discuss prior art, both the good and the bad, in relation to this proposal. +A few examples of what this can include are: + +- For language, library, cargo, tools, and compiler proposals: Does this feature exist in other programming languages and what experience have their community had? +- For community proposals: Is this done by some other community and what were their experiences with it? +- For other teams: What lessons can we learn from what other communities have done here? +- Papers: Are there any published papers or great posts that discuss this? If you have some relevant papers to refer to, this can serve as a more detailed theoretical background. + +This section is intended to encourage you as an author to think about the lessons from other languages, provide readers of your RFC with a fuller picture. +If there is no prior art, that is fine - your ideas are interesting to us whether they are brand new or if it is an adaptation from other languages. + +Note that while precedent set by other languages is some motivation, it does not on its own motivate an RFC. +Please also take into consideration that rust sometimes intentionally diverges from common language features. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +- What parts of the design do you expect to resolve through the RFC process before this gets merged? +- What parts of the design do you expect to resolve through the implementation of this feature before stabilization? +- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? + +# Future possibilities +[future-possibilities]: #future-possibilities + +Think about what the natural extension and evolution of your proposal would +be and how it would affect the language and project as a whole in a holistic +way. Try to use this section as a tool to more fully consider all possible +interactions with the project and language in your proposal. +Also consider how the this all fits into the roadmap for the project +and of the relevant sub-team. + +This is also a good place to "dump ideas", if they are out of scope for the +RFC you are writing but otherwise related. + +If you have tried and cannot think of any future possibilities, +you may simply state that you cannot think of anything. + +Note that having something written down in the future-possibilities section +is not a reason to accept the current or a future RFC; such notes should be +in the section on motivation or rationale in this or subsequent RFCs. +The section merely provides additional information. From dfd9bec6bb993aac862067a4e53b1555f7a0ddd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 16 Aug 2019 09:57:55 +0200 Subject: [PATCH 02/51] Rename 0000-variadic_tuples.md to 0000-variadic-tuples.md --- text/{0000-variadic_tuples.md => 0000-variadic-tuples.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename text/{0000-variadic_tuples.md => 0000-variadic-tuples.md} (100%) diff --git a/text/0000-variadic_tuples.md b/text/0000-variadic-tuples.md similarity index 100% rename from text/0000-variadic_tuples.md rename to text/0000-variadic-tuples.md From cee363a2f56c6d7ebab0d479cc183bf0293508ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 16 Aug 2019 11:19:13 +0200 Subject: [PATCH 03/51] Update 0000-variadic-tuples.md --- text/0000-variadic-tuples.md | 135 +++++++++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 4 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 8e48d0048d2..bd12d7ced12 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -1,21 +1,140 @@ -- Feature Name: (fill me in with a unique ident, `my_awesome_feature`) -- Start Date: (fill me in with today's date, YYYY-MM-DD) +- Feature Name: variadic_tuples +- Start Date: 2019-08-16 - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary [summary]: #summary -One paragraph explanation of the feature. +Tuples types are ordered set of type, but users can only use tuple with a specified number of types. + +This RFC aims to allow the use of a _variadic tuple_ to be able to write implementation for tuples with an arbitrary number of type. # Motivation [motivation]: #motivation -Why are we doing this? What use cases does it support? What is the expected outcome? +## Arbitrary tuple arity support + +Currently, when a user wants to either use or add behavior to tuples, he writes an impl for each size of tuple. +For easier maintenance, it is usually done with a `macro_rules` and implements up to 12 arity tuple. (ex: `Hash` implementation in `std`). + +The proposed RFC provides an easier way to define the implementation for those tuples and don't limit the arity of tuple supported. +Also, the compiler will compile only required tuple arity implementation. + # Guide-level explanation [guide-level-explanation]: #guide-level-explanation +The _variadic tuple_ occurs in two form: a declarative form and an expansion form. + +The declarative form is `..#T` and an expansion form is `T#..`. + +Note: To illustrate the RFC, we will use the current implementation of the `Hash` trait for tuples. + +``` +// Quote from Rust source code +// This macro implements `Hash` for a tuple. +// It is used like this: `impl_hash_tuple! { A B C D E F }` for a 6-arity tuple. +macro_rules! impl_hash_tuple { + () => ( + #[stable(feature = "rust1", since = "1.0.0")] + impl Hash for () { + fn hash(&self, _state: &mut H) {} + } + ); + + ( $($name:ident)+) => ( + #[stable(feature = "rust1", since = "1.0.0")] + impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized { + #[allow(non_snake_case)] + fn hash(&self, state: &mut S) { + let ($(ref $name,)+) = *self; + $($name.hash(state);)+ + } + } + ); +} + +macro_rules! last_type { + ($a:ident,) => { $a }; + ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; +} +``` + +## Declaring a _variadic tuple_ + +To declare a _variadic tuple_, we use `..#T`, where `T` is a type identifier. + +For instance: +* `struct VariadicStruct<..#T1> ..` +* `impl<..#Head> ..` +* `impl ..` +* `fn my_function<..#A> ..` +* `fn my_function ..` + +You can think this like a rule you give to the compiler to generated appropriate code when it runs into specific patterns: +* `VariadicStruct` matches `VariadicStruct<..#T1>` where `..#T1` maps to `int, usize` +* `VariadicStruct` matches `VariadicStruct<..#T1>` where `..#T1` maps to `int, usize, usize` +(We will see implementation examples later, with the expansion form) + +## Expanding _variadic tuple_ + +When expanding a tuple, we use the form `T#..`, but more generally: `#..` where `` is an expression or a block expression using the identifier `T`. + +Let's implement the `Hash` trait: + + +``` +// For the example, we consider the impl for (A, B, C). So `..#T matches `A, B, C` +// We have the first expansion here, `T#..` expands to `A, B, C` +impl<..#T, Last> Hash for (T#.., Last) +where + {T: Hash}#.., // Expands to `A: Hash, B: Hash, C: Hash` + Last: Hash + ?Sized, { + + #[allow(non_snake_case)] + fn hash(&self, state: &mut S) { + let ({ref T}#.., ref last) = *self; // Expands to `let (ref A, ref B, ref C, ref last) = *self;` + (T.hash(state)#.., last.hash(state)); // Expands to `(A.hash(state), B.hash(state), C.hash(state), last.hash(state));` + } +} +``` + +## Allowed usages of _variadic tuple_ + +### Declarative form + +* Struct generic parameters : `struct MyStruct<..#T>` +* Function generic parameters : `fn my_function<..#T>` +* Type alias declaration : `type MyTuple<..#T>` +* impl block generic parameters : `impl<..#T>` + +### Expansion form + +* Struct member declaration: + ``` + struct MyStruct<..#T> { + arrays: ([T; 32]#..), + } + ``` +* Function arguments : `fn my_function<..#T>(values: &(Vec#..))` +* Function return type : `fn my_function<..#T>(values: &(Vec#..)) -> (&[T]#..)` +* Function body : +``` +fn my_function<..#T>(values: &(Vec#..)) -> (&[T]#..) { + let ({ref T}#..) = values; + (T#..) +} +``` +* Type alias definition : `type TupleOfVec<..#T> = (Vec#..);` +* impl block type : `impl<..#T> MyStruct` +* where clause : +``` +impl<..#T> MyStruct +where {T: Hash}#.. +``` + + Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: - Introducing new named concepts. @@ -69,6 +188,11 @@ Please also take into consideration that rust sometimes intentionally diverges f # Unresolved questions [unresolved-questions]: #unresolved-questions +* Tuple expansion may not be reserved only for _variadic tuple_, maybe it can be used as well on fixed arity tuple as well? (For consistency) +* When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a + way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) + + - What parts of the design do you expect to resolve through the RFC process before this gets merged? - What parts of the design do you expect to resolve through the implementation of this feature before stabilization? - What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? @@ -76,6 +200,9 @@ Please also take into consideration that rust sometimes intentionally diverges f # Future possibilities [future-possibilities]: #future-possibilities +* Be able to create identifiers in an expansion form from the _variadic tuple_. + For instance, if `..#T` is `A, B, C`, then `let ({ref v%T%}#..) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` + Think about what the natural extension and evolution of your proposal would be and how it would affect the language and project as a whole in a holistic way. Try to use this section as a tool to more fully consider all possible From 5f9c1a36213b3c54307d2b2ed187cbd6017d1d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 16 Aug 2019 11:21:12 +0200 Subject: [PATCH 04/51] Update 0000-variadic-tuples.md --- text/0000-variadic-tuples.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index bd12d7ced12..48850474151 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -31,7 +31,7 @@ The declarative form is `..#T` and an expansion form is `T#..`. Note: To illustrate the RFC, we will use the current implementation of the `Hash` trait for tuples. -``` +```rust // Quote from Rust source code // This macro implements `Hash` for a tuple. // It is used like this: `impl_hash_tuple! { A B C D E F }` for a 6-arity tuple. @@ -84,7 +84,7 @@ When expanding a tuple, we use the form `T#..`, but more generally: ` Hash for (T#.., Last) @@ -112,7 +112,7 @@ where ### Expansion form * Struct member declaration: - ``` + ```rust struct MyStruct<..#T> { arrays: ([T; 32]#..), } @@ -120,7 +120,7 @@ where * Function arguments : `fn my_function<..#T>(values: &(Vec#..))` * Function return type : `fn my_function<..#T>(values: &(Vec#..)) -> (&[T]#..)` * Function body : -``` +```rust fn my_function<..#T>(values: &(Vec#..)) -> (&[T]#..) { let ({ref T}#..) = values; (T#..) @@ -129,7 +129,7 @@ fn my_function<..#T>(values: &(Vec#..)) -> (&[T]#..) { * Type alias definition : `type TupleOfVec<..#T> = (Vec#..);` * impl block type : `impl<..#T> MyStruct` * where clause : -``` +```rust impl<..#T> MyStruct where {T: Hash}#.. ``` From 52dbba64d79443bff47e708084526dc973f787e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 16 Aug 2019 11:50:39 +0200 Subject: [PATCH 05/51] Update 0000-variadic-tuples.md --- text/0000-variadic-tuples.md | 101 +++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 22 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 48850474151..c2c7606a727 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -63,18 +63,18 @@ macro_rules! last_type { ## Declaring a _variadic tuple_ -To declare a _variadic tuple_, we use `..#T`, where `T` is a type identifier. +To declare a _variadic tuple_, we use `(..#T)`, where `T` is a type identifier. For instance: -* `struct VariadicStruct<..#T1> ..` -* `impl<..#Head> ..` -* `impl ..` -* `fn my_function<..#A> ..` -* `fn my_function ..` +* `struct VariadicStruct<(..#T1)> ..` +* `impl<(..#Head)> ..` +* `impl ..` +* `fn my_function<(..#A)> ..` +* `fn my_function ..` You can think this like a rule you give to the compiler to generated appropriate code when it runs into specific patterns: -* `VariadicStruct` matches `VariadicStruct<..#T1>` where `..#T1` maps to `int, usize` -* `VariadicStruct` matches `VariadicStruct<..#T1>` where `..#T1` maps to `int, usize, usize` +* `VariadicStruct<(int, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize)` +* `VariadicStruct<(int, usize, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize, usize)` (We will see implementation examples later, with the expansion form) ## Expanding _variadic tuple_ @@ -83,11 +83,10 @@ When expanding a tuple, we use the form `T#..`, but more generally: ` Hash for (T#.., Last) +impl<(..#T), Last> Hash for (T#.., Last) where {T: Hash}#.., // Expands to `A: Hash, B: Hash, C: Hash` Last: Hash + ?Sized, { @@ -104,37 +103,39 @@ where ### Declarative form -* Struct generic parameters : `struct MyStruct<..#T>` -* Function generic parameters : `fn my_function<..#T>` -* Type alias declaration : `type MyTuple<..#T>` -* impl block generic parameters : `impl<..#T>` +* Struct generic parameters : `struct MyStruct<(..#T)>` +* Function generic parameters : `fn my_function<(..#T)>` +* Type alias declaration : `type MyTuple<(..#T)>` +* impl block generic parameters : `impl<(..#T)>` ### Expansion form * Struct member declaration: ```rust - struct MyStruct<..#T> { + struct MyStruct<(..#T)> { arrays: ([T; 32]#..), } ``` -* Function arguments : `fn my_function<..#T>(values: &(Vec#..))` -* Function return type : `fn my_function<..#T>(values: &(Vec#..)) -> (&[T]#..)` +* Function arguments : `fn my_function<(..#T)>(values: &(Vec#..))` +* Function return type : `fn my_function<(..#T)>(values: &(Vec#..)) -> (&[T]#..)` * Function body : ```rust -fn my_function<..#T>(values: &(Vec#..)) -> (&[T]#..) { +fn my_function<(..#T)>(values: &(Vec#..)) -> (&[T]#..) { let ({ref T}#..) = values; (T#..) } ``` -* Type alias definition : `type TupleOfVec<..#T> = (Vec#..);` -* impl block type : `impl<..#T> MyStruct` +* Type alias definition : `type TupleOfVec<(..#T)> = (Vec#..);` +* impl block type : `impl<(..#T)> MyStruct` * where clause : ```rust -impl<..#T> MyStruct +impl<(..#T)> MyStruct<(T#..)> where {T: Hash}#.. ``` + + Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: - Introducing new named concepts. @@ -148,6 +149,57 @@ For implementation-oriented RFCs (e.g. for compiler internals), this section sho # Reference-level explanation [reference-level-explanation]: #reference-level-explanation +## Recursion + +To implement some feature, we may want to use recursion over the arity of the tuple. +For instance, let's implement a trait that gives the arity of a tuple: + +```rust +trait Arity { + const VALUE: usize; +} + +impl Arity for (Head, Tail#..) { + const VALUE: usize = <(Tail#..) as Arity>::VALUE + 1; +} +impl Arity for () { + const VALUE: usize = 0; +} +``` + +Note: +* The `impl Arity for (Head, Tail#..)` is the recursive implementation. +* The `impl Arity for ()` is the termination of the recursive implementation. + +And when we compile the following code: +```rust +fn main() { + println!("Arity of (bool, usize): {}", <(bool, usize) as Arity>::VALUE); +} +``` +The compiler will execute these steps: +1. Search `impl` of `Arity` for `(bool, usize)` +1. `impl` not found, Search variadic `impl` of `Arity` for `(bool, usize)` +1. Variadic impl found: `impl Arity for (Head, Tail#..)` +1. Generate `impl` of `Arity` for `(bool, usize)` + 1. Requires `impl` of `Arity` for `(usize,)` + 1. Search `impl` of `Arity` for `(usize,)` + 1. `impl` not found, Search variadic `impl` of `Arity` for `(usize,)` + 1. Variadic impl found: `impl Arity for (Head, Tail#..)` + 1. Generate `impl` of `Arity` for `(usize,)` + 1. Requires `impl` of `Arity` for `()` + 1. Search `impl` of `Arity` for `()` + 1. `impl` found + 1. Generation of `impl` of `Arity` for `(usize,)` completed +1. Generation of `impl` of `Arity` for `(bool, usize)` completed + +## Using multiple _variadic tuple_ + +``` +``` + + + This is the technical portion of the RFC. Explain the design in sufficient detail that: - Its interaction with other features is clear. @@ -171,6 +223,8 @@ Why should we *not* do this? # Prior art [prior-art]: #prior-art +C++11 sets a decent precedent with its variadic templates, which can be used to define type-safe variadic functions, among other things. C++11 has a special case for variadic parameter packs. + Discuss prior art, both the good and the bad, in relation to this proposal. A few examples of what this can include are: @@ -201,7 +255,10 @@ Please also take into consideration that rust sometimes intentionally diverges f [future-possibilities]: #future-possibilities * Be able to create identifiers in an expansion form from the _variadic tuple_. - For instance, if `..#T` is `A, B, C`, then `let ({ref v%T%}#..) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` + For instance, if `(..#T)` is `(A, B, C)`, then `let ({ref v%T%}#..) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` + + + Think about what the natural extension and evolution of your proposal would be and how it would affect the language and project as a whole in a holistic From afe7bfc5dc4f6cc3d1ae5517ee30d0fee2b630b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 16 Aug 2019 11:56:57 +0200 Subject: [PATCH 06/51] Update 0000-variadic-tuples.md --- text/0000-variadic-tuples.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index c2c7606a727..fa7d0b3179f 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -195,8 +195,24 @@ The compiler will execute these steps: ## Using multiple _variadic tuple_ +```rust +trait Append { + type Out; + + fn append(self, value: T) -> Self::Out; +} + +impl<(..#L), (..#R)> Append<(R#..)> for (L#..) { + type Out = (L#.., R#..); + + fn append(self, value: (R#..)) -> Self::Out; { + let (L#..) = self; + let (R#..) = value; + (L#.., R#..) + } +} ``` -``` + From 03c8bc272f9a45a30e07d953de453ca65bd1f1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 16 Aug 2019 11:58:15 +0200 Subject: [PATCH 07/51] Update 0000-variadic-tuples.md --- text/0000-variadic-tuples.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index fa7d0b3179f..d3f04a4cee9 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -133,7 +133,7 @@ impl<(..#T)> MyStruct<(T#..)> where {T: Hash}#.. ``` - +--- Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: @@ -213,7 +213,7 @@ impl<(..#L), (..#R)> Append<(R#..)> for (L#..) { } ``` - +--- This is the technical portion of the RFC. Explain the design in sufficient detail that: @@ -241,6 +241,8 @@ Why should we *not* do this? C++11 sets a decent precedent with its variadic templates, which can be used to define type-safe variadic functions, among other things. C++11 has a special case for variadic parameter packs. +--- + Discuss prior art, both the good and the bad, in relation to this proposal. A few examples of what this can include are: @@ -274,7 +276,7 @@ Please also take into consideration that rust sometimes intentionally diverges f For instance, if `(..#T)` is `(A, B, C)`, then `let ({ref v%T%}#..) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` - +--- Think about what the natural extension and evolution of your proposal would be and how it would affect the language and project as a whole in a holistic From 130124efd611975492f3051cafeb858a91b8b084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Tue, 20 Aug 2019 10:57:34 +0200 Subject: [PATCH 08/51] Updated errors --- text/0000-variadic-tuples.md | 427 +++++++++++++++++++++++++++++------ 1 file changed, 360 insertions(+), 67 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index d3f04a4cee9..dd086610cb9 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -4,30 +4,35 @@ - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary + [summary]: #summary -Tuples types are ordered set of type, but users can only use tuple with a specified number of types. +Tuples types are ordered set of type, but users can only use tuple with fixed arity. -This RFC aims to allow the use of a _variadic tuple_ to be able to write implementation for tuples with an arbitrary number of type. +This RFC aims to allow the use of a _variadic tuple_ which is a tuple with an arbitrary arity. # Motivation + [motivation]: #motivation ## Arbitrary tuple arity support -Currently, when a user wants to either use or add behavior to tuples, he writes an impl for each size of tuple. -For easier maintenance, it is usually done with a `macro_rules` and implements up to 12 arity tuple. (ex: `Hash` implementation in `std`). +Currently, when a user wants to either use or add behavior to tuples, he writes an impl for each tuple arity. +For easier maintenance, it is usually done with a `macro_rules` and implemented up to 12 arity tuple. (see [ `Hash` implementation in `std`](https://github.com/rust-lang/rust/blob/master/src/libcore/hash/mod.rs)). -The proposed RFC provides an easier way to define the implementation for those tuples and don't limit the arity of tuple supported. -Also, the compiler will compile only required tuple arity implementation. +_Variadic tuple_ will provide several benefits considering trait implementation for tuple or using tuples: +- Implementations will be easier to write +- Implementations will be easier to read and maintain +- The compiler will compile implementation only for required tuple arity # Guide-level explanation + [guide-level-explanation]: #guide-level-explanation The _variadic tuple_ occurs in two form: a declarative form and an expansion form. -The declarative form is `..#T` and an expansion form is `T#..`. +The declarative form is `(..#T)` and an expansion form is `(T#..)` Note: To illustrate the RFC, we will use the current implementation of the `Hash` trait for tuples. @@ -66,29 +71,33 @@ macro_rules! last_type { To declare a _variadic tuple_, we use `(..#T)`, where `T` is a type identifier. For instance: -* `struct VariadicStruct<(..#T1)> ..` -* `impl<(..#Head)> ..` -* `impl ..` -* `fn my_function<(..#A)> ..` -* `fn my_function ..` + +- `struct VariadicStruct<(..#T1)>` : declares a struct with a _variadic tuple_ identified by `T1` in its generic parameters +- `impl<(..#Head)>`: is an implementation block that uses a _variadic tuple_ identified by `Head` +- `impl`: same as above, but with other generic parameters +- `fn my_function<(..#A)>`: a function can also have _variadic tuple_ +- `fn my_function`: there can be several _variadic tuple_ declared in a generic parameter group You can think this like a rule you give to the compiler to generated appropriate code when it runs into specific patterns: -* `VariadicStruct<(int, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize)` -* `VariadicStruct<(int, usize, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize, usize)` -(We will see implementation examples later, with the expansion form) + +- `VariadicStruct<(int, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize)` +- `VariadicStruct<(int, usize, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize, usize)` + (We will see implementation examples later, with the expansion form) ## Expanding _variadic tuple_ -When expanding a tuple, we use the form `T#..`, but more generally: `#..` where `` is an expression or a block expression using the identifier `T`. +At some point, we need to use the types that are declared in the declaration form, this is where we use the expansion form. + +When expanding a tuple, we use the form `T#..`, but more generally: `#..` where `` is an expression or a block expression using the identifier `T`. Let's implement the `Hash` trait: ```rust -// For the example, we consider the impl for (A, B, C). So `..#T matches `A, B, C` -// We have the first expansion here, `T#..` expands to `A, B, C` +// For the example, we consider the impl for (A, B, C). So `(..#T)` matches `(A, B, C)` +// We have the first expansion here, `(T#.., Last)` expands to `(A, B, C, Last)` impl<(..#T), Last> Hash for (T#.., Last) where - {T: Hash}#.., // Expands to `A: Hash, B: Hash, C: Hash` + {T: Hash}#.., // Expands to `A: Hash, B: Hash, C: Hash,` Last: Hash + ?Sized, { #[allow(non_snake_case)] @@ -99,42 +108,66 @@ where } ``` -## Allowed usages of _variadic tuple_ +## Allowed usages of _variadic tuples_ ### Declarative form -* Struct generic parameters : `struct MyStruct<(..#T)>` -* Function generic parameters : `fn my_function<(..#T)>` -* Type alias declaration : `type MyTuple<(..#T)>` -* impl block generic parameters : `impl<(..#T)>` +- Struct generic parameters : `struct MyStruct<(..#T)>` +- Function generic parameters : `fn my_function<(..#T)>` +- Type alias declaration : `type MyTuple<(..#T)>` +- impl block generic parameters : `impl<(..#T)>` ### Expansion form -* Struct member declaration: +- Struct member declaration + ```rust struct MyStruct<(..#T)> { arrays: ([T; 32]#..), } ``` -* Function arguments : `fn my_function<(..#T)>(values: &(Vec#..))` -* Function return type : `fn my_function<(..#T)>(values: &(Vec#..)) -> (&[T]#..)` -* Function body : + +- Function arguments + +```rust +fn my_function<(..#T)>(values: &(Vec#..)) +``` + +- Function return type + +```rust +fn my_function<(..#T)>(values: &(Vec#..)) -> (&[T]#..) +``` + +- Function body + ```rust fn my_function<(..#T)>(values: &(Vec#..)) -> (&[T]#..) { let ({ref T}#..) = values; (T#..) } ``` -* Type alias definition : `type TupleOfVec<(..#T)> = (Vec#..);` -* impl block type : `impl<(..#T)> MyStruct` -* where clause : + +- Type alias definition + +```rust +type TupleOfVec<(..#T)> = (Vec#..); +``` + +- impl block type + +```rust +impl<(..#T)> MyStruct<(HashMap#..)> +``` + +- where clause + ```rust impl<(..#T)> MyStruct<(T#..)> where {T: Hash}#.. ``` ---- - +------ Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: @@ -147,12 +180,13 @@ Explain the proposal as if it was already included in the language and you were For implementation-oriented RFCs (e.g. for compiler internals), this section should focus on how compiler contributors should think about the change, and give examples of its concrete impact. For policy RFCs, this section should provide an example-driven introduction to the policy, and explain its impact in concrete terms. # Reference-level explanation + [reference-level-explanation]: #reference-level-explanation ## Recursion To implement some feature, we may want to use recursion over the arity of the tuple. -For instance, let's implement a trait that gives the arity of a tuple: +For instance, let's implement a trait that gives the arity of a tuple as a `const`value: ```rust trait Arity { @@ -168,44 +202,147 @@ impl Arity for () { ``` Note: -* The `impl Arity for (Head, Tail#..)` is the recursive implementation. -* The `impl Arity for ()` is the termination of the recursive implementation. + +- The `impl Arity for (Head, Tail#..)` is the recursive implementation. +- The `impl Arity for ()` is the termination of the recursive implementation. And when we compile the following code: + ```rust fn main() { println!("Arity of (bool, usize): {}", <(bool, usize) as Arity>::VALUE); } ``` + The compiler will execute these steps: + 1. Search `impl` of `Arity` for `(bool, usize)` -1. `impl` not found, Search variadic `impl` of `Arity` for `(bool, usize)` -1. Variadic impl found: `impl Arity for (Head, Tail#..)` -1. Generate `impl` of `Arity` for `(bool, usize)` - 1. Requires `impl` of `Arity` for `(usize,)` - 1. Search `impl` of `Arity` for `(usize,)` - 1. `impl` not found, Search variadic `impl` of `Arity` for `(usize,)` - 1. Variadic impl found: `impl Arity for (Head, Tail#..)` - 1. Generate `impl` of `Arity` for `(usize,)` - 1. Requires `impl` of `Arity` for `()` - 1. Search `impl` of `Arity` for `()` - 1. `impl` found - 1. Generation of `impl` of `Arity` for `(usize,)` completed -1. Generation of `impl` of `Arity` for `(bool, usize)` completed - -## Using multiple _variadic tuple_ +2. `impl` not found, Search variadic `impl` of `Arity` for `(bool, usize)` +3. Variadic impl found: `impl Arity for (Head, Tail#..)` +4. Generate `impl` of `Arity` for `(bool, usize)` + 1. Requires `impl` of `Arity` for `(usize,)` + 2. Search `impl` of `Arity` for `(usize,)` + 3. `impl` not found, Search variadic `impl` of `Arity` for `(usize,)` + 4. Variadic impl found: `impl Arity for (Head, Tail#..)` + 5. Generate `impl` of `Arity` for `(usize,)` + 1. Requires `impl` of `Arity` for `()` + 2. Search `impl` of `Arity` for `()` + 3. `impl` found + 6. Generation of `impl` of `Arity` for `(usize,)` completed +5. Generation of `impl` of `Arity` for `(bool, usize)` completed + +### Recursion errors + +#### Missing implementation message + +An error can occur if the compiler don't find an implementation while generating _variadic tuple_ implementations. + +Let's consider this code: + +```rust +trait Arity { + const VALUE: usize; +} + +impl Arity for (Head, Tail#..) { + const VALUE: usize = <(Tail#..) as Arity>::VALUE + 1; +} + +fn main() { + let arity = <(usize, bool, u8) as Arity>::VALUE; +} +``` + +This code must not compile as the termination implementation is missing. +So we will have a `E0277`error: + +```rust +error[E0277]: the trait bound `(): Arity` is not satisfied + --> src/main.rs:10:4 + | +7 | let arity = <(usize, bool, u8) as Arity>::VALUE; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Arity` is not implemented for `()` + | + = help: impl `Arity` for `(usize, bool, u8)` requires impl `Arity` for `(bool, u8)` + note: matched by variadic tuple impl of `Arity` + --> src/main.rs:5:1 + | +5 | impl Arity for (Head, Tail#..) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: impl `Arity` for `(bool, u8)` requires impl `Arity` for `(u8,)`. + note: matched by variadic tuple impl of `Arity` + --> src/main.rs:5:1 + | +5 | impl Arity for (Head, Tail#..) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: impl `Arity` for `(u8,)` requires impl `Arity` for `()`. + note: matched by variadic tuple impl of `Arity` + --> src/main.rs:5:1 + | +5 | impl Arity for (Head, Tail#..) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +#### Cycle dependency error + +As a _variadic tuple_ implementation may depend on other _variadic tuple_ implementation, there can be dependency cycle issue. + +```rust +trait A { const VALUE: usize = 1; } +trait B { const VALUE: usize = 2; } + +impl A for (Head, T#..) +where (T#..): B { const VALUE: usize = 3; } + +impl B for (Head, T#..) +where (T#..): A { const VALUE: usize = 4; } + +fn main() { + let v = <(usize, bool) as A>::VALUE; +} +``` + +This code won't compile because the impl for `A` requires the impl for `B` and the impl for `B` requires the impl for `A`. + +This kind of error can already by created without _variadic tuple_ (`E0275`), but _variadic tuple_ will introduce another place where this can happen. So we should have this error: ```rust -trait Append { +error[E0275]: overflow evaluating the requirement `(usize, bool): A` + --> src/main.rs:11:13 + | +10 | let v = <(usize, bool) as A>::VALUE; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: required by `A::VALUE` + --> src/main.rs:1:11 + | +1 | trait A { const VALUE: usize = 1; } + | ^^^^^^^^^^^^^^^^^^^^^^^ +``` + +## Using multiple _variadic tuples_ + +### Expansion forms without _variadic tuple_ identifiers + +Expansion forms without _variadic tuple_ identifiers are forbidden. + +### Single identifier expansion forms + +We can declare and use multiple _variadic tuples_, if the expansion forms only involve a single _variadic tuple_ identifier, there is no constraints. + +See this example of a `trait`that merge two tuples: + +```rust +trait Merge { type Out; fn append(self, value: T) -> Self::Out; } -impl<(..#L), (..#R)> Append<(R#..)> for (L#..) { +impl<(..#L), (..#R)> Merge<(R#..)> for (L#..) { type Out = (L#.., R#..); - fn append(self, value: (R#..)) -> Self::Out; { + fn merge(self, value: (R#..)) -> Self::Out; { let (L#..) = self; let (R#..) = value; (L#.., R#..) @@ -213,23 +350,174 @@ impl<(..#L), (..#R)> Append<(R#..)> for (L#..) { } ``` ---- +Note: a _variadic tuple_ identifier may occur more than once in an expansion form, for instance: + +```rust +fn double<(..#T)>(input: (#T..)) -> (T#..) + where {T: Add}#.., { + ({T + T}#..) +} +``` + +### Multiple identifier expansion forms + +An expansion form may include multiple different _variadic tuple_ identifiers. However, both _variadic tuple_ must have the same arity. + +For instance, let's consider this `struct`: + +```rust +struct MegaMap<(..#Key), (..#Value)> { + maps: (HashMap#..) +} +``` + +Then the following usages are valid: + +```rust +MegaMap<(usize,), (bool,)> +MegaMap<(usize, i8), (String, Vec)> +``` + +And these one are invalid: + +```rust +MegaMap<(usize,), (bool, bool)> +MegaMap<(usize, bool, String), (usize, bool)> +``` + +### Expansion errors + +_Variadic tuple_ expansions have their specific constraints, and if violated the compiler needs to issue an error. + +Also, _variadic tuple_ expansion will generate code and may produce obscure errors for existing compile error. To help user debug their compile issue, we need to provide information about the expansion the compiler tried to resolve. + +#### Invalid _variadic tuple_ expansion error + +This will happen when the compiler tries to expand an expansion form with invalid _variadic tuple_. +We need to introduce a new compile error for this one, let's call it `EXXXX` + +There are two kinds of invalid expansion errors + +- No _variadic tuple_ identifier is found in the expansion form +- The expansion form contains multiple _variadic tuple_ identifiers, but those have different arities + +##### Different arities in an expansion form error + +So, the following code + +```rust +struct MegaMap<(..#Key), (..#Value)> { + maps: (HashMap#..) +} + +impl<(..#Key), (..#Value)> for MegaMap<(Key#..), (Value#..)> { + pub fn new() -> Self { + Self { + maps: (HashMap::new()#..) + } + } +} + +fn main() { + let mega_map: MegaMap<(bool,), (usize, String)> = MegaMap::new(); +} +``` + +Will produce this error +```rust +error[EXXXX]: variadic tuple expansion form `(HashMap::new()#..)` can't be expanded + --> src/main.rs:8:17 + | +10 | maps: (HashMap::new()#..) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: when expanded with different variadic tuple arity `(..#Key) = (bool,)` and `(..#Value) = (usize, String)` + --> src/main.rs:14:16 + | +14 | let mega_map: MegaMap<(bool,), (usize, String)> = MegaMap::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +#### Missing _variadic tuple_ identifier error + +The following code + +```rust +fn make_mega_map<(..#Key), (..#Value)>() -> (HashMap#..) { + (HashMap::::new()#..) +} + +fn main() { + let mega_map = make_mega_map::<(usize, bool), (bool, String)>(); +} +``` + +Will produce this error + +```rust +error[EXXXX]: variadic tuple expansion form `(HashMap::::new()#..)` can't be expanded + --> src/main.rs:2:4 + | +2 | (HashMap::::new()#..) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: no variadic tuple identifier was found in the expansion form +note: when expanding with `(..#Key) = (usize, bool)` and `(..#Value) = (bool, String)` + --> src/main.rs:6:16 + | +6 | let mega_map = make_mega_map::<(usize, bool), (bool, String)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +#### Help and note for existing errors + +##### Unknown identifier in an expansion form + +If we consider this code: + +```rust +fn make_mega_map<(..#Key), (..#Value)>() -> (HashMap#..) { + (HashMap::::new()#..) +} + +fn main() { + let mega_map = make_mega_map::<(usize, bool), (bool, String)>(); +} +``` -This is the technical portion of the RFC. Explain the design in sufficient detail that: +Then the expansion form is valid, even though the `Value2` identifier is probably mistyped. +In that case, the expansion will be resolved as: -- Its interaction with other features is clear. -- It is reasonably clear how the feature would be implemented. -- Corner cases are dissected by example. +```rust +fn make_mega_map<(usize, bool), (bool, String)>() -> (HashMap, HashMap) { + (HashMap::::new(), HashMap::::new()) +} +``` -The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work. +Leading to a compile error with additional notes + +```rust +error[E0412]: cannot find type `Value2` in this scope + --> src/main.rs:10:22 + | +10 | let mega_map = make_mega_map::<(usize, bool), (bool, String)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope +note: when expanding with `(..#Key) = (usize, bool)` and `(..#Value) = (bool, String)` + --> src/main.rs:2:4 + | +2 | (HashMap::::new()#..) + | +``` # Drawbacks + [drawbacks]: #drawbacks Why should we *not* do this? # Rationale and alternatives + [rationale-and-alternatives]: #rationale-and-alternatives - Why is this design the best in the space of possible designs? @@ -237,11 +525,12 @@ Why should we *not* do this? - What is the impact of not doing this? # Prior art + [prior-art]: #prior-art C++11 sets a decent precedent with its variadic templates, which can be used to define type-safe variadic functions, among other things. C++11 has a special case for variadic parameter packs. ---- +------ Discuss prior art, both the good and the bad, in relation to this proposal. A few examples of what this can include are: @@ -258,25 +547,29 @@ Note that while precedent set by other languages is some motivation, it does not Please also take into consideration that rust sometimes intentionally diverges from common language features. # Unresolved questions + [unresolved-questions]: #unresolved-questions -* Tuple expansion may not be reserved only for _variadic tuple_, maybe it can be used as well on fixed arity tuple as well? (For consistency) -* When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a +- Tuple expansion may not be reserved only for _variadic tuple_, maybe it can be used as well on fixed arity tuple as well? (For consistency) +- When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) - - What parts of the design do you expect to resolve through the RFC process before this gets merged? - What parts of the design do you expect to resolve through the implementation of this feature before stabilization? - What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? # Future possibilities + [future-possibilities]: #future-possibilities -* Be able to create identifiers in an expansion form from the _variadic tuple_. +- Be able to create identifiers in an expansion form from the _variadic tuple_. For instance, if `(..#T)` is `(A, B, C)`, then `let ({ref v%T%}#..) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` + - This feature will let user to have more flexibility when implementing code with _variadic tuple_ +- Improve the error message for `E0275` by providing the sequence of evaluated elements to give more help to the user about what can create the overflow. + - In the context of _variadic tuple_, this can be the sequence of _variadic tuple_ implementation that are tried by the compiler. + - But, in the more generic case where two traits implementations requires each others, providing the dependency cycle can be really helpful. - ---- +------ Think about what the natural extension and evolution of your proposal would be and how it would affect the language and project as a whole in a holistic From 352674cfcd09ff7bfc7088c0dd237b6964a57a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Tue, 27 Aug 2019 21:56:30 +0200 Subject: [PATCH 09/51] cleaned rfc --- text/0000-variadic-tuples.md | 60 +----------------------------------- 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index dd086610cb9..cef4d060473 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -167,18 +167,6 @@ impl<(..#T)> MyStruct<(T#..)> where {T: Hash}#.. ``` ------- - -Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means: - -- Introducing new named concepts. -- Explaining the feature largely in terms of examples. -- Explaining how Rust programmers should *think* about the feature, and how it should impact the way they use Rust. It should explain the impact as concretely as possible. -- If applicable, provide sample error messages, deprecation warnings, or migration guidance. -- If applicable, describe the differences between teaching this to existing Rust programmers and new Rust programmers. - -For implementation-oriented RFCs (e.g. for compiler internals), this section should focus on how compiler contributors should think about the change, and give examples of its concrete impact. For policy RFCs, this section should provide an example-driven introduction to the policy, and explain its impact in concrete terms. - # Reference-level explanation [reference-level-explanation]: #reference-level-explanation @@ -186,7 +174,7 @@ For implementation-oriented RFCs (e.g. for compiler internals), this section sho ## Recursion To implement some feature, we may want to use recursion over the arity of the tuple. -For instance, let's implement a trait that gives the arity of a tuple as a `const`value: +For instance, let's implement a trait that gives the arity of a tuple as a `const` value: ```rust trait Arity { @@ -514,38 +502,16 @@ note: when expanding with `(..#Key) = (usize, bool)` and `(..#Value) = (bool, St [drawbacks]: #drawbacks -Why should we *not* do this? - # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives -- Why is this design the best in the space of possible designs? -- What other designs have been considered and what is the rationale for not choosing them? -- What is the impact of not doing this? - # Prior art [prior-art]: #prior-art C++11 sets a decent precedent with its variadic templates, which can be used to define type-safe variadic functions, among other things. C++11 has a special case for variadic parameter packs. ------- - -Discuss prior art, both the good and the bad, in relation to this proposal. -A few examples of what this can include are: - -- For language, library, cargo, tools, and compiler proposals: Does this feature exist in other programming languages and what experience have their community had? -- For community proposals: Is this done by some other community and what were their experiences with it? -- For other teams: What lessons can we learn from what other communities have done here? -- Papers: Are there any published papers or great posts that discuss this? If you have some relevant papers to refer to, this can serve as a more detailed theoretical background. - -This section is intended to encourage you as an author to think about the lessons from other languages, provide readers of your RFC with a fuller picture. -If there is no prior art, that is fine - your ideas are interesting to us whether they are brand new or if it is an adaptation from other languages. - -Note that while precedent set by other languages is some motivation, it does not on its own motivate an RFC. -Please also take into consideration that rust sometimes intentionally diverges from common language features. - # Unresolved questions [unresolved-questions]: #unresolved-questions @@ -554,10 +520,6 @@ Please also take into consideration that rust sometimes intentionally diverges f - When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) -- What parts of the design do you expect to resolve through the RFC process before this gets merged? -- What parts of the design do you expect to resolve through the implementation of this feature before stabilization? -- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC? - # Future possibilities [future-possibilities]: #future-possibilities @@ -568,23 +530,3 @@ Please also take into consideration that rust sometimes intentionally diverges f - Improve the error message for `E0275` by providing the sequence of evaluated elements to give more help to the user about what can create the overflow. - In the context of _variadic tuple_, this can be the sequence of _variadic tuple_ implementation that are tried by the compiler. - But, in the more generic case where two traits implementations requires each others, providing the dependency cycle can be really helpful. - ------- - -Think about what the natural extension and evolution of your proposal would -be and how it would affect the language and project as a whole in a holistic -way. Try to use this section as a tool to more fully consider all possible -interactions with the project and language in your proposal. -Also consider how the this all fits into the roadmap for the project -and of the relevant sub-team. - -This is also a good place to "dump ideas", if they are out of scope for the -RFC you are writing but otherwise related. - -If you have tried and cannot think of any future possibilities, -you may simply state that you cannot think of anything. - -Note that having something written down in the future-possibilities section -is not a reason to accept the current or a future RFC; such notes should be -in the section on motivation or rationale in this or subsequent RFCs. -The section merely provides additional information. From 72255df25005f10f24dc20bed56995145e27704b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Wed, 28 Aug 2019 09:33:09 +0200 Subject: [PATCH 10/51] Uppdated with feedback --- text/0000-variadic-tuples.md | 96 ++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index cef4d060473..8f716e56139 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -20,7 +20,7 @@ This RFC aims to allow the use of a _variadic tuple_ which is a tuple with an ar Currently, when a user wants to either use or add behavior to tuples, he writes an impl for each tuple arity. For easier maintenance, it is usually done with a `macro_rules` and implemented up to 12 arity tuple. (see [ `Hash` implementation in `std`](https://github.com/rust-lang/rust/blob/master/src/libcore/hash/mod.rs)). -_Variadic tuple_ will provide several benefits considering trait implementation for tuple or using tuples: +Variadic tuple will provide several benefits considering trait implementation for tuple or using tuples: - Implementations will be easier to write - Implementations will be easier to read and maintain @@ -30,7 +30,7 @@ _Variadic tuple_ will provide several benefits considering trait implementation [guide-level-explanation]: #guide-level-explanation -The _variadic tuple_ occurs in two form: a declarative form and an expansion form. +The variadic tuple occurs in two form: a declarative form and an expansion form. The declarative form is `(..#T)` and an expansion form is `(T#..)` @@ -66,17 +66,17 @@ macro_rules! last_type { } ``` -## Declaring a _variadic tuple_ +## Declaring a variadic tuple -To declare a _variadic tuple_, we use `(..#T)`, where `T` is a type identifier. +To declare a variadic tuple, we use `(..#T)`, where `T` is a type identifier. For instance: -- `struct VariadicStruct<(..#T1)>` : declares a struct with a _variadic tuple_ identified by `T1` in its generic parameters -- `impl<(..#Head)>`: is an implementation block that uses a _variadic tuple_ identified by `Head` +- `struct VariadicStruct<(..#T1)>` : declares a struct with a variadic tuple identified by `T1` in its generic parameters +- `impl<(..#Head)>`: is an implementation block that uses a variadic tuple identified by `Head` - `impl`: same as above, but with other generic parameters -- `fn my_function<(..#A)>`: a function can also have _variadic tuple_ -- `fn my_function`: there can be several _variadic tuple_ declared in a generic parameter group +- `fn my_function<(..#A)>`: a function can also have variadic tuple +- `fn my_function`: there can be several variadic tuple declared in a generic parameter group You can think this like a rule you give to the compiler to generated appropriate code when it runs into specific patterns: @@ -84,11 +84,11 @@ You can think this like a rule you give to the compiler to generated appropriate - `VariadicStruct<(int, usize, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize, usize)` (We will see implementation examples later, with the expansion form) -## Expanding _variadic tuple_ +## Expanding variadic tuple At some point, we need to use the types that are declared in the declaration form, this is where we use the expansion form. -When expanding a tuple, we use the form `T#..`, but more generally: `#..` where `` is an expression or a block expression using the identifier `T`. +When expanding a tuple, we use the form `T#..`, but more generally: `#..` where `` is pattern optionally enclosed by parenthesis using the identifier `T`. Let's implement the `Hash` trait: @@ -97,18 +97,18 @@ Let's implement the `Hash` trait: // We have the first expansion here, `(T#.., Last)` expands to `(A, B, C, Last)` impl<(..#T), Last> Hash for (T#.., Last) where - {T: Hash}#.., // Expands to `A: Hash, B: Hash, C: Hash,` + (T: Hash)#.., // Expands to `A: Hash, B: Hash, C: Hash,` Last: Hash + ?Sized, { #[allow(non_snake_case)] fn hash(&self, state: &mut S) { - let ({ref T}#.., ref last) = *self; // Expands to `let (ref A, ref B, ref C, ref last) = *self;` + let ((ref T)#.., ref last) = *self; // Expands to `let (ref A, ref B, ref C, ref last) = *self;` (T.hash(state)#.., last.hash(state)); // Expands to `(A.hash(state), B.hash(state), C.hash(state), last.hash(state));` } } ``` -## Allowed usages of _variadic tuples_ +## Allowed usages of variadic tuples ### Declarative form @@ -143,7 +143,7 @@ fn my_function<(..#T)>(values: &(Vec#..)) -> (&[T]#..) ```rust fn my_function<(..#T)>(values: &(Vec#..)) -> (&[T]#..) { - let ({ref T}#..) = values; + let ((ref T)#..) = values; (T#..) } ``` @@ -164,7 +164,7 @@ impl<(..#T)> MyStruct<(HashMap#..)> ```rust impl<(..#T)> MyStruct<(T#..)> -where {T: Hash}#.. +where (T: Hash)#.. ``` # Reference-level explanation @@ -223,7 +223,7 @@ The compiler will execute these steps: #### Missing implementation message -An error can occur if the compiler don't find an implementation while generating _variadic tuple_ implementations. +An error can occur if the compiler don't find an implementation while generating variadic tuple implementations. Let's consider this code: @@ -273,7 +273,7 @@ error[E0277]: the trait bound `(): Arity` is not satisfied #### Cycle dependency error -As a _variadic tuple_ implementation may depend on other _variadic tuple_ implementation, there can be dependency cycle issue. +As a variadic tuple implementation may depend on other variadic tuple implementation, there can be dependency cycle issue. ```rust trait A { const VALUE: usize = 1; } @@ -292,7 +292,7 @@ fn main() { This code won't compile because the impl for `A` requires the impl for `B` and the impl for `B` requires the impl for `A`. -This kind of error can already by created without _variadic tuple_ (`E0275`), but _variadic tuple_ will introduce another place where this can happen. So we should have this error: +This kind of error can already by created without variadic tuple (`E0275`), but variadic tuple will introduce another place where this can happen. So we should have this error: ```rust error[E0275]: overflow evaluating the requirement `(usize, bool): A` @@ -308,15 +308,24 @@ note: required by `A::VALUE` | ^^^^^^^^^^^^^^^^^^^^^^^ ``` -## Using multiple _variadic tuples_ +## Using multiple variadic tuples -### Expansion forms without _variadic tuple_ identifiers +### Recursive variadic tuples -Expansion forms without _variadic tuple_ identifiers are forbidden. +Recursive variadic tuples are forbidden. +Example: + +```rust +fn my_func<(..#((..#T)))>() { ..} +``` + +### Expansion forms without variadic tuple identifiers + +Expansion forms without variadic tuple identifiers are forbidden. ### Single identifier expansion forms -We can declare and use multiple _variadic tuples_, if the expansion forms only involve a single _variadic tuple_ identifier, there is no constraints. +We can declare and use multiple variadic tuples, if the expansion forms only involve a single variadic tuple identifier, there is no constraints. See this example of a `trait`that merge two tuples: @@ -338,18 +347,18 @@ impl<(..#L), (..#R)> Merge<(R#..)> for (L#..) { } ``` -Note: a _variadic tuple_ identifier may occur more than once in an expansion form, for instance: +Note: a variadic tuple identifier may occur more than once in an expansion form, for instance: ```rust fn double<(..#T)>(input: (#T..)) -> (T#..) - where {T: Add}#.., { + where (T: Add)#.., { ({T + T}#..) } ``` ### Multiple identifier expansion forms -An expansion form may include multiple different _variadic tuple_ identifiers. However, both _variadic tuple_ must have the same arity. +An expansion form may include multiple different variadic tuple identifiers. However, both variadic tuple must have the same arity. For instance, let's consider this `struct`: @@ -375,19 +384,19 @@ MegaMap<(usize, bool, String), (usize, bool)> ### Expansion errors -_Variadic tuple_ expansions have their specific constraints, and if violated the compiler needs to issue an error. +Variadic tuple expansions have their specific constraints, and if violated the compiler needs to issue an error. -Also, _variadic tuple_ expansion will generate code and may produce obscure errors for existing compile error. To help user debug their compile issue, we need to provide information about the expansion the compiler tried to resolve. +Also, variadic tuple expansion will generate code and may produce obscure errors for existing compile error. To help user debug their compile issue, we need to provide information about the expansion the compiler tried to resolve. -#### Invalid _variadic tuple_ expansion error +#### Invalid variadic tuple expansion error -This will happen when the compiler tries to expand an expansion form with invalid _variadic tuple_. +This will happen when the compiler tries to expand an expansion form with invalid variadic tuple. We need to introduce a new compile error for this one, let's call it `EXXXX` There are two kinds of invalid expansion errors -- No _variadic tuple_ identifier is found in the expansion form -- The expansion form contains multiple _variadic tuple_ identifiers, but those have different arities +- No variadic tuple identifier is found in the expansion form +- The expansion form contains multiple variadic tuple identifiers, but those have different arities ##### Different arities in an expansion form error @@ -427,7 +436,7 @@ note: when expanded with different variadic tuple arity `(..#Key) = (bool,)` and | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` -#### Missing _variadic tuple_ identifier error +#### Missing variadic tuple identifier error The following code @@ -516,17 +525,30 @@ C++11 sets a decent precedent with its variadic templates, which can be used to [unresolved-questions]: #unresolved-questions -- Tuple expansion may not be reserved only for _variadic tuple_, maybe it can be used as well on fixed arity tuple as well? (For consistency) +- Tuple expansion may not be reserved only for variadic tuple, maybe it can be used as well on fixed arity tuple as well? (For consistency) - When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) +- Maybe a better syntax can be found that includes the length constraint for variadic tuples. +Example, instead of +```rust +fn my_function<(..#R), (..#L)>(r: (R#..), l: (L#..)) -> ((R, L)#..) { ... } +``` +Use +```rust +fn my_function<(..#(R, L))>(r: (R#..), l: (L#..)) -> ((R, L)#..) { ... } +``` +To enforce that variadic tuples `R` and `L` have the same arity. + # Future possibilities [future-possibilities]: #future-possibilities -- Be able to create identifiers in an expansion form from the _variadic tuple_. - For instance, if `(..#T)` is `(A, B, C)`, then `let ({ref v%T%}#..) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` - - This feature will let user to have more flexibility when implementing code with _variadic tuple_ +- Be able to create identifiers in an expansion form from the variadic tuple. + For instance, if `(..#T)` is `(A, B, C)`, then `let ((ref v%T%)#..) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` + - This feature will let user to have more flexibility when implementing code with variadic tuple - Improve the error message for `E0275` by providing the sequence of evaluated elements to give more help to the user about what can create the overflow. - - In the context of _variadic tuple_, this can be the sequence of _variadic tuple_ implementation that are tried by the compiler. + - In the context of variadic tuple, this can be the sequence of variadic tuple implementation that are tried by the compiler. - But, in the more generic case where two traits implementations requires each others, providing the dependency cycle can be really helpful. + +- Supporting recrusive variadic tuple (ie, declaration like: `(..#((..#T)))`) From dc336590d93bba53c15ae99b5583d088c8f2e76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Wed, 28 Aug 2019 22:27:59 +0200 Subject: [PATCH 11/51] Updated from feedback - Use same syntax for declaration form and expansion form - Constraint variadic tuple with same arity in declaration --- text/0000-variadic-tuples.md | 279 +++++++++++++---------------------- 1 file changed, 101 insertions(+), 178 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 8f716e56139..b1b9ac6f5e4 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -32,7 +32,7 @@ Variadic tuple will provide several benefits considering trait implementation fo The variadic tuple occurs in two form: a declarative form and an expansion form. -The declarative form is `(..#T)` and an expansion form is `(T#..)` +The declarative form is `(..#T)` and an example of an expansion form is `(..#Vec)` Note: To illustrate the RFC, we will use the current implementation of the `Hash` trait for tuples. @@ -84,26 +84,48 @@ You can think this like a rule you give to the compiler to generated appropriate - `VariadicStruct<(int, usize, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize, usize)` (We will see implementation examples later, with the expansion form) +### Multiple variadic tuple sharing the same arity + +You can declare that several variadic tuple have the same arity in a generic parameter group: + +```rust +/// Here we have 3 variadic tuple: T1, T2, T3 +/// T2 and T3 have the same arity +/// The arity of T1 is independent of the others +fn my_function<(..#T1), (..#(T2, T3))>() { + ... +} +``` + +See [Multiple identifier expansion forms](### Multiple identifier expansion forms) for a more detailed usage. + ## Expanding variadic tuple At some point, we need to use the types that are declared in the declaration form, this is where we use the expansion form. -When expanding a tuple, we use the form `T#..`, but more generally: `#..` where `` is pattern optionally enclosed by parenthesis using the identifier `T`. +When expanding a tuple, we use the form `..#T`, but more generally: `..#` where `` is pattern using the identifier `T`. + +Note: The `` can be enclosed by braces or parenthesis when the expression is complex. +So you can have 3 different forms: + +1. `(..#Vec)`: simple form +2. `(..#(ref T))`: parenthesis form +3. `(..#{let mut r = T::default(); r += 2; r})`: braces form Let's implement the `Hash` trait: ```rust // For the example, we consider the impl for (A, B, C). So `(..#T)` matches `(A, B, C)` // We have the first expansion here, `(T#.., Last)` expands to `(A, B, C, Last)` -impl<(..#T), Last> Hash for (T#.., Last) +impl<(..#T), Last> Hash for (..#T, Last) where - (T: Hash)#.., // Expands to `A: Hash, B: Hash, C: Hash,` + ..#(T: Hash), // Expands to `A: Hash, B: Hash, C: Hash,` Last: Hash + ?Sized, { #[allow(non_snake_case)] fn hash(&self, state: &mut S) { - let ((ref T)#.., ref last) = *self; // Expands to `let (ref A, ref B, ref C, ref last) = *self;` - (T.hash(state)#.., last.hash(state)); // Expands to `(A.hash(state), B.hash(state), C.hash(state), last.hash(state));` + let (..#(ref T), ref last) = *self; // Expands to `let (ref A, ref B, ref C, ref last) = *self;` + (..#T.hash(state), last.hash(state)); // Expands to `(A.hash(state), B.hash(state), C.hash(state), last.hash(state));` } } ``` @@ -112,6 +134,8 @@ where ### Declarative form +The declarative form is used in a generic parameter group, so it can occur in: + - Struct generic parameters : `struct MyStruct<(..#T)>` - Function generic parameters : `fn my_function<(..#T)>` - Type alias declaration : `type MyTuple<(..#T)>` @@ -119,52 +143,30 @@ where ### Expansion form -- Struct member declaration +The expansion form can occur in many places. - ```rust - struct MyStruct<(..#T)> { - arrays: ([T; 32]#..), - } - ``` - -- Function arguments - -```rust -fn my_function<(..#T)>(values: &(Vec#..)) -``` - -- Function return type +Various examples: ```rust -fn my_function<(..#T)>(values: &(Vec#..)) -> (&[T]#..) -``` - -- Function body +type TupleOfVec<(..#T)> = (..#Vec); -```rust -fn my_function<(..#T)>(values: &(Vec#..)) -> (&[T]#..) { - let ((ref T)#..) = values; - (T#..) +fn my_function<(..#T)>(values: &(..#Vec)) -> (..#&[T]) +where ..#(T: Clone,) { + let (..#(ref T)) = values; + (..#T) } -``` -- Type alias definition - -```rust -type TupleOfVec<(..#T)> = (Vec#..); -``` - -- impl block type - -```rust -impl<(..#T)> MyStruct<(HashMap#..)> -``` - -- where clause - -```rust -impl<(..#T)> MyStruct<(T#..)> -where (T: Hash)#.. +struct MyStruct<(..#T)> { + arrays: (..#[T; 4]), +} +impl<(..#T)> MyStruct<(..#Vec)> +where ..#(T: Clone + 'static,) { + pub fn new() -> Self { + Self { + arrays: (..#[Vec::new(), Vec::new(), Vec::new(), Vec::new()]) + } + } +} ``` # Reference-level explanation @@ -181,8 +183,8 @@ trait Arity { const VALUE: usize; } -impl Arity for (Head, Tail#..) { - const VALUE: usize = <(Tail#..) as Arity>::VALUE + 1; +impl Arity for (Head, ..#Tail) { + const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; } impl Arity for () { const VALUE: usize = 0; @@ -191,7 +193,7 @@ impl Arity for () { Note: -- The `impl Arity for (Head, Tail#..)` is the recursive implementation. +- The `impl Arity for (Head, ..#Tail)` is the recursive implementation. - The `impl Arity for ()` is the termination of the recursive implementation. And when we compile the following code: @@ -206,12 +208,12 @@ The compiler will execute these steps: 1. Search `impl` of `Arity` for `(bool, usize)` 2. `impl` not found, Search variadic `impl` of `Arity` for `(bool, usize)` -3. Variadic impl found: `impl Arity for (Head, Tail#..)` +3. Variadic impl found: `impl Arity for (Head, ..#Tail)` 4. Generate `impl` of `Arity` for `(bool, usize)` 1. Requires `impl` of `Arity` for `(usize,)` 2. Search `impl` of `Arity` for `(usize,)` 3. `impl` not found, Search variadic `impl` of `Arity` for `(usize,)` - 4. Variadic impl found: `impl Arity for (Head, Tail#..)` + 4. Variadic impl found: `impl Arity for (Head, ..#Tail)` 5. Generate `impl` of `Arity` for `(usize,)` 1. Requires `impl` of `Arity` for `()` 2. Search `impl` of `Arity` for `()` @@ -232,8 +234,8 @@ trait Arity { const VALUE: usize; } -impl Arity for (Head, Tail#..) { - const VALUE: usize = <(Tail#..) as Arity>::VALUE + 1; +impl Arity for (Head, ..#Tail) { + const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; } fn main() { @@ -255,19 +257,19 @@ error[E0277]: the trait bound `(): Arity` is not satisfied note: matched by variadic tuple impl of `Arity` --> src/main.rs:5:1 | -5 | impl Arity for (Head, Tail#..) { +5 | impl Arity for (Head, ..#Tail) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: impl `Arity` for `(bool, u8)` requires impl `Arity` for `(u8,)`. note: matched by variadic tuple impl of `Arity` --> src/main.rs:5:1 | -5 | impl Arity for (Head, Tail#..) { +5 | impl Arity for (Head, ..#Tail) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: impl `Arity` for `(u8,)` requires impl `Arity` for `()`. note: matched by variadic tuple impl of `Arity` --> src/main.rs:5:1 | -5 | impl Arity for (Head, Tail#..) { +5 | impl Arity for (Head, ..#Tail) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` @@ -279,11 +281,11 @@ As a variadic tuple implementation may depend on other variadic tuple implementa trait A { const VALUE: usize = 1; } trait B { const VALUE: usize = 2; } -impl A for (Head, T#..) -where (T#..): B { const VALUE: usize = 3; } +impl A for (Head, ..#T) +where (..#T): B { const VALUE: usize = 3; } -impl B for (Head, T#..) -where (T#..): A { const VALUE: usize = 4; } +impl B for (Head, ..#T) +where (..#T): A { const VALUE: usize = 4; } fn main() { let v = <(usize, bool) as A>::VALUE; @@ -321,7 +323,7 @@ fn my_func<(..#((..#T)))>() { ..} ### Expansion forms without variadic tuple identifiers -Expansion forms without variadic tuple identifiers are forbidden. +In that case, the expansion forms resolves to `()`. ### Single identifier expansion forms @@ -336,13 +338,13 @@ trait Merge { fn append(self, value: T) -> Self::Out; } -impl<(..#L), (..#R)> Merge<(R#..)> for (L#..) { - type Out = (L#.., R#..); +impl<(..#L), (..#R)> Merge<(..#R)> for (..#L) { + type Out = (..#L, ..#R); - fn merge(self, value: (R#..)) -> Self::Out; { - let (L#..) = self; - let (R#..) = value; - (L#.., R#..) + fn merge(self, value: (..#R)) -> Self::Out; { + let (..#L) = self; + let (..#R) = value; + (..#L, ..#R) } } ``` @@ -350,9 +352,9 @@ impl<(..#L), (..#R)> Merge<(R#..)> for (L#..) { Note: a variadic tuple identifier may occur more than once in an expansion form, for instance: ```rust -fn double<(..#T)>(input: (#T..)) -> (T#..) - where (T: Add)#.., { - ({T + T}#..) +fn double<(..#T)>(input: (..#T)) -> (..#T) + where ..#(T: Add), { + (..#(T + T)) } ``` @@ -360,112 +362,44 @@ fn double<(..#T)>(input: (#T..)) -> (T#..) An expansion form may include multiple different variadic tuple identifiers. However, both variadic tuple must have the same arity. -For instance, let's consider this `struct`: +To ensure this, the declaration of these variadic tuples is a bit different: ```rust -struct MegaMap<(..#Key), (..#Value)> { - maps: (HashMap#..) +struct MegaMap<(..#(Key, Value))> { + maps: (..#HashMap) } ``` -Then the following usages are valid: - -```rust -MegaMap<(usize,), (bool,)> -MegaMap<(usize, i8), (String, Vec)> -``` +So the syntax `(..#(Key, Value))` declares 2 variadic tuples with identifiers `Key` and `Value` that have the same arity. -And these one are invalid: +To use this syntax, the user must follow the same pattern: ```rust -MegaMap<(usize,), (bool, bool)> -MegaMap<(usize, bool, String), (usize, bool)> +MegaMap<((usize, bool), )> +MegaMap<((usize, i8), (String, Vec))> ``` -### Expansion errors - -Variadic tuple expansions have their specific constraints, and if violated the compiler needs to issue an error. - -Also, variadic tuple expansion will generate code and may produce obscure errors for existing compile error. To help user debug their compile issue, we need to provide information about the expansion the compiler tried to resolve. - -#### Invalid variadic tuple expansion error - -This will happen when the compiler tries to expand an expansion form with invalid variadic tuple. -We need to introduce a new compile error for this one, let's call it `EXXXX` - -There are two kinds of invalid expansion errors - -- No variadic tuple identifier is found in the expansion form -- The expansion form contains multiple variadic tuple identifiers, but those have different arities - -##### Different arities in an expansion form error - -So, the following code +Note: Both identifiers `Key` and `Value` can be used in the same expansion form, but the can also be used in separate expansion forms. +Example: ```rust -struct MegaMap<(..#Key), (..#Value)> { - maps: (HashMap#..) -} - -impl<(..#Key), (..#Value)> for MegaMap<(Key#..), (Value#..)> { - pub fn new() -> Self { - Self { - maps: (HashMap::new()#..) - } - } +struct MegaMap<(..#(Key, Value))> { + keys: (..#Vec), + values: (..#Vec), } - -fn main() { - let mega_map: MegaMap<(bool,), (usize, String)> = MegaMap::new(); +// Then if we expand the syntax we have: +struct MegaMap<((usize, bool), (i32, string))> { + keys: (Vec, Vec), + values: (Vec, Vec), } ``` -Will produce this error - -```rust -error[EXXXX]: variadic tuple expansion form `(HashMap::new()#..)` can't be expanded - --> src/main.rs:8:17 - | -10 | maps: (HashMap::new()#..) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: when expanded with different variadic tuple arity `(..#Key) = (bool,)` and `(..#Value) = (usize, String)` - --> src/main.rs:14:16 - | -14 | let mega_map: MegaMap<(bool,), (usize, String)> = MegaMap::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``` - -#### Missing variadic tuple identifier error - -The following code - -```rust -fn make_mega_map<(..#Key), (..#Value)>() -> (HashMap#..) { - (HashMap::::new()#..) -} +### Expansion errors -fn main() { - let mega_map = make_mega_map::<(usize, bool), (bool, String)>(); -} -``` +Variadic tuple expansion will generate code and may produce obscure errors for existing compile error. To help user debug their compile issue, we need to provide information about the expansion the compiler tried to resolve. -Will produce this error - -```rust -error[EXXXX]: variadic tuple expansion form `(HashMap::::new()#..)` can't be expanded - --> src/main.rs:2:4 - | -2 | (HashMap::::new()#..) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: no variadic tuple identifier was found in the expansion form -note: when expanding with `(..#Key) = (usize, bool)` and `(..#Value) = (bool, String)` - --> src/main.rs:6:16 - | -6 | let mega_map = make_mega_map::<(usize, bool), (bool, String)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``` +TODO: Add an error when multiple independent variadic tuple identifier are used in a single expansion form. +ie: `fn my_func<(..#K), (..#V)>() -> (..#HashMap) { ... }` #### Help and note for existing errors @@ -474,12 +408,12 @@ note: when expanding with `(..#Key) = (usize, bool)` and `(..#Value) = (bool, St If we consider this code: ```rust -fn make_mega_map<(..#Key), (..#Value)>() -> (HashMap#..) { - (HashMap::::new()#..) +fn make_mega_map<(..#(Key, Value))>() -> (..#HashMap) { + (..#HashMap::::new()) } fn main() { - let mega_map = make_mega_map::<(usize, bool), (bool, String)>(); + let mega_map = make_mega_map::<(usize, bool), (f32, String)>(); } ``` @@ -487,8 +421,8 @@ Then the expansion form is valid, even though the `Value2` identifier is probabl In that case, the expansion will be resolved as: ```rust -fn make_mega_map<(usize, bool), (bool, String)>() -> (HashMap, HashMap) { - (HashMap::::new(), HashMap::::new()) +fn make_mega_map<(usize, bool), (f32, String)>() -> (HashMap, HashMap) { + (HashMap::::new(), HashMap::::new()) } ``` @@ -498,12 +432,12 @@ Leading to a compile error with additional notes error[E0412]: cannot find type `Value2` in this scope --> src/main.rs:10:22 | -10 | let mega_map = make_mega_map::<(usize, bool), (bool, String)>(); +10 | let mega_map = make_mega_map::<(usize, bool), (f32, String)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope -note: when expanding with `(..#Key) = (usize, bool)` and `(..#Value) = (bool, String)` +note: when expanding with `(..#(Key, Value)) = ((usize, bool), (f32, String))` --> src/main.rs:2:4 | -2 | (HashMap::::new()#..) +2 | (..#HashMap::::new()) | ``` @@ -529,23 +463,12 @@ C++11 sets a decent precedent with its variadic templates, which can be used to - When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) -- Maybe a better syntax can be found that includes the length constraint for variadic tuples. -Example, instead of -```rust -fn my_function<(..#R), (..#L)>(r: (R#..), l: (L#..)) -> ((R, L)#..) { ... } -``` -Use -```rust -fn my_function<(..#(R, L))>(r: (R#..), l: (L#..)) -> ((R, L)#..) { ... } -``` -To enforce that variadic tuples `R` and `L` have the same arity. - # Future possibilities [future-possibilities]: #future-possibilities - Be able to create identifiers in an expansion form from the variadic tuple. - For instance, if `(..#T)` is `(A, B, C)`, then `let ((ref v%T%)#..) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` + For instance, if `(..#T)` is `(A, B, C)`, then `let (..#(ref v%T%)) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` - This feature will let user to have more flexibility when implementing code with variadic tuple - Improve the error message for `E0275` by providing the sequence of evaluated elements to give more help to the user about what can create the overflow. - In the context of variadic tuple, this can be the sequence of variadic tuple implementation that are tried by the compiler. From 49fac42081a2762cdd2dfdd346ae0d5d4a09b6af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Wed, 28 Aug 2019 22:36:48 +0200 Subject: [PATCH 12/51] Added note for nested variadic tuples --- text/0000-variadic-tuples.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index b1b9ac6f5e4..df7d07ad42b 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -462,6 +462,8 @@ C++11 sets a decent precedent with its variadic templates, which can be used to - Tuple expansion may not be reserved only for variadic tuple, maybe it can be used as well on fixed arity tuple as well? (For consistency) - When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) + +- TODO: Consider nested variadic tuples (similar co [C++ nested parameter packs](http://www.enseignement.polytechnique.fr/informatique/INF478/docs/Cpp/en/cpp/language/parameter_pack.html)) # Future possibilities From a58f381b1035fce9a2a496f41512b883ee2d20c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 29 Aug 2019 09:45:26 +0200 Subject: [PATCH 13/51] Updated type-level pattern matching --- text/0000-variadic-tuples.md | 41 +++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index df7d07ad42b..c21389cce54 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -173,6 +173,40 @@ where ..#(T: Clone + 'static,) { [reference-level-explanation]: #reference-level-explanation +## Syntax + +### Declarative form + +#### Grammar + +The declarative form can occur only in generic parameter groups. It can be either `(..#)` where `` is an identifier or `(..#)` where `` is a pattern made of a tuple of identifiers. + +Examples: + +- `(..#)`: `(..#A)`, `(..#_MyType)`, `(..#Identifier)` +- `(..#)`: `(..#(A, B))`, `(..#(_T1, _T2, _T3))`, `(..#(A, _T2, Ident3, __TZ))` + +Invalid examples: + +- (..#)`: `(..#Vec) +- `(..#)`: `(..#(Vec, B))`, `(..#(_T1, HashMap<_T2, _T3>))` + +#### Syntax type + +For this syntax: `(..#T)`, then `..#T`defines a list of types identified by `T`and `(..#T)`is a tuple type made with the list of type `..#T`. + +For this syntax: `(..#(A, B))`, `..#(A, B)`is a list of 2-tuple types and `(..#(A, B))`is a tuple type made with the list of 2-tuple type `..#(A, B)` + +### Expansion form + +#### Grammar + +An expansion form using the variadic tuples `A` and `B` have this syntax: `..#` where `` is an expression using the identifiers `A` and `B`. + +#### Syntax type + +An expansion form is an expression. + ## Recursion To implement some feature, we may want to use recursion over the arity of the tuple. @@ -399,7 +433,10 @@ struct MegaMap<((usize, bool), (i32, string))> { Variadic tuple expansion will generate code and may produce obscure errors for existing compile error. To help user debug their compile issue, we need to provide information about the expansion the compiler tried to resolve. TODO: Add an error when multiple independent variadic tuple identifier are used in a single expansion form. -ie: `fn my_func<(..#K), (..#V)>() -> (..#HashMap) { ... }` +ie: `fn my_func<(..#K), (..#V)>() -> (..#HashMap) { ... }` -> `K` and `V` may have different arities. + +TODO: Add an error when the type-level pattern matching is incorrect. +ie: `fn my_func<(..#(K, Vec))() { ... }` -> `(K, Vec)` is not a tuple of identifiers. #### Help and note for existing errors @@ -462,8 +499,6 @@ C++11 sets a decent precedent with its variadic templates, which can be used to - Tuple expansion may not be reserved only for variadic tuple, maybe it can be used as well on fixed arity tuple as well? (For consistency) - When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) - -- TODO: Consider nested variadic tuples (similar co [C++ nested parameter packs](http://www.enseignement.polytechnique.fr/informatique/INF478/docs/Cpp/en/cpp/language/parameter_pack.html)) # Future possibilities From 24de71f93f1439b71f29548760b7915d1ad90003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 29 Aug 2019 16:12:19 +0200 Subject: [PATCH 14/51] added todo --- text/0000-variadic-tuples.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index c21389cce54..66e506d1816 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -255,6 +255,8 @@ The compiler will execute these steps: 6. Generation of `impl` of `Arity` for `(usize,)` completed 5. Generation of `impl` of `Arity` for `(bool, usize)` completed +// TODO: recursion termination for fn + ### Recursion errors #### Missing implementation message From 0e672b256aeec7047fcb66cae03f9e21986d42e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 29 Aug 2019 23:49:58 +0200 Subject: [PATCH 15/51] Updated RFC from feedbacks Separated variadic tuple type and variadic tuple Added destructuration of variadic tuple --- text/0000-variadic-tuples.md | 396 ++++++++++++++++++++--------------- 1 file changed, 224 insertions(+), 172 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 66e506d1816..b6a924d9cce 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -30,9 +30,11 @@ Variadic tuple will provide several benefits considering trait implementation fo [guide-level-explanation]: #guide-level-explanation -The variadic tuple occurs in two form: a declarative form and an expansion form. +Let's call a _variadic tuple type_ a tuple type with an arbitrary arity and a _variadic tuple_ an instance of a variadic tuple type. -The declarative form is `(..#T)` and an example of an expansion form is `(..#Vec)` +The variadic tuple type occurs in two form: a declarative form and an expansion form. And the variadic tuple only occurs in expansion forms. + +For a variadic tuple type, the declarative form is `(..#T)` and an example of an expansion form is `(..#Vec)`. Note: To illustrate the RFC, we will use the current implementation of the `Hash` trait for tuples. @@ -66,106 +68,177 @@ macro_rules! last_type { } ``` -## Declaring a variadic tuple +## Variadic tuple type + +### Declaration + +Variadic tuple types are always declared in a generic parameter group. + +There are two different syntaxes: -To declare a variadic tuple, we use `(..#T)`, where `T` is a type identifier. +1. `(..#T)`: declare a single variadic tuple type identified by `T` +2. `(..#(T1, T2, ..., Tn))`: declare n variadic tuple types identified by `T1`, `T2`, ..., `Tn`, all these variadic tuple types have the same arity. -For instance: +Declaration examples: -- `struct VariadicStruct<(..#T1)>` : declares a struct with a variadic tuple identified by `T1` in its generic parameters -- `impl<(..#Head)>`: is an implementation block that uses a variadic tuple identified by `Head` +- struct VariadicStruct<(..#T1)>` : declares a struct with a variadic tuple type identified by `T1` in its generic parameters +- `impl<(..#Head)>`: is an implementation block that uses a variadic tuple type identified by `Head` - `impl`: same as above, but with other generic parameters -- `fn my_function<(..#A)>`: a function can also have variadic tuple -- `fn my_function`: there can be several variadic tuple declared in a generic parameter group +- `fn my_function<(..#A)>`: a function can also have variadic tuple types +- `fn my_function`: there can be several variadic tuple types declared in a generic parameter group + +Usage examples: + +```rust +struct VariadicStruct<(..#T)> +VariadicStruct<(usize,)> // => (..#T) matches (usize,) +VariadicStruct<(usize, bool)> // => (..#T) matches (usize, bool) + +fn variadic_fn<(..#(T1, T2))>() { ... } +variadic_fn::<((usize, bool),) +// (..#(T1, T2)) matches ((usize, bool),) +// (..#T1) is (usize,) +// (..#T2) is (bool,) +variadic_fn::<((usize, bool), (String, i8)) // (..#(T1, T2)) matches ((usize, bool), (String, i8)) +// (..#T1) is (usize, String) +// (..#T2) is (bool, i8) +``` -You can think this like a rule you give to the compiler to generated appropriate code when it runs into specific patterns: +### Expansion -- `VariadicStruct<(int, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize)` -- `VariadicStruct<(int, usize, usize)>` matches `VariadicStruct<(..#T1)>` where `(..#T1)` maps to `(int, usize, usize)` - (We will see implementation examples later, with the expansion form) +The expansion syntax is: `..#` where `` is an expression using the variadic tuple type identifiers `T1`, `T2`, ..., `Tn`. -### Multiple variadic tuple sharing the same arity +Note: The expression in an expansion form can be enclosed by parenthesis for clarity. Ex: `..#(T: Clone,)`. -You can declare that several variadic tuple have the same arity in a generic parameter group: +The expansion form is allowed in all places where a type is allowed and in `where` bounds. + +Examples: ```rust -/// Here we have 3 variadic tuple: T1, T2, T3 -/// T2 and T3 have the same arity -/// The arity of T1 is independent of the others -fn my_function<(..#T1), (..#(T2, T3))>() { - ... +type TuplesOfRef<'a, (..#T)> = (..#&'a T); +TuplesOfRef<'b, (usize, bool)>; // = (&'b usize, &'b bool) + +struct MegaMap<(..#(K, V))> { + maps: (..#HashMap), } +// +// struct MegaMap<((usize, bool), (String, i8))> { +// maps: (HashMap, HashMap), +// } + +fn append<(..#L), (..#R)>(l: (..#L), r: (..#R)) -> (..#L, ..#R) +where ..#(L: 'static + Clone), ..#(R: 'static + Clone) { ... } +// +// append<(usize, Vec), (&'static str, u8, i16)>( +// l: (usize, Vec), +// r: (&'static str, u8, i16) +// ) -> (usize, Vec, &'static str, u8, i16) { ... } ``` -See [Multiple identifier expansion forms](### Multiple identifier expansion forms) for a more detailed usage. +Note: If an expansion syntax does not contains any variadic tuple type identifier, it resolves to the unit type `( )`. -## Expanding variadic tuple +Note2: If an expansion syntax contains multiple variadic tuple type identifiers, they must all have been declared together with the syntax `( ..#(T1, T2, ..., Tn))` to ensure they have the same arity. -At some point, we need to use the types that are declared in the declaration form, this is where we use the expansion form. +## Variadic tuple -When expanding a tuple, we use the form `..#T`, but more generally: `..#` where `` is pattern using the identifier `T`. +A _variadic tuple_ is a variable of a variadic tuple type. -Note: The `` can be enclosed by braces or parenthesis when the expression is complex. -So you can have 3 different forms: +### Declaration -1. `(..#Vec)`: simple form -2. `(..#(ref T))`: parenthesis form -3. `(..#{let mut r = T::default(); r += 2; r})`: braces form - -Let's implement the `Hash` trait: +A variadic tuple can be declared like any other variable: ```rust -// For the example, we consider the impl for (A, B, C). So `(..#T)` matches `(A, B, C)` -// We have the first expansion here, `(T#.., Last)` expands to `(A, B, C, Last)` -impl<(..#T), Last> Hash for (..#T, Last) -where - ..#(T: Hash), // Expands to `A: Hash, B: Hash, C: Hash,` - Last: Hash + ?Sized, { +fn my_func<(..#T)>(variadic_tuple: (..#T)) { ... } +``` - #[allow(non_snake_case)] - fn hash(&self, state: &mut S) { - let (..#(ref T), ref last) = *self; // Expands to `let (ref A, ref B, ref C, ref last) = *self;` - (..#T.hash(state), last.hash(state)); // Expands to `(A.hash(state), B.hash(state), C.hash(state), last.hash(state));` - } +### Destructuring a variadic tuple + +The main way to use a variadic tuple is by destructuring it to access its members. + +There are 3 syntaxes possible to destructure a variadic tuple for a variadic tuple `(..#T)`: + +1. `(..#v)` of variadic tuple type `(..#T)` +2. `(..#(ref v))` of variadic tuple type `(..#&T)` +3. `(..#(ref mut v))` of variadic tuple type `(..#&mut T)` + +Also, the destructure pattern can be combined with other members. For instance: + +```rust +{ + let source: (Head, ..#Tail) = _; + let (ref head, ..#(ref tail)) = &source; +} +{ + let mut source: (..#L, ..#R) = _; + let (..#(ref mut l), ..#(ref mut r)) = &mut source; } + ``` -## Allowed usages of variadic tuples +Examples: + +```rust +// The function argument is destructured as a variadic tuple with identifier `v` +fn my_func<(..#T)>((..#v): (..#T)) -> (..#T) { + (..#(v + v)) +} -### Declarative form +impl<(..#T)> Clone for (..#T) +where ..#(T: Clone) { + fn clone(&self) -> Self { + // We destructure `*self` which has a variadic tuple type `(..#T)` + let (..#(ref v)) = *self; + (..#v.clone()) + } +} +``` -The declarative form is used in a generic parameter group, so it can occur in: +### Expansion -- Struct generic parameters : `struct MyStruct<(..#T)>` -- Function generic parameters : `fn my_function<(..#T)>` -- Type alias declaration : `type MyTuple<(..#T)>` -- impl block generic parameters : `impl<(..#T)>` +An expansion form for variadic tuple has the syntax: `..#` where `T1`, `T2`, ..., `Tn` are variadic tuple type identifiers and `id1`, `id2`, ..., `idn` are variadic tuple identifiers. -### Expansion form +Note: All variadic tuple type used in the expansion form must have been declared together. The variadic tuple type used are the variadic tuple types identified by `T1`, `T2`, ..., `Tn` or the type of the variadic tuple identified by `id1`, `id2`, ..., `idn`. -The expansion form can occur in many places. +Note: An expansion form without any identifier resolves to the unit type `()`. -Various examples: +Note 2: The expression in an expansion form can be enclosed by parenthesis or braces for clarity. + +Examples: ```rust -type TupleOfVec<(..#T)> = (..#Vec); +fn my_func<(..#T)>((..#i): (..#T)) { + (..#{ println!("{}", i) }) +} -fn my_function<(..#T)>(values: &(..#Vec)) -> (..#&[T]) -where ..#(T: Clone,) { - let (..#(ref T)) = values; - (..#T) +fn clone_add<(..#T)>((..#i): (..#T)) -> (..#T) +where ..#(T: Clone + Add) { + (..#(::clone(&i) + i)) } -struct MyStruct<(..#T)> { - arrays: (..#[T; 4]), +fn merge_into<(..#(L, R))>((..#l): (..#L), (..#r): (..#R)) -> (..#L, ..#L) +where ..#(L: From) { + (..#l, ..#(R as Into>::into(r))) } -impl<(..#T)> MyStruct<(..#Vec)> -where ..#(T: Clone + 'static,) { - pub fn new() -> Self { - Self { - arrays: (..#[Vec::new(), Vec::new(), Vec::new(), Vec::new()]) +``` + +## The `Hash`trait + +Let's implement the `Hash` trait: + +```rust +// For the example, we consider the impl for (A, B, C). So `(..#T)` matches `(A, B, C)` +// We have the first expansion here, `(..#T, Last)` expands to `(A, B, C, Last)` +impl<(..#T), Last> Hash for (..#T, Last) +where + ..#(T: Hash,), // Expands to `A: Hash, B: Hash, C: Hash,` + Last: Hash + ?Sized, { + + #[allow(non_snake_case)] + fn hash(&self, state: &mut S) { + let (..#(ref v), ref last) = *self; // Destructure self to a variadic tuple `v` and a variable `last`. The variadic tuple type of `v` is `(..#&T)` + // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let v = (a, b, c);` + (..#v.hash(state), last.hash(state)); // Expands to `(v.0.hash(state), v.1.hash(state), v.2.hash(state), last.hash(state));` } - } } ``` @@ -175,37 +248,77 @@ where ..#(T: Clone + 'static,) { ## Syntax -### Declarative form +### Variadic tuple type declaration + +A variadic tuple type identifier identifies a list of types. -#### Grammar +When declared togethers, each identifiers identifies a list of types. For instance: + +```rust +fn my_func<(..#(L, R))>() { } +my_func::<((usize, bool), (i8, f32))>(); +// `(..#(L, R))` matches `((usize, bool), (i8, f32))` +// `(..#L)` is `(usize, i8)` +// `(..#R)` is `(bool, f32)` +``` -The declarative form can occur only in generic parameter groups. It can be either `(..#)` where `` is an identifier or `(..#)` where `` is a pattern made of a tuple of identifiers. +Note: Although this looks like a type-level pattern matching, it can match against only tuple of identifiers. So the following declaration is invalid: `fn my_func<(..#(L, Vec))>() { ... }` + +### Variadic tuple type expansion + +On location where a type is expected, the expansion will resolve to a type. On where bounds it can be used to declare bounds on the type contained in the variadic tuple type. Examples: -- `(..#)`: `(..#A)`, `(..#_MyType)`, `(..#Identifier)` -- `(..#)`: `(..#(A, B))`, `(..#(_T1, _T2, _T3))`, `(..#(A, _T2, Ident3, __TZ))` +```rust +type TupleOfVec<(..#T)> = (..#Vec); -Invalid examples: +fn my_func<(..#T)>() +where ..#(T: Clone) { ... } +``` -- (..#)`: `(..#Vec) -- `(..#)`: `(..#(Vec, B))`, `(..#(_T1, HashMap<_T2, _T3>))` +### Variadic tuple declaration -#### Syntax type +The declaration of a variadic tuple variable is still a variable. Nothing new here. -For this syntax: `(..#T)`, then `..#T`defines a list of types identified by `T`and `(..#T)`is a tuple type made with the list of type `..#T`. +```rust +fn my_func<(..#T)>(input: (..#T)) { ... } +``` -For this syntax: `(..#(A, B))`, `..#(A, B)`is a list of 2-tuple types and `(..#(A, B))`is a tuple type made with the list of 2-tuple type `..#(A, B)` +### Variadic tuple destructuration -### Expansion form +When destructuring a variadic tuple it declares a variadic tuple identifiers that can be used in expansion forms. The identifier is a variable of type `(..#T)` or `(..#&T)` or `(..#&mut T)`, depending on the syntax used. -#### Grammar +```rust +{ + let source: (..#T, Tail) = _; + let (..#v, tail) = source; + // v is a variable of type `(..#T)` + let (..#(ref v), ref tail) = &source; + // v is a variable of type `(..#&T)` + let (..#(ref mut v), ref mut tail) = &mut source; + // v is a variable of type `(..#&mut T)` +} -An expansion form using the variadic tuples `A` and `B` have this syntax: `..#` where `` is an expression using the identifiers `A` and `B`. +// If we use `(..#T)` = `(A, B, C)` as an example +// Then `let (..#(ref v), ref tail) = &source` +// is equivalent to: +// `let (ref a, ref b, ref c, ref tail) = &source;` +// `let v = (a, b, c);` +``` -#### Syntax type +### Variadic tuple expansion -An expansion form is an expression. +The variadic tuple expansion are "expression template". By replacing the identifiers by its appropriate value, the variadic tuple expansion will result in a list of expressions. The full expression form will be replaced by the resolved list of expression. + +```rust +fn my_function<(..#T)>((..#i): (..#T)) { + (..#i.clone()) + // `i.clone()` is the expression template parameterized by `i` + // it will resolve into a list of expressions: `i.0.clone(), i.1.clone(), ..., i.n.clone()` + // Finally, `..#i.clone()` will be replaced by the resolved list of expressions +} +``` ## Recursion @@ -255,11 +368,21 @@ The compiler will execute these steps: 6. Generation of `impl` of `Arity` for `(usize,)` completed 5. Generation of `impl` of `Arity` for `(bool, usize)` completed -// TODO: recursion termination for fn +### Recursion with functions -### Recursion errors +```rust +fn recurse((head, ..#tail): (Head, ..#Tail)) +where Head: Debug, ..#(Tail: Debug) { + println!("{}", head); + recurse((..#tail)); +} +// Termination needs to be implemented explicitly +fn recurse<()>((): ()) { } +``` -#### Missing implementation message +## Errors + +#### Missing implementation message during variadic implementation resolution An error can occur if the compiler don't find an implementation while generating variadic tuple implementations. @@ -309,7 +432,7 @@ error[E0277]: the trait bound `(): Arity` is not satisfied | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` -#### Cycle dependency error +#### Variadic implementation cycle dependency error As a variadic tuple implementation may depend on other variadic tuple implementation, there can be dependency cycle issue. @@ -346,102 +469,35 @@ note: required by `A::VALUE` | ^^^^^^^^^^^^^^^^^^^^^^^ ``` -## Using multiple variadic tuples - -### Recursive variadic tuples - -Recursive variadic tuples are forbidden. -Example: - -```rust -fn my_func<(..#((..#T)))>() { ..} -``` - -### Expansion forms without variadic tuple identifiers - -In that case, the expansion forms resolves to `()`. - -### Single identifier expansion forms +### Invalid variadic tuple type declaration -We can declare and use multiple variadic tuples, if the expansion forms only involve a single variadic tuple identifier, there is no constraints. +TODO -See this example of a `trait`that merge two tuples: +### Invalid variadic tuple declaration -```rust -trait Merge { - type Out; - - fn append(self, value: T) -> Self::Out; -} +TODO -impl<(..#L), (..#R)> Merge<(..#R)> for (..#L) { - type Out = (..#L, ..#R); +### Invalid variadic tuple type expansion identifiers - fn merge(self, value: (..#R)) -> Self::Out; { - let (..#L) = self; - let (..#R) = value; - (..#L, ..#R) - } -} -``` - -Note: a variadic tuple identifier may occur more than once in an expansion form, for instance: - -```rust -fn double<(..#T)>(input: (..#T)) -> (..#T) - where ..#(T: Add), { - (..#(T + T)) -} -``` - -### Multiple identifier expansion forms - -An expansion form may include multiple different variadic tuple identifiers. However, both variadic tuple must have the same arity. - -To ensure this, the declaration of these variadic tuples is a bit different: - -```rust -struct MegaMap<(..#(Key, Value))> { - maps: (..#HashMap) -} -``` +TODO: Add an error when multiple independent variadic tuple identifier are used in a single expansion form. +ie: `fn my_func<(..#K), (..#V)>() -> (..#HashMap) { ... }` -> `K` and `V` may have different arities. -So the syntax `(..#(Key, Value))` declares 2 variadic tuples with identifiers `Key` and `Value` that have the same arity. +### Invalid variadic tuple expansion identifiers -To use this syntax, the user must follow the same pattern: +TODO: Occurs when a variadic tuple expansion form used variadic tuple types with different arities (not declared together) -```rust -MegaMap<((usize, bool), )> -MegaMap<((usize, i8), (String, Vec))> -``` + ```rust + fn my_func<(..#L), (..#R)>((..#l): (..#L), (..#r): (..#R)) { let _ = (..#(l, r)); } + ``` -Note: Both identifiers `Key` and `Value` can be used in the same expansion form, but the can also be used in separate expansion forms. -Example: +### Invalid variadic tuple destructuration -```rust -struct MegaMap<(..#(Key, Value))> { - keys: (..#Vec), - values: (..#Vec), -} -// Then if we expand the syntax we have: -struct MegaMap<((usize, bool), (i32, string))> { - keys: (Vec, Vec), - values: (Vec, Vec), -} -``` +TODO -### Expansion errors +## Help and note for existing errors Variadic tuple expansion will generate code and may produce obscure errors for existing compile error. To help user debug their compile issue, we need to provide information about the expansion the compiler tried to resolve. -TODO: Add an error when multiple independent variadic tuple identifier are used in a single expansion form. -ie: `fn my_func<(..#K), (..#V)>() -> (..#HashMap) { ... }` -> `K` and `V` may have different arities. - -TODO: Add an error when the type-level pattern matching is incorrect. -ie: `fn my_func<(..#(K, Vec))() { ... }` -> `(K, Vec)` is not a tuple of identifiers. - -#### Help and note for existing errors - ##### Unknown identifier in an expansion form If we consider this code: @@ -492,13 +548,12 @@ note: when expanding with `(..#(Key, Value)) = ((usize, bool), (f32, String))` [prior-art]: #prior-art -C++11 sets a decent precedent with its variadic templates, which can be used to define type-safe variadic functions, among other things. C++11 has a special case for variadic parameter packs. +C++11 sets a decent precedent with its variadic templates, which can be used to define type-safe variadic functions, among other things. This RFC is comparable to the design of _type parameter packs_ (variadic tuple type) and _function parameter pack_ (variadic tuple). # Unresolved questions [unresolved-questions]: #unresolved-questions -- Tuple expansion may not be reserved only for variadic tuple, maybe it can be used as well on fixed arity tuple as well? (For consistency) - When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) @@ -506,9 +561,6 @@ C++11 sets a decent precedent with its variadic templates, which can be used to [future-possibilities]: #future-possibilities -- Be able to create identifiers in an expansion form from the variadic tuple. - For instance, if `(..#T)` is `(A, B, C)`, then `let (..#(ref v%T%)) = value;` expands to `let (ref vA, ref vB, ref vC) = value;` - - This feature will let user to have more flexibility when implementing code with variadic tuple - Improve the error message for `E0275` by providing the sequence of evaluated elements to give more help to the user about what can create the overflow. - In the context of variadic tuple, this can be the sequence of variadic tuple implementation that are tried by the compiler. - But, in the more generic case where two traits implementations requires each others, providing the dependency cycle can be really helpful. From 4440ee427d0d483186b14852f8795b075abe9da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 29 Aug 2019 23:51:41 +0200 Subject: [PATCH 16/51] Updated syntax of examples --- text/0000-variadic-tuples.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index b6a924d9cce..692ab693e3a 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -230,14 +230,18 @@ Let's implement the `Hash` trait: // We have the first expansion here, `(..#T, Last)` expands to `(A, B, C, Last)` impl<(..#T), Last> Hash for (..#T, Last) where - ..#(T: Hash,), // Expands to `A: Hash, B: Hash, C: Hash,` + // Expands to `A: Hash, B: Hash, C: Hash,` + ..#(T: Hash,), Last: Hash + ?Sized, { #[allow(non_snake_case)] fn hash(&self, state: &mut S) { - let (..#(ref v), ref last) = *self; // Destructure self to a variadic tuple `v` and a variable `last`. The variadic tuple type of `v` is `(..#&T)` + // Destructure self to a variadic tuple `v` and a variable `last`. The variadic tuple type of `v` is `(..#&T)` // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let v = (a, b, c);` - (..#v.hash(state), last.hash(state)); // Expands to `(v.0.hash(state), v.1.hash(state), v.2.hash(state), last.hash(state));` + let (..#(ref v), ref last) = *self; + + // Expands to `(v.0.hash(state), v.1.hash(state), v.2.hash(state), last.hash(state));` + (..#v.hash(state), last.hash(state)); } } ``` From 28abff73a0d3e9f23ca1ff6afe0678e2ce6fdaa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 29 Aug 2019 23:56:57 +0200 Subject: [PATCH 17/51] Fixed some syntax issues --- text/0000-variadic-tuples.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 692ab693e3a..4a7725aaf3b 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -81,7 +81,7 @@ There are two different syntaxes: Declaration examples: -- struct VariadicStruct<(..#T1)>` : declares a struct with a variadic tuple type identified by `T1` in its generic parameters +- `struct VariadicStruct<(..#T1)>` : declares a struct with a variadic tuple type identified by `T1` in its generic parameters - `impl<(..#Head)>`: is an implementation block that uses a variadic tuple type identified by `Head` - `impl`: same as above, but with other generic parameters - `fn my_function<(..#A)>`: a function can also have variadic tuple types @@ -197,11 +197,11 @@ where ..#(T: Clone) { An expansion form for variadic tuple has the syntax: `..#` where `T1`, `T2`, ..., `Tn` are variadic tuple type identifiers and `id1`, `id2`, ..., `idn` are variadic tuple identifiers. -Note: All variadic tuple type used in the expansion form must have been declared together. The variadic tuple type used are the variadic tuple types identified by `T1`, `T2`, ..., `Tn` or the type of the variadic tuple identified by `id1`, `id2`, ..., `idn`. +Note 1: All variadic tuple type used in the expansion form must have been declared together. The variadic tuple type used are the variadic tuple types identified by `T1`, `T2`, ..., `Tn` or the type of the variadic tuple identified by `id1`, `id2`, ..., `idn`. -Note: An expansion form without any identifier resolves to the unit type `()`. +Note 2: An expansion form without any identifier resolves to the unit type `()`. -Note 2: The expression in an expansion form can be enclosed by parenthesis or braces for clarity. +Note 3: The expression in an expansion form can be enclosed by parenthesis or braces for clarity. Examples: From f51aca3307c65df7bc746f7bb74b47894e600d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 30 Aug 2019 09:08:26 +0200 Subject: [PATCH 18/51] Fixed typos --- text/0000-variadic-tuples.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 4a7725aaf3b..2c2d4d27359 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -197,7 +197,7 @@ where ..#(T: Clone) { An expansion form for variadic tuple has the syntax: `..#` where `T1`, `T2`, ..., `Tn` are variadic tuple type identifiers and `id1`, `id2`, ..., `idn` are variadic tuple identifiers. -Note 1: All variadic tuple type used in the expansion form must have been declared together. The variadic tuple type used are the variadic tuple types identified by `T1`, `T2`, ..., `Tn` or the type of the variadic tuple identified by `id1`, `id2`, ..., `idn`. +Note 1: All variadic tuple type used in the expansion form must have been declared together. The variadic tuple type used are the variadic tuple types identified by `T1`, `T2`, ..., `Tn` and the type of the variadic tuple identified by `id1`, `id2`, ..., `idn`. Note 2: An expansion form without any identifier resolves to the unit type `()`. @@ -217,7 +217,7 @@ where ..#(T: Clone + Add) { fn merge_into<(..#(L, R))>((..#l): (..#L), (..#r): (..#R)) -> (..#L, ..#L) where ..#(L: From) { - (..#l, ..#(R as Into>::into(r))) + (..#l, ..#(>::into(r))) } ``` From 231e8664c68e54ca8203aa35193172309edf0e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Sat, 31 Aug 2019 11:41:52 +0200 Subject: [PATCH 19/51] Updated the termination for functions and specialization for recursive impl --- text/0000-variadic-tuples.md | 66 +++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 2c2d4d27359..208b1988599 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -197,7 +197,7 @@ where ..#(T: Clone) { An expansion form for variadic tuple has the syntax: `..#` where `T1`, `T2`, ..., `Tn` are variadic tuple type identifiers and `id1`, `id2`, ..., `idn` are variadic tuple identifiers. -Note 1: All variadic tuple type used in the expansion form must have been declared together. The variadic tuple type used are the variadic tuple types identified by `T1`, `T2`, ..., `Tn` and the type of the variadic tuple identified by `id1`, `id2`, ..., `idn`. +Note 1: All variadic tuple type used in the expansion form must have been declared together. The variadic tuple type used are the variadic tuple types identified by `T1`, `T2`, ..., `Tn` or the type of the variadic tuple identified by `id1`, `id2`, ..., `idn`. Note 2: An expansion form without any identifier resolves to the unit type `()`. @@ -217,7 +217,7 @@ where ..#(T: Clone + Add) { fn merge_into<(..#(L, R))>((..#l): (..#L), (..#r): (..#R)) -> (..#L, ..#L) where ..#(L: From) { - (..#l, ..#(>::into(r))) + (..#l, ..#(R as Into>::into(r))) } ``` @@ -335,7 +335,7 @@ trait Arity { } impl Arity for (Head, ..#Tail) { - const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; + default const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; } impl Arity for () { const VALUE: usize = 0; @@ -346,6 +346,7 @@ Note: - The `impl Arity for (Head, ..#Tail)` is the recursive implementation. - The `impl Arity for ()` is the termination of the recursive implementation. +- We use the specialization feature here with the `default` token to declare a specialise implementation that is the termination of the recursive implementation And when we compile the following code: @@ -548,6 +549,14 @@ note: when expanding with `(..#(Key, Value)) = ((usize, bool), (f32, String))` [rationale-and-alternatives]: #rationale-and-alternatives +## Declaring and using multiple variadic tuple type with same aritiy + +In C++ multiple parameter packs can be expanded in a single expansion form as long as the packs have the same number of items, but there is no constraint concerning the declaration. + +For Rust, using the syntax `(..#(T1, T2, ..., Tn))` embeds the constraint that the variadic tuple types `T1`, `T2`, ..., `Tn` have the same arity. This is more consistent than not grouping the declaration (ie: `(..#T1), (..#T2), ..., (..#Tn))`) because the signature using the declaration contains all the information required. + +We don't need to look at the implementation or body code to know the required constraint about the variadic tuple type arities. + # Prior art [prior-art]: #prior-art @@ -558,8 +567,55 @@ C++11 sets a decent precedent with its variadic templates, which can be used to [unresolved-questions]: #unresolved-questions -- When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a - way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) +## Dynamic libraries tuple implementation assumption + +When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a +way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) + +## Termination syntax for functions + +The suggested termination syntax is too close to a duplicate function definition and this is not a behaviour that currently exists. (See this [RFC issue](https://github.com/rust-lang/rfcs/issues/1053)) + +```rust +fn recurse((head, ..#tail): (Head, ..#Tail)) +where Head: Debug, ..#(Tail: Debug) { + println!("{}", head); + recurse((..#tail)); +} +// Termination needs to be implemented explicitly +fn recurse<()>((): ()) { } +``` + +So there can be several alternative to deal with this: + +1. Forbiding variadic tuple for functions. In that case to have a similar functionality, we can use a trait as a workaround. It is more verbose but uses a trait instead. (Also, this may be dealt with in an another PR) + + ```rust + trait MyFuncTrait { + fn my_func(input: (Head, ..#T)); + } + struct MyFunctTraitHelper; + impl MyFuncTrait for MyFuncTraitHelper { + fn my_func((h, ..#i): (Head, ..#T)) { + MyFunctTraitHelper::my_func((..#i)); + } + } + impl<()> MyFuncTrait<()> for MyFuncTraitHelper { + fn my_func((): ()) { } + } + ``` + +1. Using a specific syntax to declare a specialized implementation. + + ```rust + default fn recurse((head, ..#tail): (Head, ..#Tail)) + where Head: Debug, ..#(Tail: Debug) { + println!("{}", head); + recurse((..#tail)); + } + // Termination needs to be implemented explicitly + fn recurse<()>((): ()) { } + ``` # Future possibilities From feb006ec77dafd40b5737eeb9ffd48b305bcdaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 2 Sep 2019 14:10:17 +0200 Subject: [PATCH 20/51] Updated errors --- text/0000-variadic-tuples.md | 107 +++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 12 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 208b1988599..92fbb010e79 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -108,7 +108,7 @@ variadic_fn::<((usize, bool), (String, i8)) // (..#(T1, T2)) matches ((usize, bo The expansion syntax is: `..#` where `` is an expression using the variadic tuple type identifiers `T1`, `T2`, ..., `Tn`. -Note: The expression in an expansion form can be enclosed by parenthesis for clarity. Ex: `..#(T: Clone,)`. +Note: The expression in an expansion form can be enclosed by parenthesis for clarity. Ex: `..#(T: Clone)`. The expansion form is allowed in all places where a type is allowed and in `where` bounds. @@ -476,28 +476,111 @@ note: required by `A::VALUE` ### Invalid variadic tuple type declaration -TODO +The variadic tuple type declaration is invalid when it can't be parsed as either: +- `(..#T)` +- `(..#(T1, T2, .., Tn))` -### Invalid variadic tuple declaration +```rust +struct MyStruct<(..#Vec)> { + vecs: (..#Vec) +} +``` -TODO +```rust +error[EXXXX]: invalid variadic tuple type declaration `(..#Vec)` + --> src/main.rs:1:13 + | +10 | struct MyStruct<(..#Vec)> { + | ^^^^^^^^^^^ + | +note: expected either an identifier or a tuple of identifier instead of `Vec` +``` ### Invalid variadic tuple type expansion identifiers -TODO: Add an error when multiple independent variadic tuple identifier are used in a single expansion form. -ie: `fn my_func<(..#K), (..#V)>() -> (..#HashMap) { ... }` -> `K` and `V` may have different arities. +Occurs when multiple independent variadic tuple type identifier are used in a single expansion form. + +```rust +impl<(..#K), (..#V)> MyTrait for (..#HashMap) { + +} +``` + +```rust +error[EXXXX]: invalid variadic tuple type expansion `(..#HashMap)` + --> src/main.rs:4:13 + | +10 | impl<(..#K), (..#V)> MyTrait for (..#HashMap) { + | ^^^^^^^^^^^^^^^^^^ + | +note: variadic tuple type identifiers `K`, `V` were not declared together + --> src/main.rs:4:13 + | +10 | impl<(..#K), (..#V)> MyTrait for (..#HashMap) { + | ^^^^^^^^^^^^^^ + | +hint: expected `(..#(K, V))` +``` ### Invalid variadic tuple expansion identifiers -TODO: Occurs when a variadic tuple expansion form used variadic tuple types with different arities (not declared together) +Occurs when multiple independent variadic tuple identifier are used in a single expansion form. - ```rust - fn my_func<(..#L), (..#R)>((..#l): (..#L), (..#r): (..#R)) { let _ = (..#(l, r)); } - ``` +```rust +impl<(..#K), (..#V)> MyTrait for MyStruct { + fn my_function() { + let k: (..#K) = _; + let v: (..#V) = _; + let k_v = (..#(k, v)); + } +} +``` -### Invalid variadic tuple destructuration +```rust +error[EXXXX]: invalid variadic tuple expansion `(..#(k, v))` + --> src/main.rs:4:13 + | +10 | let k_v = (..#(k, v)); + | ^^^^^^^^^^^ + | +note: variadic tuple identifiers `k`, `v` with variadic tuple type identifiers `K`, `V` were not declared together + --> src/main.rs:4:13 + | +10 | impl<(..#K), (..#V)> MyTrait for MyStruct { + | ^^^^^^^^^^^^^^ + | +hint: expected `(..#(K, V))` +``` + +### Invalid variadic tuple pattern matching + +The variadic tuple declaration is invalid when it can't be parsed as either: +- `(..#id)` +- `(..#(ref id))` +- `(..#(ref mut id))` -TODO +```rust +struct MyStruct<(..#Vec)> { + vecs: (..#Vec) +} + +impl<(..#T)> MyTrait for (..#T) { + fn my_func(&self) { + let (..#(&i)) = &self; + + } +} +``` + +```rust +error[EXXXX]: invalid variadic tuple pattern `(..#(&i))` + --> src/main.rs:4:13 + | +10 | let (..#(&i)) = &self; + | ^^^^^^^^^ + | +note: expected `(..#id)` or `(..#(ref id))` or `(..#(ref mut id))` +``` ## Help and note for existing errors From 945750f69b07a58c50105a86af059b970350542e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Tue, 3 Sep 2019 22:41:37 +0200 Subject: [PATCH 21/51] Removed fn support, added future possibilities --- text/0000-variadic-tuples.md | 191 +++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 89 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 92fbb010e79..83d0d9e87af 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -74,6 +74,8 @@ macro_rules! last_type { Variadic tuple types are always declared in a generic parameter group. +Note: variadic tuples are not supported in generic parameter group of `fn` + There are two different syntaxes: 1. `(..#T)`: declare a single variadic tuple type identified by `T` @@ -84,8 +86,7 @@ Declaration examples: - `struct VariadicStruct<(..#T1)>` : declares a struct with a variadic tuple type identified by `T1` in its generic parameters - `impl<(..#Head)>`: is an implementation block that uses a variadic tuple type identified by `Head` - `impl`: same as above, but with other generic parameters -- `fn my_function<(..#A)>`: a function can also have variadic tuple types -- `fn my_function`: there can be several variadic tuple types declared in a generic parameter group +- `impl`: there can be several variadic tuple types declared in a generic parameter group Usage examples: @@ -94,12 +95,12 @@ struct VariadicStruct<(..#T)> VariadicStruct<(usize,)> // => (..#T) matches (usize,) VariadicStruct<(usize, bool)> // => (..#T) matches (usize, bool) -fn variadic_fn<(..#(T1, T2))>() { ... } -variadic_fn::<((usize, bool),) +impl <(..#(T1, T2))> VariadicStruct<(..#(T1, T2)) { ... } +VariadicStruct::<((usize, bool),) // (..#(T1, T2)) matches ((usize, bool),) // (..#T1) is (usize,) // (..#T2) is (bool,) -variadic_fn::<((usize, bool), (String, i8)) // (..#(T1, T2)) matches ((usize, bool), (String, i8)) +VariadicStruct::<((usize, bool), (String, i8)) // (..#(T1, T2)) matches ((usize, bool), (String, i8)) // (..#T1) is (usize, String) // (..#T2) is (bool, i8) ``` @@ -126,13 +127,18 @@ struct MegaMap<(..#(K, V))> { // maps: (HashMap, HashMap), // } -fn append<(..#L), (..#R)>(l: (..#L), r: (..#R)) -> (..#L, ..#R) -where ..#(L: 'static + Clone), ..#(R: 'static + Clone) { ... } +trait Append<(..#L), (..#R)> +where ..#(L: 'static + Clone), ..#(R: 'static + Clone) { + fn append(l: (..#L), r: (..#R)) -> (..#L, ..#R) +} + // -// append<(usize, Vec), (&'static str, u8, i16)>( -// l: (usize, Vec), -// r: (&'static str, u8, i16) -// ) -> (usize, Vec, &'static str, u8, i16) { ... } +// trait Append<(usize, Vec), (&'static str, u8, i16)> { +// fn append( +// l: (usize, Vec), +// r: (&'static str, u8, i16) +// ) -> (usize, Vec, &'static str, u8, i16) { ... } +// } ``` Note: If an expansion syntax does not contains any variadic tuple type identifier, it resolves to the unit type `( )`. @@ -148,7 +154,9 @@ A _variadic tuple_ is a variable of a variadic tuple type. A variadic tuple can be declared like any other variable: ```rust -fn my_func<(..#T)>(variadic_tuple: (..#T)) { ... } +trait MyFunc<(..#T)> { + fn my_func(variadic_tuple: (..#T)) { ... } +} ``` ### Destructuring a variadic tuple @@ -179,8 +187,10 @@ Examples: ```rust // The function argument is destructured as a variadic tuple with identifier `v` -fn my_func<(..#T)>((..#v): (..#T)) -> (..#T) { - (..#(v + v)) +trait MyFunc<(..#T)> { + fn my_func((..#v): (..#T)) -> (..#T) { + (..#(v + v)) + } } impl<(..#T)> Clone for (..#T) @@ -206,19 +216,26 @@ Note 3: The expression in an expansion form can be enclosed by parenthesis or br Examples: ```rust -fn my_func<(..#T)>((..#i): (..#T)) { - (..#{ println!("{}", i) }) +trait MyFunc<(..#T)> { + fn my_func((..#i): (..#T)) { + (..#{ println!("{}", i) }) + } } -fn clone_add<(..#T)>((..#i): (..#T)) -> (..#T) +trait CloneAdd<(..#T)> where ..#(T: Clone + Add) { - (..#(::clone(&i) + i)) + fn clone_add<(..#T)>((..#i): (..#T)) -> (..#T) { + (..#(::clone(&i) + i)) + } } -fn merge_into<(..#(L, R))>((..#l): (..#L), (..#r): (..#R)) -> (..#L, ..#L) +trait MergeInto<(..#(L, R))> where ..#(L: From) { - (..#l, ..#(R as Into>::into(r))) + fn merge_into<(..#(L, R))>((..#l): (..#L), (..#r): (..#R)) -> (..#L, ..#L) { + (..#l, ..#(R as Into>::into(r))) + } } + ``` ## The `Hash`trait @@ -259,14 +276,14 @@ A variadic tuple type identifier identifies a list of types. When declared togethers, each identifiers identifies a list of types. For instance: ```rust -fn my_func<(..#(L, R))>() { } -my_func::<((usize, bool), (i8, f32))>(); +struct MyStruct<(..#(L, R))> { ... } +MyStruct::<((usize, bool), (i8, f32))> { ... } // `(..#(L, R))` matches `((usize, bool), (i8, f32))` // `(..#L)` is `(usize, i8)` // `(..#R)` is `(bool, f32)` ``` -Note: Although this looks like a type-level pattern matching, it can match against only tuple of identifiers. So the following declaration is invalid: `fn my_func<(..#(L, Vec))>() { ... }` +Note: Although this looks like a type-level pattern matching, it can match against only tuple of identifiers. So the following declaration is invalid: `struct MyStruct<(..#(L, Vec))> { ... }` ### Variadic tuple type expansion @@ -277,7 +294,7 @@ Examples: ```rust type TupleOfVec<(..#T)> = (..#Vec); -fn my_func<(..#T)>() +struct MyStruct<(..#T)> where ..#(T: Clone) { ... } ``` @@ -286,7 +303,10 @@ where ..#(T: Clone) { ... } The declaration of a variadic tuple variable is still a variable. Nothing new here. ```rust -fn my_func<(..#T)>(input: (..#T)) { ... } +trait MyFunc<(..#T)> { + fn my_func(input: (..#T)) { ... } +} + ``` ### Variadic tuple destructuration @@ -316,11 +336,13 @@ When destructuring a variadic tuple it declares a variadic tuple identifiers tha The variadic tuple expansion are "expression template". By replacing the identifiers by its appropriate value, the variadic tuple expansion will result in a list of expressions. The full expression form will be replaced by the resolved list of expression. ```rust -fn my_function<(..#T)>((..#i): (..#T)) { - (..#i.clone()) - // `i.clone()` is the expression template parameterized by `i` - // it will resolve into a list of expressions: `i.0.clone(), i.1.clone(), ..., i.n.clone()` - // Finally, `..#i.clone()` will be replaced by the resolved list of expressions +trait MyFunction<(..#T)> { + fn my_function((..#i): (..#T)) { + (..#i.clone()) + // `i.clone()` is the expression template parameterized by `i` + // it will resolve into a list of expressions: `i.0.clone(), i.1.clone(), ..., i.n.clone()` + // Finally, `..#i.clone()` will be replaced by the resolved list of expressions + } } ``` @@ -373,18 +395,6 @@ The compiler will execute these steps: 6. Generation of `impl` of `Arity` for `(usize,)` completed 5. Generation of `impl` of `Arity` for `(bool, usize)` completed -### Recursion with functions - -```rust -fn recurse((head, ..#tail): (Head, ..#Tail)) -where Head: Debug, ..#(Tail: Debug) { - println!("{}", head); - recurse((..#tail)); -} -// Termination needs to be implemented explicitly -fn recurse<()>((): ()) { } -``` - ## Errors #### Missing implementation message during variadic implementation resolution @@ -477,6 +487,7 @@ note: required by `A::VALUE` ### Invalid variadic tuple type declaration The variadic tuple type declaration is invalid when it can't be parsed as either: + - `(..#T)` - `(..#(T1, T2, .., Tn))` @@ -555,6 +566,7 @@ hint: expected `(..#(K, V))` ### Invalid variadic tuple pattern matching The variadic tuple declaration is invalid when it can't be parsed as either: + - `(..#id)` - `(..#(ref id))` - `(..#(ref mut id))` @@ -567,7 +579,6 @@ struct MyStruct<(..#Vec)> { impl<(..#T)> MyTrait for (..#T) { fn my_func(&self) { let (..#(&i)) = &self; - } } ``` @@ -591,12 +602,16 @@ Variadic tuple expansion will generate code and may produce obscure errors for e If we consider this code: ```rust -fn make_mega_map<(..#(Key, Value))>() -> (..#HashMap) { - (..#HashMap::::new()) +trait MakeMegaMap<(..#(Key, Value))> { + fn make_mega_map() -> (..#HashMap) { + (..#HashMap::::new()) + } } +impl<(..#(Key, Value))> MakeMegaMap<(..#(Key, Value))> for () {} + fn main() { - let mega_map = make_mega_map::<(usize, bool), (f32, String)>(); + let mega_map = <() as MakeMegaMap<<(usize, bool), (f32, String)>>::make_mega_map(); } ``` @@ -604,8 +619,10 @@ Then the expansion form is valid, even though the `Value2` identifier is probabl In that case, the expansion will be resolved as: ```rust -fn make_mega_map<(usize, bool), (f32, String)>() -> (HashMap, HashMap) { - (HashMap::::new(), HashMap::::new()) +trait MakeMegaMap<((usize, bool), (f32, String))> { + fn make_mega_map() -> (HashMap, HashMap) { + (HashMap::::new(), HashMap::::new()) + } } ``` @@ -615,8 +632,8 @@ Leading to a compile error with additional notes error[E0412]: cannot find type `Value2` in this scope --> src/main.rs:10:22 | -10 | let mega_map = make_mega_map::<(usize, bool), (f32, String)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope +10 | let mega_map = <() as MakeMegaMap<<(usize, bool), (f32, String)>>::make_mega_map(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope note: when expanding with `(..#(Key, Value)) = ((usize, bool), (f32, String))` --> src/main.rs:2:4 | @@ -632,7 +649,7 @@ note: when expanding with `(..#(Key, Value)) = ((usize, bool), (f32, String))` [rationale-and-alternatives]: #rationale-and-alternatives -## Declaring and using multiple variadic tuple type with same aritiy +## Declaring and using multiple variadic tuple type with same arity In C++ multiple parameter packs can be expanded in a single expansion form as long as the packs have the same number of items, but there is no constraint concerning the declaration. @@ -655,9 +672,15 @@ C++11 sets a decent precedent with its variadic templates, which can be used to When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) -## Termination syntax for functions +# Future possibilities + +[future-possibilities]: #future-possibilities -The suggested termination syntax is too close to a duplicate function definition and this is not a behaviour that currently exists. (See this [RFC issue](https://github.com/rust-lang/rfcs/issues/1053)) +## Supporting variadic tuple for function generic parameter groups + +Supporting variadic tuple for function generic parameter groups requires to provide a specialized implementation for the recursion termination. + +For instance: ```rust fn recurse((head, ..#tail): (Head, ..#Tail)) @@ -669,43 +692,33 @@ where Head: Debug, ..#(Tail: Debug) { fn recurse<()>((): ()) { } ``` -So there can be several alternative to deal with this: - -1. Forbiding variadic tuple for functions. In that case to have a similar functionality, we can use a trait as a workaround. It is more verbose but uses a trait instead. (Also, this may be dealt with in an another PR) - - ```rust - trait MyFuncTrait { - fn my_func(input: (Head, ..#T)); - } - struct MyFunctTraitHelper; - impl MyFuncTrait for MyFuncTraitHelper { - fn my_func((h, ..#i): (Head, ..#T)) { - MyFunctTraitHelper::my_func((..#i)); - } - } - impl<()> MyFuncTrait<()> for MyFuncTraitHelper { - fn my_func((): ()) { } - } - ``` - -1. Using a specific syntax to declare a specialized implementation. - - ```rust - default fn recurse((head, ..#tail): (Head, ..#Tail)) - where Head: Debug, ..#(Tail: Debug) { - println!("{}", head); - recurse((..#tail)); - } - // Termination needs to be implemented explicitly - fn recurse<()>((): ()) { } - ``` +Currently, specialization or overlapping bounds are not permitted for functions. This is a quite big requirement so this feature won't be supported in this RFC. -# Future possibilities +However when such a feature will land in Rust, supporting variadic tuple for function generic parameter will be way easier. -[future-possibilities]: #future-possibilities +Note, see the RFC issues [290](https://github.com/rust-lang/rfcs/issues/290) and [1053](https://github.com/rust-lang/rfcs/issues/1053). + +## Better utilities to manipulate tuples + +If we consider tuples as a list of types we can perform more computation at compile time and provide more possibilities for zero cost abstractions. + +Such utilities can be: + +- `TupleContains`: implemented by tuples containing the type `T` in its members +- `UniqueTuple`: implemented by all tuple, an associated type is the based on the same tuple but with only unique types +- `SortedTuple`: implemented by all tuple, an associated type is the based on the same tuple but with only sorted types +- `Arity`: a trait implemented by all tuple providing the arity of the tuple with a `const` +- An equivalent to C++'s `std::get` + +Those are not directly related to this RFC, but those utilities will be a natural additional step to better support tuple. + +## Improve the error message for `E0275` + +Improve the error message for `E0275` by providing the sequence of evaluated elements to give more help to the user about what can create the overflow. + +- In the context of variadic tuple, this can be the sequence of variadic tuple implementation that are tried by the compiler. +- But, in the more generic case where two traits implementations requires each others, providing the dependency cycle can be really helpful. -- Improve the error message for `E0275` by providing the sequence of evaluated elements to give more help to the user about what can create the overflow. - - In the context of variadic tuple, this can be the sequence of variadic tuple implementation that are tried by the compiler. - - But, in the more generic case where two traits implementations requires each others, providing the dependency cycle can be really helpful. +## Supporting recursive variadic tuple -- Supporting recrusive variadic tuple (ie, declaration like: `(..#((..#T)))`) +Supporting recrusive variadic tuple (ie, declaration like: `(..#((..#T)))`) From b1fdfdf0030db45f9a6b0604bf0ab2a9b00a921a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Wed, 4 Sep 2019 09:03:57 +0200 Subject: [PATCH 22/51] Added display bounds where required --- text/0000-variadic-tuples.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 83d0d9e87af..8221ab56da6 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -216,7 +216,8 @@ Note 3: The expression in an expansion form can be enclosed by parenthesis or br Examples: ```rust -trait MyFunc<(..#T)> { +trait MyFunc<(..#T)> +where ..#(T: Display) { fn my_func((..#i): (..#T)) { (..#{ println!("{}", i) }) } @@ -684,7 +685,7 @@ For instance: ```rust fn recurse((head, ..#tail): (Head, ..#Tail)) -where Head: Debug, ..#(Tail: Debug) { +where Head: Display, ..#(Tail: Display) { println!("{}", head); recurse((..#tail)); } From ec574aaf8e305f8c3472371bddf72cc1329aa3a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Wed, 4 Sep 2019 22:12:58 +0200 Subject: [PATCH 23/51] Always define trait for all tuple and then specialize --- text/0000-variadic-tuples.md | 84 +++++++++++++++--------------------- 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 8221ab56da6..61607b00b1d 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -357,44 +357,21 @@ trait Arity { const VALUE: usize; } -impl Arity for (Head, ..#Tail) { - default const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; +// Default implementation for all tuples +impl<(..#T)> Arity for (..#T) { + default const VALUE: usize = 0; } -impl Arity for () { - const VALUE: usize = 0; + +// Specialized implementation for the recursion +impl Arity for (Head, ..#Tail) { + const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; } ``` Note: - The `impl Arity for (Head, ..#Tail)` is the recursive implementation. -- The `impl Arity for ()` is the termination of the recursive implementation. -- We use the specialization feature here with the `default` token to declare a specialise implementation that is the termination of the recursive implementation - -And when we compile the following code: - -```rust -fn main() { - println!("Arity of (bool, usize): {}", <(bool, usize) as Arity>::VALUE); -} -``` - -The compiler will execute these steps: - -1. Search `impl` of `Arity` for `(bool, usize)` -2. `impl` not found, Search variadic `impl` of `Arity` for `(bool, usize)` -3. Variadic impl found: `impl Arity for (Head, ..#Tail)` -4. Generate `impl` of `Arity` for `(bool, usize)` - 1. Requires `impl` of `Arity` for `(usize,)` - 2. Search `impl` of `Arity` for `(usize,)` - 3. `impl` not found, Search variadic `impl` of `Arity` for `(usize,)` - 4. Variadic impl found: `impl Arity for (Head, ..#Tail)` - 5. Generate `impl` of `Arity` for `(usize,)` - 1. Requires `impl` of `Arity` for `()` - 2. Search `impl` of `Arity` for `()` - 3. `impl` found - 6. Generation of `impl` of `Arity` for `(usize,)` completed -5. Generation of `impl` of `Arity` for `(bool, usize)` completed +- The `impl<(..#T)> Arity for (..#T)` is the default implementation and will act as the termination of the recursion. ## Errors @@ -422,30 +399,13 @@ This code must not compile as the termination implementation is missing. So we will have a `E0277`error: ```rust -error[E0277]: the trait bound `(): Arity` is not satisfied +error[E0277]: the trait bound `(bool, u8): Arity` is not satisfied --> src/main.rs:10:4 | 7 | let arity = <(usize, bool, u8) as Arity>::VALUE; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Arity` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Arity` is not implemented for `(bool, u8)` | = help: impl `Arity` for `(usize, bool, u8)` requires impl `Arity` for `(bool, u8)` - note: matched by variadic tuple impl of `Arity` - --> src/main.rs:5:1 - | -5 | impl Arity for (Head, ..#Tail) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: impl `Arity` for `(bool, u8)` requires impl `Arity` for `(u8,)`. - note: matched by variadic tuple impl of `Arity` - --> src/main.rs:5:1 - | -5 | impl Arity for (Head, ..#Tail) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: impl `Arity` for `(u8,)` requires impl `Arity` for `()`. - note: matched by variadic tuple impl of `Arity` - --> src/main.rs:5:1 - | -5 | impl Arity for (Head, ..#Tail) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` #### Variadic implementation cycle dependency error @@ -650,6 +610,30 @@ note: when expanding with `(..#(Key, Value)) = ((usize, bool), (f32, String))` [rationale-and-alternatives]: #rationale-and-alternatives +## Recursive implementations of trait with variadic tuple + +Recursive implementation is done by implementing the termination on all types and then the recursive implementation as a specialization. + +Doing this way, the Rust compiler is able to validate the generic parameters before monomorphization. + +```rust +trait Arity { + const VALUE: usize; +} + +// Default implementation for all tuples +impl<(..#T)> Arity for (..#T) { + default const VALUE: usize = 0; +} + +// Specialized implementation for the recursion +impl Arity for (Head, ..#Tail) { + // (..#Tail) does implement `Arity`, so + // <(..#Tail) as Arity> is valid. + const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; +} +``` + ## Declaring and using multiple variadic tuple type with same arity In C++ multiple parameter packs can be expanded in a single expansion form as long as the packs have the same number of items, but there is no constraint concerning the declaration. From 20084fe7528e400c13e59390389b28450e00f278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 9 Sep 2019 11:30:41 +0200 Subject: [PATCH 24/51] Removed '#' char from syntax for clarity --- text/0000-variadic-tuples.md | 286 +++++++++++++++++------------------ 1 file changed, 143 insertions(+), 143 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 61607b00b1d..1e6932637af 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -34,7 +34,7 @@ Let's call a _variadic tuple type_ a tuple type with an arbitrary arity and a _v The variadic tuple type occurs in two form: a declarative form and an expansion form. And the variadic tuple only occurs in expansion forms. -For a variadic tuple type, the declarative form is `(..#T)` and an example of an expansion form is `(..#Vec)`. +For a variadic tuple type, the declarative form is `(..T)` and an example of an expansion form is `(..Vec)`. Note: To illustrate the RFC, we will use the current implementation of the `Hash` trait for tuples. @@ -78,58 +78,58 @@ Note: variadic tuples are not supported in generic parameter group of `fn` There are two different syntaxes: -1. `(..#T)`: declare a single variadic tuple type identified by `T` -2. `(..#(T1, T2, ..., Tn))`: declare n variadic tuple types identified by `T1`, `T2`, ..., `Tn`, all these variadic tuple types have the same arity. +1. `(..T)`: declare a single variadic tuple type identified by `T` +2. `(..(T1, T2, ..., Tn))`: declare n variadic tuple types identified by `T1`, `T2`, ..., `Tn`, all these variadic tuple types have the same arity. Declaration examples: -- `struct VariadicStruct<(..#T1)>` : declares a struct with a variadic tuple type identified by `T1` in its generic parameters -- `impl<(..#Head)>`: is an implementation block that uses a variadic tuple type identified by `Head` -- `impl`: same as above, but with other generic parameters -- `impl`: there can be several variadic tuple types declared in a generic parameter group +- `struct VariadicStruct<(..T1)>` : declares a struct with a variadic tuple type identified by `T1` in its generic parameters +- `impl<(..Head)>`: is an implementation block that uses a variadic tuple type identified by `Head` +- `impl`: same as above, but with other generic parameters +- `impl`: there can be several variadic tuple types declared in a generic parameter group Usage examples: ```rust -struct VariadicStruct<(..#T)> -VariadicStruct<(usize,)> // => (..#T) matches (usize,) -VariadicStruct<(usize, bool)> // => (..#T) matches (usize, bool) +struct VariadicStruct<(..T)> +VariadicStruct<(usize,)> // => (..T) matches (usize,) +VariadicStruct<(usize, bool)> // => (..T) matches (usize, bool) -impl <(..#(T1, T2))> VariadicStruct<(..#(T1, T2)) { ... } +impl <(..(T1, T2))> VariadicStruct<(..(T1, T2)) { ... } VariadicStruct::<((usize, bool),) -// (..#(T1, T2)) matches ((usize, bool),) -// (..#T1) is (usize,) -// (..#T2) is (bool,) -VariadicStruct::<((usize, bool), (String, i8)) // (..#(T1, T2)) matches ((usize, bool), (String, i8)) -// (..#T1) is (usize, String) -// (..#T2) is (bool, i8) +// (..(T1, T2)) matches ((usize, bool),) +// (..T1) is (usize,) +// (..T2) is (bool,) +VariadicStruct::<((usize, bool), (String, i8)) // (..(T1, T2)) matches ((usize, bool), (String, i8)) +// (..T1) is (usize, String) +// (..T2) is (bool, i8) ``` ### Expansion -The expansion syntax is: `..#` where `` is an expression using the variadic tuple type identifiers `T1`, `T2`, ..., `Tn`. +The expansion syntax is: `..` where `` is an expression using the variadic tuple type identifiers `T1`, `T2`, ..., `Tn`. -Note: The expression in an expansion form can be enclosed by parenthesis for clarity. Ex: `..#(T: Clone)`. +Note: The expression in an expansion form can be enclosed by parenthesis for clarity. Ex: `..(T: Clone)`. The expansion form is allowed in all places where a type is allowed and in `where` bounds. Examples: ```rust -type TuplesOfRef<'a, (..#T)> = (..#&'a T); +type TuplesOfRef<'a, (..T)> = (..&'a T); TuplesOfRef<'b, (usize, bool)>; // = (&'b usize, &'b bool) -struct MegaMap<(..#(K, V))> { - maps: (..#HashMap), +struct MegaMap<(..(K, V))> { + maps: (..HashMap), } // // struct MegaMap<((usize, bool), (String, i8))> { // maps: (HashMap, HashMap), // } -trait Append<(..#L), (..#R)> -where ..#(L: 'static + Clone), ..#(R: 'static + Clone) { - fn append(l: (..#L), r: (..#R)) -> (..#L, ..#R) +trait Append<(..L), (..R)> +where ..(L: 'static + Clone), ..(R: 'static + Clone) { + fn append(l: (..L), r: (..R)) -> (..L, ..R) } // @@ -143,7 +143,7 @@ where ..#(L: 'static + Clone), ..#(R: 'static + Clone) { Note: If an expansion syntax does not contains any variadic tuple type identifier, it resolves to the unit type `( )`. -Note2: If an expansion syntax contains multiple variadic tuple type identifiers, they must all have been declared together with the syntax `( ..#(T1, T2, ..., Tn))` to ensure they have the same arity. +Note2: If an expansion syntax contains multiple variadic tuple type identifiers, they must all have been declared together with the syntax `( ..(T1, T2, ..., Tn))` to ensure they have the same arity. ## Variadic tuple @@ -154,8 +154,8 @@ A _variadic tuple_ is a variable of a variadic tuple type. A variadic tuple can be declared like any other variable: ```rust -trait MyFunc<(..#T)> { - fn my_func(variadic_tuple: (..#T)) { ... } +trait MyFunc<(..T)> { + fn my_func(variadic_tuple: (..T)) { ... } } ``` @@ -163,22 +163,22 @@ trait MyFunc<(..#T)> { The main way to use a variadic tuple is by destructuring it to access its members. -There are 3 syntaxes possible to destructure a variadic tuple for a variadic tuple `(..#T)`: +There are 3 syntaxes possible to destructure a variadic tuple for a variadic tuple `(..T)`: -1. `(..#v)` of variadic tuple type `(..#T)` -2. `(..#(ref v))` of variadic tuple type `(..#&T)` -3. `(..#(ref mut v))` of variadic tuple type `(..#&mut T)` +1. `(..v)` of variadic tuple type `(..T)` +2. `(..(ref v))` of variadic tuple type `(..&T)` +3. `(..(ref mut v))` of variadic tuple type `(..&mut T)` Also, the destructure pattern can be combined with other members. For instance: ```rust { - let source: (Head, ..#Tail) = _; - let (ref head, ..#(ref tail)) = &source; + let source: (Head, ..Tail) = _; + let (ref head, ..(ref tail)) = &source; } { - let mut source: (..#L, ..#R) = _; - let (..#(ref mut l), ..#(ref mut r)) = &mut source; + let mut source: (..L, ..R) = _; + let (..(ref mut l), ..(ref mut r)) = &mut source; } ``` @@ -187,25 +187,25 @@ Examples: ```rust // The function argument is destructured as a variadic tuple with identifier `v` -trait MyFunc<(..#T)> { - fn my_func((..#v): (..#T)) -> (..#T) { - (..#(v + v)) +trait MyFunc<(..T)> { + fn my_func((..v): (..T)) -> (..T) { + (..(v + v)) } } -impl<(..#T)> Clone for (..#T) -where ..#(T: Clone) { +impl<(..T)> Clone for (..T) +where ..(T: Clone) { fn clone(&self) -> Self { - // We destructure `*self` which has a variadic tuple type `(..#T)` - let (..#(ref v)) = *self; - (..#v.clone()) + // We destructure `*self` which has a variadic tuple type `(..T)` + let (..(ref v)) = *self; + (..v.clone()) } } ``` ### Expansion -An expansion form for variadic tuple has the syntax: `..#` where `T1`, `T2`, ..., `Tn` are variadic tuple type identifiers and `id1`, `id2`, ..., `idn` are variadic tuple identifiers. +An expansion form for variadic tuple has the syntax: `..` where `T1`, `T2`, ..., `Tn` are variadic tuple type identifiers and `id1`, `id2`, ..., `idn` are variadic tuple identifiers. Note 1: All variadic tuple type used in the expansion form must have been declared together. The variadic tuple type used are the variadic tuple types identified by `T1`, `T2`, ..., `Tn` or the type of the variadic tuple identified by `id1`, `id2`, ..., `idn`. @@ -217,23 +217,23 @@ Examples: ```rust trait MyFunc<(..#T)> -where ..#(T: Display) { - fn my_func((..#i): (..#T)) { - (..#{ println!("{}", i) }) +where ..(T: Display) { + fn my_func((..i): (..T)) { + (..{ println!("{}", i) }) } } -trait CloneAdd<(..#T)> -where ..#(T: Clone + Add) { - fn clone_add<(..#T)>((..#i): (..#T)) -> (..#T) { - (..#(::clone(&i) + i)) +trait CloneAdd<(..T)> +where ..(T: Clone + Add) { + fn clone_add<(..T)>((..i): (..T)) -> (..T) { + (..(::clone(&i) + i)) } } -trait MergeInto<(..#(L, R))> -where ..#(L: From) { - fn merge_into<(..#(L, R))>((..#l): (..#L), (..#r): (..#R)) -> (..#L, ..#L) { - (..#l, ..#(R as Into>::into(r))) +trait MergeInto<(..(L, R))> +where ..(L: From) { + fn merge_into<(..(L, R))>((..l): (..L), (..r): (..R)) -> (..L, ..L) { + (..l, ..(R as Into>::into(r))) } } @@ -244,22 +244,22 @@ where ..#(L: From) { Let's implement the `Hash` trait: ```rust -// For the example, we consider the impl for (A, B, C). So `(..#T)` matches `(A, B, C)` -// We have the first expansion here, `(..#T, Last)` expands to `(A, B, C, Last)` -impl<(..#T), Last> Hash for (..#T, Last) +// For the example, we consider the impl for (A, B, C). So `(..T)` matches `(A, B, C)` +// We have the first expansion here, `(..T, Last)` expands to `(A, B, C, Last)` +impl<(..T), Last> Hash for (..T, Last) where // Expands to `A: Hash, B: Hash, C: Hash,` - ..#(T: Hash,), + ..(T: Hash,), Last: Hash + ?Sized, { #[allow(non_snake_case)] fn hash(&self, state: &mut S) { - // Destructure self to a variadic tuple `v` and a variable `last`. The variadic tuple type of `v` is `(..#&T)` + // Destructure self to a variadic tuple `v` and a variable `last`. The variadic tuple type of `v` is `(..&T)` // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let v = (a, b, c);` - let (..#(ref v), ref last) = *self; + let (..(ref v), ref last) = *self; // Expands to `(v.0.hash(state), v.1.hash(state), v.2.hash(state), last.hash(state));` - (..#v.hash(state), last.hash(state)); + (..v.hash(state), last.hash(state)); } } ``` @@ -277,14 +277,14 @@ A variadic tuple type identifier identifies a list of types. When declared togethers, each identifiers identifies a list of types. For instance: ```rust -struct MyStruct<(..#(L, R))> { ... } +struct MyStruct<(..(L, R))> { ... } MyStruct::<((usize, bool), (i8, f32))> { ... } -// `(..#(L, R))` matches `((usize, bool), (i8, f32))` -// `(..#L)` is `(usize, i8)` -// `(..#R)` is `(bool, f32)` +// `(..(L, R))` matches `((usize, bool), (i8, f32))` +// `(..L)` is `(usize, i8)` +// `(..R)` is `(bool, f32)` ``` -Note: Although this looks like a type-level pattern matching, it can match against only tuple of identifiers. So the following declaration is invalid: `struct MyStruct<(..#(L, Vec))> { ... }` +Note: Although this looks like a type-level pattern matching, it can match against only tuple of identifiers. So the following declaration is invalid: `struct MyStruct<(..(L, Vec))> { ... }` ### Variadic tuple type expansion @@ -293,10 +293,10 @@ On location where a type is expected, the expansion will resolve to a type. On w Examples: ```rust -type TupleOfVec<(..#T)> = (..#Vec); +type TupleOfVec<(..T)> = (..Vec); -struct MyStruct<(..#T)> -where ..#(T: Clone) { ... } +struct MyStruct<(..T)> +where ..(T: Clone) { ... } ``` ### Variadic tuple declaration @@ -304,29 +304,29 @@ where ..#(T: Clone) { ... } The declaration of a variadic tuple variable is still a variable. Nothing new here. ```rust -trait MyFunc<(..#T)> { - fn my_func(input: (..#T)) { ... } +trait MyFunc<(..T)> { + fn my_func(input: (..T)) { ... } } ``` ### Variadic tuple destructuration -When destructuring a variadic tuple it declares a variadic tuple identifiers that can be used in expansion forms. The identifier is a variable of type `(..#T)` or `(..#&T)` or `(..#&mut T)`, depending on the syntax used. +When destructuring a variadic tuple it declares a variadic tuple identifiers that can be used in expansion forms. The identifier is a variable of type `(..T)` or `(..&T)` or `(..&mut T)`, depending on the syntax used. ```rust { - let source: (..#T, Tail) = _; - let (..#v, tail) = source; + let source: (..T, Tail) = _; + let (..v, tail) = source; // v is a variable of type `(..#T)` - let (..#(ref v), ref tail) = &source; + let (..(ref v), ref tail) = &source; // v is a variable of type `(..#&T)` - let (..#(ref mut v), ref mut tail) = &mut source; + let (..(ref mut v), ref mut tail) = &mut source; // v is a variable of type `(..#&mut T)` } -// If we use `(..#T)` = `(A, B, C)` as an example -// Then `let (..#(ref v), ref tail) = &source` +// If we use `(..T)` = `(A, B, C)` as an example +// Then `let (..(ref v), ref tail) = &source` // is equivalent to: // `let (ref a, ref b, ref c, ref tail) = &source;` // `let v = (a, b, c);` @@ -337,12 +337,12 @@ When destructuring a variadic tuple it declares a variadic tuple identifiers tha The variadic tuple expansion are "expression template". By replacing the identifiers by its appropriate value, the variadic tuple expansion will result in a list of expressions. The full expression form will be replaced by the resolved list of expression. ```rust -trait MyFunction<(..#T)> { - fn my_function((..#i): (..#T)) { - (..#i.clone()) +trait MyFunction<(..T)> { + fn my_function((..i): (..T)) { + (..i.clone()) // `i.clone()` is the expression template parameterized by `i` // it will resolve into a list of expressions: `i.0.clone(), i.1.clone(), ..., i.n.clone()` - // Finally, `..#i.clone()` will be replaced by the resolved list of expressions + // Finally, `..i.clone()` will be replaced by the resolved list of expressions } } ``` @@ -358,20 +358,20 @@ trait Arity { } // Default implementation for all tuples -impl<(..#T)> Arity for (..#T) { +impl<(..T)> Arity for (..T) { default const VALUE: usize = 0; } // Specialized implementation for the recursion -impl Arity for (Head, ..#Tail) { - const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; +impl Arity for (Head, ..Tail) { + const VALUE: usize = <(..Tail) as Arity>::VALUE + 1; } ``` Note: -- The `impl Arity for (Head, ..#Tail)` is the recursive implementation. -- The `impl<(..#T)> Arity for (..#T)` is the default implementation and will act as the termination of the recursion. +- The `impl Arity for (Head, ..Tail)` is the recursive implementation. +- The `impl<(..T)> Arity for (..T)` is the default implementation and will act as the termination of the recursion. ## Errors @@ -386,8 +386,8 @@ trait Arity { const VALUE: usize; } -impl Arity for (Head, ..#Tail) { - const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; +impl Arity for (Head, ..Tail) { + const VALUE: usize = <(..Tail) as Arity>::VALUE + 1; } fn main() { @@ -416,11 +416,11 @@ As a variadic tuple implementation may depend on other variadic tuple implementa trait A { const VALUE: usize = 1; } trait B { const VALUE: usize = 2; } -impl A for (Head, ..#T) -where (..#T): B { const VALUE: usize = 3; } +impl A for (Head, ..T) +where (..T): B { const VALUE: usize = 3; } -impl B for (Head, ..#T) -where (..#T): A { const VALUE: usize = 4; } +impl B for (Head, ..T) +where (..T): A { const VALUE: usize = 4; } fn main() { let v = <(usize, bool) as A>::VALUE; @@ -449,20 +449,20 @@ note: required by `A::VALUE` The variadic tuple type declaration is invalid when it can't be parsed as either: -- `(..#T)` -- `(..#(T1, T2, .., Tn))` +- `(..T)` +- `(..(T1, T2, .., Tn))` ```rust -struct MyStruct<(..#Vec)> { - vecs: (..#Vec) +struct MyStruct<(..Vec)> { + vecs: (..Vec) } ``` ```rust -error[EXXXX]: invalid variadic tuple type declaration `(..#Vec)` +error[EXXXX]: invalid variadic tuple type declaration `(..Vec)` --> src/main.rs:1:13 | -10 | struct MyStruct<(..#Vec)> { +10 | struct MyStruct<(..Vec)> { | ^^^^^^^^^^^ | note: expected either an identifier or a tuple of identifier instead of `Vec` @@ -473,25 +473,25 @@ note: expected either an identifier or a tuple of identifier instead of `Vec` Occurs when multiple independent variadic tuple type identifier are used in a single expansion form. ```rust -impl<(..#K), (..#V)> MyTrait for (..#HashMap) { +impl<(..K), (..V)> MyTrait for (..HashMap) { } ``` ```rust -error[EXXXX]: invalid variadic tuple type expansion `(..#HashMap)` +error[EXXXX]: invalid variadic tuple type expansion `(..HashMap)` --> src/main.rs:4:13 | -10 | impl<(..#K), (..#V)> MyTrait for (..#HashMap) { - | ^^^^^^^^^^^^^^^^^^ +10 | impl<(..#K), (..#V)> MyTrait for (..HashMap) { + | ^^^^^^^^^^^^^^^^^ | note: variadic tuple type identifiers `K`, `V` were not declared together --> src/main.rs:4:13 | -10 | impl<(..#K), (..#V)> MyTrait for (..#HashMap) { - | ^^^^^^^^^^^^^^ +10 | impl<(..K), (..V)> MyTrait for (..HashMap) { + | ^^^^^^^^^^^^ | -hint: expected `(..#(K, V))` +hint: expected `(..(K, V))` ``` ### Invalid variadic tuple expansion identifiers @@ -499,59 +499,59 @@ hint: expected `(..#(K, V))` Occurs when multiple independent variadic tuple identifier are used in a single expansion form. ```rust -impl<(..#K), (..#V)> MyTrait for MyStruct { +impl<(..K), (..V)> MyTrait for MyStruct { fn my_function() { - let k: (..#K) = _; - let v: (..#V) = _; - let k_v = (..#(k, v)); + let k: (..K) = _; + let v: (..V) = _; + let k_v = (..(k, v)); } } ``` ```rust -error[EXXXX]: invalid variadic tuple expansion `(..#(k, v))` +error[EXXXX]: invalid variadic tuple expansion `(..(k, v))` --> src/main.rs:4:13 | -10 | let k_v = (..#(k, v)); - | ^^^^^^^^^^^ +10 | let k_v = (..(k, v)); + | ^^^^^^^^^^ | note: variadic tuple identifiers `k`, `v` with variadic tuple type identifiers `K`, `V` were not declared together --> src/main.rs:4:13 | -10 | impl<(..#K), (..#V)> MyTrait for MyStruct { - | ^^^^^^^^^^^^^^ +10 | impl<(..K), (..V)> MyTrait for MyStruct { + | ^^^^^^^^^^^^ | -hint: expected `(..#(K, V))` +hint: expected `(..(K, V))` ``` ### Invalid variadic tuple pattern matching The variadic tuple declaration is invalid when it can't be parsed as either: -- `(..#id)` -- `(..#(ref id))` -- `(..#(ref mut id))` +- `(..id)` +- `(..(ref id))` +- `(..(ref mut id))` ```rust -struct MyStruct<(..#Vec)> { - vecs: (..#Vec) +struct MyStruct<(..Vec)> { + vecs: (..Vec) } -impl<(..#T)> MyTrait for (..#T) { +impl<(..T)> MyTrait for (..#T) { fn my_func(&self) { - let (..#(&i)) = &self; + let (..(&i)) = &self; } } ``` ```rust -error[EXXXX]: invalid variadic tuple pattern `(..#(&i))` +error[EXXXX]: invalid variadic tuple pattern `(..(&i))` --> src/main.rs:4:13 | -10 | let (..#(&i)) = &self; - | ^^^^^^^^^ +10 | let (..(&i)) = &self; + | ^^^^^^^^ | -note: expected `(..#id)` or `(..#(ref id))` or `(..#(ref mut id))` +note: expected `(..id)` or `(..(ref id))` or `(..(ref mut id))` ``` ## Help and note for existing errors @@ -563,13 +563,13 @@ Variadic tuple expansion will generate code and may produce obscure errors for e If we consider this code: ```rust -trait MakeMegaMap<(..#(Key, Value))> { - fn make_mega_map() -> (..#HashMap) { - (..#HashMap::::new()) +trait MakeMegaMap<(..(Key, Value))> { + fn make_mega_map() -> (..HashMap) { + (..HashMap::::new()) } } -impl<(..#(Key, Value))> MakeMegaMap<(..#(Key, Value))> for () {} +impl<(..(Key, Value))> MakeMegaMap<(..(Key, Value))> for () {} fn main() { let mega_map = <() as MakeMegaMap<<(usize, bool), (f32, String)>>::make_mega_map(); @@ -595,10 +595,10 @@ error[E0412]: cannot find type `Value2` in this scope | 10 | let mega_map = <() as MakeMegaMap<<(usize, bool), (f32, String)>>::make_mega_map(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope -note: when expanding with `(..#(Key, Value)) = ((usize, bool), (f32, String))` +note: when expanding with `(..(Key, Value)) = ((usize, bool), (f32, String))` --> src/main.rs:2:4 | -2 | (..#HashMap::::new()) +2 | (..HashMap::::new()) | ``` @@ -622,15 +622,15 @@ trait Arity { } // Default implementation for all tuples -impl<(..#T)> Arity for (..#T) { +impl<(..T)> Arity for (..T) { default const VALUE: usize = 0; } // Specialized implementation for the recursion -impl Arity for (Head, ..#Tail) { +impl Arity for (Head, ..Tail) { // (..#Tail) does implement `Arity`, so // <(..#Tail) as Arity> is valid. - const VALUE: usize = <(..#Tail) as Arity>::VALUE + 1; + const VALUE: usize = <(..Tail) as Arity>::VALUE + 1; } ``` @@ -638,7 +638,7 @@ impl Arity for (Head, ..#Tail) { In C++ multiple parameter packs can be expanded in a single expansion form as long as the packs have the same number of items, but there is no constraint concerning the declaration. -For Rust, using the syntax `(..#(T1, T2, ..., Tn))` embeds the constraint that the variadic tuple types `T1`, `T2`, ..., `Tn` have the same arity. This is more consistent than not grouping the declaration (ie: `(..#T1), (..#T2), ..., (..#Tn))`) because the signature using the declaration contains all the information required. +For Rust, using the syntax `(..(T1, T2, ..., Tn))` embeds the constraint that the variadic tuple types `T1`, `T2`, ..., `Tn` have the same arity. This is more consistent than not grouping the declaration (ie: `(..T1), (..#T2), ..., (..Tn))`) because the signature using the declaration contains all the information required. We don't need to look at the implementation or body code to know the required constraint about the variadic tuple type arities. @@ -668,10 +668,10 @@ Supporting variadic tuple for function generic parameter groups requires to prov For instance: ```rust -fn recurse((head, ..#tail): (Head, ..#Tail)) -where Head: Display, ..#(Tail: Display) { +fn recurse((head, ..tail): (Head, ..Tail)) +where Head: Display, ..(Tail: Display) { println!("{}", head); - recurse((..#tail)); + recurse((..tail)); } // Termination needs to be implemented explicitly fn recurse<()>((): ()) { } @@ -706,4 +706,4 @@ Improve the error message for `E0275` by providing the sequence of evaluated ele ## Supporting recursive variadic tuple -Supporting recrusive variadic tuple (ie, declaration like: `(..#((..#T)))`) +Supporting recrusive variadic tuple (ie, declaration like: `(..((..T)))`) From aa9d8b16713820d7fd781ea5b6fdf952839bff4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 9 Sep 2019 12:15:06 +0200 Subject: [PATCH 25/51] Updated variadic tuple iteration --- text/0000-variadic-tuples.md | 232 ++++++++++++++++++++++------------- 1 file changed, 146 insertions(+), 86 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 1e6932637af..70da0946b3a 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -32,9 +32,7 @@ Variadic tuple will provide several benefits considering trait implementation fo Let's call a _variadic tuple type_ a tuple type with an arbitrary arity and a _variadic tuple_ an instance of a variadic tuple type. -The variadic tuple type occurs in two form: a declarative form and an expansion form. And the variadic tuple only occurs in expansion forms. - -For a variadic tuple type, the declarative form is `(..T)` and an example of an expansion form is `(..Vec)`. +A variadic tuple type is declared with`(..T)` and a variadic tuple type can be expanded with `(..Vec)`. Note: To illustrate the RFC, we will use the current implementation of the `Hash` trait for tuples. @@ -74,7 +72,7 @@ macro_rules! last_type { Variadic tuple types are always declared in a generic parameter group. -Note: variadic tuples are not supported in generic parameter group of `fn` +*Note: variadic tuples are not supported in generic parameter group of `fn`* There are two different syntaxes: @@ -189,7 +187,7 @@ Examples: // The function argument is destructured as a variadic tuple with identifier `v` trait MyFunc<(..T)> { fn my_func((..v): (..T)) -> (..T) { - (..(v + v)) + ... } } @@ -198,42 +196,73 @@ where ..(T: Clone) { fn clone(&self) -> Self { // We destructure `*self` which has a variadic tuple type `(..T)` let (..(ref v)) = *self; - (..v.clone()) + ... } } ``` -### Expansion +### Iterating over variadic tuple -An expansion form for variadic tuple has the syntax: `..` where `T1`, `T2`, ..., `Tn` are variadic tuple type identifiers and `id1`, `id2`, ..., `idn` are variadic tuple identifiers. +We can iterate over the member of a variadic tuple or over the type of a variadic tuple type. -Note 1: All variadic tuple type used in the expansion form must have been declared together. The variadic tuple type used are the variadic tuple types identified by `T1`, `T2`, ..., `Tn` or the type of the variadic tuple identified by `id1`, `id2`, ..., `idn`. +*Important note: the iteration is inlined by the compiler, it is not a generic runtime heterogenous iteration of tuple members.* -Note 2: An expansion form without any identifier resolves to the unit type `()`. +We use the following syntax to iterate on variadic tuples: -Note 3: The expression in an expansion form can be enclosed by parenthesis or braces for clarity. +```rust +// The result of the for block is a variadic tuple made of +// the result of each iteration +let result: (..Option<&V>) = { + // `key` and `map` are variables iterating the variadic tuples `(..k): (..K)` and `(..maps): (..&HashMap)`, `key` will iterate by reference (because of the ref keyword) + // `KEY` and `VALUE` are type variables iterating the variadic tuple types `(..K)` and `(..V)` + // `..(k, maps)` declares the iterated variadic tuples `(..k)` and `(..maps)` + // `..(K, V)` declares the iterated variadic tuple types + for (ref key, map) type (KEY, VALUE) in ..(k, maps) type ..(K, V) { + HashMap::::get(&map, key) + } +}; +``` + +Note: when iterating over multiple variadic tuple or variadic tuple types, they must have all the same arity. To ensure this, all variadic tuple types involved must have been declared together. Examples: ```rust -trait MyFunc<(..#T)> -where ..(T: Display) { - fn my_func((..i): (..T)) { - (..{ println!("{}", i) }) - } -} +impl<(..(K, V))> MegaMap<(..(K, V))> +where ..(K: Hash), { + fn get(&self, (..k): (..K)) -> (..Option) { + let (..ref maps) = &self.maps; + + let result: (..Option<&V>) = { + for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { + HashMap::::get(&map, k) + } + }; -trait CloneAdd<(..T)> -where ..(T: Clone + Add) { - fn clone_add<(..T)>((..i): (..T)) -> (..T) { - (..(::clone(&i) + i)) + result } } -trait MergeInto<(..(L, R))> -where ..(L: From) { - fn merge_into<(..(L, R))>((..l): (..L), (..r): (..R)) -> (..L, ..L) { - (..l, ..(R as Into>::into(r))) +impl<(..T), Last> Hash for (..T, Last) +where + ..(T: Hash), + Last: Hash + ?Sized, { + + #[allow(non_snake_case)] + fn hash(&self, state: &mut S) { + let (..ref tuple, ref last) = *self; + + // Use case: only variadic tuple + for member in ..(tuple,) { + member.hash(state); + } + last.hash(state); + + // Use case: variadic tuple and type + for member type (H,) in ..(tuple,) type ..(T,) { + ::hash(&member, state); + } + last.hash(state); } } @@ -254,12 +283,17 @@ where #[allow(non_snake_case)] fn hash(&self, state: &mut S) { - // Destructure self to a variadic tuple `v` and a variable `last`. The variadic tuple type of `v` is `(..&T)` - // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let v = (a, b, c);` - let (..(ref v), ref last) = *self; - - // Expands to `(v.0.hash(state), v.1.hash(state), v.2.hash(state), last.hash(state));` - (..v.hash(state), last.hash(state)); + // Destructure self to a variadic tuple `tuple` and a variable `last`. The variadic tuple type of `tuple` is `(..&T)` + // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let tuple = (a, b, c);` + let (..ref tuple, ref last) = *self; + for member in ..(tuple,) { + member.hash(state); + } + // The for loop will be inlined as: + // v.0.hash(state); + // v.1.hash(state); + // v.2.hash(state); + last.hash(state); } } ``` @@ -318,11 +352,11 @@ When destructuring a variadic tuple it declares a variadic tuple identifiers tha { let source: (..T, Tail) = _; let (..v, tail) = source; - // v is a variable of type `(..#T)` + // v is a variable of type `(..T)` let (..(ref v), ref tail) = &source; - // v is a variable of type `(..#&T)` + // v is a variable of type `(..&T)` let (..(ref mut v), ref mut tail) = &mut source; - // v is a variable of type `(..#&mut T)` + // v is a variable of type `(..&mut T)` } // If we use `(..T)` = `(A, B, C)` as an example @@ -332,21 +366,69 @@ When destructuring a variadic tuple it declares a variadic tuple identifiers tha // `let v = (a, b, c);` ``` -### Variadic tuple expansion +### Variadic tuple iteration + +The syntax for the variadic tuple iteration is: + +```rust +for $var_id type $type_var_id in $variadic_tuples type $variadic_tuple_types { + $body +} +``` + +`$var_id` is a pattern matching the tuple to iterate, it follows the same rules as the variadic tuple destructuration, only 3 syntaxes are allowed for an identifier: `id`, `ref id` or `ref mut id`. (like: `(key value)`, `(ref key, value)`, `(ref mut key, value)`) + +`$type_var_id` is a pattern matching the variadic tuple types to iterate, but it has only the first syntax allowed. (No ref, or mut). -The variadic tuple expansion are "expression template". By replacing the identifiers by its appropriate value, the variadic tuple expansion will result in a list of expressions. The full expression form will be replaced by the resolved list of expression. +`$variadic_tuples` declares the iterated variadic tuples, it has the syntax `..id` or `..(id1, id2, ..., idn)`. + +`$variadic_tuple_types` declares the iterated variadic tuple types, it has the syntax `..ID` or `..(ID1, ID2, ..., IDn)`. + +Example: ```rust -trait MyFunction<(..T)> { - fn my_function((..i): (..T)) { - (..i.clone()) - // `i.clone()` is the expression template parameterized by `i` - // it will resolve into a list of expressions: `i.0.clone(), i.1.clone(), ..., i.n.clone()` - // Finally, `..i.clone()` will be replaced by the resolved list of expressions +impl<(..(K, V))> MegaMap<(..(K, V))> +where ..(K: Hash), { + fn get(&self, (..k): (..K)) -> (..Option) { + let (..ref maps) = &self.maps; + + let result: (..Option<&V>) = { + for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { + HashMap::::get(&map, k) + } + }; + + // for the compiler, the for block has a kind of + // `[[(variadic_tuple, variadic_tuple_type)], [variadic_tuple_type]] -> (variadic_tuple, variadic_tuple_type)` + // + // But, we can decompose in two separate steps: + // `{ HashMap::::get(&map, k) }` is a generic fn: + // ```rust + // fn block_body(k: &K, map: &HashMap) -> Option<&V> + // where K: Hash { // Inherit bounds from context (here: the trait) + // HashMap::::get(&map, k) + // } + // ``` + // + // Then the for loop is an inlined for loop calling the + // `block_body` + // + // ```rust + // ( + // block_body::(&k.0, maps.0), + // block_body::(&k.1, maps.1), + // ... + // block_body::(&k.n, maps.n), + // ) + // ``` + + result } } ``` + + ## Recursion To implement some feature, we may want to use recursion over the arity of the tuple. @@ -494,36 +576,6 @@ note: variadic tuple type identifiers `K`, `V` were not declared together hint: expected `(..(K, V))` ``` -### Invalid variadic tuple expansion identifiers - -Occurs when multiple independent variadic tuple identifier are used in a single expansion form. - -```rust -impl<(..K), (..V)> MyTrait for MyStruct { - fn my_function() { - let k: (..K) = _; - let v: (..V) = _; - let k_v = (..(k, v)); - } -} -``` - -```rust -error[EXXXX]: invalid variadic tuple expansion `(..(k, v))` - --> src/main.rs:4:13 - | -10 | let k_v = (..(k, v)); - | ^^^^^^^^^^ - | -note: variadic tuple identifiers `k`, `v` with variadic tuple type identifiers `K`, `V` were not declared together - --> src/main.rs:4:13 - | -10 | impl<(..K), (..V)> MyTrait for MyStruct { - | ^^^^^^^^^^^^ - | -hint: expected `(..(K, V))` -``` - ### Invalid variadic tuple pattern matching The variadic tuple declaration is invalid when it can't be parsed as either: @@ -565,7 +617,9 @@ If we consider this code: ```rust trait MakeMegaMap<(..(Key, Value))> { fn make_mega_map() -> (..HashMap) { - (..HashMap::::new()) + for () type (KEY, VALUE) in () type ..(Key, Value2) { + HashMap::::new() + } } } @@ -577,16 +631,6 @@ fn main() { ``` Then the expansion form is valid, even though the `Value2` identifier is probably mistyped. -In that case, the expansion will be resolved as: - -```rust -trait MakeMegaMap<((usize, bool), (f32, String))> { - fn make_mega_map() -> (HashMap, HashMap) { - (HashMap::::new(), HashMap::::new()) - } -} -``` - Leading to a compile error with additional notes ```rust @@ -597,9 +641,9 @@ error[E0412]: cannot find type `Value2` in this scope | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope note: when expanding with `(..(Key, Value)) = ((usize, bool), (f32, String))` --> src/main.rs:2:4 - | -2 | (..HashMap::::new()) - | + | for () type (KEY, VALUE) in () type ..(Key, Value2) { +2 | HashMap::::new() ^^^^^^^ + | } ``` # Drawbacks @@ -634,6 +678,22 @@ impl Arity for (Head, ..Tail) { } ``` +## Iteration over variadic tuples syntax + +When iterating over variadic tuples, we need to define both variable and type variable. To do so, we use the for loop syntax and separate variables and type variables with the `type` keyword. + +This keyword is already reserved and has no meaning inside a for loop, so it can be used here. + +```rust +let result: (..Option<&V>) = { + for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { + HashMap::::get(&map, k) + } +}; +``` + + + ## Declaring and using multiple variadic tuple type with same arity In C++ multiple parameter packs can be expanded in a single expansion form as long as the packs have the same number of items, but there is no constraint concerning the declaration. From 5a103ef268ad1d2c2d7ad76fa148106c7fe2a3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 9 Sep 2019 16:07:10 +0200 Subject: [PATCH 26/51] Fixed missing brackets --- text/0000-variadic-tuples.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 70da0946b3a..05353486f57 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -93,12 +93,12 @@ struct VariadicStruct<(..T)> VariadicStruct<(usize,)> // => (..T) matches (usize,) VariadicStruct<(usize, bool)> // => (..T) matches (usize, bool) -impl <(..(T1, T2))> VariadicStruct<(..(T1, T2)) { ... } -VariadicStruct::<((usize, bool),) +impl <(..(T1, T2))> VariadicStruct<(..(T1, T2))> { ... } +VariadicStruct::<((usize, bool),)> // (..(T1, T2)) matches ((usize, bool),) // (..T1) is (usize,) // (..T2) is (bool,) -VariadicStruct::<((usize, bool), (String, i8)) // (..(T1, T2)) matches ((usize, bool), (String, i8)) +VariadicStruct::<((usize, bool), (String, i8))> // (..(T1, T2)) matches ((usize, bool), (String, i8)) // (..T1) is (usize, String) // (..T2) is (bool, i8) ``` From 7f5aedb2adf03f062b29fb4fd7031df6b8d34999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Tue, 10 Sep 2019 21:44:28 +0200 Subject: [PATCH 27/51] Updated syntax to allow tuple merge --- text/0000-variadic-tuples.md | 68 +++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 05353486f57..2abf3e1bc74 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -90,8 +90,8 @@ Usage examples: ```rust struct VariadicStruct<(..T)> -VariadicStruct<(usize,)> // => (..T) matches (usize,) -VariadicStruct<(usize, bool)> // => (..T) matches (usize, bool) +VariadicStruct<(usize,)> // => (..T) matches (usize,) +VariadicStruct<(usize, bool)> // => (..T) matches (usize, bool) impl <(..(T1, T2))> VariadicStruct<(..(T1, T2))> { ... } VariadicStruct::<((usize, bool),)> @@ -153,7 +153,7 @@ A variadic tuple can be declared like any other variable: ```rust trait MyFunc<(..T)> { - fn my_func(variadic_tuple: (..T)) { ... } + fn my_func(variadic_tuple: (..T)) { ... } } ``` @@ -186,7 +186,7 @@ Examples: ```rust // The function argument is destructured as a variadic tuple with identifier `v` trait MyFunc<(..T)> { - fn my_func((..v): (..T)) -> (..T) { + fn my_func((..v): (..T)) -> (..T) { ... } } @@ -217,9 +217,9 @@ let result: (..Option<&V>) = { // `KEY` and `VALUE` are type variables iterating the variadic tuple types `(..K)` and `(..V)` // `..(k, maps)` declares the iterated variadic tuples `(..k)` and `(..maps)` // `..(K, V)` declares the iterated variadic tuple types - for (ref key, map) type (KEY, VALUE) in ..(k, maps) type ..(K, V) { + (for (ref key, map) type (KEY, VALUE) in ..(k, maps) type ..(K, V) { HashMap::::get(&map, key) - } + }) }; ``` @@ -234,9 +234,9 @@ where ..(K: Hash), { let (..ref maps) = &self.maps; let result: (..Option<&V>) = { - for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { + (for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { HashMap::::get(&map, k) - } + }) }; result @@ -253,19 +253,35 @@ where let (..ref tuple, ref last) = *self; // Use case: only variadic tuple - for member in ..(tuple,) { + (for member in ..(tuple,) { member.hash(state); - } + }); last.hash(state); // Use case: variadic tuple and type - for member type (H,) in ..(tuple,) type ..(T,) { + (for member type (H,) in ..(tuple,) type ..(T,) { ::hash(&member, state); - } + }); last.hash(state); } } +trait Merge<(..R)> { + type Value; + fn merge(self, r: (..R)) -> Self::Value; +} + +impl<(..L), (..R)> Merge<(..R)> for (..L) { + type Value = (..L, ..R); + + fn merge(self, r: (..R)) -> Self::Value { + let (..l) = self; + ( + for (l1,) in ..(l,) { l1 }, + for (r1,) in ..(r,) { r1 }, + ) + } +} ``` ## The `Hash`trait @@ -277,22 +293,24 @@ Let's implement the `Hash` trait: // We have the first expansion here, `(..T, Last)` expands to `(A, B, C, Last)` impl<(..T), Last> Hash for (..T, Last) where - // Expands to `A: Hash, B: Hash, C: Hash,` + // Expands to `A: Hash, B: Hash, C: Hash,` ..(T: Hash,), Last: Hash + ?Sized, { #[allow(non_snake_case)] fn hash(&self, state: &mut S) { - // Destructure self to a variadic tuple `tuple` and a variable `last`. The variadic tuple type of `tuple` is `(..&T)` - // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let tuple = (a, b, c);` + // Destructure self to a variadic tuple `tuple` and a variable `last`. The variadic tuple type of `tuple` is `(..&T)` + // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let tuple = (a, b, c);` let (..ref tuple, ref last) = *self; - for member in ..(tuple,) { + (for member in ..(tuple,) { member.hash(state); - } + }); // The for loop will be inlined as: - // v.0.hash(state); - // v.1.hash(state); - // v.2.hash(state); + // ( + // { v.0.hash(state); }, + // { v.1.hash(state); }, + // { v.2.hash(state); }, + // ); last.hash(state); } } @@ -339,7 +357,7 @@ The declaration of a variadic tuple variable is still a variable. Nothing new he ```rust trait MyFunc<(..T)> { - fn my_func(input: (..T)) { ... } + fn my_func(input: (..T)) { ... } } ``` @@ -393,9 +411,9 @@ where ..(K: Hash), { let (..ref maps) = &self.maps; let result: (..Option<&V>) = { - for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { + (for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { HashMap::::get(&map, k) - } + }) }; // for the compiler, the for block has a kind of @@ -672,8 +690,8 @@ impl<(..T)> Arity for (..T) { // Specialized implementation for the recursion impl Arity for (Head, ..Tail) { - // (..#Tail) does implement `Arity`, so - // <(..#Tail) as Arity> is valid. + // (..#Tail) does implement `Arity`, so + // <(..#Tail) as Arity> is valid. const VALUE: usize = <(..Tail) as Arity>::VALUE + 1; } ``` From 048f9d1a002ac4b585ccf2b53ad96543999a8f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Tue, 10 Sep 2019 22:38:15 +0200 Subject: [PATCH 28/51] Updated RFC with feedbacks --- text/0000-variadic-tuples.md | 69 +++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 2abf3e1bc74..e3bc58e02b3 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -126,7 +126,9 @@ struct MegaMap<(..(K, V))> { // } trait Append<(..L), (..R)> -where ..(L: 'static + Clone), ..(R: 'static + Clone) { +where + ..(L: 'static + Clone), + ..(R: 'static + Clone), { fn append(l: (..L), r: (..R)) -> (..L, ..R) } @@ -457,13 +459,15 @@ trait Arity { const VALUE: usize; } -// Default implementation for all tuples -impl<(..T)> Arity for (..T) { - default const VALUE: usize = 0; +// Termination implementation of the recursion +impl<()> Arity for () { + const VALUE: usize = 0; } // Specialized implementation for the recursion -impl Arity for (Head, ..Tail) { +impl Arity for (Head, ..Tail) +where + (..Tail): Arity, { const VALUE: usize = <(..Tail) as Arity>::VALUE + 1; } ``` @@ -486,7 +490,9 @@ trait Arity { const VALUE: usize; } -impl Arity for (Head, ..Tail) { +impl Arity for (Head, ..Tail) +where + (..Tail): Arity, { const VALUE: usize = <(..Tail) as Arity>::VALUE + 1; } @@ -503,9 +509,11 @@ error[E0277]: the trait bound `(bool, u8): Arity` is not satisfied --> src/main.rs:10:4 | 7 | let arity = <(usize, bool, u8) as Arity>::VALUE; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Arity` is not implemented for `(bool, u8)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Arity` is not implemented for `()` | = help: impl `Arity` for `(usize, bool, u8)` requires impl `Arity` for `(bool, u8)` + = help: impl `Arity` for `(bool, u8)` requires impl `Arity` for `(u8,)` + = help: impl `Arity` for `(u8,)` requires impl `Arity` for `()` ``` #### Variadic implementation cycle dependency error @@ -672,30 +680,6 @@ note: when expanding with `(..(Key, Value)) = ((usize, bool), (f32, String))` [rationale-and-alternatives]: #rationale-and-alternatives -## Recursive implementations of trait with variadic tuple - -Recursive implementation is done by implementing the termination on all types and then the recursive implementation as a specialization. - -Doing this way, the Rust compiler is able to validate the generic parameters before monomorphization. - -```rust -trait Arity { - const VALUE: usize; -} - -// Default implementation for all tuples -impl<(..T)> Arity for (..T) { - default const VALUE: usize = 0; -} - -// Specialized implementation for the recursion -impl Arity for (Head, ..Tail) { - // (..#Tail) does implement `Arity`, so - // <(..#Tail) as Arity> is valid. - const VALUE: usize = <(..Tail) as Arity>::VALUE + 1; -} -``` - ## Iteration over variadic tuples syntax When iterating over variadic tuples, we need to define both variable and type variable. To do so, we use the for loop syntax and separate variables and type variables with the `type` keyword. @@ -730,16 +714,37 @@ C++11 sets a decent precedent with its variadic templates, which can be used to [unresolved-questions]: #unresolved-questions +## Variadic tuple expansion syntax is confusing + +Using a syntax like `..(id,)` in an expression is ambiguous with the range syntax. So this one needs to be changed. + +An example with context: +```rust +let result: (..Option<&V>) = { + for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { + HashMap::::get(&map, k) + } +}; +``` + ## Dynamic libraries tuple implementation assumption When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) +## Variadic tuple for functions + +Supporting variadic tuple for function with recursive implementation over the variadic tuples is not possible. (See below). + +However, when the funtion is not recursive over the variadic tuple, it can be a nice addition to help implementation of libraries using tuples. + +In that case, the compiler must detect if there is such a recursion an issue a compile error. + # Future possibilities [future-possibilities]: #future-possibilities -## Supporting variadic tuple for function generic parameter groups +## Supporting variadic tuple for function generic parameter groups with recursion Supporting variadic tuple for function generic parameter groups requires to provide a specialized implementation for the recursion termination. From 02e0bbe1991a959f069e1275c941a786021a0762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 12 Sep 2019 10:22:45 +0200 Subject: [PATCH 29/51] Added support for functions --- text/0000-variadic-tuples.md | 85 +++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index e3bc58e02b3..4d95a92031a 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -72,8 +72,6 @@ macro_rules! last_type { Variadic tuple types are always declared in a generic parameter group. -*Note: variadic tuples are not supported in generic parameter group of `fn`* - There are two different syntaxes: 1. `(..T)`: declare a single variadic tuple type identified by `T` @@ -82,7 +80,8 @@ There are two different syntaxes: Declaration examples: - `struct VariadicStruct<(..T1)>` : declares a struct with a variadic tuple type identified by `T1` in its generic parameters -- `impl<(..Head)>`: is an implementation block that uses a variadic tuple type identified by `Head` +- `fn my_func<(..T1), (..T2)>()`: a function can have variadic tuple type parameters +- `impl<(..Head)>`: is an implementation block that uses a variadic tuple type identified by `Head` - `impl`: same as above, but with other generic parameters - `impl`: there can be several variadic tuple types declared in a generic parameter group @@ -125,19 +124,19 @@ struct MegaMap<(..(K, V))> { // maps: (HashMap, HashMap), // } -trait Append<(..L), (..R)> +fn append<(..L), (..R)>(l: (..L), r: (..R)) -> (..L, ..R) where - ..(L: 'static + Clone), - ..(R: 'static + Clone), { - fn append(l: (..L), r: (..R)) -> (..L, ..R) + ..(L: 'static + Clone), + ..(R: 'static + Clone), { + ... } // -// trait Append<(usize, Vec), (&'static str, u8, i16)> { -// fn append( +// fn append<(usize, Vec), (&'static str, u8, i16)>( // l: (usize, Vec), // r: (&'static str, u8, i16) -// ) -> (usize, Vec, &'static str, u8, i16) { ... } +// ) -> (usize, Vec, &'static str, u8, i16) { +// ... // } ``` @@ -154,9 +153,7 @@ A _variadic tuple_ is a variable of a variadic tuple type. A variadic tuple can be declared like any other variable: ```rust -trait MyFunc<(..T)> { - fn my_func(variadic_tuple: (..T)) { ... } -} +fn my_func<(..T)>(variadic_tuple: (..T)) { ... } ``` ### Destructuring a variadic tuple @@ -187,10 +184,8 @@ Examples: ```rust // The function argument is destructured as a variadic tuple with identifier `v` -trait MyFunc<(..T)> { - fn my_func((..v): (..T)) -> (..T) { - ... - } +fn my_func<(..T)>((..v): (..T)) -> (..T) { + ... } impl<(..T)> Clone for (..T) @@ -358,10 +353,7 @@ where ..(T: Clone) { ... } The declaration of a variadic tuple variable is still a variable. Nothing new here. ```rust -trait MyFunc<(..T)> { - fn my_func(input: (..T)) { ... } -} - +fn my_func<(..T)>(input: (..T)) { ... } ``` ### Variadic tuple destructuration @@ -467,7 +459,7 @@ impl<()> Arity for () { // Specialized implementation for the recursion impl Arity for (Head, ..Tail) where - (..Tail): Arity, { + (..Tail): Arity, { const VALUE: usize = <(..Tail) as Arity>::VALUE + 1; } ``` @@ -477,9 +469,52 @@ Note: - The `impl Arity for (Head, ..Tail)` is the recursive implementation. - The `impl<(..T)> Arity for (..T)` is the default implementation and will act as the termination of the recursion. +### Recursion for functions + +Recursion for functions over variadic tuple is not supported. + +Consider this code: +```rust +fn arity((h, ..tail): (Head, ..Tail)) -> usize { + arity::<(..Tail)>((..tail)) + 1 +} +// We need to define an explicit implementation of `fn arity<()>`, but there is no mechanism in Rust +// currently to specialize a function implementation +// So we don't deal with this use case in this RFC +// Instead, the compiler will issue a compile error +``` + ## Errors -#### Missing implementation message during variadic implementation resolution +### Recursive function implementation over variadic tuple + +Recursive function implementation over variadic tuple are not supported. + +The following code: +```rust +fn arity((h, ..tail): (Head, ..Tail)) -> usize { + arity::<(..Tail)>((..tail)) + 1 +} +``` + +Will issue: +```rust +error[EXXXX]: the function `fn arity` is recursive over variadic tuple, this is not supported + --> src/main.rs:10:4 + | +7 | fn arity((h, ..tail): (Head, ..Tail)) -> usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: The implementation of `arity` requires an implementation with `arity::<(..Tail)>` + --> src/main.rs:11:4 + | +8 | arity::<(..Tail)>((..tail)) + 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `arity` must be called with either the same generic arguments or without variadic tuple types +``` + +### Missing implementation message during variadic implementation resolution An error can occur if the compiler don't find an implementation while generating variadic tuple implementations. @@ -492,7 +527,7 @@ trait Arity { impl Arity for (Head, ..Tail) where - (..Tail): Arity, { + (..Tail): Arity, { const VALUE: usize = <(..Tail) as Arity>::VALUE + 1; } @@ -516,7 +551,7 @@ error[E0277]: the trait bound `(bool, u8): Arity` is not satisfied = help: impl `Arity` for `(u8,)` requires impl `Arity` for `()` ``` -#### Variadic implementation cycle dependency error +### Variadic implementation cycle dependency error As a variadic tuple implementation may depend on other variadic tuple implementation, there can be dependency cycle issue. From eb4f7737668a89f87e172187e045a9af53f9c6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 12 Sep 2019 10:31:06 +0200 Subject: [PATCH 30/51] Updated with trait utilities library --- text/0000-variadic-tuples.md | 95 +++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 7 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 4d95a92031a..4c496b42840 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -729,7 +729,79 @@ let result: (..Option<&V>) = { }; ``` +## Variadic tuple utilities library +The iteration for loop syntax can be combined with utilities to have more flexibility. + +Example: + +```rust +// Trait utilities + +// Merge two tuple togethers +trait Merge<(..R> { + type Value; + fn merge(self, r: (..R)) -> Self::Value; +} +impl<(..L), (..R)> Merge<(..R)> for (..L) { + type Value = (..L, ..R); + fn merge(self, (..r): (..R)) -> Self::Value { + let (..l) = self; + (for (l,) in ..(l,) { l }, for (r,) in ..(r,) { r }) + } +} + +// Reverse a tuple's members +trait Rev { + type Value; + fn rev(self) -> Self::Value; +} +impl Rev for () { + type Value = (); + fn rev(self) -> Self::Value { () } +} +impl Rev for (Head, ..Tail) +where + (..Tail): Rev, + <(..Tail)>::Value: Merge<(Head,)> { + type Value = <<(..Tail)>::Value as Merge<(Head,)>>::Output; + + fn rev(self) -> Self::Value { + let (h, ..t) = self; + let rev_t = <(..Tail) as Rev>::rev((..t)); rev_t.merge((h,)) + } +} + +// Utility to create a tuple of a single type, for instance: ToT = (..T) -> (..usize) +// We could have a syntaxic sugar to do this (future RFC?) +trait ToT { + type Value = T; +} +impl ToT for A { } + + +// Example usage +// Reverse the tuple and provide a tuple with the hashes of the tuple members +fn reverse_tuple_and_hash<(..T), (..RevT)>(value: (..T)) -> (<(..T) as Rev>::Value, (..>::Value)), +where + (..T): Rev, + ..(T: Hash), { + + let (..rev_t) = <(..T) as Rev>::rev(value); + + // Here we use the identifiers of the reversed variadic tuple and variadic tuple type in the iteration + let hashes = (for (rev_t,) type (RevT,) in ..(&rev_t) type ..(RevT,) { + let mut s = DefaultHasher::new(); + ::hash(&rev_t, &mut s); + s.finish() + }); + + ( + (for (rev_t,) in ..(rev_t,) { rev_t }), + hashes, + ) +} +``` ## Declaring and using multiple variadic tuple type with same arity @@ -803,17 +875,26 @@ Note, see the RFC issues [290](https://github.com/rust-lang/rfcs/issues/290) and ## Better utilities to manipulate tuples -If we consider tuples as a list of types we can perform more computation at compile time and provide more possibilities for zero cost abstractions. +Some utilities can be provided as libraries (see [Variadic tuple utilities library](##variadic-tuple-utilities-library)), but some will requires implementions provided by the compiler. Such utilities can be: +```rust +// mod std::tuple +trait Unique<(..T)> { + // A tuple without members with the same type + type Value; +} -- `TupleContains`: implemented by tuples containing the type `T` in its members -- `UniqueTuple`: implemented by all tuple, an associated type is the based on the same tuple but with only unique types -- `SortedTuple`: implemented by all tuple, an associated type is the based on the same tuple but with only sorted types -- `Arity`: a trait implemented by all tuple providing the arity of the tuple with a `const` -- An equivalent to C++'s `std::get` +trait Sorted<(..T)> { + // A tuple where its members are sorted by TypeId + type Value; +} -Those are not directly related to this RFC, but those utilities will be a natural additional step to better support tuple. +trait Get<(..T)> { + // Get the value of the ith member of a tuple + fn get(&self, index: usize) -> Option<&V>; +} +``` ## Improve the error message for `E0275` From 2f32df0938388e2eb6dec28ce5bb2473baf0adbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 12 Sep 2019 10:38:59 +0200 Subject: [PATCH 31/51] Added future possibility for syntaxic sugar --- text/0000-variadic-tuples.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 4c496b42840..1cfc01af39a 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -873,6 +873,39 @@ However when such a feature will land in Rust, supporting variadic tuple for fun Note, see the RFC issues [290](https://github.com/rust-lang/rfcs/issues/290) and [1053](https://github.com/rust-lang/rfcs/issues/1053). +## Syntaxic sugar to create tuple with the same type of a specific arity + +Consider this use case: +```rust +trait ToT { + type Value = T; +} +impl ToT for A { } + +fn tuple_of_hashes<(..T)>((..t): (..T)) -> (..::Value) { + (for (t,) in ..(t,) { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + }) +} +``` + +We use the `ToT` trait to produce a tuple of `usize` with the same arity of `T`. +We may find a syntaxic sugar to do the same thing, like: `(@T..usize)` meaning: +evaluate the `(..usize)` variadic tuple type expansion with the arity of `T`. + +So it would be rewritten as: +```rust +fn tuple_of_hashes<(..T)>((..t): (..T)) -> (@T..usize) { + (for (t,) in ..(t,) { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + }) +} +``` + ## Better utilities to manipulate tuples Some utilities can be provided as libraries (see [Variadic tuple utilities library](##variadic-tuple-utilities-library)), but some will requires implementions provided by the compiler. From df4c61729fea7402f3584554947ee53965041984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 12 Sep 2019 22:29:30 +0200 Subject: [PATCH 32/51] Fixed syntax issues --- text/0000-variadic-tuples.md | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 1cfc01af39a..812f294f4ca 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -250,13 +250,13 @@ where let (..ref tuple, ref last) = *self; // Use case: only variadic tuple - (for member in ..(tuple,) { + (for member in ..tuple { member.hash(state); }); last.hash(state); // Use case: variadic tuple and type - (for member type (H,) in ..(tuple,) type ..(T,) { + (for member type H in ..tuple type ..T { ::hash(&member, state); }); last.hash(state); @@ -274,11 +274,21 @@ impl<(..L), (..R)> Merge<(..R)> for (..L) { fn merge(self, r: (..R)) -> Self::Value { let (..l) = self; ( - for (l1,) in ..(l,) { l1 }, - for (r1,) in ..(r,) { r1 }, + for l1 in ..l { l1 }, + for r1 in ..r { r1 }, ) } } + +trait Integer { + fn one() -> Self; +} + +fn add_one<(..T)>((..t): (..T)) -> (..T) +where + ..(T: Integer + Add), { + (for t type T in ..t type ..T { t + T::one() }) +} ``` ## The `Hash`trait @@ -299,7 +309,7 @@ where // Destructure self to a variadic tuple `tuple` and a variable `last`. The variadic tuple type of `tuple` is `(..&T)` // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let tuple = (a, b, c);` let (..ref tuple, ref last) = *self; - (for member in ..(tuple,) { + (for member in ..tuple { member.hash(state); }); // The for loop will be inlined as: @@ -747,7 +757,7 @@ impl<(..L), (..R)> Merge<(..R)> for (..L) { type Value = (..L, ..R); fn merge(self, (..r): (..R)) -> Self::Value { let (..l) = self; - (for (l,) in ..(l,) { l }, for (r,) in ..(r,) { r }) + (for l in ..l { l }, for r in ..r { r }) } } @@ -790,14 +800,14 @@ where let (..rev_t) = <(..T) as Rev>::rev(value); // Here we use the identifiers of the reversed variadic tuple and variadic tuple type in the iteration - let hashes = (for (rev_t,) type (RevT,) in ..(&rev_t) type ..(RevT,) { + let hashes = (for rev_t type RevT in ..&rev_t type ..RevT { let mut s = DefaultHasher::new(); ::hash(&rev_t, &mut s); s.finish() }); ( - (for (rev_t,) in ..(rev_t,) { rev_t }), + (for rev_t in ..rev_t { rev_t }), hashes, ) } @@ -883,7 +893,7 @@ trait ToT { impl ToT for A { } fn tuple_of_hashes<(..T)>((..t): (..T)) -> (..::Value) { - (for (t,) in ..(t,) { + (for t in ..t { let mut s = DefaultHasher::new(); t.hash(&mut s); s.finish() @@ -898,7 +908,7 @@ evaluate the `(..usize)` variadic tuple type expansion with the arity of `T`. So it would be rewritten as: ```rust fn tuple_of_hashes<(..T)>((..t): (..T)) -> (@T..usize) { - (for (t,) in ..(t,) { + (for t in ..t { let mut s = DefaultHasher::new(); t.hash(&mut s); s.finish() From 10d416e0af5e0d177b3c6bbbb7304ad1be242d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 12 Sep 2019 23:15:18 +0200 Subject: [PATCH 33/51] Added formal syntax definitions --- text/0000-variadic-tuples.md | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 812f294f4ca..c9e9d4788e0 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -329,6 +329,8 @@ where ## Syntax +Note EBNF syntax is based on [Rust's grammar](https://doc.rust-lang.org/nightly/grammar.html). + ### Variadic tuple type declaration A variadic tuple type identifier identifies a list of types. @@ -343,6 +345,13 @@ MyStruct::<((usize, bool), (i8, f32))> { ... } // `(..R)` is `(bool, f32)` ``` +variadic tuple type declaration +```ebnf +var_tuple_type_decl : single_var_tuple_decl | multiple_var_tuple_decl; +single_var_tuple_decl : "(.." ident ")"; +multiple_var_tuple_decl: "(..(" ident ["," ident] * "))"; +``` + Note: Although this looks like a type-level pattern matching, it can match against only tuple of identifiers. So the following declaration is invalid: `struct MyStruct<(..(L, Vec))> { ... }` ### Variadic tuple type expansion @@ -358,6 +367,18 @@ struct MyStruct<(..T)> where ..(T: Clone) { ... } ``` +variadic tuple type expansion +```ebnf +var_tuple_type_exp : raw_var_tuple_type_exp | par_var_tuple_type_exp; +raw_var_tuple_type_exp : ".." type_expr; +par_var_tuple_type_exp : "..(" type_expr ")"; +``` + +variadic tuple type expansion in where bounds +```ebnf +var_tuple_type_exp_where : "..(" type_expr ":" bound-list ")"; +``` + ### Variadic tuple declaration The declaration of a variadic tuple variable is still a variable. Nothing new here. @@ -388,6 +409,14 @@ When destructuring a variadic tuple it declares a variadic tuple identifiers tha // `let v = (a, b, c);` ``` +variadic tuple destructuration +```ebnf +tuple_destr : "(" tuple_destr_ident_any [ "," tuple_destr_ident_any ] * ")"; +tuple_destr_ident_any : [ tuple_destr_ident_var | tuple_destr_ident ]; +tuple_destr_ident : ident | "ref" ident | "ref" "mut" ident; +tuple_destr_ident_var : ".." ident | "..(" "ref" ident ")" | "..(" "ref" "mut" ident ")"; +``` + ### Variadic tuple iteration The syntax for the variadic tuple iteration is: @@ -449,6 +478,16 @@ where ..(K: Hash), { } ``` +variadic tuple iteration +```ebnf +for_var_tuple : for_var_tuple_with_tuple_and_type | for_var_tuple_with_type | for_var_tuple_with_tuple; +for_var_tuple_with_tuple_and_type : "for" for_tuple_destr "type" for_tuple_type_destr "in" for_tuple_ident "type" for_tuple_ident block_expr; +for_var_tuple_with_type : "for" "type" for_tuple_type_destr "in" "type" for_tuple_ident block_expr; +for_var_tuple_with_tuple : "for" for_tuple_destr "in" for_tuple_ident block_expr; +for_tuple_destr : tuple_destr_ident | "(" tuple_destr_ident [ "," tuple_destr_ident ] * ")"; +for_tuple_ident : ident | "(" ident [ "," ident ] * ")"; +for_tuple_type_destr : for_tuple_ident; +``` ## Recursion From 3b5653987c1333b866df79c81fd13ba51e1e3e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 12 Sep 2019 23:24:07 +0200 Subject: [PATCH 34/51] Fix syntax --- text/0000-variadic-tuples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index c9e9d4788e0..d5b6e1fbc8a 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -271,7 +271,7 @@ trait Merge<(..R)> { impl<(..L), (..R)> Merge<(..R)> for (..L) { type Value = (..L, ..R); - fn merge(self, r: (..R)) -> Self::Value { + fn merge(self, (..r): (..R)) -> Self::Value { let (..l) = self; ( for l1 in ..l { l1 }, From 56289633ac09b14defafa836751209b89d4b4d00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 12 Sep 2019 23:44:19 +0200 Subject: [PATCH 35/51] Added syntaxic sugar for optional parenthesis --- text/0000-variadic-tuples.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index d5b6e1fbc8a..22dadde8d14 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -922,6 +922,23 @@ However when such a feature will land in Rust, supporting variadic tuple for fun Note, see the RFC issues [290](https://github.com/rust-lang/rfcs/issues/290) and [1053](https://github.com/rust-lang/rfcs/issues/1053). +## Syntaxic sugar to make enclosing parenthesis optional + +For generic parameter group containing one variadic tuple type, it may be conveninent to omit the parenthesis. + +```rust +// Instead of +struct MyStruct; +// Write +struct MyStruct; + +// And the expansions will matches +// Instead of +MyStruct::; +// Write +MyStruct::; +``` + ## Syntaxic sugar to create tuple with the same type of a specific arity Consider this use case: From 1e1038856573397496533bf9d39eb0ba6f6004b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 12 Sep 2019 23:55:24 +0200 Subject: [PATCH 36/51] Fixed the confusion about variadic tuple identifiers --- text/0000-variadic-tuples.md | 71 ++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 22dadde8d14..b52a4867ada 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -158,7 +158,7 @@ fn my_func<(..T)>(variadic_tuple: (..T)) { ... } ### Destructuring a variadic tuple -The main way to use a variadic tuple is by destructuring it to access its members. +A variadic tuple can be destructured to manipulate its members There are 3 syntaxes possible to destructure a variadic tuple for a variadic tuple `(..T)`: @@ -171,10 +171,14 @@ Also, the destructure pattern can be combined with other members. For instance: ```rust { let source: (Head, ..Tail) = _; + // `head` is a variable of type `Head` + // `tail` is a tuple variable of type `(..&Tail)` let (ref head, ..(ref tail)) = &source; } { let mut source: (..L, ..R) = _; + // `l` is a tuple variable of type `(..&mut L)` + // `r` is a tuple variable of type `(..&mut R)` let (..(ref mut l), ..(ref mut r)) = &mut source; } @@ -184,15 +188,17 @@ Examples: ```rust // The function argument is destructured as a variadic tuple with identifier `v` -fn my_func<(..T)>((..v): (..T)) -> (..T) { +fn my_func((head, ..v): (Head, ..T)) -> (..T) { ... } -impl<(..T)> Clone for (..T) -where ..(T: Clone) { +impl Clone for (Head, ..T) +where + ..(T: Clone), + Head: Clone, { fn clone(&self) -> Self { - // We destructure `*self` which has a variadic tuple type `(..T)` - let (..(ref v)) = *self; + // We destructure `*self` which has a variadic tuple type `(Head, ..T)` + let (ref head, ..(ref v)) = *self; ... } } @@ -210,9 +216,9 @@ We use the following syntax to iterate on variadic tuples: // The result of the for block is a variadic tuple made of // the result of each iteration let result: (..Option<&V>) = { - // `key` and `map` are variables iterating the variadic tuples `(..k): (..K)` and `(..maps): (..&HashMap)`, `key` will iterate by reference (because of the ref keyword) + // `key` and `map` are variables iterating the variadic tuples `k: (..K)` and `maps: (..&HashMap)`, `key` will iterate by reference (because of the ref keyword) // `KEY` and `VALUE` are type variables iterating the variadic tuple types `(..K)` and `(..V)` - // `..(k, maps)` declares the iterated variadic tuples `(..k)` and `(..maps)` + // `..(k, maps)` declares the iterated variadic tuples `k` and `maps` // `..(K, V)` declares the iterated variadic tuple types (for (ref key, map) type (KEY, VALUE) in ..(k, maps) type ..(K, V) { HashMap::::get(&map, key) @@ -227,11 +233,9 @@ Examples: ```rust impl<(..(K, V))> MegaMap<(..(K, V))> where ..(K: Hash), { - fn get(&self, (..k): (..K)) -> (..Option) { - let (..ref maps) = &self.maps; - + fn get(&self, k: (..K)) -> (..Option) { let result: (..Option<&V>) = { - (for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { + (for (ref k, map) type (K, V) in ..(k, &self.maps) type ..(K, V) { HashMap::::get(&map, k) }) }; @@ -271,10 +275,9 @@ trait Merge<(..R)> { impl<(..L), (..R)> Merge<(..R)> for (..L) { type Value = (..L, ..R); - fn merge(self, (..r): (..R)) -> Self::Value { - let (..l) = self; + fn merge(self, r: (..R)) -> Self::Value { ( - for l1 in ..l { l1 }, + for l1 in ..self { l1 }, for r1 in ..r { r1 }, ) } @@ -389,17 +392,17 @@ fn my_func<(..T)>(input: (..T)) { ... } ### Variadic tuple destructuration -When destructuring a variadic tuple it declares a variadic tuple identifiers that can be used in expansion forms. The identifier is a variable of type `(..T)` or `(..&T)` or `(..&mut T)`, depending on the syntax used. +When destructuring a variadic tuple, we can destructure the variadic parts into tuple variables. The identifier is a variable of type `(..T)` or `(..&T)` or `(..&mut T)`, depending on the syntax used. ```rust { let source: (..T, Tail) = _; - let (..v, tail) = source; // v is a variable of type `(..T)` - let (..(ref v), ref tail) = &source; + let (..v, tail) = source; // v is a variable of type `(..&T)` + let (..(ref v), ref tail) = &source; + // v is a variable of type `(..&mut T)` let (..(ref mut v), ref mut tail) = &mut source; - // v is a variable of type `(..&mut T)` } // If we use `(..T)` = `(A, B, C)` as an example @@ -440,11 +443,10 @@ Example: ```rust impl<(..(K, V))> MegaMap<(..(K, V))> where ..(K: Hash), { - fn get(&self, (..k): (..K)) -> (..Option) { - let (..ref maps) = &self.maps; + fn get(&self, k: (..K)) -> (..Option) { let result: (..Option<&V>) = { - (for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { + (for (ref k, map) type (K, V) in ..(k, &self.maps) type ..(K, V) { HashMap::::get(&map, k) }) }; @@ -525,7 +527,7 @@ Recursion for functions over variadic tuple is not supported. Consider this code: ```rust fn arity((h, ..tail): (Head, ..Tail)) -> usize { - arity::<(..Tail)>((..tail)) + 1 + arity::<(..Tail)>(tail) + 1 } // We need to define an explicit implementation of `fn arity<()>`, but there is no mechanism in Rust // currently to specialize a function implementation @@ -542,7 +544,7 @@ Recursive function implementation over variadic tuple are not supported. The following code: ```rust fn arity((h, ..tail): (Head, ..Tail)) -> usize { - arity::<(..Tail)>((..tail)) + 1 + arity::<(..Tail)>(tail) + 1 } ``` @@ -557,7 +559,7 @@ error[EXXXX]: the function `fn arity` is recursive over variadic tuple, this is = help: The implementation of `arity` requires an implementation with `arity::<(..Tail)>` --> src/main.rs:11:4 | -8 | arity::<(..Tail)>((..tail)) + 1 +8 | arity::<(..Tail)>(tail) + 1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: `arity` must be called with either the same generic arguments or without variadic tuple types @@ -674,7 +676,7 @@ impl<(..K), (..V)> MyTrait for (..HashMap) { error[EXXXX]: invalid variadic tuple type expansion `(..HashMap)` --> src/main.rs:4:13 | -10 | impl<(..#K), (..#V)> MyTrait for (..HashMap) { +10 | impl<(..K), (..V)> MyTrait for (..HashMap) { | ^^^^^^^^^^^^^^^^^ | note: variadic tuple type identifiers `K`, `V` were not declared together @@ -727,7 +729,7 @@ If we consider this code: ```rust trait MakeMegaMap<(..(Key, Value))> { fn make_mega_map() -> (..HashMap) { - for () type (KEY, VALUE) in () type ..(Key, Value2) { + for type (KEY, VALUE) in type ..(Key, Value2) { HashMap::::new() } } @@ -751,8 +753,8 @@ error[E0412]: cannot find type `Value2` in this scope | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope note: when expanding with `(..(Key, Value)) = ((usize, bool), (f32, String))` --> src/main.rs:2:4 - | for () type (KEY, VALUE) in () type ..(Key, Value2) { -2 | HashMap::::new() ^^^^^^^ + | for type (KEY, VALUE) in type ..(Key, Value2) { +2 | HashMap::::new() ^^^^^^^ | } ``` @@ -794,9 +796,8 @@ trait Merge<(..R> { } impl<(..L), (..R)> Merge<(..R)> for (..L) { type Value = (..L, ..R); - fn merge(self, (..r): (..R)) -> Self::Value { - let (..l) = self; - (for l in ..l { l }, for r in ..r { r }) + fn merge(self, r: (..R)) -> Self::Value { + (for l in ..self { l }, for r in ..r { r }) } } @@ -817,7 +818,7 @@ where fn rev(self) -> Self::Value { let (h, ..t) = self; - let rev_t = <(..Tail) as Rev>::rev((..t)); rev_t.merge((h,)) + let rev_t = <(..Tail) as Rev>::rev(t); rev_t.merge((h,)) } } @@ -836,7 +837,7 @@ where (..T): Rev, ..(T: Hash), { - let (..rev_t) = <(..T) as Rev>::rev(value); + let rev_t = <(..T) as Rev>::rev(value); // Here we use the identifiers of the reversed variadic tuple and variadic tuple type in the iteration let hashes = (for rev_t type RevT in ..&rev_t type ..RevT { @@ -910,7 +911,7 @@ For instance: fn recurse((head, ..tail): (Head, ..Tail)) where Head: Display, ..(Tail: Display) { println!("{}", head); - recurse((..tail)); + recurse(tail); } // Termination needs to be implemented explicitly fn recurse<()>((): ()) { } From bf5536377a75b87152efbfccecf51ab0c53d24af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 13 Sep 2019 00:03:24 +0200 Subject: [PATCH 37/51] Added bound lists in generic parameter groups (future) --- text/0000-variadic-tuples.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index b52a4867ada..50403f2cd89 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -973,6 +973,19 @@ fn tuple_of_hashes<(..T)>((..t): (..T)) -> (@T..usize) { } ``` +## Supporting bounds inside generic parameter groups + +Writing such code feels natural +```rust +impl<(..(T: Clone))> Clone for (..T) { + fn clone(&self) -> Self { + (for c in self { c.clone() }) + } +} +``` + +So for variadic tuple that are declared alone, we may authorize bound lists. + ## Better utilities to manipulate tuples Some utilities can be provided as libraries (see [Variadic tuple utilities library](##variadic-tuple-utilities-library)), but some will requires implementions provided by the compiler. From 2d025821f66cccfbee46d4e78d0dd87903613c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 13 Sep 2019 09:42:32 +0200 Subject: [PATCH 38/51] Simplified ebnf --- text/0000-variadic-tuples.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 50403f2cd89..b34e493b886 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -416,8 +416,8 @@ variadic tuple destructuration ```ebnf tuple_destr : "(" tuple_destr_ident_any [ "," tuple_destr_ident_any ] * ")"; tuple_destr_ident_any : [ tuple_destr_ident_var | tuple_destr_ident ]; -tuple_destr_ident : ident | "ref" ident | "ref" "mut" ident; -tuple_destr_ident_var : ".." ident | "..(" "ref" ident ")" | "..(" "ref" "mut" ident ")"; +tuple_destr_ident : [ "ref" | "ref" "mut" ]? ident; +tuple_destr_ident_var : ".." ident | "..(" [ "ref" | "ref" "mut" ] ident ")"; ``` ### Variadic tuple iteration From d0e3b223b0e53f8a41e4363294fbf1105066f1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 13 Sep 2019 10:09:03 +0200 Subject: [PATCH 39/51] Simplified ebnf --- text/0000-variadic-tuples.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index b34e493b886..09d1e07aa08 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -416,8 +416,8 @@ variadic tuple destructuration ```ebnf tuple_destr : "(" tuple_destr_ident_any [ "," tuple_destr_ident_any ] * ")"; tuple_destr_ident_any : [ tuple_destr_ident_var | tuple_destr_ident ]; -tuple_destr_ident : [ "ref" | "ref" "mut" ]? ident; -tuple_destr_ident_var : ".." ident | "..(" [ "ref" | "ref" "mut" ] ident ")"; +tuple_destr_ident : [ "ref" "mut"? ]? ident; +tuple_destr_ident_var : ".." ident | "..(" [ "ref" "mut"? ] ident ")"; ``` ### Variadic tuple iteration From 61ad089240995e260d065f9d5d8e751771632520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 13 Sep 2019 10:36:55 +0200 Subject: [PATCH 40/51] Updated with the @ binding pattern --- text/0000-variadic-tuples.md | 70 +++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 09d1e07aa08..d7aec2a7bc3 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -162,9 +162,9 @@ A variadic tuple can be destructured to manipulate its members There are 3 syntaxes possible to destructure a variadic tuple for a variadic tuple `(..T)`: -1. `(..v)` of variadic tuple type `(..T)` -2. `(..(ref v))` of variadic tuple type `(..&T)` -3. `(..(ref mut v))` of variadic tuple type `(..&mut T)` +1. `(v @ ..)` of variadic tuple type `(..T)` +2. `(ref v @ ..))` of variadic tuple type `(..&T)` +3. `(ref mut v @ ..)` of variadic tuple type `(..&mut T)` Also, the destructure pattern can be combined with other members. For instance: @@ -173,13 +173,13 @@ Also, the destructure pattern can be combined with other members. For instance: let source: (Head, ..Tail) = _; // `head` is a variable of type `Head` // `tail` is a tuple variable of type `(..&Tail)` - let (ref head, ..(ref tail)) = &source; + let (ref head, ref tail @ ..) = source; } { let mut source: (..L, ..R) = _; // `l` is a tuple variable of type `(..&mut L)` // `r` is a tuple variable of type `(..&mut R)` - let (..(ref mut l), ..(ref mut r)) = &mut source; + let (ref mut @ l .., ref mut r @ ..) = source; } ``` @@ -188,7 +188,7 @@ Examples: ```rust // The function argument is destructured as a variadic tuple with identifier `v` -fn my_func((head, ..v): (Head, ..T)) -> (..T) { +fn my_func((head, v @ ..): (Head, ..T)) -> (..T) { ... } @@ -198,7 +198,7 @@ where Head: Clone, { fn clone(&self) -> Self { // We destructure `*self` which has a variadic tuple type `(Head, ..T)` - let (ref head, ..(ref v)) = *self; + let (ref head, ref v @ ..) = *self; ... } } @@ -251,7 +251,7 @@ where #[allow(non_snake_case)] fn hash(&self, state: &mut S) { - let (..ref tuple, ref last) = *self; + let (ref tuple @ .., ref last) = *self; // Use case: only variadic tuple (for member in ..tuple { @@ -311,7 +311,7 @@ where fn hash(&self, state: &mut S) { // Destructure self to a variadic tuple `tuple` and a variable `last`. The variadic tuple type of `tuple` is `(..&T)` // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let tuple = (a, b, c);` - let (..ref tuple, ref last) = *self; + let (ref tuple @ .., ref last) = *self; (for member in ..tuple { member.hash(state); }); @@ -398,11 +398,11 @@ When destructuring a variadic tuple, we can destructure the variadic parts into { let source: (..T, Tail) = _; // v is a variable of type `(..T)` - let (..v, tail) = source; + let (v @ .., tail) = source; // v is a variable of type `(..&T)` - let (..(ref v), ref tail) = &source; + let (ref v @ .., ref tail) = &source; // v is a variable of type `(..&mut T)` - let (..(ref mut v), ref mut tail) = &mut source; + let (ref mut v @ ..), ref mut tail) = &mut source; } // If we use `(..T)` = `(A, B, C)` as an example @@ -416,8 +416,8 @@ variadic tuple destructuration ```ebnf tuple_destr : "(" tuple_destr_ident_any [ "," tuple_destr_ident_any ] * ")"; tuple_destr_ident_any : [ tuple_destr_ident_var | tuple_destr_ident ]; -tuple_destr_ident : [ "ref" "mut"? ]? ident; -tuple_destr_ident_var : ".." ident | "..(" [ "ref" "mut"? ] ident ")"; +tuple_destr_ident : [ "ref" "mut" ? ] ? ident; +tuple_destr_ident_var : [ "ref" "mut" ? ] ? ident "@" ".."; ``` ### Variadic tuple iteration @@ -491,7 +491,6 @@ for_tuple_ident : ident | "(" ident [ "," ident ] * ")"; for_tuple_type_destr : for_tuple_ident; ``` - ## Recursion To implement some feature, we may want to use recursion over the arity of the tuple. @@ -526,7 +525,7 @@ Recursion for functions over variadic tuple is not supported. Consider this code: ```rust -fn arity((h, ..tail): (Head, ..Tail)) -> usize { +fn arity((h, tail @ ..): (Head, ..Tail)) -> usize { arity::<(..Tail)>(tail) + 1 } // We need to define an explicit implementation of `fn arity<()>`, but there is no mechanism in Rust @@ -543,7 +542,7 @@ Recursive function implementation over variadic tuple are not supported. The following code: ```rust -fn arity((h, ..tail): (Head, ..Tail)) -> usize { +fn arity((h, tail @ ..): (Head, ..Tail)) -> usize { arity::<(..Tail)>(tail) + 1 } ``` @@ -553,8 +552,8 @@ Will issue: error[EXXXX]: the function `fn arity` is recursive over variadic tuple, this is not supported --> src/main.rs:10:4 | -7 | fn arity((h, ..tail): (Head, ..Tail)) -> usize - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +7 | fn arity((h, tail @ ..): (Head, ..Tail)) -> usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: The implementation of `arity` requires an implementation with `arity::<(..Tail)>` --> src/main.rs:11:4 @@ -692,9 +691,9 @@ hint: expected `(..(K, V))` The variadic tuple declaration is invalid when it can't be parsed as either: -- `(..id)` -- `(..(ref id))` -- `(..(ref mut id))` +- `(id @ ..)` +- `(ref id @ ..)` +- `(ref mut id @ ..)` ```rust struct MyStruct<(..Vec)> { @@ -715,7 +714,7 @@ error[EXXXX]: invalid variadic tuple pattern `(..(&i))` 10 | let (..(&i)) = &self; | ^^^^^^^^ | -note: expected `(..id)` or `(..(ref id))` or `(..(ref mut id))` +note: expected `(id @ ..)` or `(ref id @ ..)` or `(ref mut id @ ..)` ``` ## Help and note for existing errors @@ -817,7 +816,7 @@ where type Value = <<(..Tail)>::Value as Merge<(Head,)>>::Output; fn rev(self) -> Self::Value { - let (h, ..t) = self; + let (h, t @ ..) = self; let rev_t = <(..Tail) as Rev>::rev(t); rev_t.merge((h,)) } } @@ -897,6 +896,29 @@ However, when the funtion is not recursive over the variadic tuple, it can be a In that case, the compiler must detect if there is such a recursion an issue a compile error. +## Variadic tuple destructuration with multiple `..` + +A use case involving destructuration of multiple variadic tuple is a split operator for variadic tuples: + +```rust +fn split<(..L), (..R)>(value: (..L, ..R)) -> ((..L), (..R)) { + // This involves multiple `..` patterns which is not allowed + // and for a reason, even if we have the variadic tuple types to`"guess" + // how the split is performed, it is still not explicit + let (l @ .., r @ ..) = value; + (l, r) +} +``` + +Maybe this kind of use case can be solved by annotating the binding: +```rust +fn split<(..L), (..R)>(value: (..L, ..R)) -> ((..L), (..R)) { + let (l @ .. : (..L), r @ .. : (..R)) = value; + (l, r) +} +``` + + # Future possibilities [future-possibilities]: #future-possibilities From a3d35c47586741fcd15031e2e4512c03f8fad3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 23 Sep 2019 09:21:02 +0200 Subject: [PATCH 41/51] Updated for loop syntax --- text/0000-variadic-tuples.md | 75 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index d7aec2a7bc3..4a668b75e0c 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -218,9 +218,9 @@ We use the following syntax to iterate on variadic tuples: let result: (..Option<&V>) = { // `key` and `map` are variables iterating the variadic tuples `k: (..K)` and `maps: (..&HashMap)`, `key` will iterate by reference (because of the ref keyword) // `KEY` and `VALUE` are type variables iterating the variadic tuple types `(..K)` and `(..V)` - // `..(k, maps)` declares the iterated variadic tuples `k` and `maps` - // `..(K, V)` declares the iterated variadic tuple types - (for (ref key, map) type (KEY, VALUE) in ..(k, maps) type ..(K, V) { + // `(k, maps)` declares the iterated variadic tuples `k` and `maps` + // `` declares the iterated variadic tuple types + (for (ref key, map) @in (k, maps) { HashMap::::get(&map, key) }) }; @@ -235,7 +235,7 @@ impl<(..(K, V))> MegaMap<(..(K, V))> where ..(K: Hash), { fn get(&self, k: (..K)) -> (..Option) { let result: (..Option<&V>) = { - (for (ref k, map) type (K, V) in ..(k, &self.maps) type ..(K, V) { + (for (ref k, map) @in (k, &self.maps) { HashMap::::get(&map, k) }) }; @@ -254,13 +254,13 @@ where let (ref tuple @ .., ref last) = *self; // Use case: only variadic tuple - (for member in ..tuple { + (for member @in tuple { member.hash(state); }); last.hash(state); // Use case: variadic tuple and type - (for member type H in ..tuple type ..T { + (for member @in tuple { ::hash(&member, state); }); last.hash(state); @@ -277,8 +277,8 @@ impl<(..L), (..R)> Merge<(..R)> for (..L) { fn merge(self, r: (..R)) -> Self::Value { ( - for l1 in ..self { l1 }, - for r1 in ..r { r1 }, + for l1 @in self { l1 }, + for r1 @in r { r1 }, ) } } @@ -290,7 +290,7 @@ trait Integer { fn add_one<(..T)>((..t): (..T)) -> (..T) where ..(T: Integer + Add), { - (for t type T in ..t type ..T { t + T::one() }) + (for t @in t { t + T::one() }) } ``` @@ -312,7 +312,7 @@ where // Destructure self to a variadic tuple `tuple` and a variable `last`. The variadic tuple type of `tuple` is `(..&T)` // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let tuple = (a, b, c);` let (ref tuple @ .., ref last) = *self; - (for member in ..tuple { + (for member @in tuple { member.hash(state); }); // The for loop will be inlined as: @@ -425,7 +425,7 @@ tuple_destr_ident_var : [ "ref" "mut" ? ] ? ident "@" ".."; The syntax for the variadic tuple iteration is: ```rust -for $var_id type $type_var_id in $variadic_tuples type $variadic_tuple_types { +for $var_id <$type_var_id> @in $variadic_tuples <$variadic_tuple_types> { $body } ``` @@ -446,8 +446,8 @@ where ..(K: Hash), { fn get(&self, k: (..K)) -> (..Option) { let result: (..Option<&V>) = { - (for (ref k, map) type (K, V) in ..(k, &self.maps) type ..(K, V) { - HashMap::::get(&map, k) + (for (ref k, map) @in (k, &self.maps) { + HashMap::::get(&map, k) }) }; @@ -482,13 +482,9 @@ where ..(K: Hash), { variadic tuple iteration ```ebnf -for_var_tuple : for_var_tuple_with_tuple_and_type | for_var_tuple_with_type | for_var_tuple_with_tuple; -for_var_tuple_with_tuple_and_type : "for" for_tuple_destr "type" for_tuple_type_destr "in" for_tuple_ident "type" for_tuple_ident block_expr; -for_var_tuple_with_type : "for" "type" for_tuple_type_destr "in" "type" for_tuple_ident block_expr; -for_var_tuple_with_tuple : "for" for_tuple_destr "in" for_tuple_ident block_expr; -for_tuple_destr : tuple_destr_ident | "(" tuple_destr_ident [ "," tuple_destr_ident ] * ")"; -for_tuple_ident : ident | "(" ident [ "," ident ] * ")"; -for_tuple_type_destr : for_tuple_ident; +for_var_tuple : "for" for_tuple_ident ? for_tuple_type_ident ? "@in" for_tuple_ident ? for_tuple_type_ident ? block_expr; +for_tuple_ident : ident | "(" ident [ "," ident ] * ")"; +for_tuple_type_ident : "<" ident [ "," ident ] * ">"; ``` ## Recursion @@ -773,8 +769,8 @@ This keyword is already reserved and has no meaning inside a for loop, so it can ```rust let result: (..Option<&V>) = { - for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { - HashMap::::get(&map, k) + for (ref k, map) @in (k, maps) { + HashMap::::get(&map, k) } }; ``` @@ -796,7 +792,7 @@ trait Merge<(..R> { impl<(..L), (..R)> Merge<(..R)> for (..L) { type Value = (..L, ..R); fn merge(self, r: (..R)) -> Self::Value { - (for l in ..self { l }, for r in ..r { r }) + (for l @in self { l }, for r @in r { r }) } } @@ -846,7 +842,7 @@ where }); ( - (for rev_t in ..rev_t { rev_t }), + (for rev_t @in rev_t { rev_t }), hashes, ) } @@ -870,19 +866,6 @@ C++11 sets a decent precedent with its variadic templates, which can be used to [unresolved-questions]: #unresolved-questions -## Variadic tuple expansion syntax is confusing - -Using a syntax like `..(id,)` in an expression is ambiguous with the range syntax. So this one needs to be changed. - -An example with context: -```rust -let result: (..Option<&V>) = { - for (ref k, map) type (K, V) in ..(k, maps) type ..(K, V) { - HashMap::::get(&map, k) - } -}; -``` - ## Dynamic libraries tuple implementation assumption When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a @@ -945,7 +928,7 @@ However when such a feature will land in Rust, supporting variadic tuple for fun Note, see the RFC issues [290](https://github.com/rust-lang/rfcs/issues/290) and [1053](https://github.com/rust-lang/rfcs/issues/1053). -## Syntaxic sugar to make enclosing parenthesis optional +## Syntaxic sugar to make enclosing parenthesis optional in variadic tuple declarations For generic parameter group containing one variadic tuple type, it may be conveninent to omit the parenthesis. @@ -962,6 +945,22 @@ MyStruct::; MyStruct::; ``` +## Syntaxic sugar to make enclosing parenthesis optional in for loop + +In for loop iterating only on variadic tuples, the parenthesis may be dropped + +```rust +// Instead of +(for (k, v) @in (key, values) { + ... +}) +// Write +(for (k, v) @in key, values { + ... +}) +``` + + ## Syntaxic sugar to create tuple with the same type of a specific arity Consider this use case: From 8bac830c6b7fd1045d77591179453dc3b803971c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 23 Sep 2019 16:56:44 +0200 Subject: [PATCH 42/51] Updated with optional parenthesis for for loops --- text/0000-variadic-tuples.md | 43 +++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 4a668b75e0c..f211b5980b1 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -446,9 +446,9 @@ where ..(K: Hash), { fn get(&self, k: (..K)) -> (..Option) { let result: (..Option<&V>) = { - (for (ref k, map) @in (k, &self.maps) { + for (ref k, map) @in (k, &self.maps) { HashMap::::get(&map, k) - }) + } }; // for the compiler, the for block has a kind of @@ -487,6 +487,39 @@ for_tuple_ident : ident | "(" ident [ "," ident ] * ")"; for_tuple_type_ident : "<" ident [ "," ident ] * ">"; ``` +Note: When using a single for loop to create a tuple, the outer parenthesis are optional: +```rust +// Both syntaxes are equivalent: +let result: (..Option<&V>) = for (ref k, map) @in (k, &self.maps) { + HashMap::::get(&map, k) +}; + +let result: (..Option<&V>) = (for (ref k, map) @in (k, &self.maps) { + HashMap::::get(&map, k) +}); +``` + +Note2: When using multiple for loops to create a tuple, the parenthesis must be explicit: +```rust +// We have a single tuple with all member at the same level +fn append<(..L), (..R)>(l: (..L), r: (..R)) -> (..L, ..R) { + ( + for l1 @in l { l1 }, + for r1 @in r { r1 }, + ) +} + +// Is not equivalent to: +fn append<(..L), (..R)>(l: (..L), r: (..R)) -> ((..L), ..R) { + ( + (for l1 @in l { l1 }), + for r1 @in r { r1 }, + ) +} +// Where only the tuple `r` is destructured. +``` + + ## Recursion To implement some feature, we may want to use recursion over the arity of the tuple. @@ -724,7 +757,7 @@ If we consider this code: ```rust trait MakeMegaMap<(..(Key, Value))> { fn make_mega_map() -> (..HashMap) { - for type (KEY, VALUE) in type ..(Key, Value2) { + for @in { HashMap::::new() } } @@ -748,8 +781,8 @@ error[E0412]: cannot find type `Value2` in this scope | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope note: when expanding with `(..(Key, Value)) = ((usize, bool), (f32, String))` --> src/main.rs:2:4 - | for type (KEY, VALUE) in type ..(Key, Value2) { -2 | HashMap::::new() ^^^^^^^ + | for @in { +2 | HashMap::::new() | } ``` From fdce18090ecc7a83a524d9cb82d63d8e32d216ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Wed, 25 Sep 2019 09:11:33 +0200 Subject: [PATCH 43/51] Various typo fixes --- text/0000-variadic-tuples.md | 110 ++++++++++------------------------- 1 file changed, 32 insertions(+), 78 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index f211b5980b1..2a1e8b13f7a 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -20,7 +20,7 @@ This RFC aims to allow the use of a _variadic tuple_ which is a tuple with an ar Currently, when a user wants to either use or add behavior to tuples, he writes an impl for each tuple arity. For easier maintenance, it is usually done with a `macro_rules` and implemented up to 12 arity tuple. (see [ `Hash` implementation in `std`](https://github.com/rust-lang/rust/blob/master/src/libcore/hash/mod.rs)). -Variadic tuple will provide several benefits considering trait implementation for tuple or using tuples: +Variadic tuple will provide several benefits considering trait implementation for tuple or using variadic tuples: - Implementations will be easier to write - Implementations will be easier to read and maintain @@ -32,7 +32,7 @@ Variadic tuple will provide several benefits considering trait implementation fo Let's call a _variadic tuple type_ a tuple type with an arbitrary arity and a _variadic tuple_ an instance of a variadic tuple type. -A variadic tuple type is declared with`(..T)` and a variadic tuple type can be expanded with `(..Vec)`. +A variadic tuple type is declared with `(..T)` and a variadic tuple type can be expanded with `(..Vec)`. Note: To illustrate the RFC, we will use the current implementation of the `Hash` trait for tuples. @@ -84,6 +84,7 @@ Declaration examples: - `impl<(..Head)>`: is an implementation block that uses a variadic tuple type identified by `Head` - `impl`: same as above, but with other generic parameters - `impl`: there can be several variadic tuple types declared in a generic parameter group +- `impl`: and we can mix both syntaxes Usage examples: @@ -179,7 +180,7 @@ Also, the destructure pattern can be combined with other members. For instance: let mut source: (..L, ..R) = _; // `l` is a tuple variable of type `(..&mut L)` // `r` is a tuple variable of type `(..&mut R)` - let (ref mut @ l .., ref mut r @ ..) = source; + let (ref mut @ l .. : (..L), ref mut r @ .. : (..R)) = source; } ``` @@ -235,8 +236,8 @@ impl<(..(K, V))> MegaMap<(..(K, V))> where ..(K: Hash), { fn get(&self, k: (..K)) -> (..Option) { let result: (..Option<&V>) = { - (for (ref k, map) @in (k, &self.maps) { - HashMap::::get(&map, k) + (for (ref k, map) @in (k, &self.maps) { + HashMap::::get(&map, k) }) }; @@ -254,15 +255,15 @@ where let (ref tuple @ .., ref last) = *self; // Use case: only variadic tuple - (for member @in tuple { + for member @in tuple { member.hash(state); - }); + }; last.hash(state); // Use case: variadic tuple and type - (for member @in tuple { + for member @in tuple { ::hash(&member, state); - }); + }; last.hash(state); } } @@ -290,7 +291,7 @@ trait Integer { fn add_one<(..T)>((..t): (..T)) -> (..T) where ..(T: Integer + Add), { - (for t @in t { t + T::one() }) + (for t1 @in t { t1 + T1::one() }) } ``` @@ -312,9 +313,9 @@ where // Destructure self to a variadic tuple `tuple` and a variable `last`. The variadic tuple type of `tuple` is `(..&T)` // So it will be equivalent to `let (ref a, ref b, ref c, ref last) = *self; let tuple = (a, b, c);` let (ref tuple @ .., ref last) = *self; - (for member @in tuple { + for member @in tuple { member.hash(state); - }); + }; // The for loop will be inlined as: // ( // { v.0.hash(state); }, @@ -396,13 +397,13 @@ When destructuring a variadic tuple, we can destructure the variadic parts into ```rust { - let source: (..T, Tail) = _; + let mut source: (..T, Tail) = _; // v is a variable of type `(..T)` let (v @ .., tail) = source; // v is a variable of type `(..&T)` - let (ref v @ .., ref tail) = &source; + let (ref v @ .., ref tail) = source; // v is a variable of type `(..&mut T)` - let (ref mut v @ ..), ref mut tail) = &mut source; + let (ref mut v @ ..), ref mut tail) = source; } // If we use `(..T)` = `(A, B, C)` as an example @@ -434,9 +435,9 @@ for $var_id <$type_var_id> @in $variadic_tuples <$variadic_tuple_types> { `$type_var_id` is a pattern matching the variadic tuple types to iterate, but it has only the first syntax allowed. (No ref, or mut). -`$variadic_tuples` declares the iterated variadic tuples, it has the syntax `..id` or `..(id1, id2, ..., idn)`. +`$variadic_tuples` declares the iterated variadic tuples, it has the syntax `id` or `(id1, id2, ..., idn)`. -`$variadic_tuple_types` declares the iterated variadic tuple types, it has the syntax `..ID` or `..(ID1, ID2, ..., IDn)`. +`$variadic_tuple_types` declares the iterated variadic tuple types, it has the syntax `` or ``. Example: @@ -713,7 +714,7 @@ note: variadic tuple type identifiers `K`, `V` were not declared together 10 | impl<(..K), (..V)> MyTrait for (..HashMap) { | ^^^^^^^^^^^^ | -hint: expected `(..(K, V))` +hint: expected `impl<(..(K, V))>` instead of `impl<(..K), (..V)>` ``` ### Invalid variadic tuple pattern matching @@ -725,11 +726,11 @@ The variadic tuple declaration is invalid when it can't be parsed as either: - `(ref mut id @ ..)` ```rust -struct MyStruct<(..Vec)> { +struct MyStruct<(..T)> { vecs: (..Vec) } -impl<(..T)> MyTrait for (..#T) { +impl<(..T)> MyTrait for (..T) { fn my_func(&self) { let (..(&i)) = &self; } @@ -746,46 +747,6 @@ error[EXXXX]: invalid variadic tuple pattern `(..(&i))` note: expected `(id @ ..)` or `(ref id @ ..)` or `(ref mut id @ ..)` ``` -## Help and note for existing errors - -Variadic tuple expansion will generate code and may produce obscure errors for existing compile error. To help user debug their compile issue, we need to provide information about the expansion the compiler tried to resolve. - -##### Unknown identifier in an expansion form - -If we consider this code: - -```rust -trait MakeMegaMap<(..(Key, Value))> { - fn make_mega_map() -> (..HashMap) { - for @in { - HashMap::::new() - } - } -} - -impl<(..(Key, Value))> MakeMegaMap<(..(Key, Value))> for () {} - -fn main() { - let mega_map = <() as MakeMegaMap<<(usize, bool), (f32, String)>>::make_mega_map(); -} -``` - -Then the expansion form is valid, even though the `Value2` identifier is probably mistyped. -Leading to a compile error with additional notes - -```rust -error[E0412]: cannot find type `Value2` in this scope - --> src/main.rs:10:22 - | -10 | let mega_map = <() as MakeMegaMap<<(usize, bool), (f32, String)>>::make_mega_map(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope -note: when expanding with `(..(Key, Value)) = ((usize, bool), (f32, String))` - --> src/main.rs:2:4 - | for @in { -2 | HashMap::::new() - | } -``` - # Drawbacks [drawbacks]: #drawbacks @@ -796,9 +757,9 @@ note: when expanding with `(..(Key, Value)) = ((usize, bool), (f32, String))` ## Iteration over variadic tuples syntax -When iterating over variadic tuples, we need to define both variable and type variable. To do so, we use the for loop syntax and separate variables and type variables with the `type` keyword. - -This keyword is already reserved and has no meaning inside a for loop, so it can be used here. +When iterating over variadic tuples, we need to define both variable and type variable. To do so, we use a for loop syntax that is close to the existing one with the folowing differences: +- Instead of `in` we use `@in` to explicitly state which kind of for loop is expected +- Generics variable and lists are enclosed by brackets, like they are in generic parameters ```rust let result: (..Option<&V>) = { @@ -818,7 +779,7 @@ Example: // Trait utilities // Merge two tuple togethers -trait Merge<(..R> { +trait Merge<(..R)> { type Value; fn merge(self, r: (..R)) -> Self::Value; } @@ -841,12 +802,13 @@ impl Rev for () { impl Rev for (Head, ..Tail) where (..Tail): Rev, - <(..Tail)>::Value: Merge<(Head,)> { - type Value = <<(..Tail)>::Value as Merge<(Head,)>>::Output; + <(..Tail) as Rev>::Value: Merge<(Head,)> { + type Value = <<(..Tail) as Rev>::Value as Merge<(Head,)>>::Output; fn rev(self) -> Self::Value { let (h, t @ ..) = self; - let rev_t = <(..Tail) as Rev>::rev(t); rev_t.merge((h,)) + let rev_t = <(..Tail) as Rev>::rev(t); + rev_t.merge((h,)) } } @@ -868,9 +830,9 @@ where let rev_t = <(..T) as Rev>::rev(value); // Here we use the identifiers of the reversed variadic tuple and variadic tuple type in the iteration - let hashes = (for rev_t type RevT in ..&rev_t type ..RevT { + let hashes = (for ref rev_t in rev_t { let mut s = DefaultHasher::new(); - ::hash(&rev_t, &mut s); + ::hash(rev_t, &mut s); s.finish() }); @@ -885,7 +847,7 @@ where In C++ multiple parameter packs can be expanded in a single expansion form as long as the packs have the same number of items, but there is no constraint concerning the declaration. -For Rust, using the syntax `(..(T1, T2, ..., Tn))` embeds the constraint that the variadic tuple types `T1`, `T2`, ..., `Tn` have the same arity. This is more consistent than not grouping the declaration (ie: `(..T1), (..#T2), ..., (..Tn))`) because the signature using the declaration contains all the information required. +For Rust, using the syntax `(..(T1, T2, ..., Tn))` embeds the constraint that the variadic tuple types `T1`, `T2`, ..., `Tn` have the same arity. This is more consistent than not grouping the declaration (ie: `(..T1), (..T2), ..., (..Tn))`) because the signature using the declaration contains all the information required. We don't need to look at the implementation or body code to know the required constraint about the variadic tuple type arities. @@ -904,14 +866,6 @@ C++11 sets a decent precedent with its variadic templates, which can be used to When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) -## Variadic tuple for functions - -Supporting variadic tuple for function with recursive implementation over the variadic tuples is not possible. (See below). - -However, when the funtion is not recursive over the variadic tuple, it can be a nice addition to help implementation of libraries using tuples. - -In that case, the compiler must detect if there is such a recursion an issue a compile error. - ## Variadic tuple destructuration with multiple `..` A use case involving destructuration of multiple variadic tuple is a split operator for variadic tuples: From 255da4705f5344cc093f0183496d951472c437f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 3 Oct 2019 10:02:41 +0200 Subject: [PATCH 44/51] Fixed feedbacks from comments --- text/0000-variadic-tuples.md | 56 ++++++++++++------------------------ 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 2a1e8b13f7a..75d239f0132 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -149,22 +149,14 @@ Note2: If an expansion syntax contains multiple variadic tuple type identifiers, A _variadic tuple_ is a variable of a variadic tuple type. -### Declaration - -A variadic tuple can be declared like any other variable: - -```rust -fn my_func<(..T)>(variadic_tuple: (..T)) { ... } -``` - ### Destructuring a variadic tuple -A variadic tuple can be destructured to manipulate its members +A variadic tuple can be destructured to manipulate its members. There are 3 syntaxes possible to destructure a variadic tuple for a variadic tuple `(..T)`: 1. `(v @ ..)` of variadic tuple type `(..T)` -2. `(ref v @ ..))` of variadic tuple type `(..&T)` +2. `(ref v @ ..)` of variadic tuple type `(..&T)` 3. `(ref mut v @ ..)` of variadic tuple type `(..&mut T)` Also, the destructure pattern can be combined with other members. For instance: @@ -172,7 +164,7 @@ Also, the destructure pattern can be combined with other members. For instance: ```rust { let source: (Head, ..Tail) = _; - // `head` is a variable of type `Head` + // `head` is a variable of type `&Head` // `tail` is a tuple variable of type `(..&Tail)` let (ref head, ref tail @ ..) = source; } @@ -180,7 +172,7 @@ Also, the destructure pattern can be combined with other members. For instance: let mut source: (..L, ..R) = _; // `l` is a tuple variable of type `(..&mut L)` // `r` is a tuple variable of type `(..&mut R)` - let (ref mut @ l .. : (..L), ref mut r @ .. : (..R)) = source; + let (ref mut @ l .., ref mut r @ ..) = source; } ``` @@ -295,7 +287,7 @@ where } ``` -## The `Hash`trait +## The `Hash` trait Let's implement the `Hash` trait: @@ -371,27 +363,19 @@ struct MyStruct<(..T)> where ..(T: Clone) { ... } ``` -variadic tuple type expansion +* variadic tuple type ```ebnf var_tuple_type_exp : raw_var_tuple_type_exp | par_var_tuple_type_exp; raw_var_tuple_type_exp : ".." type_expr; par_var_tuple_type_exp : "..(" type_expr ")"; ``` -variadic tuple type expansion in where bounds +* variadic bounds ```ebnf var_tuple_type_exp_where : "..(" type_expr ":" bound-list ")"; ``` -### Variadic tuple declaration - -The declaration of a variadic tuple variable is still a variable. Nothing new here. - -```rust -fn my_func<(..T)>(input: (..T)) { ... } -``` - -### Variadic tuple destructuration +### Destructuring a variadic tuple When destructuring a variadic tuple, we can destructure the variadic parts into tuple variables. The identifier is a variable of type `(..T)` or `(..&T)` or `(..&mut T)`, depending on the syntax used. @@ -403,7 +387,7 @@ When destructuring a variadic tuple, we can destructure the variadic parts into // v is a variable of type `(..&T)` let (ref v @ .., ref tail) = source; // v is a variable of type `(..&mut T)` - let (ref mut v @ ..), ref mut tail) = source; + let (ref mut v @ .., ref mut tail) = source; } // If we use `(..T)` = `(A, B, C)` as an example @@ -413,7 +397,7 @@ When destructuring a variadic tuple, we can destructure the variadic parts into // `let v = (a, b, c);` ``` -variadic tuple destructuration +* variadic tuple destructuration ```ebnf tuple_destr : "(" tuple_destr_ident_any [ "," tuple_destr_ident_any ] * ")"; tuple_destr_ident_any : [ tuple_destr_ident_var | tuple_destr_ident ]; @@ -481,7 +465,7 @@ where ..(K: Hash), { } ``` -variadic tuple iteration +* variadic tuple iteration ```ebnf for_var_tuple : "for" for_tuple_ident ? for_tuple_type_ident ? "@in" for_tuple_ident ? for_tuple_type_ident ? block_expr; for_tuple_ident : ident | "(" ident [ "," ident ] * ")"; @@ -500,7 +484,7 @@ let result: (..Option<&V>) = (for (ref k, map) @in (k, &self.maps) }); ``` -Note2: When using multiple for loops to create a tuple, the parenthesis must be explicit: +Note: When using multiple for loops to create a tuple, the parenthesis must be explicit: ```rust // We have a single tuple with all member at the same level fn append<(..L), (..R)>(l: (..L), r: (..R)) -> (..L, ..R) { @@ -719,11 +703,7 @@ hint: expected `impl<(..(K, V))>` instead of `impl<(..K), (..V)>` ### Invalid variadic tuple pattern matching -The variadic tuple declaration is invalid when it can't be parsed as either: - -- `(id @ ..)` -- `(ref id @ ..)` -- `(ref mut id @ ..)` +The variadic tuple declaration is invalid when it can't be parsed. ```rust struct MyStruct<(..T)> { @@ -813,7 +793,7 @@ where } // Utility to create a tuple of a single type, for instance: ToT = (..T) -> (..usize) -// We could have a syntaxic sugar to do this (future RFC?) +// We could have a syntactic sugar to do this (future RFC?) trait ToT { type Value = T; } @@ -915,7 +895,7 @@ However when such a feature will land in Rust, supporting variadic tuple for fun Note, see the RFC issues [290](https://github.com/rust-lang/rfcs/issues/290) and [1053](https://github.com/rust-lang/rfcs/issues/1053). -## Syntaxic sugar to make enclosing parenthesis optional in variadic tuple declarations +## Make enclosing parenthesis optional in variadic tuple declarations For generic parameter group containing one variadic tuple type, it may be conveninent to omit the parenthesis. @@ -932,7 +912,7 @@ MyStruct::; MyStruct::; ``` -## Syntaxic sugar to make enclosing parenthesis optional in for loop +## Syntactic sugar to make enclosing parenthesis optional in for loop In for loop iterating only on variadic tuples, the parenthesis may be dropped @@ -948,7 +928,7 @@ In for loop iterating only on variadic tuples, the parenthesis may be dropped ``` -## Syntaxic sugar to create tuple with the same type of a specific arity +## Syntactic sugar to create tuple with the same type of a specific arity Consider this use case: ```rust @@ -967,7 +947,7 @@ fn tuple_of_hashes<(..T)>((..t): (..T)) -> (..::Value) { ``` We use the `ToT` trait to produce a tuple of `usize` with the same arity of `T`. -We may find a syntaxic sugar to do the same thing, like: `(@T..usize)` meaning: +We may find a syntactic sugar to do the same thing, like: `(@T..usize)` meaning: evaluate the `(..usize)` variadic tuple type expansion with the arity of `T`. So it would be rewritten as: From c5810cca50ef3e7516162d5a6dfc05ac5bb214c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 3 Oct 2019 10:04:46 +0200 Subject: [PATCH 45/51] Added formatting --- text/0000-variadic-tuples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 75d239f0132..5c399cb85e1 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -341,7 +341,7 @@ MyStruct::<((usize, bool), (i8, f32))> { ... } // `(..R)` is `(bool, f32)` ``` -variadic tuple type declaration +* variadic tuple type declaration ```ebnf var_tuple_type_decl : single_var_tuple_decl | multiple_var_tuple_decl; single_var_tuple_decl : "(.." ident ")"; From 7d787a0e08ba08df115cfdbca52676e629b2567e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Thu, 3 Oct 2019 10:09:17 +0200 Subject: [PATCH 46/51] Updated generalized type ascription link --- text/0000-variadic-tuples.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 5c399cb85e1..629e898cb21 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -868,6 +868,8 @@ fn split<(..L), (..R)>(value: (..L, ..R)) -> ((..L), (..R)) { } ``` +In that case it will requires the [generalized type ascription](https://github.com/rust-lang/rfcs/pull/2522) feature. + # Future possibilities From d0469b4603992fc7df71d46e57b7be28740bcd12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Fri, 4 Oct 2019 08:57:20 +0200 Subject: [PATCH 47/51] Removed dynamic libraries issue Dynamic libraries are not an issue as machine code for required implementation is embedded in dylibs --- text/0000-variadic-tuples.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 629e898cb21..ae7cd4f9d96 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -841,11 +841,6 @@ C++11 sets a decent precedent with its variadic templates, which can be used to [unresolved-questions]: #unresolved-questions -## Dynamic libraries tuple implementation assumption - -When using dynamic libraries, client libraries may relies that the host contains code up to a specific tuple arity. So we need to have a -way to enforce the compiler to generate all the implementation up to a specific tuple arity. (12 will keep backward comptibility with current `std` impl) - ## Variadic tuple destructuration with multiple `..` A use case involving destructuration of multiple variadic tuple is a split operator for variadic tuples: From dee3fcaa06709597deb2830b8387e7c009d2070d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 7 Oct 2019 09:29:51 +0200 Subject: [PATCH 48/51] Added todo in drawbacks --- text/0000-variadic-tuples.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index ae7cd4f9d96..a2177f8db5a 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -731,6 +731,8 @@ note: expected `(id @ ..)` or `(ref id @ ..)` or `(ref mut id @ ..)` [drawbacks]: #drawbacks +TODO + # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives From 5b5e6b560822b2f1355d766173a15fc578b0c561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 7 Oct 2019 09:43:12 +0200 Subject: [PATCH 49/51] Updated Bounding variadic tuples in patterns --- text/0000-variadic-tuples.md | 50 +++++------------------------------- 1 file changed, 7 insertions(+), 43 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index a2177f8db5a..033b0a892de 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -149,52 +149,16 @@ Note2: If an expansion syntax contains multiple variadic tuple type identifiers, A _variadic tuple_ is a variable of a variadic tuple type. -### Destructuring a variadic tuple - -A variadic tuple can be destructured to manipulate its members. - -There are 3 syntaxes possible to destructure a variadic tuple for a variadic tuple `(..T)`: +### Bounding variadic tuples in patterns -1. `(v @ ..)` of variadic tuple type `(..T)` -2. `(ref v @ ..)` of variadic tuple type `(..&T)` -3. `(ref mut v @ ..)` of variadic tuple type `(..&mut T)` - -Also, the destructure pattern can be combined with other members. For instance: +We can use `..` to bound variables to variadic tuples. ```rust -{ - let source: (Head, ..Tail) = _; - // `head` is a variable of type `&Head` - // `tail` is a tuple variable of type `(..&Tail)` - let (ref head, ref tail @ ..) = source; -} -{ - let mut source: (..L, ..R) = _; - // `l` is a tuple variable of type `(..&mut L)` - // `r` is a tuple variable of type `(..&mut R)` - let (ref mut @ l .., ref mut r @ ..) = source; -} - -``` - -Examples: - -```rust -// The function argument is destructured as a variadic tuple with identifier `v` -fn my_func((head, v @ ..): (Head, ..T)) -> (..T) { - ... -} - -impl Clone for (Head, ..T) -where - ..(T: Clone), - Head: Clone, { - fn clone(&self) -> Self { - // We destructure `*self` which has a variadic tuple type `(Head, ..T)` - let (ref head, ref v @ ..) = *self; - ... - } -} +// Examples +let source: (Head, ..Tail) +let (head, tail @ ..): (Head, (..Tail)) = source; +let (head, tail @ ..): (&Head, (..&Tail)) = &source; +let (head, tail @ ..): (&mut Head, (..&mut Tail)) = &mut source; ``` ### Iterating over variadic tuple From 2f006e408f1784a8bee0d1c24e1583a8c7f6ea32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 7 Oct 2019 09:45:17 +0200 Subject: [PATCH 50/51] Updated description --- text/0000-variadic-tuples.md | 1 + 1 file changed, 1 insertion(+) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index 033b0a892de..c268297ba93 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -152,6 +152,7 @@ A _variadic tuple_ is a variable of a variadic tuple type. ### Bounding variadic tuples in patterns We can use `..` to bound variables to variadic tuples. +We can as well bind by reference depending on the original expression's type. ```rust // Examples From 931a5ccd631a72503308a2a32810105a1f3442df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Vauchelles?= Date: Mon, 7 Oct 2019 10:15:36 +0200 Subject: [PATCH 51/51] Updated motivation section --- text/0000-variadic-tuples.md | 79 ++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/text/0000-variadic-tuples.md b/text/0000-variadic-tuples.md index c268297ba93..b55443d314c 100644 --- a/text/0000-variadic-tuples.md +++ b/text/0000-variadic-tuples.md @@ -26,15 +26,11 @@ Variadic tuple will provide several benefits considering trait implementation fo - Implementations will be easier to read and maintain - The compiler will compile implementation only for required tuple arity -# Guide-level explanation - -[guide-level-explanation]: #guide-level-explanation +## Use cases -Let's call a _variadic tuple type_ a tuple type with an arbitrary arity and a _variadic tuple_ an instance of a variadic tuple type. +### `Hash` trait -A variadic tuple type is declared with `(..T)` and a variadic tuple type can be expanded with `(..Vec)`. - -Note: To illustrate the RFC, we will use the current implementation of the `Hash` trait for tuples. +We can look at the current implementation of the `Hash` trait to see the difference with the suggested implementation: ```rust // Quote from Rust source code @@ -66,6 +62,75 @@ macro_rules! last_type { } ``` +The implementation will translate to: +```rust +impl<(..T), Last> Hash for (..T, Last) +where + ..(T: Hash,), + Last: Hash + ?Sized, { + + #[allow(non_snake_case)] + fn hash(&self, state: &mut S) { + let (ref tuple @ .., ref last) = *self; + for member @in tuple { + member.hash(state); + }; + last.hash(state); + } +} +``` + + +### Easier zero cost abstraction with tuples + +We can use tuples as list of types, and use ZST i ntuples to define behaviours only at compile time. + +For instance, we can use a ZST to define a capability and a tuple as a list of capabilities. +In that way, we can define implementaions that can only be used for specific capabilities: + +```rust +// We define 4 capabilities here +struct CanRead; +struct CanAdd; +struct CanWrite; +struct CanRemove; + +struct Token<(..C)>; + +// A helper to know if a tuple contains a specific type +trait Has { +const VALUE: bool; +} +impl Has for () { +const VALUE: bool = false; +} +impl Has for (Head, ..Tuple) +where (..Tuple): Has, { +const VALUE: bool = TypeId::of::() == TypeId::of::() || (..Tuple)::VALUE; +} + +// Use this function only with tokens with read capabitilites +fn read<(..T)>(token: Token<(..T)>) +where T: Has { + // We use the static_assert crate here, the compiler will issue an error if we use an invalid token. + const_assert!(T::Value); +} +``` + +# Guide-level explanation + +[guide-level-explanation]: #guide-level-explanation + + +In Rust, you can combine any number of types together to form a tuple. For example, you could have a function which orders a meal that returns a Drink, a Meal, and a Side. We could represent this as the tuple (Drink, Meal, Side). + +In this case, the tuple has three items, but really, we can have any number. If we have no items, we get (), the "empty tuple" or "unit" type. We can even put a type T in a tuple with only one item, whose type is (T,). + +If we want to be able to cover any size of tuple, we use what's called a variadic tuple type, whose instances are variadic tuples. + + +A variadic tuple type is declared with `(..T)` and a variadic tuple type can be expanded with `(..Vec)`. + ## Variadic tuple type ### Declaration