diff --git a/gui/src/rust/lib/macro-utils/src/lib.rs b/gui/src/rust/lib/macro-utils/src/lib.rs index 64121cc059..f7c84ca2c3 100644 --- a/gui/src/rust/lib/macro-utils/src/lib.rs +++ b/gui/src/rust/lib/macro-utils/src/lib.rs @@ -7,13 +7,13 @@ pub use enso_prelude as prelude; use crate::prelude::*; +use proc_macro2::TokenStream; +use proc_macro2::TokenTree; use quote::quote; use syn; use syn::visit::Visit; -use proc_macro2::TokenStream; -use proc_macro2::TokenTree; - - +use syn::WhereClause; +use syn::WherePredicate; // ========================= // === Token Stream Utils === @@ -240,6 +240,18 @@ pub fn variant_depends_on +// =================== +// === WhereClause === +// =================== + +/// Creates a new where clause from provided sequence of where predicates. +pub fn new_where_clause(predicates:impl IntoIterator) -> WhereClause { + let predicates = syn::punctuated::Punctuated::from_iter(predicates); + WhereClause {where_token:default(),predicates} +} + + + // ============= // === Tests === // ============= diff --git a/gui/src/rust/lib/shapely/impl/tests/derive_clone_ref.rs b/gui/src/rust/lib/shapely/impl/tests/derive_clone_ref.rs index a794408023..f98c26d1c9 100644 --- a/gui/src/rust/lib/shapely/impl/tests/derive_clone_ref.rs +++ b/gui/src/rust/lib/shapely/impl/tests/derive_clone_ref.rs @@ -36,3 +36,21 @@ struct StructUnnamedBound(T); #[derive(CloneRef,Clone)] #[clone_ref(bound="T:CloneRef,U:CloneRef")] struct StructUnnamedBoundTwoPatams(T,U); + +#[derive(Clone,CloneRef)] +#[clone_ref(bound="T:Clone+Display")] +struct StructBoundGeneric(Rc); + +#[derive(CloneRef,Derivative)] +#[derivative(Clone(bound=""))] +// Note: CloneRef "knows" about `Display` bound. +struct StructGenericLifetime<'t>(Rc<&'t String>); + +#[derive(CloneRef,Derivative)] +#[derivative(Clone(bound=""))] +struct StructWhereClause(Rc) where T:Debug; + +#[derive(CloneRef,Clone)] +#[clone_ref(bound="T:CloneRef")] +// Here derive macro must correctly merge user-provided bound, generics list bound and where clause. +struct StructVariousBounds(T) where T:Debug; diff --git a/gui/src/rust/lib/shapely/macros/src/derive_clone_ref.rs b/gui/src/rust/lib/shapely/macros/src/derive_clone_ref.rs index 46bfe6f16f..54b7b2d1dc 100644 --- a/gui/src/rust/lib/shapely/macros/src/derive_clone_ref.rs +++ b/gui/src/rust/lib/shapely/macros/src/derive_clone_ref.rs @@ -5,11 +5,12 @@ use macro_utils::identifier_sequence; use macro_utils::index_sequence; use macro_utils::path_matching_ident; use syn::Attribute; -use syn::Ident; +use syn::DeriveInput; use syn::Data; use syn::DataEnum; use syn::DataStruct; use syn::Fields; +use syn::Ident; use syn::Lit; use syn::Meta; use syn::MetaNameValue; @@ -19,6 +20,7 @@ use syn::WhereClause; use syn::WherePredicate; + // ============== // === Consts === // ============== @@ -184,8 +186,7 @@ pub fn clone_ref_bounds(attr:&Attribute) -> Option> { /// Derives `CloneRef` implementation, refer to `crate::derive_clone_ref` for details. pub fn derive (input:proc_macro::TokenStream) -> proc_macro::TokenStream { - let decl = syn::parse_macro_input!(input as syn::DeriveInput); - let params = &decl.generics.params.iter().collect::>(); + let decl = syn::parse_macro_input!(input as DeriveInput); let ident = &decl.ident; let body = match &decl.data { Data::Struct(data_struct) => body_for_struct(ident,data_struct), @@ -193,10 +194,20 @@ pub fn derive Data::Union(_) => panic!("CloneRef cannot be derived for an untagged union input."), }; - let bounds = decl.attrs.iter().filter_map(clone_ref_bounds).flatten(); + + let (impl_generics, ty_generics, inherent_where_clause_opt) = &decl.generics.split_for_impl(); + + // Where clause must contain both user-provided bounds and bounds inherent due to type + // declaration-level where clause. + let user_requested_bounds = decl.attrs.iter().filter_map(clone_ref_bounds).flatten(); + let mut where_clause = macro_utils::new_where_clause(user_requested_bounds); + for inherent_where_clause in inherent_where_clause_opt { + where_clause.predicates.extend(inherent_where_clause.predicates.iter().cloned()) + } + let output = quote!{ - impl <#(#params),*> CloneRef for #ident<#(#params),*> - where #(#bounds),* { + impl #impl_generics CloneRef for #ident #ty_generics + #where_clause { fn clone_ref(&self) -> Self { #body }