|
1 | 1 | //! Helper functions that serve as the immediate implementation of
|
2 | 2 | //! `tcx.$query(..)` and its variations.
|
3 | 3 |
|
| 4 | +use std::fmt::Debug; |
| 5 | + |
| 6 | +use rustc_data_structures::fingerprint::Fingerprint; |
| 7 | +use rustc_query_system::dep_graph::{DepKind, DepNodeParams}; |
| 8 | +use rustc_query_system::ich::StableHashingContext; |
4 | 9 | use rustc_query_system::query::{QueryCache, QueryMode, try_get_cached};
|
5 | 10 | use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
|
6 | 11 |
|
| 12 | +use crate::dep_graph; |
7 | 13 | use crate::query::IntoQueryParam;
|
8 | 14 | use crate::query::erase::{self, Erase, EraseType};
|
9 | 15 | use crate::ty::TyCtxt;
|
|
76 | 82 | .unwrap_or(Ok(()))
|
77 | 83 | }
|
78 | 84 | }
|
| 85 | + |
| 86 | +/// Common implementation of query feeding, used by `define_feedable!`. |
| 87 | +pub(crate) fn query_feed<'tcx, Cache, Value>( |
| 88 | + tcx: TyCtxt<'tcx>, |
| 89 | + dep_kind: DepKind, |
| 90 | + hasher: Option<fn(&mut StableHashingContext<'_>, &Value) -> Fingerprint>, |
| 91 | + cache: &Cache, |
| 92 | + key: Cache::Key, |
| 93 | + erased: Erase<Value>, |
| 94 | +) where |
| 95 | + Cache: QueryCache<Value = Erase<Value>>, |
| 96 | + Cache::Key: DepNodeParams<TyCtxt<'tcx>>, |
| 97 | + Value: EraseType + Debug, |
| 98 | +{ |
| 99 | + let value = erase::restore::<Value>(erased); |
| 100 | + |
| 101 | + match try_get_cached(tcx, cache, &key) { |
| 102 | + Some(old) => { |
| 103 | + let old = erase::restore::<Value>(old); |
| 104 | + if let Some(hasher) = hasher { |
| 105 | + let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx |
| 106 | + .with_stable_hashing_context(|mut hcx| { |
| 107 | + (hasher(&mut hcx, &value), hasher(&mut hcx, &old)) |
| 108 | + }); |
| 109 | + if old_hash != value_hash { |
| 110 | + // We have an inconsistency. This can happen if one of the two |
| 111 | + // results is tainted by errors. In this case, delay a bug to |
| 112 | + // ensure compilation is doomed, and keep the `old` value. |
| 113 | + tcx.dcx().delayed_bug(format!( |
| 114 | + "Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\ |
| 115 | + old value: {old:?}\nnew value: {value:?}", |
| 116 | + )); |
| 117 | + } |
| 118 | + } else { |
| 119 | + // The query is `no_hash`, so we have no way to perform a sanity check. |
| 120 | + // If feeding the same value multiple times needs to be supported, |
| 121 | + // the query should not be marked `no_hash`. |
| 122 | + bug!( |
| 123 | + "Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\ |
| 124 | + old value: {old:?}\nnew value: {value:?}", |
| 125 | + ) |
| 126 | + } |
| 127 | + } |
| 128 | + None => { |
| 129 | + let dep_node = dep_graph::DepNode::construct(tcx, dep_kind, &key); |
| 130 | + let dep_node_index = tcx.dep_graph.with_feed_task(dep_node, tcx, &value, hasher); |
| 131 | + cache.complete(key, erased, dep_node_index); |
| 132 | + } |
| 133 | + } |
| 134 | +} |
0 commit comments