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()
}
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()
})
},
@ -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| &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 {
@ -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<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,
{
@ -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()
})
},

View file

@ -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

View file

@ -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,
&params,
&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);