Bug 1653339 - Teach style_derive's map_type_params about mapping self correctly. r=boris
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 16 Jul 2020 18:51:21 +0000 (2020-07-16)
changeset 540799 da77d5528a0819c4e61a92f642542b55da81183e
parent 540798 5e9a7815de712ddc8ab5bb784b644a03e5f2e6b4
child 540800 9d4220211ae01b3b755be1c89159523ba661a837
push id37609
push userrmaries@mozilla.com
push dateFri, 17 Jul 2020 03:27:56 +0000 (2020-07-17)
treeherdermozilla-central@f6127ce5c744 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersboris
bugs1653339
milestone80.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 1653339 - Teach style_derive's map_type_params about mapping self correctly. r=boris Consider the following: struct Complex<T> { something: T, #[compute(field_bound)] something_else: Generic<Self, T>, } That will generate: impl<T> ToComputedValue for Complex<T> where T: ToComputedValue, Generic<Self, T>: ToComputedValue<ComputedValue = Generic<Self, <T as ToComputedValue>::ComputedValue>>, { // ... } That last clause is obviously incorrect. map_type_params correctly maps the T, but it should know also about Self. Ideally we could just do the same as for T and do: <Self as ToComputedValue>::ComputedValue But that doesn't quite work, because we are in that implementation of the trait, and the compiler rightfully complains about we don't yet knowing the computed type. So we need to pass it explicitly, which is simple enough, if a bit annoying. Differential Revision: https://phabricator.services.mozilla.com/D83816
servo/components/derive_common/cg.rs
servo/components/style_derive/to_computed_value.rs
--- a/servo/components/derive_common/cg.rs
+++ b/servo/components/derive_common/cg.rs
@@ -149,79 +149,85 @@ pub fn fmap_trait_output(input: &DeriveI
             colon2_token: Default::default(),
             gt_token: Default::default(),
             lt_token: Default::default(),
         }),
     };
     segment.into()
 }
 
-pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type
+pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], self_type: &Path, f: &mut F) -> Type
 where
     F: FnMut(&Ident) -> Type,
 {
     match *ty {
         Type::Slice(ref inner) => Type::from(TypeSlice {
-            elem: Box::new(map_type_params(&inner.elem, params, f)),
+            elem: Box::new(map_type_params(&inner.elem, params, self_type, f)),
             ..inner.clone()
         }),
         Type::Array(ref inner) => {
             //ref ty, ref expr) => {
             Type::from(TypeArray {
-                elem: Box::new(map_type_params(&inner.elem, params, f)),
+                elem: Box::new(map_type_params(&inner.elem, params, self_type, f)),
                 ..inner.clone()
             })
         },
         ref ty @ Type::Never(_) => ty.clone(),
         Type::Tuple(ref inner) => Type::from(TypeTuple {
             elems: inner
                 .elems
                 .iter()
-                .map(|ty| map_type_params(&ty, params, f))
+                .map(|ty| map_type_params(&ty, params, self_type, f))
                 .collect(),
             ..inner.clone()
         }),
         Type::Path(TypePath {
             qself: None,
             ref path,
         }) => {
             if let Some(ident) = path_to_ident(path) {
                 if params.iter().any(|ref param| &param.ident == ident) {
                     return f(ident);
                 }
+                if ident == "Self" {
+                    return Type::from(TypePath {
+                        qself: None,
+                        path: self_type.clone(),
+                    });
+                }
             }
             Type::from(TypePath {
                 qself: None,
-                path: map_type_params_in_path(path, params, f),
+                path: map_type_params_in_path(path, params, self_type, f),
             })
         },
         Type::Path(TypePath {
             ref qself,
             ref path,
         }) => Type::from(TypePath {
             qself: qself.as_ref().map(|qself| QSelf {
-                ty: Box::new(map_type_params(&qself.ty, params, f)),
+                ty: Box::new(map_type_params(&qself.ty, params, self_type, f)),
                 position: qself.position,
                 ..qself.clone()
             }),
-            path: map_type_params_in_path(path, params, f),
+            path: map_type_params_in_path(path, params, self_type, f),
         }),
         Type::Paren(ref inner) => Type::from(TypeParen {
-            elem: Box::new(map_type_params(&inner.elem, params, f)),
+            elem: Box::new(map_type_params(&inner.elem, params, self_type, f)),
             ..inner.clone()
         }),
         Type::Group(ref inner) => Type::from(TypeGroup {
-            elem: Box::new(map_type_params(&inner.elem, params, f)),
+            elem: Box::new(map_type_params(&inner.elem, params, self_type, f)),
             ..inner.clone()
         }),
         ref ty => panic!("type {:?} cannot be mapped yet", ty),
     }
 }
 
-fn map_type_params_in_path<F>(path: &Path, params: &[&TypeParam], f: &mut F) -> Path
+fn map_type_params_in_path<F>(path: &Path, params: &[&TypeParam], self_type: &Path, f: &mut F) -> Path
 where
     F: FnMut(&Ident) -> Type,
 {
     Path {
         leading_colon: path.leading_colon,
         segments: path
             .segments
             .iter()
@@ -231,21 +237,21 @@ where
                     PathArguments::AngleBracketed(ref data) => {
                         PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                             args: data
                                 .args
                                 .iter()
                                 .map(|arg| match arg {
                                     ty @ &GenericArgument::Lifetime(_) => ty.clone(),
                                     &GenericArgument::Type(ref data) => {
-                                        GenericArgument::Type(map_type_params(data, params, f))
+                                        GenericArgument::Type(map_type_params(data, params, self_type, f))
                                     },
                                     &GenericArgument::Binding(ref data) => {
                                         GenericArgument::Binding(Binding {
-                                            ty: map_type_params(&data.ty, params, f),
+                                            ty: map_type_params(&data.ty, params, self_type, f),
                                             ..data.clone()
                                         })
                                     },
                                     ref arg => panic!("arguments {:?} cannot be mapped yet", arg),
                                 })
                                 .collect(),
                             ..data.clone()
                         })
--- a/servo/components/style_derive/to_computed_value.rs
+++ b/servo/components/style_derive/to_computed_value.rs
@@ -42,22 +42,25 @@ pub fn derive_to_value(
         BindStyle::Ref | BindStyle::RefMut => false,
     };
 
     let params = input.generics.type_params().collect::<Vec<_>>();
     for param in &params {
         cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path));
     }
 
+    let computed_value_type = cg::fmap_trait_output(&input, &trait_path, &output_type_name);
+
     let mut add_field_bound = |binding: &BindingInfo| {
         let ty = &binding.ast().ty;
 
         let output_type = cg::map_type_params(
             ty,
             &params,
+            &computed_value_type,
             &mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name),
         );
 
         cg::add_predicate(
             &mut where_clause,
             parse_quote!(
                 #ty: #trait_path<#output_type_name = #output_type>
             ),
@@ -137,17 +140,16 @@ pub fn derive_to_value(
             }
         };
 
         (to_body, from_body)
     };
 
     input.generics.where_clause = where_clause;
     let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
-    let computed_value_type = cg::fmap_trait_output(&input, &trait_path, &output_type_name);
 
     let impl_ = trait_impl(from_body, to_body);
 
     quote! {
         impl #impl_generics #trait_path for #name #ty_generics #where_clause {
             type #output_type_name = #computed_value_type;
 
             #impl_