| 
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