servo: Merge #20258 - Continue to improve style_derive (from servo:derive-all-the-things); r=emilio
authorAnthony Ramine <n.oxyde@gmail.com>
Fri, 09 Mar 2018 17:29:05 -0500
changeset 462512 31d94cfa44e855ad81fb70779f6568ed902e930e
parent 462511 9a200b344efec72f896bf4ebda15a53b357da00a
child 462513 fbc3768c446ad1b74439e6a16e08e353656b1c0c
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
milestone60.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
servo: Merge #20258 - Continue to improve style_derive (from servo:derive-all-the-things); r=emilio Source-Repo: https://github.com/servo/servo Source-Revision: 909ebff1844c3fcf95ea3b479b61077ff5a552e2
servo/components/style/values/computed/mod.rs
servo/components/style/values/computed/percentage.rs
servo/components/style/values/generics/grid.rs
servo/components/style/values/generics/image.rs
servo/components/style/values/generics/transform.rs
servo/components/style_derive/cg.rs
servo/components/style_derive/to_animated_value.rs
servo/components/style_derive/to_computed_value.rs
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -288,18 +288,17 @@ impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedV
         (self.values.len(), Some(self.values.len()))
     }
 }
 
 /// A trait to represent the conversion between computed and specified values.
 ///
 /// This trait is derivable with `#[derive(ToComputedValue)]`. The derived
 /// implementation just calls `ToComputedValue::to_computed_value` on each field
-/// of the passed value, or `Clone::clone` if the field is annotated with
-/// `#[compute(clone)]`. The deriving code assumes that if the type isn't
+/// of the passed value. The deriving code assumes that if the type isn't
 /// generic, then the trait can be implemented as simple `Clone::clone` calls,
 /// this means that a manual implementation with `ComputedValue = Self` is bogus
 /// if it returns anything else than a clone.
 pub trait ToComputedValue {
     /// The computed value type we're going to be converted to.
     type ComputedValue;
 
     /// Convert a specified value to a computed value, using itself and the data
--- a/servo/components/style/values/computed/percentage.rs
+++ b/servo/components/style/values/computed/percentage.rs
@@ -6,17 +6,17 @@
 
 use std::fmt;
 use style_traits::{CssWriter, ToCss};
 use values::{CSSFloat, serialize_percentage};
 
 /// A computed percentage.
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default, MallocSizeOf)]
-#[derive(PartialEq, PartialOrd, ToAnimatedZero)]
+#[derive(PartialEq, PartialOrd, ToAnimatedZero, ToComputedValue)]
 pub struct Percentage(pub CSSFloat);
 
 impl Percentage {
     /// 0%
     #[inline]
     pub fn zero() -> Self {
         Percentage(0.)
     }
--- a/servo/components/style/values/generics/grid.rs
+++ b/servo/components/style/values/generics/grid.rs
@@ -383,17 +383,16 @@ impl Parse for RepeatCount<specified::In
 pub struct TrackRepeat<L, I> {
     /// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`)
     pub count: RepeatCount<I>,
     /// `<line-names>` accompanying `<track_size>` values.
     ///
     /// If there's no `<line-names>`, then it's represented by an empty vector.
     /// For N `<track-size>` values, there will be N+1 `<line-names>`, and so this vector's
     /// length is always one value more than that of the `<track-size>`.
-    #[compute(clone)]
     pub line_names: Box<[Box<[CustomIdent]>]>,
     /// `<track-size>` values.
     pub track_sizes: Vec<TrackSize<L>>,
 }
 
 impl<L: ToCss, I: ToCss> ToCss for TrackRepeat<L, I> {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
@@ -662,17 +661,17 @@ impl ToCss for LineNameList {
 /// Variants for `<grid-template-rows> | <grid-template-columns>`
 /// Subgrid deferred to Level 2 spec due to lack of implementation.
 /// But it's implemented in gecko, so we have to as well.
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
 pub enum GridTemplateComponent<L, I> {
     /// `none` value.
     None,
     /// The grid `<track-list>`
-    TrackList(TrackList<L, I>),
+    TrackList(#[compute(field_bound)] TrackList<L, I>),
     /// A `subgrid <line-name-list>?`
     Subgrid(LineNameList),
 }
 
 impl<L, I> GridTemplateComponent<L, I> {
     /// Returns length of the <track-list>s <track-size>
     pub fn track_list_len(&self) -> usize {
         match *self {
--- a/servo/components/style/values/generics/image.rs
+++ b/servo/components/style/values/generics/image.rs
@@ -37,20 +37,18 @@ pub enum Image<Gradient, MozImageRect, I
 /// <https://drafts.csswg.org/css-images/#gradients>
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
 pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color, Angle> {
     /// Gradients can be linear or radial.
     pub kind: GradientKind<LineDirection, Length, LengthOrPercentage, Position, Angle>,
     /// The color stops and interpolation hints.
     pub items: Vec<GradientItem<Color, LengthOrPercentage>>,
     /// True if this is a repeating gradient.
-    #[compute(clone)]
     pub repeating: bool,
     /// Compatibility mode.
-    #[compute(clone)]
     pub compat_mode: CompatMode,
 }
 
 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
 /// Whether we used the modern notation or the compatibility `-webkit`, `-moz` prefixes.
 pub enum CompatMode {
     /// Modern syntax.
     Modern,
--- a/servo/components/style/values/generics/transform.rs
+++ b/servo/components/style/values/generics/transform.rs
@@ -242,54 +242,49 @@ pub enum TransformOperation<Angle, Numbe
     ///
     /// The value must be greater than or equal to zero.
     #[css(function)]
     Perspective(Length),
     /// A intermediate type for interpolation of mismatched transform lists.
     #[allow(missing_docs)]
     #[css(comma, function = "interpolatematrix")]
     InterpolateMatrix {
-        #[compute(ignore_bound)]
         from_list: Transform<
             TransformOperation<
                 Angle,
                 Number,
                 Length,
                 Integer,
                 LengthOrPercentage,
             >,
         >,
-        #[compute(ignore_bound)]
         to_list: Transform<
             TransformOperation<
                 Angle,
                 Number,
                 Length,
                 Integer,
                 LengthOrPercentage,
             >,
         >,
-        #[compute(clone)]
         progress: computed::Percentage,
     },
     /// A intermediate type for accumulation of mismatched transform lists.
     #[allow(missing_docs)]
     #[css(comma, function = "accumulatematrix")]
     AccumulateMatrix {
-        #[compute(ignore_bound)]
         from_list: Transform<
             TransformOperation<
                 Angle,
                 Number,
                 Length,
                 Integer,
                 LengthOrPercentage,
             >,
         >,
-        #[compute(ignore_bound)]
         to_list: Transform<
             TransformOperation<
                 Angle,
                 Number,
                 Length,
                 Integer,
                 LengthOrPercentage,
             >,
--- a/servo/components/style_derive/cg.rs
+++ b/servo/components/style_derive/cg.rs
@@ -49,18 +49,17 @@ impl<'input, 'path> WhereClause<'input, 
         if let Type::Path(syn::TypePath { ref path, .. }) = *ty {
             if path_to_ident(path).is_some() {
                 add_predicate(&mut self.inner, where_predicate(ty.clone(), trait_path, None));
                 return;
             }
         }
 
         let output_type = map_type_params(ty, &self.params, &mut |ident| {
-            let ty = Type::Path(syn::TypePath { qself: None, path: ident.clone().into() });
-            fmap_output_type(ty, trait_path, output)
+            parse_quote!(<#ident as ::#trait_path>::#output)
         });
 
         let pred = where_predicate(
             ty.clone(),
             trait_path,
             Some((output, output_type)),
         );
 
@@ -106,57 +105,43 @@ where
             let expr = f(field.clone());
             quote! { let #mapped_field = #expr; }
         }));
         computations.append_all(mapped);
         Some(computations)
     })
 }
 
-fn fmap_output_type(
-    ty: Type,
+pub fn fmap_trait_output(
+    input: &DeriveInput,
     trait_path: &Path,
     trait_output: Ident,
-) -> Type {
-    parse_quote!(<#ty as ::#trait_path>::#trait_output)
-}
-
-pub fn fmap_trait_parts<'input, 'path>(
-    input: &'input DeriveInput,
-    trait_path: &'path Path,
-    trait_output: Ident,
-) -> (ImplGenerics<'input>, TypeGenerics<'input>, WhereClause<'input, 'path>, Path) {
-    let (impl_generics, ty_generics, mut where_clause) = trait_parts(input, trait_path);
-    where_clause.trait_output = Some(trait_output);
-    let output_ty = PathSegment {
+) -> Path {
+    let segment = PathSegment {
         ident: input.ident.clone(),
         arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
             args: input.generics.params.iter().map(|arg| {
                 match arg {
                     &GenericParam::Lifetime(ref data) => GenericArgument::Lifetime(data.lifetime.clone()),
                     &GenericParam::Type(ref data) => {
                         let ident = data.ident;
                         GenericArgument::Type(
-                            fmap_output_type(
-                                parse_quote!(#ident),
-                                trait_path,
-                                trait_output
-                            )
+                            parse_quote!(<#ident as ::#trait_path>::#trait_output),
                         )
                     },
                     ref arg => panic!("arguments {:?} cannot be mapped yet", arg)
                 }
             }).collect(),
             colon2_token: Default::default(),
             gt_token: Default::default(),
             lt_token: Default::default(),
 
         })
     };
-    (impl_generics, ty_generics, where_clause, output_ty.into())
+    segment.into()
 }
 
 pub fn is_parameterized(
     ty: &Type,
     params: &[&TypeParam],
     found: Option<&mut HashSet<Ident>>,
 ) -> bool {
     struct IsParameterized<'a, 'b> {
--- a/servo/components/style_derive/to_animated_value.rs
+++ b/servo/components/style_derive/to_animated_value.rs
@@ -1,31 +1,42 @@
 /* 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 http://mozilla.org/MPL/2.0/. */
 
 use cg;
 use quote;
-use syn::{self, Ident};
+use syn::DeriveInput;
 use synstructure::BindStyle;
 
-pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
-    let name = &input.ident;
-    let trait_path = parse_quote!(values::animated::ToAnimatedValue);
-    let (impl_generics, ty_generics, mut where_clause, animated_value_type) =
-        cg::fmap_trait_parts(&input, &trait_path, Ident::from("AnimatedValue"));
+pub fn derive(mut input: DeriveInput) -> quote::Tokens {
+    let mut where_clause = input.generics.where_clause.take();
+    for param in input.generics.type_params() {
+        cg::add_predicate(
+            &mut where_clause,
+            parse_quote!(#param: ::values::animated::ToAnimatedValue),
+        );
+    }
 
     let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| {
-        where_clause.add_trait_bound(&binding.ast().ty);
         quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding))
     });
     let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| {
         quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding))
     });
 
+    input.generics.where_clause = where_clause;
+    let name = &input.ident;
+    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+    let animated_value_type = cg::fmap_trait_output(
+        &input,
+        &parse_quote!(values::animated::ToAnimatedValue),
+        "AnimatedValue".into(),
+    );
+
     quote! {
         impl #impl_generics ::values::animated::ToAnimatedValue for #name #ty_generics #where_clause {
             type AnimatedValue = #animated_value_type;
 
             #[allow(unused_variables)]
             #[inline]
             fn to_animated_value(self) -> Self::AnimatedValue {
                 match self {
--- a/servo/components/style_derive/to_computed_value.rs
+++ b/servo/components/style_derive/to_computed_value.rs
@@ -1,29 +1,67 @@
 /* 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 http://mozilla.org/MPL/2.0/. */
 
 use cg;
 use quote::Tokens;
-use syn::{Ident, DeriveInput};
+use syn::DeriveInput;
 use synstructure::BindStyle;
 
-pub fn derive(input: DeriveInput) -> Tokens {
+pub fn derive(mut input: DeriveInput) -> Tokens {
+    let mut where_clause = input.generics.where_clause.take();
+    let (to_body, from_body) = {
+        let params = input.generics.type_params().collect::<Vec<_>>();
+        for param in &params {
+            cg::add_predicate(
+                &mut where_clause,
+                parse_quote!(#param: ::values::computed::ToComputedValue),
+            );
+        }
+
+        let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
+            let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast());
+            if attrs.field_bound {
+                let ty = &binding.ast().ty;
+
+                let output_type = cg::map_type_params(ty, &params, &mut |ident| {
+                    parse_quote!(<#ident as ::values::computed::ToComputedValue>::ComputedValue)
+                });
+
+                cg::add_predicate(
+                    &mut where_clause,
+                    parse_quote!(
+                        #ty: ::values::computed::ToComputedValue<ComputedValue = #output_type>
+                    ),
+                );
+            }
+            quote! {
+                ::values::computed::ToComputedValue::to_computed_value(#binding, context)
+            }
+        });
+        let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
+            quote! {
+                ::values::computed::ToComputedValue::from_computed_value(#binding)
+            }
+        });
+
+        (to_body, from_body)
+    };
+
+    input.generics.where_clause = where_clause;
     let name = &input.ident;
-    let trait_path = parse_quote!(values::computed::ToComputedValue);
-    let (impl_generics, ty_generics, mut where_clause, computed_value_type) =
-        cg::fmap_trait_parts(&input, &trait_path, Ident::from("ComputedValue"));
+    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
 
-    if input.generics.params.is_empty() {
+    if input.generics.type_params().next().is_none() {
         return quote! {
             impl #impl_generics ::values::computed::ToComputedValue for #name #ty_generics
             #where_clause
             {
-                type ComputedValue = #computed_value_type;
+                type ComputedValue = Self;
 
                 #[inline]
                 fn to_computed_value(
                     &self,
                     _context: &::values::computed::Context,
                 ) -> Self::ComputedValue {
                     ::std::clone::Clone::clone(self)
                 }
@@ -31,49 +69,21 @@ pub fn derive(input: DeriveInput) -> Tok
                 #[inline]
                 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
                     ::std::clone::Clone::clone(computed)
                 }
             }
         }
     }
 
-    let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
-        let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast());
-        if attrs.clone {
-            if cg::is_parameterized(&binding.ast().ty, &where_clause.params, None) {
-                cg::add_predicate(
-                    &mut where_clause.inner,
-                    cg::where_predicate(
-                        binding.ast().ty.clone(),
-                        &parse_quote!(std::clone::Clone),
-                        None,
-                    ),
-                );
-            }
-            quote! { ::std::clone::Clone::clone(#binding) }
-        } else {
-            if !attrs.ignore_bound {
-                where_clause.add_trait_bound(&binding.ast().ty);
-            }
-            quote! {
-                ::values::computed::ToComputedValue::to_computed_value(#binding, context)
-            }
-        }
-    });
-    let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
-        let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast());
-        if attrs.clone {
-            quote! { ::std::clone::Clone::clone(#binding) }
-        } else {
-            quote! {
-                ::values::computed::ToComputedValue::from_computed_value(#binding)
-            }
-        }
-    });
+    let computed_value_type = cg::fmap_trait_output(
+        &input,
+        &parse_quote!(values::computed::ToComputedValue),
+        "ComputedValue".into(),
+    );
 
     quote! {
         impl #impl_generics ::values::computed::ToComputedValue for #name #ty_generics #where_clause {
             type ComputedValue = #computed_value_type;
 
             #[allow(unused_variables)]
             #[inline]
             fn to_computed_value(&self, context: &::values::computed::Context) -> Self::ComputedValue {
@@ -90,11 +100,10 @@ pub fn derive(input: DeriveInput) -> Tok
             }
         }
     }
 }
 
 #[darling(attributes(compute), default)]
 #[derive(Default, FromField)]
 struct ComputedValueAttrs {
-    clone: bool,
-    ignore_bound: bool,
+    field_bound: bool,
 }