From f27003c810b45f850a18c55b0f8134a9e52a3082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 16 Jul 2020 18:51:21 +0000 Subject: [PATCH] style: Teach style_derive's map_type_params about mapping self correctly. Consider the following: struct Complex { something: T, #[compute(field_bound)] something_else: Generic, } That will generate: impl ToComputedValue for Complex where T: ToComputedValue, Generic: 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: ::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 --- components/derive_common/cg.rs | 30 +++++++++++-------- .../style_derive/specified_value_info.rs | 1 + components/style_derive/to_computed_value.rs | 4 ++- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/components/derive_common/cg.rs b/components/derive_common/cg.rs index c51c0d7750b..8abfd871496 100644 --- a/components/derive_common/cg.rs +++ b/components/derive_common/cg.rs @@ -154,19 +154,19 @@ pub fn fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: & segment.into() } -pub fn map_type_params(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type +pub fn map_type_params(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() }) }, @@ -175,7 +175,7 @@ where 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() }), @@ -187,10 +187,16 @@ where if params.iter().any(|ref param| ¶m.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 { @@ -198,25 +204,25 @@ where 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(path: &Path, params: &[&TypeParam], f: &mut F) -> Path +fn map_type_params_in_path(path: &Path, params: &[&TypeParam], self_type: &Path, f: &mut F) -> Path where F: FnMut(&Ident) -> Type, { @@ -236,11 +242,11 @@ where .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() }) }, diff --git a/components/style_derive/specified_value_info.rs b/components/style_derive/specified_value_info.rs index b9473c64008..c477f4a7cf9 100644 --- a/components/style_derive/specified_value_info.rs +++ b/components/style_derive/specified_value_info.rs @@ -112,6 +112,7 @@ pub fn derive(mut input: DeriveInput) -> TokenStream { let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + quote! { impl #impl_generics style_traits::SpecifiedValueInfo for #name #ty_generics #where_clause diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index 5fe2be5af75..5e0f595c6b9 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -47,12 +47,15 @@ pub fn derive_to_value( 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, ¶ms, + &computed_value_type, &mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name), ); @@ -142,7 +145,6 @@ pub fn derive_to_value( 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);