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
This commit is contained in:
Emilio Cobos Álvarez 2020-07-16 18:51:21 +00:00
Родитель 63ae9a2469
Коммит a4fa8230aa
2 изменённых файлов: 21 добавлений и 13 удалений

Просмотреть файл

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

Просмотреть файл

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