From 9b24a451f6d77ecefc43a5b690930c19eb704c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 3 Mar 2019 11:31:21 +0000 Subject: [PATCH] style: When deriving something with an output type, map preconditions 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 --- components/style_derive/cg.rs | 64 ++++++++++++++++++++ components/style_derive/to_animated_value.rs | 6 ++ components/style_derive/to_computed_value.rs | 6 ++ 3 files changed, 76 insertions(+) diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs index 6eeca384bfa4..880cb07378bf 100644 --- a/components/style_derive/cg.rs +++ b/components/style_derive/cg.rs @@ -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 +/// where +/// T: Zero, +/// { +/// ... +/// } +/// +/// Add the necessary `where` clauses so that the output type of a trait +/// fulfils them. +/// +/// For example: +/// +/// ::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, + 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, pred: WherePredicate) { where_clause .get_or_insert(parse_quote!(where)) diff --git a/components/style_derive/to_animated_value.rs b/components/style_derive/to_animated_value.rs index b53cf9c3d416..1aba9b3327e4 100644 --- a/components/style_derive/to_animated_value.rs +++ b/components/style_derive/to_animated_value.rs @@ -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, diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index 682617405028..b0b2aa6af634 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -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::>(); for param in ¶ms {