Support SystemParam types with const generics (#7001)

# Objective

* Currently, the `SystemParam` derive does not support types with const generic parameters.
  * If you try to use const generics, the error message is cryptic and unhelpful.
* Continuation of the work started in #6867 and #6957.

## Solution

Allow const generic parameters to be used with `#[derive(SystemParam)]`.
This commit is contained in:
JoJoJet 2022-12-25 00:06:23 +00:00
parent fa2b5f2b36
commit 0d98327ce7
2 changed files with 29 additions and 6 deletions

View file

@ -14,8 +14,8 @@ use syn::{
punctuated::Punctuated, punctuated::Punctuated,
spanned::Spanned, spanned::Spanned,
token::Comma, token::Comma,
DeriveInput, Field, GenericParam, Ident, Index, LitInt, Meta, MetaList, NestedMeta, Result, ConstParam, DeriveInput, Field, GenericParam, Ident, Index, LitInt, Meta, MetaList, NestedMeta,
Token, TypeParam, Result, Token, TypeParam,
}; };
struct AllTuples { struct AllTuples {
@ -416,7 +416,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
let lifetimeless_generics: Vec<_> = generics let lifetimeless_generics: Vec<_> = generics
.params .params
.iter() .iter()
.filter(|g| matches!(g, GenericParam::Type(_))) .filter(|g| !matches!(g, GenericParam::Lifetime(_)))
.collect(); .collect();
let mut punctuated_generics = Punctuated::<_, Token![,]>::new(); let mut punctuated_generics = Punctuated::<_, Token![,]>::new();
@ -425,12 +425,32 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
default: None, default: None,
..g.clone() ..g.clone()
}), }),
GenericParam::Const(g) => GenericParam::Const(ConstParam {
default: None,
..g.clone()
}),
_ => unreachable!(), _ => unreachable!(),
})); }));
let mut punctuated_generics_no_bounds = punctuated_generics.clone();
for g in &mut punctuated_generics_no_bounds {
match g {
GenericParam::Type(g) => g.bounds.clear(),
GenericParam::Lifetime(g) => g.bounds.clear(),
GenericParam::Const(_) => {}
}
}
let mut punctuated_type_generic_idents = Punctuated::<_, Token![,]>::new();
punctuated_type_generic_idents.extend(lifetimeless_generics.iter().filter_map(|g| match g {
GenericParam::Type(g) => Some(&g.ident),
_ => None,
}));
let mut punctuated_generic_idents = Punctuated::<_, Token![,]>::new(); let mut punctuated_generic_idents = Punctuated::<_, Token![,]>::new();
punctuated_generic_idents.extend(lifetimeless_generics.iter().map(|g| match g { punctuated_generic_idents.extend(lifetimeless_generics.iter().map(|g| match g {
GenericParam::Type(g) => &g.ident, GenericParam::Type(g) => &g.ident,
GenericParam::Const(g) => &g.ident,
_ => unreachable!(), _ => unreachable!(),
})); }));
@ -470,15 +490,15 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
} }
#[doc(hidden)] #[doc(hidden)]
type State<'w, 's, #punctuated_generic_idents> = FetchState< type State<'w, 's, #punctuated_generics_no_bounds> = FetchState<
(#(<#tuple_types as #path::system::SystemParam>::State,)*), (#(<#tuple_types as #path::system::SystemParam>::State,)*),
#punctuated_generic_idents #punctuated_generic_idents
>; >;
#[doc(hidden)] #[doc(hidden)]
#state_struct_visibility struct FetchState <TSystemParamState, #punctuated_generic_idents> { #state_struct_visibility struct FetchState <TSystemParamState, #punctuated_generics> {
state: TSystemParamState, state: TSystemParamState,
marker: std::marker::PhantomData<fn()->(#punctuated_generic_idents)> marker: std::marker::PhantomData<fn()->(#punctuated_type_generic_idents)>
} }
unsafe impl<'__w, '__s, #punctuated_generics> #path::system::SystemParamState for unsafe impl<'__w, '__s, #punctuated_generics> #path::system::SystemParamState for

View file

@ -1772,6 +1772,9 @@ mod tests {
#[derive(Resource)] #[derive(Resource)]
pub struct R<const I: usize>; pub struct R<const I: usize>;
#[derive(SystemParam)]
pub struct ConstGenericParam<'w, const I: usize>(Res<'w, R<I>>);
#[derive(SystemParam)] #[derive(SystemParam)]
pub struct LongParam<'w> { pub struct LongParam<'w> {
_r0: Res<'w, R<0>>, _r0: Res<'w, R<0>>,