Rollup merge of #104898 - oli-obk:group_all_the_things, r=wesleywiser
Put all cached values into a central struct instead of just the stable hash cc `@nnethercote` this allows re-use of the type for Predicate without duplicating all the logic for the non-hash cached fields
This commit is contained in:
commit
db416ea195
@ -4,8 +4,6 @@ use std::hash::{Hash, Hasher};
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::fingerprint::Fingerprint;
|
|
||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct PrivateZst;
|
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<T> {
|
|
||||||
pub internee: T,
|
|
||||||
pub stable_hash: Fingerprint,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PartialEq> PartialEq for WithStableHash<T> {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.internee.eq(&other.internee)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Eq> Eq for WithStableHash<T> {}
|
|
||||||
|
|
||||||
impl<T: Ord> PartialOrd for WithStableHash<T> {
|
|
||||||
fn partial_cmp(&self, other: &WithStableHash<T>) -> Option<Ordering> {
|
|
||||||
Some(self.internee.cmp(&other.internee))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Ord> Ord for WithStableHash<T> {
|
|
||||||
fn cmp(&self, other: &WithStableHash<T>) -> Ordering {
|
|
||||||
self.internee.cmp(&other.internee)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Deref for WithStableHash<T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn deref(&self) -> &T {
|
|
||||||
&self.internee
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Hash> Hash for WithStableHash<T> {
|
|
||||||
#[inline]
|
|
||||||
fn hash<H: Hasher>(&self, s: &mut H) {
|
|
||||||
if self.stable_hash != Fingerprint::ZERO {
|
|
||||||
self.stable_hash.hash(s)
|
|
||||||
} else {
|
|
||||||
self.internee.hash(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithStableHash<T> {
|
|
||||||
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)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -10,7 +10,7 @@ declare_tool_lint! {
|
|||||||
/// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to
|
/// 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
|
/// 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
|
/// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which
|
||||||
/// is a reference to an `Interned<TyS>`)
|
/// is a reference to an `Interned<TyKind>`)
|
||||||
pub rustc::PASS_BY_VALUE,
|
pub rustc::PASS_BY_VALUE,
|
||||||
Warn,
|
Warn,
|
||||||
"pass by reference of a type flagged as `#[rustc_pass_by_value]`",
|
"pass by reference of a type flagged as `#[rustc_pass_by_value]`",
|
||||||
|
@ -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`.
|
/// 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
|
/// 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,
|
[] hir_id_set: rustc_hir::HirIdSet,
|
||||||
|
|
||||||
// Interned types
|
// Interned types
|
||||||
[] tys: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::TyS<'tcx>>,
|
[] tys: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::TyKind<'tcx>>,
|
||||||
[] predicates: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::PredicateS<'tcx>>,
|
[] predicates: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::PredicateKind<'tcx>>,
|
||||||
[] consts: rustc_middle::ty::ConstS<'tcx>,
|
[] consts: rustc_middle::ty::ConstS<'tcx>,
|
||||||
|
|
||||||
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
|
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
|
||||||
|
@ -103,7 +103,7 @@ impl hash::Hash for Allocation {
|
|||||||
/// Interned types generally have an `Outer` type and an `Inner` type, where
|
/// Interned types generally have an `Outer` type and an `Inner` type, where
|
||||||
/// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
|
/// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
|
||||||
/// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
|
/// 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
|
/// Here things are different because only const allocations are interned. This
|
||||||
/// means that both the inner type (`Allocation`) and the outer type
|
/// means that both the inner type (`Allocation`) and the outer type
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
//! Type context book-keeping.
|
//! Type context book-keeping.
|
||||||
|
|
||||||
|
#![allow(rustc::usage_of_ty_tykind)]
|
||||||
|
|
||||||
use crate::arena::Arena;
|
use crate::arena::Arena;
|
||||||
use crate::dep_graph::{DepGraph, DepKindStruct};
|
use crate::dep_graph::{DepGraph, DepKindStruct};
|
||||||
use crate::hir::place::Place as HirPlace;
|
use crate::hir::place::Place as HirPlace;
|
||||||
@ -19,15 +21,15 @@ use crate::ty::{
|
|||||||
self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
|
self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
|
||||||
ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid,
|
ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid,
|
||||||
GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
|
GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
|
||||||
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy,
|
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, ProjectionTy, Region,
|
||||||
Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut,
|
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy,
|
||||||
UintTy, Visibility,
|
Visibility,
|
||||||
};
|
};
|
||||||
use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts};
|
use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
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::memmap::Mmap;
|
||||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||||
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
|
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::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::sty::TyKind::*;
|
||||||
|
use rustc_type_ir::WithCachedTypeInfo;
|
||||||
use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags};
|
use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags};
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
@ -137,13 +140,13 @@ pub struct CtxtInterners<'tcx> {
|
|||||||
|
|
||||||
// Specifically use a speedy hash algorithm for these hash sets, since
|
// Specifically use a speedy hash algorithm for these hash sets, since
|
||||||
// they're accessed quite often.
|
// they're accessed quite often.
|
||||||
type_: InternedSet<'tcx, WithStableHash<TyS<'tcx>>>,
|
type_: InternedSet<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>,
|
||||||
const_lists: InternedSet<'tcx, List<ty::Const<'tcx>>>,
|
const_lists: InternedSet<'tcx, List<ty::Const<'tcx>>>,
|
||||||
substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
|
substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
|
||||||
canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
|
canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
|
||||||
region: InternedSet<'tcx, RegionKind<'tcx>>,
|
region: InternedSet<'tcx, RegionKind<'tcx>>,
|
||||||
poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
|
poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
|
||||||
predicate: InternedSet<'tcx, WithStableHash<PredicateS<'tcx>>>,
|
predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
|
||||||
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
|
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
|
||||||
projs: InternedSet<'tcx, List<ProjectionKind>>,
|
projs: InternedSet<'tcx, List<ProjectionKind>>,
|
||||||
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
|
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
|
||||||
@ -194,15 +197,12 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||||||
let stable_hash =
|
let stable_hash =
|
||||||
self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);
|
self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);
|
||||||
|
|
||||||
let ty_struct = TyS {
|
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
|
||||||
kind,
|
internee: kind,
|
||||||
|
stable_hash,
|
||||||
flags: flags.flags,
|
flags: flags.flags,
|
||||||
outer_exclusive_binder: flags.outer_exclusive_binder,
|
outer_exclusive_binder: flags.outer_exclusive_binder,
|
||||||
};
|
}))
|
||||||
|
|
||||||
InternedInSet(
|
|
||||||
self.arena.alloc(WithStableHash { internee: ty_struct, stable_hash }),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.0,
|
.0,
|
||||||
))
|
))
|
||||||
@ -246,16 +246,12 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||||||
let stable_hash =
|
let stable_hash =
|
||||||
self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);
|
self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);
|
||||||
|
|
||||||
let predicate_struct = PredicateS {
|
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
|
||||||
kind,
|
internee: kind,
|
||||||
|
stable_hash,
|
||||||
flags: flags.flags,
|
flags: flags.flags,
|
||||||
outer_exclusive_binder: flags.outer_exclusive_binder,
|
outer_exclusive_binder: flags.outer_exclusive_binder,
|
||||||
};
|
}))
|
||||||
|
|
||||||
InternedInSet(
|
|
||||||
self.arena
|
|
||||||
.alloc(WithStableHash { internee: predicate_struct, stable_hash }),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.0,
|
.0,
|
||||||
))
|
))
|
||||||
@ -2104,7 +2100,7 @@ macro_rules! sty_debug_print {
|
|||||||
let shards = tcx.interners.type_.lock_shards();
|
let shards = tcx.interners.type_.lock_shards();
|
||||||
let types = shards.iter().flat_map(|shard| shard.keys());
|
let types = shards.iter().flat_map(|shard| shard.keys());
|
||||||
for &InternedInSet(t) in types {
|
for &InternedInSet(t) in types {
|
||||||
let variant = match t.kind {
|
let variant = match t.internee {
|
||||||
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
|
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
|
||||||
ty::Float(..) | ty::Str | ty::Never => continue,
|
ty::Float(..) | ty::Str | ty::Never => continue,
|
||||||
ty::Error(_) => /* unimportant */ 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)]
|
#[allow(rustc::usage_of_ty_tykind)]
|
||||||
impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
|
impl<'tcx, T> Borrow<T> for InternedInSet<'tcx, WithCachedTypeInfo<T>> {
|
||||||
fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
|
fn borrow<'a>(&'a self) -> &'a T {
|
||||||
&self.0.kind
|
&self.0.internee
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
|
impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, WithCachedTypeInfo<T>> {
|
||||||
fn eq(&self, other: &InternedInSet<'tcx, WithStableHash<TyS<'tcx>>>) -> bool {
|
fn eq(&self, other: &InternedInSet<'tcx, WithCachedTypeInfo<T>>) -> bool {
|
||||||
// The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
|
// The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
|
||||||
// `x == y`.
|
// `x == y`.
|
||||||
self.0.kind == other.0.kind
|
self.0.internee == other.0.internee
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {}
|
impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, WithCachedTypeInfo<T>> {}
|
||||||
|
|
||||||
impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
|
impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, WithCachedTypeInfo<T>> {
|
||||||
fn hash<H: Hasher>(&self, s: &mut H) {
|
fn hash<H: Hasher>(&self, s: &mut H) {
|
||||||
// The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
|
// The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
|
||||||
self.0.kind.hash(s)
|
self.0.internee.hash(s)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>>
|
|
||||||
for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>>
|
|
||||||
{
|
|
||||||
fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
|
|
||||||
&self.0.kind
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {
|
|
||||||
fn eq(&self, other: &InternedInSet<'tcx, WithStableHash<PredicateS<'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, WithStableHash<PredicateS<'tcx>>> {}
|
|
||||||
|
|
||||||
impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<PredicateS<'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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
//!
|
//!
|
||||||
//! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html
|
//! ["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::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||||
pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||||
pub use self::AssocItemContainer::*;
|
pub use self::AssocItemContainer::*;
|
||||||
@ -32,7 +34,7 @@ use rustc_ast::node_id::NodeMap;
|
|||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
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::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
|
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
@ -50,6 +52,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
|||||||
use rustc_span::{ExpnId, Span};
|
use rustc_span::{ExpnId, Span};
|
||||||
use rustc_target::abi::{Align, Integer, IntegerType, VariantIdx};
|
use rustc_target::abi::{Align, Integer, IntegerType, VariantIdx};
|
||||||
pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
||||||
|
use rustc_type_ir::WithCachedTypeInfo;
|
||||||
pub use subst::*;
|
pub use subst::*;
|
||||||
pub use vtable::*;
|
pub use vtable::*;
|
||||||
|
|
||||||
@ -445,86 +448,22 @@ pub struct CReaderCacheKey {
|
|||||||
pub pos: usize,
|
pub pos: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a type.
|
/// Use this rather than `TyKind`, whenever possible.
|
||||||
///
|
|
||||||
/// 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<TyS>`.
|
|
||||||
/// - `Ty` (which contains a reference to a `Interned<TyS>`) or `Interned<TyS>`
|
|
||||||
/// 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.
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
|
||||||
#[rustc_diagnostic_item = "Ty"]
|
#[rustc_diagnostic_item = "Ty"]
|
||||||
#[rustc_pass_by_value]
|
#[rustc_pass_by_value]
|
||||||
pub struct Ty<'tcx>(Interned<'tcx, WithStableHash<TyS<'tcx>>>);
|
pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>);
|
||||||
|
|
||||||
impl<'tcx> TyCtxt<'tcx> {
|
impl<'tcx> TyCtxt<'tcx> {
|
||||||
/// A "bool" type used in rustc_mir_transform unit tests when we
|
/// A "bool" type used in rustc_mir_transform unit tests when we
|
||||||
/// have not spun up a TyCtxt.
|
/// have not spun up a TyCtxt.
|
||||||
pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = Ty(Interned::new_unchecked(&WithStableHash {
|
pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> =
|
||||||
internee: TyS {
|
Ty(Interned::new_unchecked(&WithCachedTypeInfo {
|
||||||
kind: ty::Bool,
|
internee: ty::Bool,
|
||||||
|
stable_hash: Fingerprint::ZERO,
|
||||||
flags: TypeFlags::empty(),
|
flags: TypeFlags::empty(),
|
||||||
outer_exclusive_binder: DebruijnIndex::from_usize(0),
|
outer_exclusive_binder: DebruijnIndex::from_usize(0),
|
||||||
},
|
}));
|
||||||
stable_hash: Fingerprint::ZERO,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> 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 {
|
impl ty::EarlyBoundRegion {
|
||||||
@ -535,28 +474,18 @@ impl ty::EarlyBoundRegion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a predicate.
|
/// Use this rather than `PredicateKind`, whenever possible.
|
||||||
///
|
|
||||||
/// 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.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)]
|
||||||
#[rustc_pass_by_value]
|
#[rustc_pass_by_value]
|
||||||
pub struct Predicate<'tcx>(Interned<'tcx, WithStableHash<PredicateS<'tcx>>>);
|
pub struct Predicate<'tcx>(
|
||||||
|
Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
|
||||||
|
);
|
||||||
|
|
||||||
impl<'tcx> Predicate<'tcx> {
|
impl<'tcx> Predicate<'tcx> {
|
||||||
/// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`.
|
/// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
|
pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
|
||||||
self.0.kind
|
self.0.internee
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -631,21 +560,6 @@ impl<'tcx> Predicate<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> 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<'_> {
|
impl rustc_errors::IntoDiagnosticArg for Predicate<'_> {
|
||||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||||
rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
|
rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
|
||||||
@ -1028,7 +942,7 @@ impl<'tcx> Term<'tcx> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
match ptr & TAG_MASK {
|
match ptr & TAG_MASK {
|
||||||
TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked(
|
TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked(
|
||||||
&*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
|
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
|
||||||
))),
|
))),
|
||||||
CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
|
CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
|
||||||
&*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
|
&*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
|
||||||
@ -1072,7 +986,7 @@ impl<'tcx> TermKind<'tcx> {
|
|||||||
TermKind::Ty(ty) => {
|
TermKind::Ty(ty) => {
|
||||||
// Ensure we can use the tag bits.
|
// Ensure we can use the tag bits.
|
||||||
assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
|
assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
|
||||||
(TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
|
(TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo<ty::TyKind<'tcx>> as usize)
|
||||||
}
|
}
|
||||||
TermKind::Const(ct) => {
|
TermKind::Const(ct) => {
|
||||||
// Ensure we can use the tag bits.
|
// Ensure we can use the tag bits.
|
||||||
@ -2692,8 +2606,7 @@ mod size_asserts {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
use rustc_data_structures::static_assert_size;
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
static_assert_size!(PredicateS<'_>, 48);
|
static_assert_size!(PredicateKind<'_>, 32);
|
||||||
static_assert_size!(TyS<'_>, 40);
|
static_assert_size!(WithCachedTypeInfo<TyKind<'_>>, 56);
|
||||||
static_assert_size!(WithStableHash<TyS<'_>>, 56);
|
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
@ -1611,7 +1611,7 @@ impl<'tcx> Region<'tcx> {
|
|||||||
impl<'tcx> Ty<'tcx> {
|
impl<'tcx> Ty<'tcx> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn kind(self) -> &'tcx TyKind<'tcx> {
|
pub fn kind(self) -> &'tcx TyKind<'tcx> {
|
||||||
&self.0.0.kind
|
&self.0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -6,10 +6,11 @@ use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
|
|||||||
use crate::ty::visit::{TypeVisitable, TypeVisitor};
|
use crate::ty::visit::{TypeVisitable, TypeVisitor};
|
||||||
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
|
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_hir::def_id::DefId;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
use rustc_serialize::{self, Decodable, Encodable};
|
use rustc_serialize::{self, Decodable, Encodable};
|
||||||
|
use rustc_type_ir::WithCachedTypeInfo;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use core::intrinsics;
|
use core::intrinsics;
|
||||||
@ -84,7 +85,7 @@ impl<'tcx> GenericArgKind<'tcx> {
|
|||||||
GenericArgKind::Type(ty) => {
|
GenericArgKind::Type(ty) => {
|
||||||
// Ensure we can use the tag bits.
|
// Ensure we can use the tag bits.
|
||||||
assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
|
assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
|
||||||
(TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
|
(TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo<ty::TyKind<'tcx>> as usize)
|
||||||
}
|
}
|
||||||
GenericArgKind::Const(ct) => {
|
GenericArgKind::Const(ct) => {
|
||||||
// Ensure we can use the tag bits.
|
// Ensure we can use the tag bits.
|
||||||
@ -162,7 +163,7 @@ impl<'tcx> GenericArg<'tcx> {
|
|||||||
&*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>),
|
&*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>),
|
||||||
))),
|
))),
|
||||||
TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
|
TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
|
||||||
&*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
|
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
|
||||||
))),
|
))),
|
||||||
CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
|
CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
|
||||||
&*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
|
&*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
|
||||||
|
@ -19,9 +19,11 @@ use std::mem::discriminant;
|
|||||||
|
|
||||||
pub mod codec;
|
pub mod codec;
|
||||||
pub mod sty;
|
pub mod sty;
|
||||||
|
pub mod ty_info;
|
||||||
|
|
||||||
pub use codec::*;
|
pub use codec::*;
|
||||||
pub use sty::*;
|
pub use sty::*;
|
||||||
|
pub use ty_info::*;
|
||||||
|
|
||||||
/// Needed so we can use #[derive(HashStable_Generic)]
|
/// Needed so we can use #[derive(HashStable_Generic)]
|
||||||
pub trait HashStableContext {}
|
pub trait HashStableContext {}
|
||||||
|
122
compiler/rustc_type_ir/src/ty_info.rs
Normal file
122
compiler/rustc_type_ir/src/ty_info.rs
Normal file
@ -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<T> {
|
||||||
|
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<T: PartialEq> PartialEq for WithCachedTypeInfo<T> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.internee.eq(&other.internee)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq> Eq for WithCachedTypeInfo<T> {}
|
||||||
|
|
||||||
|
impl<T: Ord> PartialOrd for WithCachedTypeInfo<T> {
|
||||||
|
fn partial_cmp(&self, other: &WithCachedTypeInfo<T>) -> Option<Ordering> {
|
||||||
|
Some(self.internee.cmp(&other.internee))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Ord> Ord for WithCachedTypeInfo<T> {
|
||||||
|
fn cmp(&self, other: &WithCachedTypeInfo<T>) -> Ordering {
|
||||||
|
self.internee.cmp(&other.internee)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for WithCachedTypeInfo<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&self.internee
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Hash> Hash for WithCachedTypeInfo<T> {
|
||||||
|
#[inline]
|
||||||
|
fn hash<H: Hasher>(&self, s: &mut H) {
|
||||||
|
if self.stable_hash != Fingerprint::ZERO {
|
||||||
|
self.stable_hash.hash(s)
|
||||||
|
} else {
|
||||||
|
self.internee.hash(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithCachedTypeInfo<T> {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user