fix generics for relationships (#18136)

# Objective
Allow Relationship to be derived for structs with generics.

fixes #18133
## Solution

"X" inside #[relationship_target(relationship = X)] was previously
parsed as Idents,
now they are parsed as syn::Type

## Testing

```rust
#[derive(Component)]
#[relationship(relationship_target = Attachments<T>)]
pub struct AttachedTo<T: Send + Sync + 'static> {
    #[relationship]
    pub entity: Entity,
    pub marker: PhantomData<T>,
}

#[derive(Component)]
#[relationship_target(relationship = AttachedTo<T>)]
pub struct Attachments<T: Send + Sync + 'static> {
    #[relationship]
    entities: Vec<Entity>,
    pub marker: PhantomData<T>,
}
```
This now compiles!
This commit is contained in:
Tim Overbeek 2025-03-03 20:33:29 +01:00 committed by GitHub
parent 236091adce
commit 173680944f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -10,7 +10,7 @@ use syn::{
spanned::Spanned, spanned::Spanned,
token::{Comma, Paren}, token::{Comma, Paren},
Data, DataStruct, DeriveInput, ExprClosure, ExprPath, Field, Fields, Ident, Index, LitStr, Data, DataStruct, DeriveInput, ExprClosure, ExprPath, Field, Fields, Ident, Index, LitStr,
Member, Path, Result, Token, Visibility, Member, Path, Result, Token, Type, Visibility,
}; };
pub fn derive_event(input: TokenStream) -> TokenStream { pub fn derive_event(input: TokenStream) -> TokenStream {
@ -474,11 +474,11 @@ enum RequireFunc {
} }
struct Relationship { struct Relationship {
relationship_target: Ident, relationship_target: Type,
} }
struct RelationshipTarget { struct RelationshipTarget {
relationship: Ident, relationship: Type,
linked_spawn: bool, linked_spawn: bool,
} }
@ -613,14 +613,14 @@ impl Parse for Relationship {
input.parse::<relationship_target>()?; input.parse::<relationship_target>()?;
input.parse::<Token![=]>()?; input.parse::<Token![=]>()?;
Ok(Relationship { Ok(Relationship {
relationship_target: input.parse::<Ident>()?, relationship_target: input.parse::<Type>()?,
}) })
} }
} }
impl Parse for RelationshipTarget { impl Parse for RelationshipTarget {
fn parse(input: syn::parse::ParseStream) -> Result<Self> { fn parse(input: syn::parse::ParseStream) -> Result<Self> {
let mut relationship_ident = None; let mut relationship_type: Option<Type> = None;
let mut linked_spawn_exists = false; let mut linked_spawn_exists = false;
syn::custom_keyword!(relationship); syn::custom_keyword!(relationship);
syn::custom_keyword!(linked_spawn); syn::custom_keyword!(linked_spawn);
@ -629,7 +629,7 @@ impl Parse for RelationshipTarget {
if input.peek(relationship) { if input.peek(relationship) {
input.parse::<relationship>()?; input.parse::<relationship>()?;
input.parse::<Token![=]>()?; input.parse::<Token![=]>()?;
relationship_ident = Some(input.parse::<Ident>()?); relationship_type = Some(input.parse()?);
} else if input.peek(linked_spawn) { } else if input.peek(linked_spawn) {
input.parse::<linked_spawn>()?; input.parse::<linked_spawn>()?;
linked_spawn_exists = true; linked_spawn_exists = true;
@ -644,7 +644,7 @@ impl Parse for RelationshipTarget {
} }
} }
let relationship = relationship_ident.ok_or_else(|| syn::Error::new(input.span(), "RelationshipTarget derive must specify a relationship via #[relationship_target(relationship = X)"))?; let relationship = relationship_type.ok_or_else(|| syn::Error::new(input.span(), "RelationshipTarget derive must specify a relationship via #[relationship_target(relationship = X)"))?;
Ok(RelationshipTarget { Ok(RelationshipTarget {
relationship, relationship,
linked_spawn: linked_spawn_exists, linked_spawn: linked_spawn_exists,