1use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
5
6use crate::dep_graph;
7use crate::dep_graph::{DepKind, DepNodeKey};
8use crate::query::erase::{self, Erasable, Erased};
9use crate::query::plumbing::QueryVTable;
10use crate::query::{QueryCache, QueryMode};
11use crate::ty::TyCtxt;
12
13#[inline(always)]
18fn try_get_cached<'tcx, C>(tcx: TyCtxt<'tcx>, cache: &C, key: &C::Key) -> Option<C::Value>
19where
20 C: QueryCache,
21{
22 match cache.lookup(key) {
23 Some((value, index)) => {
24 tcx.prof.query_cache_hit(index.into());
25 tcx.dep_graph.read_index(index);
26 Some(value)
27 }
28 None => None,
29 }
30}
31
32#[inline(always)]
35pub(crate) fn query_get_at<'tcx, Cache>(
36 tcx: TyCtxt<'tcx>,
37 execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
38 query_cache: &Cache,
39 span: Span,
40 key: Cache::Key,
41) -> Cache::Value
42where
43 Cache: QueryCache,
44{
45 match try_get_cached(tcx, query_cache, &key) {
46 Some(value) => value,
47 None => execute_query(tcx, span, key, QueryMode::Get).unwrap(),
48 }
49}
50
51#[inline]
54pub(crate) fn query_ensure<'tcx, Cache>(
55 tcx: TyCtxt<'tcx>,
56 execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
57 query_cache: &Cache,
58 key: Cache::Key,
59 check_cache: bool,
60) where
61 Cache: QueryCache,
62{
63 if try_get_cached(tcx, query_cache, &key).is_none() {
64 execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache });
65 }
66}
67
68#[inline]
71pub(crate) fn query_ensure_error_guaranteed<'tcx, Cache, T>(
72 tcx: TyCtxt<'tcx>,
73 execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
74 query_cache: &Cache,
75 key: Cache::Key,
76 check_cache: bool,
77) -> Result<(), ErrorGuaranteed>
78where
79 Cache: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
80 Result<T, ErrorGuaranteed>: Erasable,
81{
82 if let Some(res) = try_get_cached(tcx, query_cache, &key) {
83 erase::restore_val(res).map(drop)
84 } else {
85 execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache })
86 .map(erase::restore_val)
87 .map(|res| res.map(drop))
88 .unwrap_or(Ok(()))
95 }
96}
97
98pub(crate) fn query_feed<'tcx, Cache>(
100 tcx: TyCtxt<'tcx>,
101 dep_kind: DepKind,
102 query_vtable: &QueryVTable<'tcx, Cache>,
103 cache: &Cache,
104 key: Cache::Key,
105 value: Cache::Value,
106) where
107 Cache: QueryCache,
108 Cache::Key: DepNodeKey<TyCtxt<'tcx>>,
109{
110 let format_value = query_vtable.format_value;
111
112 match try_get_cached(tcx, cache, &key) {
114 Some(old) => {
115 if let Some(hasher_fn) = query_vtable.hash_result {
119 let (old_hash, value_hash) = tcx.with_stable_hashing_context(|ref mut hcx| {
120 (hasher_fn(hcx, &old), hasher_fn(hcx, &value))
121 });
122 if old_hash != value_hash {
123 tcx.dcx().delayed_bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Trying to feed an already recorded value for query {2:?} key={3:?}:\nold value: {0}\nnew value: {1}",
format_value(&old), format_value(&value), dep_kind, key))
})format!(
127 "Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\
128 old value: {old}\nnew value: {value}",
129 old = format_value(&old),
130 value = format_value(&value),
131 ));
132 }
133 } else {
134 crate::util::bug::bug_fmt(format_args!("Trying to feed an already recorded value for query {2:?} key={3:?}:\nold value: {0}\nnew value: {1}",
format_value(&old), format_value(&value), dep_kind, key))bug!(
138 "Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\
139 old value: {old}\nnew value: {value}",
140 old = format_value(&old),
141 value = format_value(&value),
142 )
143 }
144 }
145 None => {
146 let dep_node = dep_graph::DepNode::construct(tcx, dep_kind, &key);
149 let dep_node_index = tcx.dep_graph.with_feed_task(
150 dep_node,
151 tcx,
152 &value,
153 query_vtable.hash_result,
154 query_vtable.format_value,
155 );
156 cache.complete(key, value, dep_node_index);
157 }
158 }
159}