diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs index 76a1288e6d3..ba94f3776eb 100644 --- a/compiler/rustc_data_structures/src/intern.rs +++ b/compiler/rustc_data_structures/src/intern.rs @@ -4,8 +4,6 @@ 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; @@ -110,86 +108,5 @@ where } } -/// A helper type that you can wrap round your own type in order to automatically -/// cache the stable hash on creation and not recompute it whenever the stable hash -/// of the type is computed. -/// This is only done in incremental mode. You can also opt out of caching by using -/// StableHash::ZERO for the hash, in which case the hash gets computed each time. -/// This is useful if you have values that you intern but never (can?) use for stable -/// hashing. -#[derive(Copy, Clone)] -pub struct WithStableHash { - pub internee: T, - pub stable_hash: Fingerprint, -} - -impl PartialEq for WithStableHash { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.internee.eq(&other.internee) - } -} - -impl Eq for WithStableHash {} - -impl PartialOrd for WithStableHash { - fn partial_cmp(&self, other: &WithStableHash) -> Option { - Some(self.internee.cmp(&other.internee)) - } -} - -impl Ord for WithStableHash { - fn cmp(&self, other: &WithStableHash) -> Ordering { - self.internee.cmp(&other.internee) - } -} - -impl Deref for WithStableHash { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - &self.internee - } -} - -impl Hash for WithStableHash { - #[inline] - fn hash(&self, s: &mut H) { - if self.stable_hash != Fingerprint::ZERO { - self.stable_hash.hash(s) - } else { - self.internee.hash(s) - } - } -} - -impl, CTX> HashStable for WithStableHash { - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - if self.stable_hash == Fingerprint::ZERO || cfg!(debug_assertions) { - // 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(); - self.internee.hash_stable(hcx, &mut hasher); - hasher.finish() - }; - if cfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO { - assert_eq!( - stable_hash, self.stable_hash, - "cached stable hash does not match freshly computed stable hash" - ); - } - stable_hash.hash_stable(hcx, hasher); - } else { - self.stable_hash.hash_stable(hcx, hasher); - } - } -} - #[cfg(test)] mod tests; diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index cf1d82f4c06..0fa81b7e4e0 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -10,7 +10,7 @@ declare_tool_lint! { /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to /// always be passed by value. This is usually used for types that are thin wrappers around /// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which - /// is a reference to an `Interned`) + /// is a reference to an `Interned`) pub rustc::PASS_BY_VALUE, Warn, "pass by reference of a type flagged as `#[rustc_pass_by_value]`", diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 9aed75931bf..6de68841fe9 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -1,3 +1,5 @@ +#![allow(rustc::usage_of_ty_tykind)] + /// This higher-order macro declares a list of types which can be allocated by `Arena`. /// /// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type @@ -89,8 +91,8 @@ macro_rules! arena_types { [] hir_id_set: rustc_hir::HirIdSet, // Interned types - [] tys: rustc_data_structures::intern::WithStableHash>, - [] predicates: rustc_data_structures::intern::WithStableHash>, + [] tys: rustc_type_ir::WithCachedTypeInfo>, + [] predicates: rustc_type_ir::WithCachedTypeInfo>, [] consts: rustc_middle::ty::ConstS<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 5f911d5884a..221105ac48f 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -103,7 +103,7 @@ impl hash::Hash for Allocation { /// Interned types generally have an `Outer` type and an `Inner` type, where /// `Outer` is a newtype around `Interned`, and all the operations are /// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an -/// outer type and `TyS` is its inner type. +/// outer type and `TyKind` is its inner type. /// /// Here things are different because only const allocations are interned. This /// means that both the inner type (`Allocation`) and the outer type diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c39d04d3819..82ca1b87535 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1,5 +1,7 @@ //! Type context book-keeping. +#![allow(rustc::usage_of_ty_tykind)] + use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; use crate::hir::place::Place as HirPlace; @@ -19,15 +21,15 @@ use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, - PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, - Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, - UintTy, Visibility, + PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, ProjectionTy, Region, + RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, + Visibility, }; use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts}; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::intern::{Interned, WithStableHash}; +use rustc_data_structures::intern::Interned; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; @@ -68,6 +70,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; +use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags}; use std::any::Any; @@ -137,13 +140,13 @@ pub struct CtxtInterners<'tcx> { // Specifically use a speedy hash algorithm for these hash sets, since // they're accessed quite often. - type_: InternedSet<'tcx, WithStableHash>>, + type_: InternedSet<'tcx, WithCachedTypeInfo>>, const_lists: InternedSet<'tcx, List>>, substs: InternedSet<'tcx, InternalSubsts<'tcx>>, canonical_var_infos: InternedSet<'tcx, List>>, region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List>>, - predicate: InternedSet<'tcx, WithStableHash>>, + predicate: InternedSet<'tcx, WithCachedTypeInfo>>>, predicates: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, @@ -194,15 +197,12 @@ impl<'tcx> CtxtInterners<'tcx> { let stable_hash = self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind); - let ty_struct = TyS { - kind, + InternedInSet(self.arena.alloc(WithCachedTypeInfo { + internee: kind, + stable_hash, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, - }; - - InternedInSet( - self.arena.alloc(WithStableHash { internee: ty_struct, stable_hash }), - ) + })) }) .0, )) @@ -246,16 +246,12 @@ impl<'tcx> CtxtInterners<'tcx> { let stable_hash = self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind); - let predicate_struct = PredicateS { - kind, + InternedInSet(self.arena.alloc(WithCachedTypeInfo { + internee: kind, + stable_hash, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, - }; - - InternedInSet( - self.arena - .alloc(WithStableHash { internee: predicate_struct, stable_hash }), - ) + })) }) .0, )) @@ -2104,7 +2100,7 @@ macro_rules! sty_debug_print { let shards = tcx.interners.type_.lock_shards(); let types = shards.iter().flat_map(|shard| shard.keys()); for &InternedInSet(t) in types { - let variant = match t.kind { + let variant = match t.internee { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, ty::Error(_) => /* unimportant */ continue, @@ -2214,51 +2210,26 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> { } #[allow(rustc::usage_of_ty_tykind)] -impl<'tcx> Borrow> for InternedInSet<'tcx, WithStableHash>> { - fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { - &self.0.kind +impl<'tcx, T> Borrow for InternedInSet<'tcx, WithCachedTypeInfo> { + fn borrow<'a>(&'a self) -> &'a T { + &self.0.internee } } -impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash>> { - fn eq(&self, other: &InternedInSet<'tcx, WithStableHash>>) -> bool { +impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, WithCachedTypeInfo> { + fn eq(&self, other: &InternedInSet<'tcx, WithCachedTypeInfo>) -> bool { // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals // `x == y`. - self.0.kind == other.0.kind + self.0.internee == other.0.internee } } -impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash>> {} +impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, WithCachedTypeInfo> {} -impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash>> { +impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, WithCachedTypeInfo> { fn hash(&self, s: &mut H) { // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. - self.0.kind.hash(s) - } -} - -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, 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, WithStableHash>> {} - -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) + self.0.internee.hash(s) } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f89a8cdfdee..cd679ffdfbc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -9,6 +9,8 @@ //! //! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html +#![allow(rustc::usage_of_ty_tykind)] + pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; pub use self::AssocItemContainer::*; @@ -32,7 +34,7 @@ use rustc_ast::node_id::NodeMap; use rustc_attr as attr; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_data_structures::intern::{Interned, WithStableHash}; +use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; @@ -50,6 +52,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, Span}; use rustc_target::abi::{Align, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; +use rustc_type_ir::WithCachedTypeInfo; pub use subst::*; pub use vtable::*; @@ -445,86 +448,22 @@ pub struct CReaderCacheKey { pub pos: usize, } -/// Represents a type. -/// -/// IMPORTANT: -/// - This is a very "dumb" struct (with no derives and no `impls`). -/// - Values of this type are always interned and thus unique, and are stored -/// as an `Interned`. -/// - `Ty` (which contains a reference to a `Interned`) or `Interned` -/// should be used everywhere instead of `TyS`. In particular, `Ty` has most -/// of the relevant methods. -#[derive(PartialEq, Eq, PartialOrd, Ord)] -#[allow(rustc::usage_of_ty_tykind)] -pub(crate) struct TyS<'tcx> { - /// This field shouldn't be used directly and may be removed in the future. - /// Use `Ty::kind()` instead. - kind: TyKind<'tcx>, - - /// This field provides fast access to information that is also contained - /// in `kind`. - /// - /// This field shouldn't be used directly and may be removed in the future. - /// Use `Ty::flags()` instead. - flags: TypeFlags, - - /// This field provides fast access to information that is also contained - /// in `kind`. - /// - /// This is a kind of confusing thing: it stores the smallest - /// binder such that - /// - /// (a) the binder itself captures nothing but - /// (b) all the late-bound things within the type are captured - /// by some sub-binder. - /// - /// So, for a type without any late-bound things, like `u32`, this - /// will be *innermost*, because that is the innermost binder that - /// captures nothing. But for a type `&'D u32`, where `'D` is a - /// late-bound region with De Bruijn index `D`, this would be `D + 1` - /// -- the binder itself does not capture `D`, but `D` is captured - /// by an inner binder. - /// - /// We call this concept an "exclusive" binder `D` because all - /// De Bruijn indices within the type are contained within `0..D` - /// (exclusive). - outer_exclusive_binder: ty::DebruijnIndex, -} - -/// Use this rather than `TyS`, whenever possible. +/// Use this rather than `TyKind`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_diagnostic_item = "Ty"] #[rustc_pass_by_value] -pub struct Ty<'tcx>(Interned<'tcx, WithStableHash>>); +pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo>>); impl<'tcx> TyCtxt<'tcx> { /// A "bool" type used in rustc_mir_transform unit tests when we /// have not spun up a TyCtxt. - pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = Ty(Interned::new_unchecked(&WithStableHash { - internee: TyS { - kind: ty::Bool, + pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = + Ty(Interned::new_unchecked(&WithCachedTypeInfo { + internee: ty::Bool, + stable_hash: Fingerprint::ZERO, flags: TypeFlags::empty(), outer_exclusive_binder: DebruijnIndex::from_usize(0), - }, - stable_hash: Fingerprint::ZERO, - })); -} - -impl<'a, 'tcx> HashStable> for TyS<'tcx> { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let TyS { - kind, - - // The other fields just provide fast access to information that is - // also contained in `kind`, so no need to hash them. - flags: _, - - outer_exclusive_binder: _, - } = self; - - kind.hash_stable(hcx, hasher) - } + })); } impl ty::EarlyBoundRegion { @@ -535,28 +474,18 @@ impl ty::EarlyBoundRegion { } } -/// Represents a predicate. -/// -/// See comments on `TyS`, which apply here too (albeit for -/// `PredicateS`/`Predicate` rather than `TyS`/`Ty`). -#[derive(Debug)] -pub(crate) struct PredicateS<'tcx> { - kind: Binder<'tcx, PredicateKind<'tcx>>, - flags: TypeFlags, - /// See the comment for the corresponding field of [TyS]. - outer_exclusive_binder: ty::DebruijnIndex, -} - -/// Use this rather than `PredicateS`, whenever possible. +/// Use this rather than `PredicateKind`, whenever possible. #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] -pub struct Predicate<'tcx>(Interned<'tcx, WithStableHash>>); +pub struct Predicate<'tcx>( + Interned<'tcx, WithCachedTypeInfo>>>, +); impl<'tcx> Predicate<'tcx> { /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`. #[inline] pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> { - self.0.kind + self.0.internee } #[inline(always)] @@ -631,21 +560,6 @@ impl<'tcx> Predicate<'tcx> { } } -impl<'a, 'tcx> HashStable> for PredicateS<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let PredicateS { - ref kind, - - // The other fields just provide fast access to information that is - // also contained in `kind`, so no need to hash them. - flags: _, - outer_exclusive_binder: _, - } = self; - - kind.hash_stable(hcx, hasher); - } -} - impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) @@ -1028,7 +942,7 @@ impl<'tcx> Term<'tcx> { unsafe { match ptr & TAG_MASK { TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const WithStableHash>), + &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), ))), CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), @@ -1072,7 +986,7 @@ impl<'tcx> TermKind<'tcx> { TermKind::Ty(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 WithStableHash> as usize) + (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo> as usize) } TermKind::Const(ct) => { // Ensure we can use the tag bits. @@ -2692,8 +2606,7 @@ mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // tidy-alphabetical-start - static_assert_size!(PredicateS<'_>, 48); - static_assert_size!(TyS<'_>, 40); - static_assert_size!(WithStableHash>, 56); + static_assert_size!(PredicateKind<'_>, 32); + static_assert_size!(WithCachedTypeInfo>, 56); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 1eec119616e..9cbda95a4df 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1611,7 +1611,7 @@ impl<'tcx> Region<'tcx> { impl<'tcx> Ty<'tcx> { #[inline(always)] pub fn kind(self) -> &'tcx TyKind<'tcx> { - &self.0.0.kind + &self.0.0 } #[inline(always)] diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 23507d28045..a1b084a5e89 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -6,10 +6,11 @@ use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; use crate::ty::visit::{TypeVisitable, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; -use rustc_data_structures::intern::{Interned, WithStableHash}; +use rustc_data_structures::intern::Interned; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; +use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; use core::intrinsics; @@ -84,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 WithStableHash> as usize) + (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo> as usize) } GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. @@ -162,7 +163,7 @@ impl<'tcx> GenericArg<'tcx> { &*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>), ))), TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const WithStableHash>), + &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo>), ))), CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 581993ba7d8..e3f7a1bd033 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -19,9 +19,11 @@ use std::mem::discriminant; pub mod codec; pub mod sty; +pub mod ty_info; pub use codec::*; pub use sty::*; +pub use ty_info::*; /// Needed so we can use #[derive(HashStable_Generic)] pub trait HashStableContext {} diff --git a/compiler/rustc_type_ir/src/ty_info.rs b/compiler/rustc_type_ir/src/ty_info.rs new file mode 100644 index 00000000000..4e5d424886a --- /dev/null +++ b/compiler/rustc_type_ir/src/ty_info.rs @@ -0,0 +1,122 @@ +use std::{ + cmp::Ordering, + hash::{Hash, Hasher}, + ops::Deref, +}; + +use rustc_data_structures::{ + fingerprint::Fingerprint, + stable_hasher::{HashStable, StableHasher}, +}; + +use crate::{DebruijnIndex, TypeFlags}; + +/// A helper type that you can wrap round your own type in order to automatically +/// cache the stable hash, type flags and debruijn index on creation and +/// not recompute it whenever the information is needed. +/// This is only done in incremental mode. You can also opt out of caching by using +/// StableHash::ZERO for the hash, in which case the hash gets computed each time. +/// This is useful if you have values that you intern but never (can?) use for stable +/// hashing. +#[derive(Copy, Clone)] +pub struct WithCachedTypeInfo { + pub internee: T, + pub stable_hash: Fingerprint, + + /// This field provides fast access to information that is also contained + /// in `kind`. + /// + /// This field shouldn't be used directly and may be removed in the future. + /// Use `Ty::flags()` instead. + pub flags: TypeFlags, + + /// This field provides fast access to information that is also contained + /// in `kind`. + /// + /// This is a kind of confusing thing: it stores the smallest + /// binder such that + /// + /// (a) the binder itself captures nothing but + /// (b) all the late-bound things within the type are captured + /// by some sub-binder. + /// + /// So, for a type without any late-bound things, like `u32`, this + /// will be *innermost*, because that is the innermost binder that + /// captures nothing. But for a type `&'D u32`, where `'D` is a + /// late-bound region with De Bruijn index `D`, this would be `D + 1` + /// -- the binder itself does not capture `D`, but `D` is captured + /// by an inner binder. + /// + /// We call this concept an "exclusive" binder `D` because all + /// De Bruijn indices within the type are contained within `0..D` + /// (exclusive). + pub outer_exclusive_binder: DebruijnIndex, +} + +impl PartialEq for WithCachedTypeInfo { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.internee.eq(&other.internee) + } +} + +impl Eq for WithCachedTypeInfo {} + +impl PartialOrd for WithCachedTypeInfo { + fn partial_cmp(&self, other: &WithCachedTypeInfo) -> Option { + Some(self.internee.cmp(&other.internee)) + } +} + +impl Ord for WithCachedTypeInfo { + fn cmp(&self, other: &WithCachedTypeInfo) -> Ordering { + self.internee.cmp(&other.internee) + } +} + +impl Deref for WithCachedTypeInfo { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.internee + } +} + +impl Hash for WithCachedTypeInfo { + #[inline] + fn hash(&self, s: &mut H) { + if self.stable_hash != Fingerprint::ZERO { + self.stable_hash.hash(s) + } else { + self.internee.hash(s) + } + } +} + +impl, CTX> HashStable for WithCachedTypeInfo { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + if self.stable_hash == Fingerprint::ZERO || cfg!(debug_assertions) { + // 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(); + self.internee.hash_stable(hcx, &mut hasher); + hasher.finish() + }; + if cfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO { + assert_eq!( + stable_hash, self.stable_hash, + "cached stable hash does not match freshly computed stable hash" + ); + } + stable_hash.hash_stable(hcx, hasher); + } else { + self.stable_hash.hash_stable(hcx, hasher); + } + } +}