Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HashStable_NoContext to simplify HashStable implementations in rustc_type_ir #117580

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions compiler/rustc_ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in `rustc_middle`.
pub trait HashStableContext:
rustc_type_ir::HashStableContext + rustc_span::HashStableContext
{
pub trait HashStableContext: rustc_span::HashStableContext {
fn hash_attr(&mut self, _: &ast::Attribute, hasher: &mut StableHasher);
}

Expand Down
79 changes: 54 additions & 25 deletions compiler/rustc_macros/src/hash_stable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,51 +38,80 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
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(
mut s: synstructure::Structure<'_>,
s: synstructure::Structure<'_>,
) -> proc_macro2::TokenStream {
let generic: syn::GenericParam = parse_quote!(__CTX);
s.add_bounds(synstructure::AddBounds::Generics);
s.add_impl_generic(generic);
s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
hash_stable_derive_with_mode(s, HashStableMode::Generic)
}

let discriminant = hash_stable_discriminant(&mut s);
let body = hash_stable_body(&mut s);
pub(crate) fn hash_stable_no_context_derive(
s: synstructure::Structure<'_>,
) -> proc_macro2::TokenStream {
hash_stable_derive_with_mode(s, HashStableMode::NoContext)
}

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 }
}
},
)
enum HashStableMode {
// Use the query-system aware stable hashing context.
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,
}

pub(crate) fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
let generic: syn::GenericParam = parse_quote!('__ctx);
s.add_bounds(synstructure::AddBounds::Generics);
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);

let discriminant = hash_stable_discriminant(&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(
quote!(
::rustc_data_structures::stable_hasher::HashStable<
::rustc_query_system::ich::StableHashingContext<'__ctx>,
#context
>
),
quote! {
#[inline]
fn hash_stable(
&self,
__hcx: &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
__hcx: &mut #context,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
#discriminant
match *self { #body }
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ decl_derive!(
[HashStable_Generic, attributes(stable_hasher)] =>
hash_stable::hash_stable_generic_derive
);
decl_derive!(
[HashStable_NoContext] =>
/// `HashStable` implementation that has no `HashStableContext` bound and
/// which adds `where` bounds for `HashStable` based off of fields and not
/// generics. This is suitable for use in crates like `rustc_type_ir`.
hash_stable::hash_stable_no_context_derive
);

decl_derive!([Decodable] => serialize::decodable_derive);
decl_derive!([Encodable] => serialize::encodable_derive);
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_query_system/src/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,3 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
});
}
}

impl<'ctx> rustc_type_ir::HashStableContext for StableHashingContext<'ctx> {}
18 changes: 1 addition & 17 deletions compiler/rustc_type_ir/src/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ use std::fmt;
use std::hash::Hash;
use std::ops::ControlFlow;

#[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};

use crate::fold::{FallibleTypeFolder, TypeFoldable};
use crate::visit::{TypeVisitable, TypeVisitor};
use crate::{Interner, UniverseIndex};
Expand All @@ -14,7 +11,7 @@ use crate::{Interner, UniverseIndex};
/// numbered starting from 0 in order of first appearance.
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = "V: Clone"), Hash(bound = "V: Hash"))]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub struct Canonical<I: Interner, V> {
pub value: V,
pub max_universe: UniverseIndex,
Expand Down Expand Up @@ -61,19 +58,6 @@ impl<I: Interner, V> Canonical<I, V> {
}
}

#[cfg(feature = "nightly")]
impl<CTX: crate::HashStableContext, I: Interner, V: HashStable<CTX>> HashStable<CTX>
for Canonical<I, V>
where
I::CanonicalVars: HashStable<CTX>,
{
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
self.value.hash_stable(hcx, hasher);
self.max_universe.hash_stable(hcx, hasher);
self.variables.hash_stable(hcx, hasher);
}
}

impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}

impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> {
Expand Down
45 changes: 1 addition & 44 deletions compiler/rustc_type_ir/src/const_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use self::ConstKind::*;
Ord = "feature_allow_slow_enum",
Hash(bound = "")
)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum ConstKind<I: Interner> {
/// A const generic parameter.
Param(I::ParamConst),
Expand Down Expand Up @@ -47,49 +47,6 @@ pub enum ConstKind<I: Interner> {
Expr(I::ExprConst),
}

#[cfg(feature = "nightly")]
const fn const_kind_discriminant<I: Interner>(value: &ConstKind<I>) -> usize {
match value {
Param(_) => 0,
Infer(_) => 1,
Bound(_, _) => 2,
Placeholder(_) => 3,
Unevaluated(_) => 4,
Value(_) => 5,
Error(_) => 6,
Expr(_) => 7,
}
}

#[cfg(feature = "nightly")]
impl<CTX: crate::HashStableContext, I: Interner> HashStable<CTX> for ConstKind<I>
where
I::ParamConst: HashStable<CTX>,
I::BoundConst: HashStable<CTX>,
I::PlaceholderConst: HashStable<CTX>,
I::AliasConst: HashStable<CTX>,
I::ValueConst: HashStable<CTX>,
I::ErrorGuaranteed: HashStable<CTX>,
I::ExprConst: HashStable<CTX>,
{
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
const_kind_discriminant(self).hash_stable(hcx, hasher);
match self {
Param(p) => p.hash_stable(hcx, hasher),
Infer(i) => i.hash_stable(hcx, hasher),
Bound(d, b) => {
d.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
}
Placeholder(p) => p.hash_stable(hcx, hasher),
Unevaluated(u) => u.hash_stable(hcx, hasher),
Value(v) => v.hash_stable(hcx, hasher),
Error(e) => e.hash_stable(hcx, hasher),
Expr(e) => e.hash_stable(hcx, hasher),
}
}
}

impl<I: Interner> PartialEq for ConstKind<I> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
Expand Down
9 changes: 3 additions & 6 deletions compiler/rustc_type_ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ pub use region_kind::*;
pub use ty_info::*;
pub use ty_kind::*;

/// Needed so we can use #[derive(HashStable_Generic)]
pub trait HashStableContext {}

rustc_index::newtype_index! {
/// A [De Bruijn index][dbi] is a standard means of representing
/// regions (and perhaps later types) in a higher-ranked setting. In
Expand Down Expand Up @@ -94,7 +91,7 @@ rustc_index::newtype_index! {
/// is the outer fn.
///
/// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
#[debug_format = "DebruijnIndex({})"]
#[gate_rustc_only]
pub struct DebruijnIndex {
Expand Down Expand Up @@ -179,7 +176,7 @@ pub fn debug_bound_var<T: std::fmt::Write>(
}

#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "nightly", derive(Decodable, Encodable, Hash, HashStable_Generic))]
#[cfg_attr(feature = "nightly", derive(Decodable, Encodable, Hash, HashStable_NoContext))]
#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
pub enum Variance {
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
Expand Down Expand Up @@ -295,7 +292,7 @@ rustc_index::newtype_index! {
/// declared, but a type name in a non-zero universe is a placeholder
/// type -- an idealized representative of "types in general" that we
/// use for checking generic functions.
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
#[debug_format = "U{}"]
#[gate_rustc_only]
pub struct UniverseIndex {}
Expand Down
Loading
Loading