style: Teach style_derive's map_type_params about mapping self correctly.

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
This commit is contained in:
Emilio Cobos Álvarez 2020-07-16 18:51:21 +00:00
parent 65a06d5003
commit f27003c810
3 changed files with 22 additions and 13 deletions

View file

@ -154,19 +154,19 @@ pub fn fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: &
segment.into() 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 where
F: FnMut(&Ident) -> Type, F: FnMut(&Ident) -> Type,
{ {
match *ty { match *ty {
Type::Slice(ref inner) => Type::from(TypeSlice { 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() ..inner.clone()
}), }),
Type::Array(ref inner) => { Type::Array(ref inner) => {
//ref ty, ref expr) => { //ref ty, ref expr) => {
Type::from(TypeArray { 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() ..inner.clone()
}) })
}, },
@ -175,7 +175,7 @@ where
elems: inner elems: inner
.elems .elems
.iter() .iter()
.map(|ty| map_type_params(&ty, params, f)) .map(|ty| map_type_params(&ty, params, self_type, f))
.collect(), .collect(),
..inner.clone() ..inner.clone()
}), }),
@ -187,10 +187,16 @@ where
if params.iter().any(|ref param| &param.ident == ident) { if params.iter().any(|ref param| &param.ident == ident) {
return f(ident); return f(ident);
} }
if ident == "Self" {
return Type::from(TypePath {
qself: None,
path: self_type.clone(),
});
}
} }
Type::from(TypePath { Type::from(TypePath {
qself: None, 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 { Type::Path(TypePath {
@ -198,25 +204,25 @@ where
ref path, ref path,
}) => Type::from(TypePath { }) => Type::from(TypePath {
qself: qself.as_ref().map(|qself| QSelf { 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, position: qself.position,
..qself.clone() ..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 { 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() ..inner.clone()
}), }),
Type::Group(ref inner) => Type::from(TypeGroup { 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() ..inner.clone()
}), }),
ref ty => panic!("type {:?} cannot be mapped yet", ty), 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 where
F: FnMut(&Ident) -> Type, F: FnMut(&Ident) -> Type,
{ {
@ -236,11 +242,11 @@ where
.map(|arg| match arg { .map(|arg| match arg {
ty @ &GenericArgument::Lifetime(_) => ty.clone(), ty @ &GenericArgument::Lifetime(_) => ty.clone(),
&GenericArgument::Type(ref data) => { &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(ref data) => {
GenericArgument::Binding(Binding { GenericArgument::Binding(Binding {
ty: map_type_params(&data.ty, params, f), ty: map_type_params(&data.ty, params, self_type, f),
..data.clone() ..data.clone()
}) })
}, },

View file

@ -112,6 +112,7 @@ pub fn derive(mut input: DeriveInput) -> TokenStream {
let name = &input.ident; let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
quote! { quote! {
impl #impl_generics style_traits::SpecifiedValueInfo for #name #ty_generics impl #impl_generics style_traits::SpecifiedValueInfo for #name #ty_generics
#where_clause #where_clause

View file

@ -47,12 +47,15 @@ pub fn derive_to_value(
cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path)); 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 mut add_field_bound = |binding: &BindingInfo| {
let ty = &binding.ast().ty; let ty = &binding.ast().ty;
let output_type = cg::map_type_params( let output_type = cg::map_type_params(
ty, ty,
&params, &params,
&computed_value_type,
&mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name), &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; input.generics.where_clause = where_clause;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); 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); let impl_ = trait_impl(from_body, to_body);