iroha icon indicating copy to clipboard operation
iroha copied to clipboard

Associated types and derive trait bounds

Open DCNick3 opened this issue 1 year ago • 0 comments

The problem & its context

In a lot of cases an automatically-derived trait bound is not correct. For example:

pub struct SetKeyValue<O: Identifiable> {
    pub object: O::Id,
    pub key: Name,
    pub value: JsonString,
}

The impl iroha_schema_derive generates a has incorrect trait bounds inferred: O: Identifiable + IntoSchema, while in reality what it needs is O: Identifiable + TypeId, O::Id: IntoSchema (that is, TypeId type parameters and IntoSchema on types used in the fields).

This is also a problem for std derives and serde.

The simplistic algorithm that only involves the type parameters is used in compiler-builtin derives, as well as in a lot of ecosystem crates (like serde). It's my understanding that this is mostly done because doing it correctly was hard due to limitations in trait type-checking (https://github.com/rust-lang/rust/issues/26925, https://github.com/serde-rs/serde/issues/2463).

In both serde and iroha_schema_derive there is an escape hatch that lets you specify the trait bounds manually. For std derives, there are crates that allow you to do this (for example derive-where).

Specifying trait bounds manually is not ideal, but works well enough for hand-written types. When using macro_rules! it's basically impossible though, since it requires generating string literals and passing then to attr macros. This is currently blocking me from implementing query projections (#5063)

parity_scale_codec has an algorithm that actually looks at the fields of structures it works on, and in most cases generates more correct bounds. There are still some issues with it, but they are much more mild. As a testament to parity_scale_codec's approach robustness: we did not have to use any of the escape hatch mechanisms provided (#[codec(dumb_trait_bound)], #[codec(encode_bound)], #[codec(decode_bound)], #[codec(mel_bound)]) by them in any of the iroha code.

The (local) solution

The solution, in the context of #5063, is twofold:

  • for iroha_schema_derive, which we control, use the trait bound generation algorithm from parity_scale_codec: #5132
  • for serde, which we don't control, and it doesn't seem likely that this issue will be remedied soon (serde-rs/serde#2784, serde-rs/serde#2463, serde-rs/serde#2736, serde-rs/serde#2727), the best solution I can come up with is to make a helper proc macro that will generate the right #[serde(bounds(...))] with a similar algorithm

DCNick3 avatar Oct 07 '24 09:10 DCNick3