Unify HashStable implementations

This commit is contained in:
Michael Goulet 2023-11-19 23:25:25 +00:00
parent 426bc70ad6
commit c9143ea1d9
1 changed files with 52 additions and 67 deletions

View File

@ -38,95 +38,80 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
attrs attrs
} }
pub(crate) fn hash_stable_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
hash_stable_derive_with_mode(s, HashStableMode::Normal)
}
pub(crate) fn hash_stable_generic_derive( pub(crate) fn hash_stable_generic_derive(
mut s: synstructure::Structure<'_>, s: synstructure::Structure<'_>,
) -> proc_macro2::TokenStream { ) -> proc_macro2::TokenStream {
let generic: syn::GenericParam = parse_quote!(__CTX); hash_stable_derive_with_mode(s, HashStableMode::Generic)
s.add_bounds(synstructure::AddBounds::Generics);
s.add_impl_generic(generic);
s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
let discriminant = hash_stable_discriminant(&mut s);
let body = hash_stable_body(&mut s);
s.bound_impl(
quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
quote! {
#[inline]
fn hash_stable(
&self,
__hcx: &mut __CTX,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
#discriminant
match *self { #body }
}
},
)
} }
pub(crate) fn hash_stable_no_context_derive( pub(crate) fn hash_stable_no_context_derive(
mut s: synstructure::Structure<'_>, s: synstructure::Structure<'_>,
) -> proc_macro2::TokenStream { ) -> proc_macro2::TokenStream {
let generic: syn::GenericParam = parse_quote!(__CTX); hash_stable_derive_with_mode(s, HashStableMode::NoContext)
s.add_bounds(synstructure::AddBounds::Fields);
s.add_impl_generic(generic);
let body = s.each(|bi| {
let attrs = parse_attributes(bi.ast());
if attrs.ignore {
quote! {}
} else if let Some(project) = attrs.project {
quote! {
(&#bi.#project).hash_stable(__hcx, __hasher);
}
} else {
quote! {
#bi.hash_stable(__hcx, __hasher);
}
}
});
let discriminant = match s.ast().data {
syn::Data::Enum(_) => quote! {
::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
},
syn::Data::Struct(_) => quote! {},
syn::Data::Union(_) => panic!("cannot derive on union"),
};
s.bound_impl(
quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
quote! {
#[inline]
fn hash_stable(
&self,
__hcx: &mut __CTX,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
#discriminant
match *self { #body }
}
},
)
} }
pub(crate) fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { enum HashStableMode {
let generic: syn::GenericParam = parse_quote!('__ctx); // Use the query-system aware stable hashing context.
s.add_bounds(synstructure::AddBounds::Generics); Normal,
// Emit a generic implementation that uses a crate-local `StableHashingContext`
// trait, when the crate is upstream of `rustc_middle`.
Generic,
// Emit a hash-stable implementation that takes no context,
// and emits per-field where clauses for (almost-)perfect derives.
NoContext,
}
fn hash_stable_derive_with_mode(
mut s: synstructure::Structure<'_>,
mode: HashStableMode,
) -> proc_macro2::TokenStream {
let generic: syn::GenericParam = match mode {
HashStableMode::Normal => parse_quote!('__ctx),
HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX),
};
// no_context impl is able to derive by-field, which is closer to a perfect derive.
s.add_bounds(match mode {
HashStableMode::Normal | HashStableMode::Generic => synstructure::AddBounds::Generics,
HashStableMode::NoContext => synstructure::AddBounds::Fields,
});
// For generic impl, add `where __CTX: HashStableContext`.
match mode {
HashStableMode::Normal => {}
HashStableMode::Generic => {
s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
}
HashStableMode::NoContext => {}
}
s.add_impl_generic(generic); s.add_impl_generic(generic);
let discriminant = hash_stable_discriminant(&mut s); let discriminant = hash_stable_discriminant(&mut s);
let body = hash_stable_body(&mut s); let body = hash_stable_body(&mut s);
let context: syn::Type = match mode {
HashStableMode::Normal => {
parse_quote!(::rustc_query_system::ich::StableHashingContext<'__ctx>)
}
HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX),
};
s.bound_impl( s.bound_impl(
quote!( quote!(
::rustc_data_structures::stable_hasher::HashStable< ::rustc_data_structures::stable_hasher::HashStable<
::rustc_query_system::ich::StableHashingContext<'__ctx>, #context
> >
), ),
quote! { quote! {
#[inline] #[inline]
fn hash_stable( fn hash_stable(
&self, &self,
__hcx: &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>, __hcx: &mut #context,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
#discriminant #discriminant
match *self { #body } match *self { #body }