diff --git a/text/0000-derive-bound-control.md b/text/0000-derive-bound-control.md new file mode 100644 index 00000000000..7b502e4b2d1 --- /dev/null +++ b/text/0000-derive-bound-control.md @@ -0,0 +1,904 @@ +- Feature Name: derive_bound_control +- Start Date: 2018-02-26 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +This RFC gives users a way to control trait bounds on derived +implementations by allowing them to omit default bounds on type +parameters or add bounds for field types. This is achieved with +the two attributes `#[derive_no_bound(Trait)]` and +`#[derive_field_bound(Trait)]`. + +The semantics of `#[derive_no_bound(Trait)]` for a type parameter `P` are: +> The type parameter `P` does not need to satisfy `Trait` for any field +> referencing it to be `Trait` + +The semantics of `#[derive_field_bound(Trait)]` on a field are that the type +of the field is added to the `where`-clause of the referenced `Trait` +as: `FieldType: Trait`. + +# Motivation +[motivation]: #motivation + +The deriving mechanism of Rust allows the author to prototype faster and reduce +pain by significantly reducing boilerplate in many cases. Deriving also allows +readers of code to easily see when a bunch of simple delegating `impl`s are +defined instead of reading such boilerplate as manual `impl`s. + +Unfortunately, there are many cases where deriving fails to produce +the code intended by manual implementations. Either the `impl`s produced +are too restrictive by imposing bounds that shouldn't be there, which is +solved by `#[derive_no_bound(..)]`, or not enough bounds are imposed. +When the latter is the case, deriving may fail entirely. This is solved +by `#[derive_field_bound(..)]`. + +The crate `serde` provides the attribute `#[serde(bound = "T: MyTrait")]`. +This can be used solve the same issues as in this RFC. This RFC proposes a +common mechanism to be used for all derivable traits in the standard library, +as well as in custom derive macros. By doing so, a common language is given +to users who can now use this method regardless of what trait is being derived +in all of the ecosystem. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +## Removing bounds in derive with `#[derive_no_bound]` + +Let's consider a simple new-type around an `Arc`: + +```rust +#[derive(Clone)] +struct MyArc<#[derive_no_bound] T>(Arc); +``` + +or, to apply `#[derive_no_bound]` to all type parameters, which is in this case +equivalent: + +```rust +#[derive(Clone)] +#[derive_no_bound] +struct MyArc(Arc); +``` + +The resulting `impl` will be of the form: + +```rust +// There is no bound T: Clone! +impl Clone for MyArc { /* .. */ } +``` + +We see that `#[derive_no_bound]` on `T` is an instruction to the derive macro +for `Clone` that it should not add `T: Clone`. This applies to any trait being +derived and not just `Clone`. This works since `Arc: Clone` holds regardless +of whether `T: Clone` or not. + +But what if you want to differentiate between the deriving behavior +of various traits? Let's derive another trait, `PartialEq`, but still +use `#[derive_no_bound(..)]`: + +```rust +#[derive(Clone, PartialEq)] +struct MyArc<#[derive_no_bound(Clone)] T>(Arc); +``` + +We can equivalently write: + +```rust +#[derive(Clone, PartialEq)] +#[derive_no_bound(Clone)] +struct MyArc(Arc); +``` + +Here, a meaningful `PartialEq` for `MyArc` requires that `T: PartialEq`. +Therefore, we don't want that bound to be removed from the `impl` of `PartialEq` +for `MyArc`. Instead, we use `#[derive_no_bound(Clone)]` and the resulting +`impl`s will be: + +```rust +// As before: +impl Clone for MyArc { /* .. */ } + +// And `T: PartialEq` is there as expected! +impl PartialEq for MyArc { /* .. */ } +``` + +[proptest]: https://docs.rs/proptest/ +[`Strategy`]: https://docs.rs/proptest/*/proptest/strategy/trait.Strategy.html + +Let's consider this scenario in action with a real world example and create +a wrapper around a trait object of [`Strategy`] in the crate [proptest]: + +```rust +#[derive(Clone, Debug)] +pub struct ArcStrategy<#[derive_no_bound(Clone)] T> { + source: Arc>>> +} + +// Debug is required as seen in these snippets: +pub trait ValueTree { type Value: Debug; } +pub trait Strategy: Debug { type Value: ValueTree; } +``` + +In this case, the generated code will be: + +```rust +impl Clone for ArcStrategy { /* .. */ } +impl Debug for ArcStrategy { /* .. */ } +``` + +We have so far considered a single type parameter. Let's now add another. +We consider a `Refl` encoding in Rust: + +```rust +use std::marker::PhantomData; + +/// A proof term that `S` and `T` are the same type (type identity). +/// This type is only every inhabited when `S` is nominally equivalent to `T`. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive_no_bound] +pub struct Id(PhantomData<(*mut S, *mut T)>); + +// .. +``` + +This will generate the following `impl`s: + +```rust +impl Copy for Id { /* .. */ } +impl Clone for Id { /* .. */ } +impl Debug for Id { /* .. */ } +impl Hash for Id { /* .. */ } +impl PartialEq for Id { /* .. */ } +impl Eq for Id { /* .. */ } +impl PartialOrd for Id { /* .. */ } +impl Ord for Id { /* .. */ } +``` + +In this case in particular, we've reduced a lot of clutter as well as +unnecessary typing. + +Why do we need to be able to remove bounds on different parameters +independently? Because their behavior may diverge. Let's consider such +a type where this is the case: + +```rust +#[derive(Clone)] +struct Foo<#[derive_no_bound] S, T> { + bar: Arc, + baz: T, +} +``` + +The generated code in this case is: + +```rust +impl Clone for Foo { /* .. */ } +``` + +With an even more complex scenario we have: + +```rust +#[derive(Clone, PartialEq)] +struct Foo<#[derive_no_bound(Clone)] S, + T, + #[derive_no_bound(Clone, PartialEq)] U> { + bar: Arc, + baz: T, + quux: PhantomData +} +``` + +and the generated code is: + +```rust +impl Clone for Foo { /* .. */ } +impl Clone for Foo { /* .. */ } +``` + +### `#[derive_no_bound]` is not `#[derive_ignore]` + +Consider the case of `Filter` as in: + +```rust +/// An iterator that filters the elements of `iter` with `predicate`. +#[derive(Clone)] +pub struct Filter { + iter: I, + predicate: P, +} +``` + +This type provides the `impl`: +```rust +impl Debug for Filter +``` + +Notice in particular that `P` lacks the bound `Debug`. +To derive `Debug` instead, you might want to reach for `#[derive_no_bound]` +on `P` in this case as in: + +```rust +#[derive(Clone, Debug)] +pub struct Filter { + iter: I, + predicate: P, +} +``` + +This however, does not work! Why? Because `#[derive_no_bound]` on `P` means that: +> The parameter `P` does not __need__ to satisfy `Trait` for any field +> referencing it to be `Trait` + +It does not mean that: +> Ignore the field `predicate` + +Therefore, deriving `Debug` will not work as above since the deriving +mechanism of `Debug` will try to generate an `impl` which does not work: + +```rust +impl Debug for Filter { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.debug_struct("Filter") + .field("iter", &self.iter) + .field("predicate", &self.predicate) // <-- Not OK! + .finish() + } +} +``` + +Instead the proper `impl`: + +```rust +impl Debug for Filter { + fn fmt(&self, f: &mut Formatter) -> Result { + f.debug_struct("Filter") + .field("iter", &self.iter) + .finish() + } +} +``` + +## Adding bounds on field types with `#[derive_field_bound]` + +To gain more exact control of the bounds put on `impl`s generated by +deriving macros you can also use the `#[derive_field_bound(..)]` attribute. + +A simple example is: + +```rust +#[derive(Clone, PartialEq, PartialOrd)] +struct Foo { + #[derive_field_bound] + bar: Bar, + baz: Baz +} +``` + +This will generate the following `impl`s: + +```rust +impl Clone for Foo +where Bar: Clone { /* .. */ } + +impl Clone for Foo +where Bar: PartialEq { /* .. */ } + +impl Clone for Foo +where Bar: PartialEq { /* .. */ } +``` + +We can also apply this to a specific trait `impl`: + +```rust +#[derive(Clone, PartialEq, PartialOrd)] +struct Foo { + #[derive_field_bound(Clone)] + bar: Bar, + #[derive_field_bound(Clone)] + baz: Baz +} +``` + +This will generate the following `impl`s: + +```rust +impl Clone for Foo +where Bar: Clone, Baz: Clone { /* .. */ } + +impl Clone for Foo { /* .. */ } + +impl Clone for Foo { /* .. */ } +``` + +We can simplify the definition above to: + +```rust +#[derive(Clone, PartialEq, PartialOrd)] +#[derive_field_bound(Clone)] +struct Foo { + bar: Bar, + baz: Baz +} +``` + +or if we want to do this for all derived traits: + +```rust +#[derive(Clone, PartialEq, PartialOrd)] +#[derive_field_bound] +struct Foo { + bar: Bar, + baz: Baz +} +``` + +### A note on visibility + +It is important to note that the following generated `impl`: + +```rust +impl Clone for Foo where Bar: Clone { /* .. */ } +``` + +only works if `Foo` is at least as visible as `Bar`. +In particular, a Rust compiler will reject the `impl` above +if `Bar` is private and `Foo` is `pub`. + +## Guidance to custom derive macro authors + +The concepts in this RFC should be taught to derive macro users, by explaining +how the attributes work with derivable traits in the standard library. +These are fairly advanced concepts. As such, they should be deferred to the end +of the book's explanation of Derivable Traits in the appendix section `21.3`. + +For users looking to implement custom derive macros, these concepts should +be explained in conjunction with guides on how to implement these macros. + +Ideally, the `syn` crate, or crates in the same space such as `synstructure`, +should also facilitate handling of the proposed attributes. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +The attributes `#[derive_no_bound(..)]` and `#[derive_field_bound(..)]` for +controlling how bounds are used by derive macros for standard library traits +and should be used for those outside in custom derive macros. + +## `#[derive_no_bound(..)]` + +### Grammar + +The attribute `#[derive_no_bound(..)]` can be placed on type definitions +directly (`struct`, `enum`, `union`) or on formal type parameters. The attribute +has the following grammar: + +```enbf +no_bound_attr : "#" "[" "derive_no_bound" no_bound_traits? "]" ; +no_bound_traits : "(" trait_list ","? ")" ; +trait_list : ident | ident "," trait_list ; +``` + +### Semantics - on a formal type parameter + +Formally: Assuming a formal type parameter `P`, and the attribute +`#[derive_no_bound(Trait)]` on `P` for a given specific trait `Trait`, +specifying the attribute `#[derive(Trait)]` shall **NOT** add a bound `P: Trait` +to either the `where`-clause or directly where `P` is brought into scope +(`impl`) in the `impl<.., P, ..> Trait<..> for Type<.., P, ..>` +generated by a derive macro for `Trait`. This does not necessarily mean that +the field which in some way references `P` does not need to implement the +`Trait` in question. + +When `#[derive_no_bound(..)]` contains a comma separated list of traits, +these semantics will apply to each trait referenced but not other traits. + +When `#[derive_no_bound]` is used (with no traits referenced), these rules will +apply to all derived traits. + +#### An example + +Given the following type definition: + +```rust +#[derive(Clone)] +struct Foo<#[derive_no_bound] S, T> { + bar: Arc, + baz: T, +} +``` + +The generated `impl` is: + +```rust +impl // <-- S: Clone is missing +Clone for Foo { /* .. */ } +``` + +### Semantics - on a type + +When `#[derive_no_bound(..)]` is applied directly on a type, this is equivalent +to specifying the identical attribute on each formal type parameter of the type. + +#### An example + +Consider a `Refl` encoding in Rust: + +```rust +use std::marker::PhantomData; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive_no_bound] +pub struct Id(PhantomData<(*mut S, *mut T)>); +``` + +The generated `impl`s are: + +```rust +impl Copy for Id { /* .. */ } +impl Clone for Id { /* .. */ } +impl Debug for Id { /* .. */ } +impl Hash for Id { /* .. */ } +impl PartialEq for Id { /* .. */ } +impl Eq for Id { /* .. */ } +impl PartialOrd for Id { /* .. */ } +impl Ord for Id { /* .. */ } +``` + +## `#[derive_field_bound(..)]` + +### Grammar + +The attribute `#[derive_field_bound(..)]` can be placed on type definitions +directly (`struct`, `enum`, `union`) or on their fields. Note in particular +that they may not be specified on variants of `enum`s. The attribute has the +following grammar: + +```enbf +field_bound_attr : "#" "[" "derive_field_bound" field_bound_traits? "]" ; +field_bound_traits : "(" trait_list ","? ")" ; +trait_list : ident | ident "," trait_list ; +``` + +### Semantics - on a field + +Formally: Assuming a field `F`, either named or unnamed, of +type `FieldType`, and the attribute `#[derive_field_bound(Trait)]` +on `F` for a specific trait`Trait`, specifying the attribute +`#[derive(Trait)]` shall add a bound `FieldType: Trait` in the +`where`-clause in the `impl<..> Trait<..> for Type<..>` generated +by a derive macro for `Trait`. + +When `#[derive_field_bound(..)]` contains a comma separated list of traits, +these semantics will apply to each trait referenced but not other traits. + +When `#[derive_field_bound]` is used (with no traits referenced), these rules +will apply to all derived traits. + +#### An example + +Given the following type definition: + +```rust +#[derive(Clone, PartialEq, PartialOrd)] +struct Foo { + #[derive_field_bound(Clone)] + bar: Bar, + baz: Baz +} +``` + +The generated `impl`s are: + +```rust +impl Clone for Foo +where Bar: Clone { /* .. */ } // <-- Note the where clause! + +impl PartialEq for Foo { /* .. */ } + +impl PartialOrd for Foo { /* .. */ } +``` + +### Semantics - on a type + +When `#[derive_field_bound(..)]` is applied directly on a type, this is +equivalent to specifying the identical attribute on each field of the type. + +#### An example + +Given the following type definition: + +```rust +#[derive(Clone, PartialEq, PartialOrd)] +#[derive_field_bound(Clone)] +struct Foo { + bar: Bar, + baz: Baz +} +``` + +The generated `impl`s are: + +```rust +impl Clone for Foo +where Bar: Clone, Baz: Clone { /* .. */ } // <-- Note! + +impl PartialEq for Foo { /* .. */ } + +impl PartialOrd for Foo { /* .. */ } +``` + +## Errors +[errors]: #errors + +An error should be issued if: + +1. `#[derive_no_bound]` is specified on a type definition without type parameters. + +2. `#[derive_no_bound(Trait)]` is specified on a type definition which does + not derive `Trait`. + +3. `#[derive_no_bound]` is specified on a type definition which does not derive + any trait. + +4. `#[derive_field_bound]` is specified on a type without fields. + +5. `#[derive_field_bound]` is specified on a field with a type which is less + visible than the type which contains the field. If `#[derive_field_bound]` + is applied on the type, then this rule applied for all fields of the type. + +6. `#[derive_field_bound(Trait)]` is specified on a field of a type definition + which does not derive `Trait`. + +7. `#[derive_field_bound]` is specified on a field of a type definition which + does not derive any trait. + +8. `#[derive_field_bound(Trait)]` is specified on a type definition and `Trait` + is registered for deriving by a custom macro which specifies + `#[proc_macro_derive(Trait, attributes())]` where `` + does not mention `derive_field_bound`. If `#[derive_field_bound]` is + specified instead, then this applies to all traits derived. + This also applies to `#[derive_no_bound]`. + +## Deriving of standard library traits + +Deriving any standard library trait will obey the semantics here specified. + +## Custom derive macros + +All custom derive macros as **encouraged** to follow the semantics here +specified so that a consistent experience is maintained in the ecosystem. + +## Structural equality + +[RFC 1445]: https://github.com/rust-lang/rfcs/pull/1445 + +[RFC 1445] and Rust currently adds the attribute `#[structural_match]` when +a type definition has `#[derive(PartialEq, Eq)]` on it and all the fields of +the type are also `#[structural_match]`. + +To use `const` as the pattern in a match arm, it has to be of a type that is +`#[structural_match]`. If it is not, as in the example below: + +```rust +fn main() { + use std::marker::PhantomData; + + pub const BOO: PhantomData = PhantomData; + + match PhantomData { + BOO => {} + } +} +``` + +... an error will be emitted saying that: + +```rust +error: to use a constant of type `std::marker::PhantomData` in a pattern, `std::marker::PhantomData` must be annotated with `#[derive(PartialEq, Eq)]` + --> src/main.rs:7:9 + | +7 | BOO => {} + | ^^^ +``` + +With respect to `#[structural_match]` this RFC does two things: + +["structural match check"]: https://github.com/rust-lang/rust/blob/58e1234cddd996378cb9df6bed537b9c08a6df73/src/libsyntax/ext/derive.rs#L73-L76 + +1. The ["structural match check"] will ignore `#[derive_no_bound]` and + `#[derive_field_bound]`. + +2. `PhantomData` will be defined as: + +```rust +#[derive(PartialEq, Eq, ...)] +#[derive_no_bound] +#[lang_item = "phantom_data"] +struct PhantomData; +``` + +With this new definition of `PhantomData`, the error above will not be +emitted and the example program will be accepted. + +This change does not move us from structural matching. A `PhantomData` +can be compared with another `PhantomData` by doing a `memcmp` logically. +This is so since a zero sized type does not exist in memory and so our logical +`memcmp` would always return `true`. Thus, two `PhantomData::`s are +structurally equal, and therefore `#[structural_match]` safely applies. +Note however that `T != U => ! [PhantomData: PartialEq]`. + +All type definitions with type parameters must use those parameters. +In the end, all valid uses of `#[derive_no_bound(PartialEq, Eq)]` must at +some depth involve either ignoring a field in `PartialEq`, in which case +`#[structural_match]` does not apply, or must involve a `PhantomData` +for which `#[structural_match]` did apply safely. + +# Drawbacks +[drawbacks]: #drawbacks + +1. It imposes expectations upon custom derive macro authors which they do + not have time for. This can be mitigated by helper crates. + +2. Flexible deriving is a nice-to-have feature but does not enable users to + express things otherwise not expressible. Arguably, the now-derivable + `impl`s should be implemented manually. + +3. The complexity of the derive system is increased. + +# Rationale and alternatives +[alternatives]: #alternatives + +The designs proposed by this RFC aims to make deriving cover `impl`s +that are not derivable today. The design has been considered against +real world scenarios. Some trade-offs and choices are discussed in the +[Unresolved questions][unresolved] section. + +As with any RFC, an alternative is to say that the status quo is good enough, +but for the reasons mentioned in the [motivation], steps should be taken to +make the derive system of Rust more flexible. + +One alternative design of this RFC would be to only permit the form +`#[derive_bound(, T: )]` and then call it +a day since the form is strictly more general. However, this form is +also less automating for a lot of cases. + +# Prior art +[prior-art]: #prior-art + +## Haskell + +[RFC 534]: https://github.com/rust-lang/rfcs/blob/master/text/0534-deriving2derive.md + +The deriving mechanism of Rust was inspired by Haskell, a fact evidenced by +the change in [RFC 534] where `#[deriving(..)]` became `#[derive(..)]`. + +As Haskell does not have a feature similar to Rust's attributes, it is not +possible to configure deriving mechanisms in Haskell. Therefore, there is no +prior art there. The features proposed here would be unique to Rust. + +## The [`derivative`] crate + +[`derivative`]: https://mcarton.github.io/rust-derivative/ + +There is some prior art among crates in Rust. The crate [`derivative`] provides +the ability to customize the deriving mechanisms of derivable standard library +traits. We will now discuss the customizations in that crate compared to this +RFC. + +The attribute form `#[derivative(Default(bound=""))]` is supported by the +`#[derive_no_bound]` attribute while the more general form is supported by +the form `#[bound(, T: )]`, which is discussed as a +possible extension of this RFC in the [Unresolved questions][unresolved]. +This more general form is also supported by the `serde` crate. + +# Unresolved questions +[unresolved]: #unresolved-questions + +## 1. Should `#[derive_no_bound]` be permitted on fields? + +Let's reconsider this example: + +```rust +#[derive(Clone, PartialEq)] +struct Foo<#[derive_no_bound(Clone)] S, + T, + #[derive_no_bound(Clone, PartialEq)] U> { + bar: Arc, + baz: T, + quux: PhantomData +} +``` + +We could also permit `#[derive_no_bound(..)]` on fields as well and +reformulate the above snippet as: + +```rust +#[derive(Clone, PartialEq)] +struct Foo { + #[derive_no_bound(Clone)] + bar: Arc, + baz: T, + #[derive_no_bound(Clone, PartialEq)] + quux: PhantomData +} +``` + +This is arguably more readable, but hinges on the semantics that bounds are +added by performing name resolution on each field's type and searching for type +parameters in those for usage. This behavior, while not very complex to encode +using visitors from the `syn` crate, is not used by derivable traits in the +standard library. Therefore, the experience would not be uniform across traits. + +Such behavior will also handle type macros poorly. Given the type position +macro `Foo` and type `Bar`: + +```rust +macro_rules! Foo { () => { T } } +struct Bar(Foo!()) +``` + +macros have no way to expand `Foo!()`. Arguably, using type position macros +are rare, but for standardization, a more robust approach is probably preferred. +A possibly path ahead is to provide the API proposed in [RFC 2320], in which +case using the field based approach becomes more robust. + +[RFC 2320]: https://github.com/rust-lang/rfcs/pull/2320 + +There's also the question of whether interpretations of `#[derive_no_bound]` +on fields is legible and intuitive, which misunderstandings so far during +development of this RFC has shown is not unlikely. + +## 2. Should `#[derive_field_bound]` and `#[derive_no_bound]` be combinable? + +Consider the following snippet: + +```rust +#[derive(Clone, PartialEq, PartialOrd)] +struct Foo { + #[derive_field_bound] + #[derive_no_bound(Clone)] + field: Bar +} +``` + +This could be interpreted as an instruction to provide the following `impl`s: + +```rust +impl Clone for Foo {..} +impl PartialEq for Foo where Bar: PartialEq {..} +impl PartialOrd for Foo where Bar: PartialOrd {..} +``` + +This is currently not proposed as it is deemed unnecessary, but the mechanism +should be considered. + +## 3. Should `#[derive_field_bound]` be named just `#[derive_bound]`? + +The latter is shorter, but less legible, wherefore we've opted to use +`#[derive_field_bound]` at the moment. + +## 4. Should the attributes not be prefixed with `derive_`? + +Prefixing with `derive_` is more legible and reduces the chance of conflict. +But it is also more verbose, especially when applied on type parameters. +The current thinking is that readability takes precedence over reducing +possible verbosity. In any case, prefixing with `derive_` is far less verbose +than manually implementing the trait. + +## 5. Permit `field: Vec<#[derive_field_bound] Arc>`? + +If so, `#[derive_bound]` is a more correct name. However, the current thinking +is that this requires parsing changes while also looking weird. This may +be a step too far - in such cases, manual `impl`s are probably better. +For these reasons, the RFC does not propose this mechanism currently. + +## 6. Permit `#[derive_bound(, T: )]`? + +[serde_bound_desc]: https://serde.rs/container-attrs.html#serdebound--t-mytrait + +Last but not least, the crate `serde` allows the attribute +`#[serde(bound = "T: MyBound")]` which replaces the `where` +clause of the `impl` generated by `serde`. This attribute +is [described][serde_bound_desc] as follows: + +> Where-clause for the `Serialize` and `Deserialize` impls. +> This replaces any trait bounds inferred by Serde. + +We could standardize this concept in the form of an attribute +`#[derive_bound(..)]` put on types with a syntax permitting: + ++ Replace bounds on impl of `Clone` and `PartialEq` with `T: Sync` + +```rust +#[derive_bound(Clone, PartialEq, T: Sync)] +``` + ++ Replace bounds on impl of `Clone` with `T: Sync + 'static` + +```rust +#[derive_bound(Clone, T: Sync + 'static)] +``` + ++ Replace bounds on all derived traits with `T: Copy` + +```rust +#[derive_bound(T: Copy)] +``` + ++ No bounds on impl of `Clone` and `PartialEq` + +```rust +#[derive_bound(Clone, PartialEq)] +``` + ++ No bounds on impl of `Clone` + +```rust +#[derive_bound(Clone)] +``` + ++ No bounds on all derived traits: + +```rust +#[derive_bound] +``` + +The syntax `TyVar: Bound` is however not allowed in attributes currently. +Changing this would require a change to the attribute grammar to permit: +`ident ":" bound`. + +Another option is to quote the bound as `"TyVar: Bound"` as done by `serde`. +This requires no larger changes, but is brittle, strange, and would require of +syntax highlighters to understand `#[derive_bound]` specially. Therefore, a more +permissible attribute syntax allowing subsets of bounds, expressions and types might be a good thing and can have positive effects elsewhere. + +[A real world example]: https://github.com/ppedrot/kravanenn/blob/61f089e2091d1f0c4eb57b2617532e7bee63508d/src/ocaml/values.rs#L10 + +[A real world example] of how `serde`'s attribute is used is: +```rust +#[derive(Debug, Clone, DeserializeState, Hash, PartialEq, Eq)] +#[serde(deserialize_state = "Seed<'de>")] +#[serde(bound(deserialize = + "T: DeserializeState<'de, Seed<'de>> + Send + Sync + 'static"))] +pub enum List { + Nil, + Cons(#[serde(deserialize_state)] ORef<(T, List)>), +} +``` + +with `#[bound]`, this is rewritten as: + +```rust +#[derive(Debug, Clone, DeserializeState, Hash, PartialEq, Eq)] +#[serde(deserialize_state = "Seed<'de>")] +#[derive_bound(Deserialize, + T: DeserializeState<'de, Seed<'de>> + Send + Sync + 'static)] +pub enum List { + Nil, + Cons(#[serde(deserialize_state)] ORef<(T, List)>), +} +``` + +## 7. Permit `#[derive_no_bound()]` and `#[derive_field_bound()]`? + +If we consider the exact syntax `#[derive_no_bound()]`, there are +two interpretations that come to mind: + +1. Equivalent to `#[derive_no_bound]`. +2. Equivalent to *"ignore the bound in an empty set of traits"*. + +The 2nd interpretation is useful for macros, while the 1st may make more +sense for a reader, which would just write `#[derive_no_bound]`. Since +the 2nd interpretation is more useful, it is probably more appropriate. +To avoid the confusion for users who write this manually, a warning could +be issued which macros may supress. + +## 8. Should the errors raised be warnings instead? + +Some, or most of the errors in the [errors] section of the +[reference-level explanation] could be warnings instead of errors to facilitate +for macro authors. This decision can be deferred to stabilization instead, or +even for post stabilization as errors of this kind can be lowered to warnings. \ No newline at end of file