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}