#[derive(CloneRef)] also works on types with type-level bounds. (https://github.com/enso-org/ide/pull/323)

Original commit: b9f9c37d96
This commit is contained in:
Michał Wawrzyniec Urbańczyk 2020-04-03 08:16:52 +02:00 committed by GitHub
parent 546aeb4ec0
commit 0c5b5b8081
3 changed files with 51 additions and 10 deletions

View File

@ -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<Item=WherePredicate>) -> WhereClause {
let predicates = syn::punctuated::Punctuated::from_iter(predicates);
WhereClause {where_token:default(),predicates}
}
// =============
// === Tests ===
// =============

View File

@ -36,3 +36,21 @@ struct StructUnnamedBound<T>(T);
#[derive(CloneRef,Clone)]
#[clone_ref(bound="T:CloneRef,U:CloneRef")]
struct StructUnnamedBoundTwoPatams<T,U>(T,U);
#[derive(Clone,CloneRef)]
#[clone_ref(bound="T:Clone+Display")]
struct StructBoundGeneric<T:Display>(Rc<T>);
#[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<T>(Rc<T>) 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:Display>(T) where T:Debug;

View File

@ -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<Vec<WherePredicate>> {
/// 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::<Vec<_>>();
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
}