diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs index 7a320b10b60..1b187cd306e 100644 --- a/compiler/rustc_data_structures/src/intern.rs +++ b/compiler/rustc_data_structures/src/intern.rs @@ -4,6 +4,8 @@ use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::ptr; +use crate::fingerprint::Fingerprint; + mod private { #[derive(Clone, Copy, Debug)] pub struct PrivateZst; @@ -108,5 +110,76 @@ where } } +/// A helper trait so that `Interned` things can cache stable hashes reproducibly. +pub trait InternedHashingContext { + fn with_def_path_and_no_spans(&mut self, f: impl FnOnce(&mut Self)); +} + +#[derive(Copy, Clone)] +pub struct InTy { + pub internee: T, + pub stable_hash: Fingerprint, +} + +impl PartialEq for InTy { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.internee.eq(&other.internee) + } +} + +impl Eq for InTy {} + +impl PartialOrd for InTy { + fn partial_cmp(&self, other: &InTy) -> Option { + Some(self.internee.cmp(&other.internee)) + } +} + +impl Ord for InTy { + fn cmp(&self, other: &InTy) -> Ordering { + self.internee.cmp(&other.internee) + } +} + +impl Deref for InTy { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.internee + } +} + +impl Hash for InTy { + #[inline] + fn hash(&self, s: &mut H) { + self.internee.hash(s) + } +} + +impl, CTX: InternedHashingContext> HashStable for InTy { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + let stable_hash = self.stable_hash; + + if stable_hash == Fingerprint::ZERO { + // No cached hash available. This can only mean that incremental is disabled. + // We don't cache stable hashes in non-incremental mode, because they are used + // so rarely that the performance actually suffers. + + // We need to build the hash as if we cached it and then hash that hash, as + // otherwise the hashes will differ between cached and non-cached mode. + let stable_hash: Fingerprint = { + let mut hasher = StableHasher::new(); + hcx.with_def_path_and_no_spans(|hcx| self.internee.hash_stable(hcx, &mut hasher)); + hasher.finish() + }; + stable_hash.hash_stable(hcx, hasher); + } else { + stable_hash.hash_stable(hcx, hasher); + } + } +} + #[cfg(test)] mod tests; diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 170dd113f6d..5141d5beb7d 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -87,7 +87,7 @@ macro_rules! arena_types { [] hir_id_set: rustc_hir::HirIdSet, // Interned types - [] tys: rustc_middle::ty::TyS<'tcx>, + [] tys: rustc_data_structures::intern::InTy>, [] predicates: rustc_middle::ty::PredicateS<'tcx>, [] consts: rustc_middle::ty::ConstS<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ac9f04ee055..bc077a673f3 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -26,7 +26,7 @@ use crate::ty::{ use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::intern::Interned; +use rustc_data_structures::intern::{InTy, Interned}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; @@ -105,7 +105,7 @@ pub struct CtxtInterners<'tcx> { // Specifically use a speedy hash algorithm for these hash sets, since // they're accessed quite often. - type_: InternedSet<'tcx, TyS<'tcx>>, + type_: InternedSet<'tcx, InTy>>, substs: InternedSet<'tcx, InternalSubsts<'tcx>>, canonical_var_infos: InternedSet<'tcx, List>>, region: InternedSet<'tcx, RegionKind>, @@ -178,10 +178,9 @@ impl<'tcx> CtxtInterners<'tcx> { kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, - stable_hash, }; - InternedInSet(self.arena.alloc(ty_struct)) + InternedInSet(self.arena.alloc(InTy { internee: ty_struct, stable_hash })) }) .0, )) @@ -2048,23 +2047,23 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> { } #[allow(rustc::usage_of_ty_tykind)] -impl<'tcx> Borrow> for InternedInSet<'tcx, TyS<'tcx>> { +impl<'tcx> Borrow> for InternedInSet<'tcx, InTy>> { fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { &self.0.kind } } -impl<'tcx> PartialEq for InternedInSet<'tcx, TyS<'tcx>> { - fn eq(&self, other: &InternedInSet<'tcx, TyS<'tcx>>) -> bool { +impl<'tcx> PartialEq for InternedInSet<'tcx, InTy>> { + fn eq(&self, other: &InternedInSet<'tcx, InTy>>) -> bool { // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals // `x == y`. self.0.kind == other.0.kind } } -impl<'tcx> Eq for InternedInSet<'tcx, TyS<'tcx>> {} +impl<'tcx> Eq for InternedInSet<'tcx, InTy>> {} -impl<'tcx> Hash for InternedInSet<'tcx, TyS<'tcx>> { +impl<'tcx> Hash for InternedInSet<'tcx, InTy>> { fn hash(&self, s: &mut H) { // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. self.0.kind.hash(s) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 653b4908ab5..39acf252698 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -31,8 +31,8 @@ use crate::ty::util::Discr; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_data_structures::intern::Interned; -use rustc_data_structures::stable_hasher::{HashStable, NodeIdHashingMode, StableHasher}; +use rustc_data_structures::intern::{InTy, Interned}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -433,32 +433,28 @@ crate struct TyS<'tcx> { /// De Bruijn indices within the type are contained within `0..D` /// (exclusive). outer_exclusive_binder: ty::DebruijnIndex, - - /// The stable hash of the type. This way hashing of types will not have to work - /// on the address of the type anymore, but can instead just read this field - stable_hash: Fingerprint, } // `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(TyS<'_>, 56); +static_assert_size!(TyS<'_>, 40); /// Use this rather than `TyS`, whenever possible. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_diagnostic_item = "Ty"] #[rustc_pass_by_value] -pub struct Ty<'tcx>(Interned<'tcx, TyS<'tcx>>); +pub struct Ty<'tcx>(Interned<'tcx, InTy>>); // Statics only used for internal testing. -pub static BOOL_TY: Ty<'static> = Ty(Interned::new_unchecked(&BOOL_TYS)); -static BOOL_TYS: TyS<'static> = TyS { +pub static BOOL_TY: Ty<'static> = + Ty(Interned::new_unchecked(&InTy { internee: BOOL_TYS, stable_hash: Fingerprint::ZERO })); +const BOOL_TYS: TyS<'static> = TyS { kind: ty::Bool, flags: TypeFlags::empty(), outer_exclusive_binder: DebruijnIndex::from_usize(0), - stable_hash: Fingerprint::ZERO, }; -impl<'a, 'tcx> HashStable> for Ty<'tcx> { +impl<'a, 'tcx> HashStable> for TyS<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let TyS { kind, @@ -468,28 +464,9 @@ impl<'a, 'tcx> HashStable> for Ty<'tcx> { flags: _, outer_exclusive_binder: _, + } = self; - stable_hash, - } = self.0.0; - - if *stable_hash == Fingerprint::ZERO { - // No cached hash available. This can only mean that incremental is disabled. - // We don't cache stable hashes in non-incremental mode, because they are used - // so rarely that the performance actually suffers. - - let stable_hash: Fingerprint = { - let mut hasher = StableHasher::new(); - hcx.while_hashing_spans(false, |hcx| { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - kind.hash_stable(hcx, &mut hasher) - }) - }); - hasher.finish() - }; - stable_hash.hash_stable(hcx, hasher); - } else { - stable_hash.hash_stable(hcx, hasher); - } + kind.hash_stable(hcx, hasher) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 9a9c529f245..7e0b0ace8c0 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3,7 +3,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::ieee::{Double, Single}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::intern::Interned; +use rustc_data_structures::intern::{InTy, Interned}; use rustc_data_structures::sso::SsoHashSet; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; @@ -1266,18 +1266,29 @@ pub trait PrettyPrinter<'tcx>: ty::Ref( _, Ty(Interned( - ty::TyS { - kind: - ty::Array( - Ty(Interned(ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, _)), - ty::Const(Interned( - ty::ConstS { - val: ty::ConstKind::Value(ConstValue::Scalar(int)), - .. - }, - _, - )), - ), + InTy { + internee: + ty::TyS { + kind: + ty::Array( + Ty(Interned( + InTy { + internee: + ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, + .. + }, + _, + )), + ty::Const(Interned( + ty::ConstS { + val: ty::ConstKind::Value(ConstValue::Scalar(int)), + .. + }, + _, + )), + ), + .. + }, .. }, _, @@ -1439,7 +1450,11 @@ pub trait PrettyPrinter<'tcx>: // Byte/string slices, printed as (byte) string literals. ( ConstValue::Slice { data, start, end }, - ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Slice(t), .. }, _)), _), + ty::Ref( + _, + Ty(Interned(InTy { internee: ty::TyS { kind: ty::Slice(t), .. }, .. }, _)), + _, + ), ) if *t == u8_type => { // The `inspect` here is okay since we checked the bounds, and there are // no relocations (we have an active slice reference here). We don't use @@ -1450,7 +1465,11 @@ pub trait PrettyPrinter<'tcx>: } ( ConstValue::Slice { data, start, end }, - ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Str, .. }, _)), _), + ty::Ref( + _, + Ty(Interned(InTy { internee: ty::TyS { kind: ty::Str, .. }, .. }, _)), + _, + ), ) => { // The `inspect` here is okay since we checked the bounds, and there are no // relocations (we have an active `str` reference here). We don't use this diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 0a6cb276f75..50357877c0a 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -6,7 +6,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor} use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; -use rustc_data_structures::intern::Interned; +use rustc_data_structures::intern::{InTy, Interned}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; @@ -85,7 +85,7 @@ impl<'tcx> GenericArgKind<'tcx> { GenericArgKind::Type(ty) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(ty.0.0) & TAG_MASK, 0); - (TYPE_TAG, ty.0.0 as *const ty::TyS<'tcx> as usize) + (TYPE_TAG, ty.0.0 as *const InTy> as usize) } GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. @@ -154,7 +154,7 @@ impl<'tcx> GenericArg<'tcx> { &*((ptr & !TAG_MASK) as *const ty::RegionKind), ))), TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const ty::TyS<'tcx>), + &*((ptr & !TAG_MASK) as *const InTy>), ))), CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 7d9a917d04c..a5cc730813f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -13,7 +13,7 @@ use rustc_apfloat::Float as _; use rustc_ast as ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::intern::Interned; +use rustc_data_structures::intern::{InTy, Interned}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -427,7 +427,7 @@ impl<'tcx> TyCtxt<'tcx> { !impl_generics.region_param(ebr, self).pure_wrt_drop } GenericArgKind::Type(Ty(Interned( - ty::TyS { kind: ty::Param(ref pt), .. }, + InTy { internee: ty::TyS { kind: ty::Param(ref pt), .. }, .. }, _, ))) => !impl_generics.type_param(pt, self).pure_wrt_drop, GenericArgKind::Const(Const(Interned( diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index 76e21be17bc..a073bf71057 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -231,4 +231,12 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { } } +impl<'a> rustc_data_structures::intern::InternedHashingContext for StableHashingContext<'a> { + fn with_def_path_and_no_spans(&mut self, f: impl FnOnce(&mut Self)) { + self.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| f(hcx)) + }); + } +} + impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}