1use std::cmp::Ordering;
2use std::hash::{Hash, Hasher};
3use std::ops::Deref;
45#[cfg(feature = "nightly")]
6use rustc_data_structures::fingerprint::Fingerprint;
7#[cfg(feature = "nightly")]
8use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
9use rustc_type_ir_macros::GenericTypeVisitable;
1011use crate::{DebruijnIndex, TypeFlags};
1213/// A helper type that you can wrap round your own type in order to automatically
14/// cache the stable hash, type flags and debruijn index on creation and
15/// not recompute it whenever the information is needed.
16/// This is only done in incremental mode. You can also opt out of caching by using
17/// StableHash::ZERO for the hash, in which case the hash gets computed each time.
18/// This is useful if you have values that you intern but never (can?) use for stable
19/// hashing.
20#[derive(#[automatically_derived]
impl<T: ::core::marker::Copy> ::core::marker::Copy for WithCachedTypeInfo<T> {
}Copy, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for WithCachedTypeInfo<T> {
#[inline]
fn clone(&self) -> WithCachedTypeInfo<T> {
WithCachedTypeInfo {
internee: ::core::clone::Clone::clone(&self.internee),
stable_hash: ::core::clone::Clone::clone(&self.stable_hash),
flags: ::core::clone::Clone::clone(&self.flags),
outer_exclusive_binder: ::core::clone::Clone::clone(&self.outer_exclusive_binder),
}
}
}Clone, GenericTypeVisitable)]
21pub struct WithCachedTypeInfo<T> {
22pub internee: T,
2324#[cfg(feature = "nightly")]
25pub stable_hash: Fingerprint,
2627/// This field provides fast access to information that is also contained
28 /// in `kind`.
29 ///
30 /// This field shouldn't be used directly and may be removed in the future.
31 /// Use `Ty::flags()` instead.
32pub flags: TypeFlags,
3334/// This field provides fast access to information that is also contained
35 /// in `kind`.
36 ///
37 /// This is a kind of confusing thing: it stores the smallest
38 /// binder such that
39 ///
40 /// (a) the binder itself captures nothing but
41 /// (b) all the late-bound things within the type are captured
42 /// by some sub-binder.
43 ///
44 /// So, for a type without any late-bound things, like `u32`, this
45 /// will be *innermost*, because that is the innermost binder that
46 /// captures nothing. But for a type `&'D u32`, where `'D` is a
47 /// late-bound region with De Bruijn index `D`, this would be `D + 1`
48 /// -- the binder itself does not capture `D`, but `D` is captured
49 /// by an inner binder.
50 ///
51 /// We call this concept an "exclusive" binder `D` because all
52 /// De Bruijn indices within the type are contained within `0..D`
53 /// (exclusive).
54pub outer_exclusive_binder: DebruijnIndex,
55}
5657impl<T: PartialEq> PartialEqfor WithCachedTypeInfo<T> {
58#[inline]
59fn eq(&self, other: &Self) -> bool {
60self.internee.eq(&other.internee)
61 }
62}
6364impl<T: Eq> Eqfor WithCachedTypeInfo<T> {}
6566impl<T: Ord> PartialOrdfor WithCachedTypeInfo<T> {
67fn partial_cmp(&self, other: &WithCachedTypeInfo<T>) -> Option<Ordering> {
68Some(self.internee.cmp(&other.internee))
69 }
70}
7172impl<T: Ord> Ordfor WithCachedTypeInfo<T> {
73fn cmp(&self, other: &WithCachedTypeInfo<T>) -> Ordering {
74self.internee.cmp(&other.internee)
75 }
76}
7778impl<T> Dereffor WithCachedTypeInfo<T> {
79type Target = T;
8081#[inline]
82fn deref(&self) -> &T {
83&self.internee
84 }
85}
8687impl<T: Hash> Hashfor WithCachedTypeInfo<T> {
88#[inline]
89fn hash<H: Hasher>(&self, s: &mut H) {
90#[cfg(feature = "nightly")]
91if self.stable_hash != Fingerprint::ZERO {
92return self.stable_hash.hash(s);
93 }
9495self.internee.hash(s)
96 }
97}
9899#[cfg(feature = "nightly")]
100impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithCachedTypeInfo<T> {
101fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
102if self.stable_hash == Fingerprint::ZERO || truecfg!(debug_assertions) {
103// No cached hash available. This can only mean that incremental is disabled.
104 // We don't cache stable hashes in non-incremental mode, because they are used
105 // so rarely that the performance actually suffers.
106107 // We need to build the hash as if we cached it and then hash that hash, as
108 // otherwise the hashes will differ between cached and non-cached mode.
109let stable_hash: Fingerprint = {
110let mut hasher = StableHasher::new();
111self.internee.hash_stable(hcx, &mut hasher);
112hasher.finish()
113 };
114if truecfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO {
115match (&stable_hash, &self.stable_hash) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::Some(format_args!("cached stable hash does not match freshly computed stable hash")));
}
}
};assert_eq!(
116 stable_hash, self.stable_hash,
117"cached stable hash does not match freshly computed stable hash"
118);
119 }
120stable_hash.hash_stable(hcx, hasher);
121 } else {
122self.stable_hash.hash_stable(hcx, hasher);
123 }
124 }
125}