Bug 1348519 - Part 1: Support field_bound on Animate. r=emilio
authorBoris Chiou <boris.chiou@gmail.com>
Sat, 12 Jan 2019 02:19:04 +0000
changeset 453597 37838b3650fd5b4c66cb1b63b366a40931076fcb
parent 453596 c28b226ee6c1d383487fb7dd75a14f419221a143
child 453598 bd4efc854419ae1643bfaeeedc67403703575ea0
push id35360
push usernbeleuzu@mozilla.com
push dateSat, 12 Jan 2019 09:39:47 +0000
treeherdermozilla-central@cb35977ae7a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1348519
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1348519 - Part 1: Support field_bound on Animate. r=emilio So we can derive Animate on more generic types. Differential Revision: https://phabricator.services.mozilla.com/D16339
servo/components/style/values/animated/mod.rs
servo/components/style_derive/animate.rs
--- a/servo/components/style/values/animated/mod.rs
+++ b/servo/components/style/values/animated/mod.rs
@@ -108,17 +108,18 @@ pub fn animate_multiplicative_factor(
 ///
 /// If a variant is annotated with `#[animation(error)]`, the corresponding
 /// `match` arm is not generated.
 ///
 /// If the two values are not similar, an error is returned unless a fallback
 /// function has been specified through `#[animate(fallback)]`.
 ///
 /// Trait bounds for type parameter `Foo` can be opted out of with
-/// `#[animation(no_bound(Foo))]` on the type definition.
+/// `#[animation(no_bound(Foo))]` on the type definition, trait bounds for
+/// fields can be opted into with `#[animation(field_bound)]` on the field.
 pub trait Animate: Sized {
     /// Animate a value towards another one, given an animation procedure.
     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>;
 }
 
 /// An animation procedure.
 ///
 /// <https://drafts.csswg.org/web-animations/#procedures-for-animating-properties>
--- a/servo/components/style_derive/animate.rs
+++ b/servo/components/style_derive/animate.rs
@@ -1,46 +1,49 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 use crate::cg;
 use darling::util::IdentList;
 use proc_macro2::TokenStream;
 use quote::TokenStreamExt;
-use syn::{DeriveInput, Path};
+use syn::{DeriveInput, Path, WhereClause};
 use synstructure::{Structure, VariantInfo};
 
 pub fn derive(mut input: DeriveInput) -> TokenStream {
     let animation_input_attrs = cg::parse_input_attrs::<AnimationInputAttrs>(&input);
     let no_bound = animation_input_attrs.no_bound.unwrap_or_default();
     let mut where_clause = input.generics.where_clause.take();
     for param in input.generics.type_params() {
         if !no_bound.contains(&param.ident) {
             cg::add_predicate(
                 &mut where_clause,
                 parse_quote!(#param: crate::values::animated::Animate),
             );
         }
     }
-    input.generics.where_clause = where_clause;
-
-    let s = Structure::new(&input);
-    let mut append_error_clause = s.variants().len() > 1;
+    let (mut match_body, append_error_clause) = {
+        let s = Structure::new(&input);
+        let mut append_error_clause = s.variants().len() > 1;
 
-    let mut match_body = s.variants().iter().fold(quote!(), |body, variant| {
-        let arm = match derive_variant_arm(variant) {
-            Ok(arm) => arm,
-            Err(()) => {
-                append_error_clause = true;
-                return body;
-            },
-        };
-        quote! { #body #arm }
-    });
+        let mut match_body = s.variants().iter().fold(quote!(), |body, variant| {
+            let arm = match derive_variant_arm(variant, &mut where_clause) {
+                Ok(arm) => arm,
+                Err(()) => {
+                    append_error_clause = true;
+                    return body;
+                },
+            };
+            quote! { #body #arm }
+        });
+        (match_body, append_error_clause)
+    };
+
+    input.generics.where_clause = where_clause;
 
     if append_error_clause {
         let input_attrs = cg::parse_input_attrs::<AnimateInputAttrs>(&input);
         if let Some(fallback) = input_attrs.fallback {
             match_body.append_all(quote! {
                 (this, other) => #fallback(this, other, procedure)
             });
         } else {
@@ -63,28 +66,35 @@ pub fn derive(mut input: DeriveInput) ->
                 match (self, other) {
                     #match_body
                 }
             }
         }
     }
 }
 
-fn derive_variant_arm(variant: &VariantInfo) -> Result<TokenStream, ()> {
+fn derive_variant_arm(
+    variant: &VariantInfo,
+    where_clause: &mut Option<WhereClause>,
+) -> Result<TokenStream, ()> {
     let variant_attrs = cg::parse_variant_attrs_from_ast::<AnimationVariantAttrs>(&variant.ast());
     if variant_attrs.error {
         return Err(());
     }
     let (this_pattern, this_info) = cg::ref_pattern(&variant, "this");
     let (other_pattern, other_info) = cg::ref_pattern(&variant, "other");
     let (result_value, result_info) = cg::value(&variant, "result");
     let mut computations = quote!();
     let iter = result_info.iter().zip(this_info.iter().zip(&other_info));
     computations.append_all(iter.map(|(result, (this, other))| {
         let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&result.ast());
+        if field_attrs.field_bound {
+            let ty = &this.ast().ty;
+            cg::add_predicate(where_clause, parse_quote!(#ty: crate::values::animated::Animate));
+        }
         if field_attrs.constant {
             quote! {
                 if #this != #other {
                     return Err(());
                 }
                 let #result = std::clone::Clone::clone(#this);
             }
         } else {
@@ -122,9 +132,10 @@ pub struct AnimationVariantAttrs {
     // variant itself.
     pub no_bound: Option<IdentList>,
 }
 
 #[darling(attributes(animation), default)]
 #[derive(Default, FromField)]
 pub struct AnimationFieldAttrs {
     pub constant: bool,
+    pub field_bound: bool,
 }