#[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 crate::prelude::*;
use proc_macro2::TokenStream;
use proc_macro2::TokenTree;
use quote::quote; use quote::quote;
use syn; use syn;
use syn::visit::Visit; use syn::visit::Visit;
use proc_macro2::TokenStream; use syn::WhereClause;
use proc_macro2::TokenTree; use syn::WherePredicate;
// ========================= // =========================
// === Token Stream Utils === // === 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 === // === Tests ===
// ============= // =============

View File

@ -36,3 +36,21 @@ struct StructUnnamedBound<T>(T);
#[derive(CloneRef,Clone)] #[derive(CloneRef,Clone)]
#[clone_ref(bound="T:CloneRef,U:CloneRef")] #[clone_ref(bound="T:CloneRef,U:CloneRef")]
struct StructUnnamedBoundTwoPatams<T,U>(T,U); 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::index_sequence;
use macro_utils::path_matching_ident; use macro_utils::path_matching_ident;
use syn::Attribute; use syn::Attribute;
use syn::Ident; use syn::DeriveInput;
use syn::Data; use syn::Data;
use syn::DataEnum; use syn::DataEnum;
use syn::DataStruct; use syn::DataStruct;
use syn::Fields; use syn::Fields;
use syn::Ident;
use syn::Lit; use syn::Lit;
use syn::Meta; use syn::Meta;
use syn::MetaNameValue; use syn::MetaNameValue;
@ -19,6 +20,7 @@ use syn::WhereClause;
use syn::WherePredicate; use syn::WherePredicate;
// ============== // ==============
// === Consts === // === 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. /// Derives `CloneRef` implementation, refer to `crate::derive_clone_ref` for details.
pub fn derive pub fn derive
(input:proc_macro::TokenStream) -> proc_macro::TokenStream { (input:proc_macro::TokenStream) -> proc_macro::TokenStream {
let decl = syn::parse_macro_input!(input as syn::DeriveInput); let decl = syn::parse_macro_input!(input as DeriveInput);
let params = &decl.generics.params.iter().collect::<Vec<_>>();
let ident = &decl.ident; let ident = &decl.ident;
let body = match &decl.data { let body = match &decl.data {
Data::Struct(data_struct) => body_for_struct(ident,data_struct), Data::Struct(data_struct) => body_for_struct(ident,data_struct),
@ -193,10 +194,20 @@ pub fn derive
Data::Union(_) => Data::Union(_) =>
panic!("CloneRef cannot be derived for an untagged union input."), 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!{ let output = quote!{
impl <#(#params),*> CloneRef for #ident<#(#params),*> impl #impl_generics CloneRef for #ident #ty_generics
where #(#bounds),* { #where_clause {
fn clone_ref(&self) -> Self { fn clone_ref(&self) -> Self {
#body #body
} }