rustc_type_ir/
ty_info.rs

1use std::cmp::Ordering;
2use std::hash::{Hash, Hasher};
3use std::ops::Deref;
4
5#[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;
10
11use crate::{DebruijnIndex, TypeFlags};
12
13/// 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(Copy, Clone, GenericTypeVisitable)]
21pub struct WithCachedTypeInfo<T> {
22    pub internee: T,
23
24    #[cfg(feature = "nightly")]
25    pub stable_hash: Fingerprint,
26
27    /// 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.
32    pub flags: TypeFlags,
33
34    /// 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).
54    pub outer_exclusive_binder: DebruijnIndex,
55}
56
57impl<T: PartialEq> PartialEq for WithCachedTypeInfo<T> {
58    #[inline]
59    fn eq(&self, other: &Self) -> bool {
60        self.internee.eq(&other.internee)
61    }
62}
63
64impl<T: Eq> Eq for WithCachedTypeInfo<T> {}
65
66impl<T: Ord> PartialOrd for WithCachedTypeInfo<T> {
67    fn partial_cmp(&self, other: &WithCachedTypeInfo<T>) -> Option<Ordering> {
68        Some(self.internee.cmp(&other.internee))
69    }
70}
71
72impl<T: Ord> Ord for WithCachedTypeInfo<T> {
73    fn cmp(&self, other: &WithCachedTypeInfo<T>) -> Ordering {
74        self.internee.cmp(&other.internee)
75    }
76}
77
78impl<T> Deref for WithCachedTypeInfo<T> {
79    type Target = T;
80
81    #[inline]
82    fn deref(&self) -> &T {
83        &self.internee
84    }
85}
86
87impl<T: Hash> Hash for WithCachedTypeInfo<T> {
88    #[inline]
89    fn hash<H: Hasher>(&self, s: &mut H) {
90        #[cfg(feature = "nightly")]
91        if self.stable_hash != Fingerprint::ZERO {
92            return self.stable_hash.hash(s);
93        }
94
95        self.internee.hash(s)
96    }
97}
98
99#[cfg(feature = "nightly")]
100impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithCachedTypeInfo<T> {
101    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
102        if self.stable_hash == Fingerprint::ZERO || cfg!(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.
106
107            // 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.
109            let stable_hash: Fingerprint = {
110                let mut hasher = StableHasher::new();
111                self.internee.hash_stable(hcx, &mut hasher);
112                hasher.finish()
113            };
114            if cfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO {
115                assert_eq!(
116                    stable_hash, self.stable_hash,
117                    "cached stable hash does not match freshly computed stable hash"
118                );
119            }
120            stable_hash.hash_stable(hcx, hasher);
121        } else {
122            self.stable_hash.hash_stable(hcx, hasher);
123        }
124    }
125}