diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 7bd4b6c0c2767..e83106b1ee515 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -89,7 +89,7 @@ macro_rules! arena_types { // Interned types [] tys: rustc_data_structures::intern::WithStableHash>, - [] predicates: rustc_middle::ty::PredicateS<'tcx>, + [] predicates: rustc_data_structures::intern::WithStableHash>, [] consts: rustc_middle::ty::ConstS<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3590aae51c3df..a1acca3097d82 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -142,7 +142,7 @@ pub struct CtxtInterners<'tcx> { canonical_var_infos: InternedSet<'tcx, List>>, region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List>>, - predicate: InternedSet<'tcx, PredicateS<'tcx>>, + predicate: InternedSet<'tcx, WithStableHash>>, predicates: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, @@ -190,20 +190,8 @@ impl<'tcx> CtxtInterners<'tcx> { self.type_ .intern(kind, |kind| { let flags = super::flags::FlagComputation::for_kind(&kind); - - // It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them. - // Without incremental, we rarely stable-hash types, so let's not do it proactively. - let stable_hash = if flags.flags.intersects(TypeFlags::NEEDS_INFER) - || sess.opts.incremental.is_none() - { - Fingerprint::ZERO - } else { - let mut hasher = StableHasher::new(); - let mut hcx = - StableHashingContext::new(sess, definitions, cstore, source_span); - kind.hash_stable(&mut hcx, &mut hasher); - hasher.finish() - }; + let stable_hash = + self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind); let ty_struct = TyS { kind, @@ -219,20 +207,54 @@ impl<'tcx> CtxtInterners<'tcx> { )) } + fn stable_hash<'a, T: HashStable>>( + &self, + flags: &ty::flags::FlagComputation, + sess: &'a Session, + definitions: &'a rustc_hir::definitions::Definitions, + cstore: &'a CrateStoreDyn, + source_span: &'a IndexVec, + val: &T, + ) -> Fingerprint { + // It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them. + // Without incremental, we rarely stable-hash types, so let's not do it proactively. + if flags.flags.intersects(TypeFlags::NEEDS_INFER) || sess.opts.incremental.is_none() { + Fingerprint::ZERO + } else { + let mut hasher = StableHasher::new(); + let mut hcx = StableHashingContext::new(sess, definitions, cstore, source_span); + val.hash_stable(&mut hcx, &mut hasher); + hasher.finish() + } + } + #[inline(never)] - fn intern_predicate(&self, kind: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { + fn intern_predicate( + &self, + kind: Binder<'tcx, PredicateKind<'tcx>>, + sess: &Session, + definitions: &rustc_hir::definitions::Definitions, + cstore: &CrateStoreDyn, + source_span: &IndexVec, + ) -> Predicate<'tcx> { Predicate(Interned::new_unchecked( self.predicate .intern(kind, |kind| { let flags = super::flags::FlagComputation::for_predicate(kind); + let stable_hash = + self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind); + let predicate_struct = PredicateS { kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, }; - InternedInSet(self.arena.alloc(predicate_struct)) + InternedInSet( + self.arena + .alloc(WithStableHash { internee: predicate_struct, stable_hash }), + ) }) .0, )) @@ -2168,23 +2190,25 @@ impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash>> { } } -impl<'tcx> Borrow>> for InternedInSet<'tcx, PredicateS<'tcx>> { +impl<'tcx> Borrow>> + for InternedInSet<'tcx, WithStableHash>> +{ fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> { &self.0.kind } } -impl<'tcx> PartialEq for InternedInSet<'tcx, PredicateS<'tcx>> { - fn eq(&self, other: &InternedInSet<'tcx, PredicateS<'tcx>>) -> bool { +impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash>> { + fn eq(&self, other: &InternedInSet<'tcx, WithStableHash>>) -> 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, PredicateS<'tcx>> {} +impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash>> {} -impl<'tcx> Hash for InternedInSet<'tcx, PredicateS<'tcx>> { +impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash>> { fn hash(&self, s: &mut H) { // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. self.0.kind.hash(s) @@ -2386,7 +2410,14 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { - self.interners.intern_predicate(binder) + self.interners.intern_predicate( + binder, + self.sess, + &self.definitions.read(), + &*self.untracked_resolutions.cstore, + // This is only used to create a stable hashing context. + &self.untracked_resolutions.source_span, + ) } #[inline] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 595b73986a87b..a32a2e175730a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -548,9 +548,9 @@ pub(crate) struct PredicateS<'tcx> { } /// Use this rather than `PredicateS`, whenever possible. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] -pub struct Predicate<'tcx>(Interned<'tcx, PredicateS<'tcx>>); +pub struct Predicate<'tcx>(Interned<'tcx, WithStableHash>>); impl<'tcx> Predicate<'tcx> { /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`. @@ -631,7 +631,7 @@ impl<'tcx> Predicate<'tcx> { } } -impl<'a, 'tcx> HashStable> for Predicate<'tcx> { +impl<'a, 'tcx> HashStable> for PredicateS<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let PredicateS { ref kind, @@ -640,7 +640,7 @@ impl<'a, 'tcx> HashStable> for Predicate<'tcx> { // also contained in `kind`, so no need to hash them. flags: _, outer_exclusive_binder: _, - } = self.0.0; + } = self; kind.hash_stable(hcx, hasher); }