Refactor how we handle trait bounds in style_derive

For the traits we derive which methods don't depend on associated types (i.e.
all of them but ToAnimatedValue and ToComputedValue), we now add trait bounds
for the actual field types directly, instead of bounding the type parameters.
This commit is contained in:
Anthony Ramine 2017-08-25 19:58:49 +02:00
parent 13d47ba69a
commit 04ad28b564
8 changed files with 75 additions and 58 deletions

View file

@ -28,9 +28,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let mut computations = quote!(); let mut computations = quote!();
let iter = result_info.iter().zip(this_info.iter().zip(&other_info)); let iter = result_info.iter().zip(this_info.iter().zip(&other_info));
computations.append_all(iter.map(|(result, (this, other))| { computations.append_all(iter.map(|(result, (this, other))| {
where_clause.predicates.push( where_clause.add_trait_bound(this.field.ty.clone());
cg::where_predicate(this.field.ty.clone(), trait_path),
);
quote! { quote! {
let #result = ::values::animated::Animate::animate(#this, #other, procedure)?; let #result = ::values::animated::Animate::animate(#this, #other, procedure)?;
} }

View file

@ -3,16 +3,39 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use darling::FromVariant; use darling::FromVariant;
use quote::Tokens; use quote::{ToTokens, Tokens};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashSet;
use std::iter; use std::iter;
use syn::{AngleBracketedParameterData, Body, DeriveInput, Ident, ImplGenerics}; use syn::{self, AngleBracketedParameterData, Body, DeriveInput, Ident};
use syn::{Path, PathParameters, PathSegment, PolyTraitRef, QSelf}; use syn::{ImplGenerics, Path, PathParameters, PathSegment, PolyTraitRef};
use syn::{TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound}; use syn::{QSelf, TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound};
use syn::{Variant, WhereBoundPredicate, WhereClause, WherePredicate}; use syn::{Variant, WhereBoundPredicate, WherePredicate};
use syn::visit::{self, Visitor}; use syn::visit::{self, Visitor};
use synstructure::{self, BindOpts, BindStyle, BindingInfo}; use synstructure::{self, BindOpts, BindStyle, BindingInfo};
pub struct WhereClause<'input, 'path> {
clause: syn::WhereClause,
params: &'input [TyParam],
trait_path: &'path [&'path str],
bounded_types: HashSet<Ty>,
}
impl<'input, 'path> ToTokens for WhereClause<'input, 'path> {
fn to_tokens(&self, tokens: &mut Tokens) {
self.clause.to_tokens(tokens);
}
}
impl<'input, 'path> WhereClause<'input, 'path> {
pub fn add_trait_bound(&mut self, ty: Ty) {
if is_parameterized(&ty, self.params) && !self.bounded_types.contains(&ty) {
self.bounded_types.insert(ty.clone());
self.clause.predicates.push(where_predicate(ty, self.trait_path));
}
}
}
pub fn fmap_match<F>( pub fn fmap_match<F>(
input: &DeriveInput, input: &DeriveInput,
bind_style: BindStyle, bind_style: BindStyle,
@ -35,11 +58,11 @@ where
}) })
} }
pub fn fmap_trait_parts<'a>( pub fn fmap_trait_parts<'input, 'path>(
input: &'a DeriveInput, input: &'input DeriveInput,
trait_path: &[&str], trait_path: &'path [&'path str],
trait_output: &str, trait_output: &str,
) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause, Path) { ) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>, Path) {
let (impl_generics, ty_generics, where_clause) = trait_parts(input, trait_path); let (impl_generics, ty_generics, where_clause) = trait_parts(input, trait_path);
let output_ty = PathSegment { let output_ty = PathSegment {
ident: input.ident.clone(), ident: input.ident.clone(),
@ -115,18 +138,17 @@ pub fn ref_pattern<'a>(
) )
} }
pub fn trait_parts<'a>( pub fn trait_parts<'input, 'path>(
input: &'a DeriveInput, input: &'input DeriveInput,
trait_path: &[&str], trait_path: &'path [&'path str],
) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause) { ) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>) {
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let mut where_clause = where_clause.clone(); let where_clause = WhereClause {
for param in &input.generics.ty_params { clause: where_clause.clone(),
where_clause.predicates.push(where_predicate( params: &input.generics.ty_params,
Ty::Path(None, param.ident.clone().into()), trait_path,
trait_path, bounded_types: HashSet::new()
)); };
}
(impl_generics, ty_generics, where_clause) (impl_generics, ty_generics, where_clause)
} }

View file

@ -30,9 +30,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
} else { } else {
let mut sum = quote!(); let mut sum = quote!();
sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| { sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| {
where_clause.predicates.push( where_clause.add_trait_bound(this.field.ty.clone());
cg::where_predicate(this.field.ty.clone(), trait_path),
);
quote! { quote! {
::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)? ::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)?
} }

View file

@ -19,11 +19,10 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
None => return Some(quote!(false)), None => return Some(quote!(false)),
Some(pair) => pair, Some(pair) => pair,
}; };
where_clause.add_trait_bound(first.field.ty.clone());
let mut expr = quote!(::style_traits::HasViewportPercentage::has_viewport_percentage(#first)); let mut expr = quote!(::style_traits::HasViewportPercentage::has_viewport_percentage(#first));
for binding in rest { for binding in rest {
where_clause.predicates.push( where_clause.add_trait_bound(binding.field.ty.clone());
cg::where_predicate(binding.field.ty.clone(), trait_path),
);
expr = quote!(#expr || ::style_traits::HasViewportPercentage::has_viewport_percentage(#binding)); expr = quote!(#expr || ::style_traits::HasViewportPercentage::has_viewport_percentage(#binding));
} }
Some(expr) Some(expr)

View file

@ -9,18 +9,20 @@ use synstructure::BindStyle;
pub fn derive(input: syn::DeriveInput) -> quote::Tokens { pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let name = &input.ident; let name = &input.ident;
let (impl_generics, ty_generics, where_clause, animated_value_type) = let trait_path = &["values", "animated", "ToAnimatedValue"];
cg::fmap_trait_parts( let (impl_generics, ty_generics, mut where_clause, animated_value_type) =
&input, cg::fmap_trait_parts(&input, trait_path, "AnimatedValue");
&["values", "animated", "ToAnimatedValue"], for param in &input.generics.ty_params {
"AnimatedValue", where_clause.add_trait_bound(
syn::Ty::Path(None, param.ident.clone().into()),
); );
}
let to_body = cg::fmap_match(&input, BindStyle::Move, |field| { let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| {
quote!(::values::animated::ToAnimatedValue::to_animated_value(#field)) quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding))
}); });
let from_body = cg::fmap_match(&input, BindStyle::Move, |field| { let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| {
quote!(::values::animated::ToAnimatedValue::from_animated_value(#field)) quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding))
}); });
quote! { quote! {

View file

@ -9,13 +9,13 @@ use synstructure::BindStyle;
pub fn derive(input: syn::DeriveInput) -> quote::Tokens { pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let name = &input.ident; let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = cg::trait_parts( let trait_path = &["values", "animated", "ToAnimatedZero"];
&input, let (impl_generics, ty_generics, mut where_clause) =
&["values", "animated", "ToAnimatedZero"], cg::trait_parts(&input, trait_path);
);
let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| { let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
quote! { ::values::animated::ToAnimatedZero::to_animated_zero(#field)? } where_clause.add_trait_bound(binding.field.ty.clone());
quote! { ::values::animated::ToAnimatedZero::to_animated_zero(#binding)? }
}); });
quote! { quote! {

View file

@ -9,18 +9,20 @@ use synstructure::BindStyle;
pub fn derive(input: syn::DeriveInput) -> quote::Tokens { pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let name = &input.ident; let name = &input.ident;
let (impl_generics, ty_generics, where_clause, computed_value_type) = let trait_path = &["values", "computed", "ToComputedValue"];
cg::fmap_trait_parts( let (impl_generics, ty_generics, mut where_clause, computed_value_type) =
&input, cg::fmap_trait_parts(&input, trait_path, "ComputedValue");
&["values", "computed", "ToComputedValue"], for param in &input.generics.ty_params {
"ComputedValue", where_clause.add_trait_bound(
syn::Ty::Path(None, param.ident.clone().into()),
); );
}
let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| { let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
quote!(::values::computed::ToComputedValue::to_computed_value(#field, context)) quote!(::values::computed::ToComputedValue::to_computed_value(#binding, context))
}); });
let from_body = cg::fmap_match(&input, BindStyle::Ref, |field| { let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
quote!(::values::computed::ToComputedValue::from_computed_value(#field)) quote!(::values::computed::ToComputedValue::from_computed_value(#binding))
}); });
quote! { quote! {

View file

@ -21,11 +21,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let mut expr = if !bindings.is_empty() { let mut expr = if !bindings.is_empty() {
let mut expr = quote! {}; let mut expr = quote! {};
for binding in bindings { for binding in bindings {
if cg::is_parameterized(&binding.field.ty, &input.generics.ty_params) { where_clause.add_trait_bound(binding.field.ty.clone());
where_clause.predicates.push(
cg::where_predicate(binding.field.ty.clone(), trait_path),
);
}
expr = quote! { expr = quote! {
#expr #expr
writer.item(#binding)?; writer.item(#binding)?;