diff --git a/CHANGELOG.md b/CHANGELOG.md index c54e73f05a..b6aaf99f91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ You can find its changes [documented below](#060---2020-06-01). - macOS: Timers not firing during modal loop. ([#1028] by [@xStrom]) - GTK: Directory selection now properly ignores file filters. ([#957] by [@xStrom]) - GTK: Don't crash when receiving an external command while a file dialog is visible. ([#1043] by [@jneem]) +- Fix derive `Data` when type param bounds are defined ([#1058] by [@chris-zen]) - Ensure that `update` is called after all commands. ([#1062] by [@jneem]) ### Visual @@ -236,11 +237,9 @@ Last release without a changelog :( [@jrmuizel]: https://github.com/jrmuizel [@scholtzan]: https://github.com/scholtzan [@covercash2]: https://github.com/covercash2 -<<<<<<< HEAD [@raphlinus]: https://github.com/raphlinus -======= [@binomial0]: https://github.com/binomial0 ->>>>>>> master +[@chris-zen]: https://github.com/chris-zen [#599]: https://github.com/linebender/druid/pull/599 [#611]: https://github.com/linebender/druid/pull/611 @@ -347,6 +346,7 @@ Last release without a changelog :( [#1049]: https://github.com/linebender/druid/pull/1049 [#1050]: https://github.com/linebender/druid/pull/1050 [#1054]: https://github.com/linebender/druid/pull/1054 +[#1058]: https://github.com/linebender/druid/pull/1058 [#1062]: https://github.com/linebender/druid/pull/1062 [Unreleased]: https://github.com/linebender/druid/compare/v0.6.0...master diff --git a/druid-derive/src/data.rs b/druid-derive/src/data.rs index e203089df5..3802a7d9b9 100644 --- a/druid-derive/src/data.rs +++ b/druid-derive/src/data.rs @@ -36,10 +36,10 @@ fn derive_struct( input: &syn::DeriveInput, s: &DataStruct, ) -> Result { - let generics_bounds = generics_bounds(&input.generics); - let generics = &input.generics; + let ident = &input.ident; + let impl_generics = generics_bounds(&input.generics); + let (_, ty_generics, where_clause) = &input.generics.split_for_impl(); - let ty = &input.ident; let fields = Fields::parse_ast(&s.fields)?; let diff = if fields.len() > 0 { @@ -54,7 +54,7 @@ fn derive_struct( }; let res = quote! { - impl<#generics_bounds> druid::Data for #ty #generics { + impl<#impl_generics> ::druid::Data for #ident #ty_generics #where_clause { fn same(&self, other: &Self) -> bool { #diff } @@ -80,14 +80,13 @@ fn derive_enum( input: &syn::DeriveInput, s: &DataEnum, ) -> Result { - let ty = &input.ident; + let ident = &input.ident; + let impl_generics = generics_bounds(&input.generics); + let (_, ty_generics, where_clause) = &input.generics.split_for_impl(); if is_c_style_enum(&s) { - let generics_bounds = generics_bounds(&input.generics); - let generics = &input.generics; - let res = quote! { - impl<#generics_bounds> ::druid::Data for #ty #generics { + impl<#impl_generics> ::druid::Data for #ident #ty_generics #where_clause { fn same(&self, other: &Self) -> bool { self == other } } }; @@ -132,7 +131,7 @@ fn derive_enum( .collect(); Ok(quote! { - (#ty :: #variant { #( #lefts ),* }, #ty :: #variant { #( #rights ),* }) => { + (#ident :: #variant { #( #lefts ),* }, #ident :: #variant { #( #rights ),* }) => { #( #tests )&&* } }) @@ -148,24 +147,21 @@ fn derive_enum( if fields.iter().filter(|field| !field.ignore).count() > 0 { Ok(quote! { - ( #ty :: #variant( #(#vars_left),* ), #ty :: #variant( #(#vars_right),* )) => { + ( #ident :: #variant( #(#vars_left),* ), #ident :: #variant( #(#vars_right),* )) => { #( #tests )&&* } }) } else { Ok(quote! { - ( #ty :: #variant , #ty :: #variant ) => { true } + ( #ident :: #variant , #ident :: #variant ) => { true } }) } } }) .collect::, syn::Error>>()?; - let generics_bounds = generics_bounds(&input.generics); - let generics = &input.generics; - let res = quote! { - impl<#generics_bounds> ::druid::Data for #ty #generics { + impl<#impl_generics> ::druid::Data for #ident #ty_generics #where_clause { fn same(&self, other: &Self) -> bool { match (self, other) { #( #cases ),* @@ -182,7 +178,15 @@ fn generics_bounds(generics: &syn::Generics) -> proc_macro2::TokenStream { let res = generics.params.iter().map(|gp| { use syn::GenericParam::*; match gp { - Type(ty) => quote_spanned!(ty.span()=> #ty : ::druid::Data), + Type(ty) => { + let ident = &ty.ident; + let bounds = &ty.bounds; + if bounds.is_empty() { + quote_spanned!(ty.span()=> #ident : ::druid::Data) + } else { + quote_spanned!(ty.span()=> #ident : #bounds + ::druid::Data) + } + } Lifetime(lf) => quote!(#lf), Const(cst) => quote!(#cst), } diff --git a/druid-derive/tests/data.rs b/druid-derive/tests/data.rs index d104bc8bc2..020bf1fa2f 100644 --- a/druid-derive/tests/data.rs +++ b/druid-derive/tests/data.rs @@ -30,6 +30,26 @@ struct MultiFieldStruct { c: String, } +trait UserTrait {} + +#[derive(Clone, Data)] +struct TypeParamForUserTraitStruct { + a: T, +} + +#[derive(Clone, Data)] +struct TypeParamForUserTraitWithWhereClauseStruct +where + T: UserTrait, +{ + b: T, +} + +#[derive(Clone, Data)] +enum TypeParamForUserTraitAndLifetimeEnum { + V1(T), +} + #[test] fn test_data_derive_same() { let plain = PlainStruct; @@ -70,4 +90,27 @@ fn test_data_derive_same() { c: "Fail".to_string() }) ); + + #[derive(Clone, Data)] + struct Value(u32); + + impl UserTrait for Value {} + + let v = TypeParamForUserTraitStruct { a: Value(1) }; + assert!(v.same(&v)); + assert_eq!(false, v.same(&TypeParamForUserTraitStruct { a: Value(2) })); + + let v = TypeParamForUserTraitWithWhereClauseStruct { b: Value(3) }; + assert!(v.same(&v)); + assert_eq!( + false, + v.same(&TypeParamForUserTraitWithWhereClauseStruct { b: Value(6) }) + ); + + let v = TypeParamForUserTraitAndLifetimeEnum::V1(Value(10)); + assert!(v.same(&v)); + assert_eq!( + false, + v.same(&TypeParamForUserTraitAndLifetimeEnum::V1(Value(12))) + ); }