about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_data_structures/src/intern.rs73
-rw-r--r--compiler/rustc_middle/src/arena.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs17
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs45
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs49
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs6
-rw-r--r--compiler/rustc_middle/src/ty/util.rs4
-rw-r--r--compiler/rustc_query_system/src/ich/hcx.rs8
8 files changed, 140 insertions, 64 deletions
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<T> {
+    pub internee: T,
+    pub stable_hash: Fingerprint,
+}
+
+impl<T: PartialEq> PartialEq for InTy<T> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.internee.eq(&other.internee)
+    }
+}
+
+impl<T: Eq> Eq for InTy<T> {}
+
+impl<T: Ord> PartialOrd for InTy<T> {
+    fn partial_cmp(&self, other: &InTy<T>) -> Option<Ordering> {
+        Some(self.internee.cmp(&other.internee))
+    }
+}
+
+impl<T: Ord> Ord for InTy<T> {
+    fn cmp(&self, other: &InTy<T>) -> Ordering {
+        self.internee.cmp(&other.internee)
+    }
+}
+
+impl<T> Deref for InTy<T> {
+    type Target = T;
+
+    #[inline]
+    fn deref(&self) -> &T {
+        &self.internee
+    }
+}
+
+impl<T: Hash> Hash for InTy<T> {
+    #[inline]
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        self.internee.hash(s)
+    }
+}
+
+impl<T: HashStable<CTX>, CTX: InternedHashingContext> HashStable<CTX> for InTy<T> {
+    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<rustc_middle::ty::TyS<'tcx>>,
             [] 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<TyS<'tcx>>>,
     substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
     canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
     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<TyKind<'tcx>> for InternedInSet<'tcx, TyS<'tcx>> {
+impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, InTy<TyS<'tcx>>> {
     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<TyS<'tcx>>> {
+    fn eq(&self, other: &InternedInSet<'tcx, InTy<TyS<'tcx>>>) -> 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<TyS<'tcx>>> {}
 
-impl<'tcx> Hash for InternedInSet<'tcx, TyS<'tcx>> {
+impl<'tcx> Hash for InternedInSet<'tcx, InTy<TyS<'tcx>>> {
     fn hash<H: Hasher>(&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<TyS<'tcx>>>);
 
 // 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<StableHashingContext<'a>> for Ty<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> 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<StableHashingContext<'a>> 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<ty::TyS<'tcx>> 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<ty::TyS<'tcx>>),
                 ))),
                 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> {}