2021-07-03 07:56:17 -07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
use proc_macro::{token_stream, Group, TokenStream, TokenTree};
|
2021-07-03 07:56:17 -07:00
|
|
|
|
|
|
|
pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
|
|
|
|
if let Some(TokenTree::Ident(ident)) = it.next() {
|
|
|
|
Some(ident.to_string())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn try_literal(it: &mut token_stream::IntoIter) -> Option<String> {
|
|
|
|
if let Some(TokenTree::Literal(literal)) = it.next() {
|
|
|
|
Some(literal.to_string())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-10 09:41:19 -07:00
|
|
|
pub(crate) fn try_string(it: &mut token_stream::IntoIter) -> Option<String> {
|
|
|
|
try_literal(it).and_then(|string| {
|
|
|
|
if string.starts_with('\"') && string.ends_with('\"') {
|
|
|
|
let content = &string[1..string.len() - 1];
|
|
|
|
if content.contains('\\') {
|
|
|
|
panic!("Escape sequences in string literals not yet handled");
|
|
|
|
}
|
|
|
|
Some(content.to_string())
|
|
|
|
} else if string.starts_with("r\"") {
|
|
|
|
panic!("Raw string literals are not yet handled");
|
2021-07-03 07:56:17 -07:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn expect_ident(it: &mut token_stream::IntoIter) -> String {
|
|
|
|
try_ident(it).expect("Expected Ident")
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn expect_punct(it: &mut token_stream::IntoIter) -> char {
|
|
|
|
if let TokenTree::Punct(punct) = it.next().expect("Reached end of token stream for Punct") {
|
|
|
|
punct.as_char()
|
|
|
|
} else {
|
|
|
|
panic!("Expected Punct");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-10 09:41:19 -07:00
|
|
|
pub(crate) fn expect_string(it: &mut token_stream::IntoIter) -> String {
|
|
|
|
try_string(it).expect("Expected string")
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn expect_string_ascii(it: &mut token_stream::IntoIter) -> String {
|
|
|
|
let string = try_string(it).expect("Expected string");
|
|
|
|
assert!(string.is_ascii(), "Expected ASCII string");
|
|
|
|
string
|
2021-07-03 07:56:17 -07:00
|
|
|
}
|
|
|
|
|
2023-03-23 05:35:10 -07:00
|
|
|
pub(crate) fn expect_group(it: &mut token_stream::IntoIter) -> Group {
|
|
|
|
if let TokenTree::Group(group) = it.next().expect("Reached end of token stream for Group") {
|
|
|
|
group
|
|
|
|
} else {
|
|
|
|
panic!("Expected Group");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-03 07:56:17 -07:00
|
|
|
pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {
|
|
|
|
if it.next().is_some() {
|
|
|
|
panic!("Expected end");
|
|
|
|
}
|
|
|
|
}
|
2023-04-24 01:11:38 -07:00
|
|
|
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
/// Parsed generics.
|
|
|
|
///
|
|
|
|
/// See the field documentation for an explanation what each of the fields represents.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// # let input = todo!();
|
|
|
|
/// 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() {
|
|
|
|
/// // ...
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
2023-04-24 01:11:38 -07:00
|
|
|
pub(crate) struct Generics {
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
/// The generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`).
|
|
|
|
///
|
|
|
|
/// Use this on type definitions e.g. `struct Foo<$decl_generics> ...` (or `union`/`enum`).
|
|
|
|
pub(crate) decl_generics: Vec<TokenTree>,
|
|
|
|
/// The generics with bounds (e.g. `T: Clone, const N: usize`).
|
|
|
|
///
|
|
|
|
/// Use this on `impl` blocks e.g. `impl<$impl_generics> Trait for ...`.
|
2023-04-24 01:11:38 -07:00
|
|
|
pub(crate) impl_generics: Vec<TokenTree>,
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
/// The generics without bounds and without default values (e.g. `T, N`).
|
|
|
|
///
|
|
|
|
/// Use this when you use the type that is declared with these generics e.g.
|
|
|
|
/// `Foo<$ty_generics>`.
|
2023-04-24 01:11:38 -07:00
|
|
|
pub(crate) ty_generics: Vec<TokenTree>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Parses the given `TokenStream` into `Generics` and the rest.
|
|
|
|
///
|
|
|
|
/// The generics are not present in the rest, but a where clause might remain.
|
|
|
|
pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) {
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
// The generics with bounds and default values.
|
|
|
|
let mut decl_generics = vec![];
|
2023-04-24 01:11:38 -07:00
|
|
|
// `impl_generics`, the declared generics with their bounds.
|
|
|
|
let mut impl_generics = vec![];
|
|
|
|
// Only the names of the generics, without any bounds.
|
|
|
|
let mut ty_generics = vec![];
|
|
|
|
// Tokens not related to the generics e.g. the `where` token and definition.
|
|
|
|
let mut rest = vec![];
|
|
|
|
// The current level of `<`.
|
|
|
|
let mut nesting = 0;
|
|
|
|
let mut toks = input.into_iter();
|
|
|
|
// If we are at the beginning of a generic parameter.
|
|
|
|
let mut at_start = true;
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
let mut skip_until_comma = false;
|
|
|
|
while let Some(tt) = toks.next() {
|
|
|
|
if nesting == 1 && matches!(&tt, TokenTree::Punct(p) if p.as_char() == '>') {
|
|
|
|
// Found the end of the generics.
|
|
|
|
break;
|
|
|
|
} else if nesting >= 1 {
|
|
|
|
decl_generics.push(tt.clone());
|
|
|
|
}
|
2023-04-24 01:11:38 -07:00
|
|
|
match tt.clone() {
|
|
|
|
TokenTree::Punct(p) if p.as_char() == '<' => {
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
if nesting >= 1 && !skip_until_comma {
|
2023-04-24 01:11:38 -07:00
|
|
|
// This is inside of the generics and part of some bound.
|
|
|
|
impl_generics.push(tt);
|
|
|
|
}
|
|
|
|
nesting += 1;
|
|
|
|
}
|
|
|
|
TokenTree::Punct(p) if p.as_char() == '>' => {
|
|
|
|
// This is a parsing error, so we just end it here.
|
|
|
|
if nesting == 0 {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
nesting -= 1;
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
if nesting >= 1 && !skip_until_comma {
|
2023-04-24 01:11:38 -07:00
|
|
|
// We are still inside of the generics and part of some bound.
|
|
|
|
impl_generics.push(tt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
TokenTree::Punct(p) if skip_until_comma && p.as_char() == ',' => {
|
2023-04-24 01:11:38 -07:00
|
|
|
if nesting == 1 {
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
impl_generics.push(tt.clone());
|
2023-04-24 01:11:38 -07:00
|
|
|
impl_generics.push(tt);
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
skip_until_comma = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ if !skip_until_comma => {
|
|
|
|
match nesting {
|
2023-04-24 01:11:38 -07:00
|
|
|
// If we haven't entered the generics yet, we still want to keep these tokens.
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
0 => rest.push(tt),
|
|
|
|
1 => {
|
|
|
|
// Here depending on the token, it might be a generic variable name.
|
|
|
|
match tt.clone() {
|
|
|
|
TokenTree::Ident(i) if at_start && i.to_string() == "const" => {
|
|
|
|
let Some(name) = toks.next() else {
|
|
|
|
// Parsing error.
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
impl_generics.push(tt);
|
|
|
|
impl_generics.push(name.clone());
|
|
|
|
ty_generics.push(name.clone());
|
|
|
|
decl_generics.push(name);
|
|
|
|
at_start = false;
|
|
|
|
}
|
|
|
|
TokenTree::Ident(_) if at_start => {
|
|
|
|
impl_generics.push(tt.clone());
|
|
|
|
ty_generics.push(tt);
|
|
|
|
at_start = false;
|
|
|
|
}
|
|
|
|
TokenTree::Punct(p) if p.as_char() == ',' => {
|
|
|
|
impl_generics.push(tt.clone());
|
|
|
|
ty_generics.push(tt);
|
|
|
|
at_start = true;
|
|
|
|
}
|
|
|
|
// Lifetimes begin with `'`.
|
|
|
|
TokenTree::Punct(p) if p.as_char() == '\'' && at_start => {
|
|
|
|
impl_generics.push(tt.clone());
|
|
|
|
ty_generics.push(tt);
|
|
|
|
}
|
|
|
|
// Generics can have default values, we skip these.
|
|
|
|
TokenTree::Punct(p) if p.as_char() == '=' => {
|
|
|
|
skip_until_comma = true;
|
|
|
|
}
|
|
|
|
_ => impl_generics.push(tt),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => impl_generics.push(tt),
|
2023-04-24 01:11:38 -07:00
|
|
|
}
|
|
|
|
}
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
_ => {}
|
2023-04-24 01:11:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
rest.extend(toks);
|
|
|
|
(
|
|
|
|
Generics {
|
|
|
|
impl_generics,
|
rust: macros: add `decl_generics` to `parse_generics()`
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@proton.me>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240309155243.482334-1-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-03-09 08:53:25 -07:00
|
|
|
decl_generics,
|
2023-04-24 01:11:38 -07:00
|
|
|
ty_generics,
|
|
|
|
},
|
|
|
|
rest,
|
|
|
|
)
|
|
|
|
}
|