Skip to main content

rustc_middle/query/
calls.rs

1//! Helper functions that serve as the immediate implementation of
2//! `tcx.$query(..)` and its variations.
3
4use std::ops::Deref;
5
6use rustc_hir::def_id::LocalDefId;
7use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
8
9use crate::dep_graph;
10use crate::dep_graph::DepNodeKey;
11use crate::query::erase::{self, Erasable, Erased};
12use crate::query::{IntoQueryKey, QueryCache, QueryMode, QueryVTable};
13use crate::ty::{self, TyCtxt};
14
15#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for TyCtxtAt<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for TyCtxtAt<'tcx> {
    #[inline]
    fn clone(&self) -> TyCtxtAt<'tcx> {
        let _: ::core::clone::AssertParamIsClone<TyCtxt<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Span>;
        *self
    }
}Clone)]
16pub struct TyCtxtAt<'tcx> {
17    pub tcx: TyCtxt<'tcx>,
18    pub span: Span,
19}
20
21impl<'tcx> Deref for TyCtxtAt<'tcx> {
22    type Target = TyCtxt<'tcx>;
23    #[inline(always)]
24    fn deref(&self) -> &Self::Target {
25        &self.tcx
26    }
27}
28
29#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for TyCtxtEnsureOk<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for TyCtxtEnsureOk<'tcx> {
    #[inline]
    fn clone(&self) -> TyCtxtEnsureOk<'tcx> {
        let _: ::core::clone::AssertParamIsClone<TyCtxt<'tcx>>;
        *self
    }
}Clone)]
30#[must_use]
31pub struct TyCtxtEnsureOk<'tcx> {
32    pub tcx: TyCtxt<'tcx>,
33}
34
35#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for TyCtxtEnsureResult<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for TyCtxtEnsureResult<'tcx> {
    #[inline]
    fn clone(&self) -> TyCtxtEnsureResult<'tcx> {
        let _: ::core::clone::AssertParamIsClone<TyCtxt<'tcx>>;
        *self
    }
}Clone)]
36#[must_use]
37pub struct TyCtxtEnsureResult<'tcx> {
38    pub tcx: TyCtxt<'tcx>,
39}
40
41#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for TyCtxtEnsureDone<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for TyCtxtEnsureDone<'tcx> {
    #[inline]
    fn clone(&self) -> TyCtxtEnsureDone<'tcx> {
        let _: ::core::clone::AssertParamIsClone<TyCtxt<'tcx>>;
        *self
    }
}Clone)]
42#[must_use]
43pub struct TyCtxtEnsureDone<'tcx> {
44    pub tcx: TyCtxt<'tcx>,
45}
46
47impl<'tcx> TyCtxtEnsureOk<'tcx> {
48    pub fn typeck(self, def_id: impl IntoQueryKey<LocalDefId>) {
49        self.typeck_root(
50            self.tcx.typeck_root_def_id(def_id.into_query_key().to_def_id()).expect_local(),
51        )
52    }
53}
54
55impl<'tcx> TyCtxt<'tcx> {
56    pub fn typeck(self, def_id: impl IntoQueryKey<LocalDefId>) -> &'tcx ty::TypeckResults<'tcx> {
57        self.typeck_root(
58            self.typeck_root_def_id(def_id.into_query_key().to_def_id()).expect_local(),
59        )
60    }
61
62    /// Returns a transparent wrapper for `TyCtxt` which uses
63    /// `span` as the location of queries performed through it.
64    #[inline(always)]
65    pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
66        TyCtxtAt { tcx: self, span }
67    }
68
69    /// FIXME: `ensure_ok`'s effects are subtle. Is this comment fully accurate?
70    ///
71    /// Wrapper that calls queries in a special "ensure OK" mode, for callers
72    /// that don't need the return value and just want to invoke a query for
73    /// its potential side-effect of emitting fatal errors.
74    ///
75    /// This can be more efficient than a normal query call, because if the
76    /// query's inputs are all green, the call can return immediately without
77    /// needing to obtain a value (by decoding one from disk or by executing
78    /// the query).
79    ///
80    /// (As with all query calls, execution is also skipped if the query result
81    /// is already cached in memory.)
82    ///
83    /// ## WARNING
84    /// A subsequent normal call to the same query might still cause it to be
85    /// executed! This can occur when the inputs are all green, but the query's
86    /// result is not cached on disk, so the query must be executed to obtain a
87    /// return value.
88    ///
89    /// Therefore, this call mode is not appropriate for callers that want to
90    /// ensure that the query is _never_ executed in the future.
91    #[inline(always)]
92    pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> {
93        TyCtxtEnsureOk { tcx: self }
94    }
95
96    /// This is a variant of `ensure_ok` only usable with queries that return
97    /// `Result<_, ErrorGuaranteed>`. Queries calls through this function will
98    /// return `Result<(), ErrorGuaranteed>`. I.e. the error status is returned
99    /// but nothing else. As with `ensure_ok`, this can be more efficient than
100    /// a normal query call.
101    #[inline(always)]
102    pub fn ensure_result(self) -> TyCtxtEnsureResult<'tcx> {
103        TyCtxtEnsureResult { tcx: self }
104    }
105
106    /// Wrapper that calls queries where callers don't need the return value and
107    /// just want to guarantee that the query won't be executed in the future.
108    ///
109    /// This is useful for queries that read from a [`Steal`] value, to ensure
110    /// that they are executed before the query that will steal the value.
111    ///
112    /// Currently this causes the query to be executed normally, but this behavior may change.
113    ///
114    /// [`Steal`]: rustc_data_structures::steal::Steal
115    #[inline(always)]
116    pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> {
117        TyCtxtEnsureDone { tcx: self }
118    }
119}
120
121/// Checks whether there is already a value for this key in the in-memory
122/// query cache, returning that value if present.
123///
124/// (Also performs some associated bookkeeping, if a value was found.)
125#[inline(always)]
126fn try_get_cached<'tcx, C>(tcx: TyCtxt<'tcx>, cache: &C, key: C::Key) -> Option<C::Value>
127where
128    C: QueryCache,
129{
130    match cache.lookup(&key) {
131        Some((value, index)) => {
132            tcx.prof.query_cache_hit(index.into());
133            tcx.dep_graph.read_index(index);
134            Some(value)
135        }
136        None => None,
137    }
138}
139
140/// Shared implementation of `tcx.$query(..)` and `tcx.at(span).$query(..)`
141/// for all queries.
142#[inline(always)]
143pub(crate) fn query_get_at<'tcx, C>(
144    tcx: TyCtxt<'tcx>,
145    span: Span,
146    query: &'tcx QueryVTable<'tcx, C>,
147    key: C::Key,
148) -> C::Value
149where
150    C: QueryCache,
151{
152    match try_get_cached(tcx, &query.cache, key) {
153        Some(value) => value,
154        None => (query.execute_query_fn)(tcx, span, key, QueryMode::Get).unwrap(),
155    }
156}
157
158/// Implementation of `tcx.ensure_ok().$query(..)` for all queries.
159#[inline]
160pub(crate) fn query_ensure_ok<'tcx, C>(
161    tcx: TyCtxt<'tcx>,
162    query: &'tcx QueryVTable<'tcx, C>,
163    key: C::Key,
164) where
165    C: QueryCache,
166{
167    match try_get_cached(tcx, &query.cache, key) {
168        Some(_value) => {}
169        None => {
170            (query.execute_query_fn)(tcx, DUMMY_SP, key, QueryMode::EnsureOk);
171        }
172    }
173}
174
175/// Implementation of `tcx.ensure_result().$query(..)` for queries that
176/// return `Result<_, ErrorGuaranteed>`.
177#[inline]
178pub(crate) fn query_ensure_result<'tcx, C, T>(
179    tcx: TyCtxt<'tcx>,
180    query: &'tcx QueryVTable<'tcx, C>,
181    key: C::Key,
182) -> Result<(), ErrorGuaranteed>
183where
184    C: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
185    Result<T, ErrorGuaranteed>: Erasable,
186{
187    let convert = |value: Erased<Result<T, ErrorGuaranteed>>| -> Result<(), ErrorGuaranteed> {
188        match erase::restore_val(value) {
189            Ok(_) => Ok(()),
190            Err(guar) => Err(guar),
191        }
192    };
193
194    match try_get_cached(tcx, &query.cache, key) {
195        Some(value) => convert(value),
196        None => {
197            match (query.execute_query_fn)(tcx, DUMMY_SP, key, QueryMode::EnsureOk) {
198                // We executed the query. Convert the successful result.
199                Some(res) => convert(res),
200
201                // Reaching here means we didn't execute the query, but we can just assume the
202                // query succeeded, because it was green in the incremental cache. If it is green,
203                // that means that the previous compilation that wrote to the incremental cache
204                // compiles successfully. That is only possible if the cache entry was `Ok(())`, so
205                // we emit that here, without actually encoding the `Result` in the cache or
206                // loading it from there.
207                None => Ok(()),
208            }
209        }
210    }
211}
212
213/// "Feeds" a feedable query by adding a given key/value pair to its in-memory cache.
214/// Called by macro-generated methods of [`rustc_middle::ty::TyCtxtFeed`].
215pub(crate) fn query_feed<'tcx, C>(
216    tcx: TyCtxt<'tcx>,
217    query: &'tcx QueryVTable<'tcx, C>,
218    key: C::Key,
219    value: C::Value,
220) where
221    C: QueryCache,
222    C::Key: DepNodeKey<'tcx>,
223{
224    let format_value = query.format_value;
225
226    // Check whether the in-memory cache already has a value for this key.
227    match try_get_cached(tcx, &query.cache, key) {
228        Some(old) => {
229            // The query already has a cached value for this key.
230            // That's OK if both values are the same, i.e. they have the same hash,
231            // so now we check their hashes.
232            if let Some(hash_value_fn) = query.hash_value_fn {
233                let (old_hash, value_hash) = tcx.with_stable_hashing_context(|ref mut hcx| {
234                    (hash_value_fn(hcx, &old), hash_value_fn(hcx, &value))
235                });
236                if old_hash != value_hash {
237                    // We have an inconsistency. This can happen if one of the two
238                    // results is tainted by errors. In this case, delay a bug to
239                    // ensure compilation is doomed, and keep the `old` value.
240                    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), query, key))
    })format!(
241                        "Trying to feed an already recorded value for query {query:?} key={key:?}:\n\
242                        old value: {old}\nnew value: {value}",
243                        old = format_value(&old),
244                        value = format_value(&value),
245                    ));
246                }
247            } else {
248                // The query is `no_hash`, so we have no way to perform a sanity check.
249                // If feeding the same value multiple times needs to be supported,
250                // the query should not be marked `no_hash`.
251                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), query, key))bug!(
252                    "Trying to feed an already recorded value for query {query:?} key={key:?}:\n\
253                    old value: {old}\nnew value: {value}",
254                    old = format_value(&old),
255                    value = format_value(&value),
256                )
257            }
258        }
259        None => {
260            // There is no cached value for this key, so feed the query by
261            // adding the provided value to the cache.
262            let dep_node = dep_graph::DepNode::construct(tcx, query.dep_kind, &key);
263            let dep_node_index = tcx.dep_graph.with_feed_task(
264                dep_node,
265                tcx,
266                &value,
267                query.hash_value_fn,
268                query.format_value,
269            );
270            query.cache.complete(key, value, dep_node_index);
271        }
272    }
273}