Skip to content

Commit

Permalink
style: When deriving something with an output type, map preconditions…
Browse files Browse the repository at this point in the history
… as well.

Otherwise, deriving ToComputedValue and ToAnimatedValue in structs or enums with
other where clauses just doesn't work.

Differential Revision: https://phabricator.services.mozilla.com/D21859
  • Loading branch information
emilio committed Mar 13, 2019
1 parent 35b8b95 commit 9b24a45
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
64 changes: 64 additions & 0 deletions components/style_derive/cg.rs
Expand Up @@ -12,6 +12,70 @@ use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple};
use syn::{Variant, WherePredicate};
use synstructure::{self, BindStyle, BindingInfo, VariantAst, VariantInfo};

/// Given an input type which has some where clauses already, like:
///
/// struct InputType<T>
/// where
/// T: Zero,
/// {
/// ...
/// }
///
/// Add the necessary `where` clauses so that the output type of a trait
/// fulfils them.
///
/// For example:
///
/// <T as ToComputedValue>::ComputedValue: Zero,
///
/// This needs to run before adding other bounds to the type parameters.
pub fn propagate_clauses_to_output_type(
where_clause: &mut Option<syn::WhereClause>,
generics: &syn::Generics,
trait_path: Path,
trait_output: Ident,
) {
let where_clause = match *where_clause {
Some(ref mut clause) => clause,
None => return,
};
let mut extra_bounds = vec![];
for pred in &where_clause.predicates {
let ty = match *pred {
syn::WherePredicate::Type(ref ty) => ty,
ref predicate => panic!("Unhanded complex where predicate: {:?}", predicate),
};

let path = match ty.bounded_ty {
syn::Type::Path(ref p) => &p.path,
ref ty => panic!("Unhanded complex where type: {:?}", ty),
};

assert!(
ty.lifetimes.is_none(),
"Unhanded complex lifetime bound: {:?}",
ty,
);

let ident = match path_to_ident(path) {
Some(i) => i,
None => panic!("Unhanded complex where type path: {:?}", path),
};

if generics.type_params().any(|param| param.ident == *ident) {
extra_bounds.push(ty.clone());
}
}

for bound in extra_bounds {
let ty = bound.bounded_ty;
let bounds = bound.bounds;
where_clause.predicates.push(
parse_quote!(<#ty as #trait_path>::#trait_output: #bounds),
)
}
}

pub fn add_predicate(where_clause: &mut Option<syn::WhereClause>, pred: WherePredicate) {
where_clause
.get_or_insert(parse_quote!(where))
Expand Down
6 changes: 6 additions & 0 deletions components/style_derive/to_animated_value.rs
Expand Up @@ -9,6 +9,12 @@ use synstructure::BindStyle;

pub fn derive(mut input: DeriveInput) -> TokenStream {
let mut where_clause = input.generics.where_clause.take();
cg::propagate_clauses_to_output_type(
&mut where_clause,
&input.generics,
parse_quote!(crate::values::animated::ToAnimatedValue),
parse_quote!(AnimatedValue),
);
for param in input.generics.type_params() {
cg::add_predicate(
&mut where_clause,
Expand Down
6 changes: 6 additions & 0 deletions components/style_derive/to_computed_value.rs
Expand Up @@ -9,6 +9,12 @@ use synstructure::BindStyle;

pub fn derive(mut input: DeriveInput) -> TokenStream {
let mut where_clause = input.generics.where_clause.take();
cg::propagate_clauses_to_output_type(
&mut where_clause,
&input.generics,
parse_quote!(crate::values::computed::ToComputedValue),
parse_quote!(ComputedValue),
);
let (to_body, from_body) = {
let params = input.generics.type_params().collect::<Vec<_>>();
for param in &params {
Expand Down

0 comments on commit 9b24a45

Please sign in to comment.