Re: [PATCH v2 1/3] rust: macros: add `decl_generics` to `parse_generics()`

From: Martin Rodriguez Reboredo
Date: Wed Dec 13 2023 - 22:13:55 EST


On 12/13/23 19:08, Benno Lossin wrote:
The generic parameters on a type definition can specify default values.
Currently `parse_generics()` cannot handle this though. For example when
parsing the following generics:

<T: Clone, const N: usize = 0>

The `impl_generics` will be set to `T: Clone, const N: usize = 0` and
`ty_generics` will be set to `T, N`. Now using the `impl_generics` on an
impl block:

impl<$($impl_generics)*> Foo {}

will result in invalid Rust code, because default values are only
available on type definitions.

Therefore add parsing support for generic parameter default values using
a new kind of generics called `decl_generics` and change the old
behavior of `impl_generics` to not contain the generic parameter default
values.

Now `Generics` has three fields:
- `impl_generics`: the generics with bounds
(e.g. `T: Clone, const N: usize`)
- `decl_generics`: the generics with bounds and default values
(e.g. `T: Clone, const N: usize = 0`)
- `ty_generics`: contains the generics without bounds and without
default values (e.g. `T, N`)

`impl_generics` is designed to be used on `impl<$impl_generics>`,
`decl_generics` for the type definition, so `struct Foo<$decl_generics>`
and `ty_generics` whenever you use the type, so `Foo<$ty_generics>`.

Here is an example that uses all three different types of generics:

let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input);
quote! {
struct Foo<$($decl_generics)*> {
// ...
}

impl<$impl_generics> Foo<$ty_generics> {
fn foo() {
// ...
}
}
}

The next commit contains a fix to the `#[pin_data]` macro making it
compatible with generic parameter default values by relying on this new
behavior.

Signed-off-by: Benno Lossin <benno.lossin@xxxxxxxxx>
---
[...]

Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@xxxxxxxxx>