| //! Helper functions that serve as the immediate implementation of | 
 | //! `tcx.$query(..)` and its variations. | 
 |  | 
 | use std::fmt::Debug; | 
 |  | 
 | use rustc_data_structures::fingerprint::Fingerprint; | 
 | use rustc_query_system::dep_graph::{DepKind, DepNodeParams}; | 
 | use rustc_query_system::ich::StableHashingContext; | 
 | use rustc_query_system::query::{QueryCache, QueryMode, try_get_cached}; | 
 | use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; | 
 |  | 
 | use crate::dep_graph; | 
 | use crate::query::IntoQueryParam; | 
 | use crate::query::erase::{self, Erase, EraseType}; | 
 | use crate::ty::TyCtxt; | 
 |  | 
 | /// Shared implementation of `tcx.$query(..)` and `tcx.at(span).$query(..)` | 
 | /// for all queries. | 
 | #[inline(always)] | 
 | pub(crate) fn query_get_at<'tcx, Cache>( | 
 |     tcx: TyCtxt<'tcx>, | 
 |     execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, | 
 |     query_cache: &Cache, | 
 |     span: Span, | 
 |     key: Cache::Key, | 
 | ) -> Cache::Value | 
 | where | 
 |     Cache: QueryCache, | 
 | { | 
 |     let key = key.into_query_param(); | 
 |     match try_get_cached(tcx, query_cache, &key) { | 
 |         Some(value) => value, | 
 |         None => execute_query(tcx, span, key, QueryMode::Get).unwrap(), | 
 |     } | 
 | } | 
 |  | 
 | /// Shared implementation of `tcx.ensure_ok().$query(..)` for most queries, | 
 | /// and `tcx.ensure_done().$query(..)` for all queries. | 
 | #[inline] | 
 | pub(crate) fn query_ensure<'tcx, Cache>( | 
 |     tcx: TyCtxt<'tcx>, | 
 |     execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, | 
 |     query_cache: &Cache, | 
 |     key: Cache::Key, | 
 |     check_cache: bool, | 
 | ) where | 
 |     Cache: QueryCache, | 
 | { | 
 |     let key = key.into_query_param(); | 
 |     if try_get_cached(tcx, query_cache, &key).is_none() { | 
 |         execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache }); | 
 |     } | 
 | } | 
 |  | 
 | /// Shared implementation of `tcx.ensure_ok().$query(..)` for queries that | 
 | /// have the `return_result_from_ensure_ok` modifier. | 
 | #[inline] | 
 | pub(crate) fn query_ensure_error_guaranteed<'tcx, Cache, T>( | 
 |     tcx: TyCtxt<'tcx>, | 
 |     execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, | 
 |     query_cache: &Cache, | 
 |     key: Cache::Key, | 
 |     check_cache: bool, | 
 | ) -> Result<(), ErrorGuaranteed> | 
 | where | 
 |     Cache: QueryCache<Value = Erase<Result<T, ErrorGuaranteed>>>, | 
 |     Result<T, ErrorGuaranteed>: EraseType, | 
 | { | 
 |     let key = key.into_query_param(); | 
 |     if let Some(res) = try_get_cached(tcx, query_cache, &key) { | 
 |         erase::restore(res).map(drop) | 
 |     } else { | 
 |         execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache }) | 
 |             .map(erase::restore) | 
 |             .map(|res| res.map(drop)) | 
 |             // Either we actually executed the query, which means we got a full `Result`, | 
 |             // or we can just assume the query succeeded, because it was green in the | 
 |             // incremental cache. If it is green, that means that the previous compilation | 
 |             // that wrote to the incremental cache compiles successfully. That is only | 
 |             // possible if the cache entry was `Ok(())`, so we emit that here, without | 
 |             // actually encoding the `Result` in the cache or loading it from there. | 
 |             .unwrap_or(Ok(())) | 
 |     } | 
 | } | 
 |  | 
 | /// Common implementation of query feeding, used by `define_feedable!`. | 
 | pub(crate) fn query_feed<'tcx, Cache, Value>( | 
 |     tcx: TyCtxt<'tcx>, | 
 |     dep_kind: DepKind, | 
 |     hasher: Option<fn(&mut StableHashingContext<'_>, &Value) -> Fingerprint>, | 
 |     cache: &Cache, | 
 |     key: Cache::Key, | 
 |     erased: Erase<Value>, | 
 | ) where | 
 |     Cache: QueryCache<Value = Erase<Value>>, | 
 |     Cache::Key: DepNodeParams<TyCtxt<'tcx>>, | 
 |     Value: EraseType + Debug, | 
 | { | 
 |     let value = erase::restore::<Value>(erased); | 
 |  | 
 |     match try_get_cached(tcx, cache, &key) { | 
 |         Some(old) => { | 
 |             let old = erase::restore::<Value>(old); | 
 |             if let Some(hasher) = hasher { | 
 |                 let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx | 
 |                     .with_stable_hashing_context(|mut hcx| { | 
 |                         (hasher(&mut hcx, &value), hasher(&mut hcx, &old)) | 
 |                     }); | 
 |                 if old_hash != value_hash { | 
 |                     // We have an inconsistency. This can happen if one of the two | 
 |                     // results is tainted by errors. In this case, delay a bug to | 
 |                     // ensure compilation is doomed, and keep the `old` value. | 
 |                     tcx.dcx().delayed_bug(format!( | 
 |                         "Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\ | 
 |                         old value: {old:?}\nnew value: {value:?}", | 
 |                     )); | 
 |                 } | 
 |             } else { | 
 |                 // The query is `no_hash`, so we have no way to perform a sanity check. | 
 |                 // If feeding the same value multiple times needs to be supported, | 
 |                 // the query should not be marked `no_hash`. | 
 |                 bug!( | 
 |                     "Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\ | 
 |                     old value: {old:?}\nnew value: {value:?}", | 
 |                 ) | 
 |             } | 
 |         } | 
 |         None => { | 
 |             let dep_node = dep_graph::DepNode::construct(tcx, dep_kind, &key); | 
 |             let dep_node_index = tcx.dep_graph.with_feed_task(dep_node, tcx, &value, hasher); | 
 |             cache.complete(key, erased, dep_node_index); | 
 |         } | 
 |     } | 
 | } |