Skip to content

Commit

Permalink
Auto merge of #117580 - compiler-errors:hash-stable-simplify-rustc_ty…
Browse files Browse the repository at this point in the history
…pe_ir, r=jackh726

Add `HashStable_NoContext` to simplify `HashStable` implementations in `rustc_type_ir`

adds `derive(HashStable_NoContext)` which is a derived `HashStable` implementation that has no `HashStableContext` bound, and which adds `where` bounds for `HashStable` based off of *fields* and not generics.

This means we can `derive(HashStable_NoContext)` in more places in `rustc_type_ir` rather than having to hand-roll implementations.
  • Loading branch information
bors committed Nov 21, 2023
2 parents c5af061 + c9143ea commit 7bd385d
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 316 deletions.
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

0 comments on commit 7bd385d

Please sign in to comment.