Auto merge of #152371 - nnethercote:rm-QueryDispatcher, r=Zalathar
Remove `QueryDispatcher` `QueryDispatcher` is a trait that existed purely because `rustc_query_system` had code that didn't have access to `TyCtxt`. That is no longer the case, so the trait can be removed. r? @Zalathar
This commit is contained in:
commit
c6936c309a
8 changed files with 160 additions and 266 deletions
|
|
@ -1,12 +1,14 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::sync::{AtomicU64, WorkerLocal};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::hir_id::OwnerId;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_query_system::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
pub(crate) use rustc_query_system::query::QueryJobId;
|
||||
use rustc_query_system::query::{CycleError, CycleErrorHandling, HashResult, QueryCache};
|
||||
use rustc_query_system::query::{CycleError, CycleErrorHandling, QueryCache};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
pub use sealed::IntoQueryParam;
|
||||
|
||||
|
|
@ -30,6 +32,8 @@ pub type TryLoadFromDiskFn<'tcx, Key, Value> = fn(
|
|||
pub type IsLoadableFromDiskFn<'tcx, Key> =
|
||||
fn(tcx: TyCtxt<'tcx>, key: &Key, index: SerializedDepNodeIndex) -> bool;
|
||||
|
||||
pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>;
|
||||
|
||||
/// Stores function pointers and other metadata for a particular query.
|
||||
///
|
||||
/// Used indirectly by query plumbing in `rustc_query_system` via a trait,
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ use rustc_middle::dep_graph::DepsType;
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_query_system::dep_graph::{DepGraphData, DepNodeKey, HasDepContext};
|
||||
use rustc_query_system::query::{
|
||||
ActiveKeyStatus, CycleError, CycleErrorHandling, QueryCache, QueryContext, QueryDispatcher,
|
||||
QueryJob, QueryJobId, QueryJobInfo, QueryLatch, QueryMap, QueryMode, QueryStackDeferred,
|
||||
QueryStackFrame, QueryState, incremental_verify_ich, report_cycle,
|
||||
ActiveKeyStatus, CycleError, CycleErrorHandling, QueryCache, QueryContext, QueryJob,
|
||||
QueryJobId, QueryJobInfo, QueryLatch, QueryMap, QueryMode, QueryStackDeferred, QueryStackFrame,
|
||||
QueryState, incremental_verify_ich, report_cycle,
|
||||
};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
||||
use crate::dep_graph::{DepContext, DepNode, DepNodeIndex};
|
||||
use crate::plumbing::QueryCtxt;
|
||||
use crate::{QueryCtxt, QueryFlags, SemiDynamicQueryDispatcher};
|
||||
|
||||
#[inline]
|
||||
fn equivalent_key<K: Eq, V>(k: &K) -> impl Fn(&(K, V)) -> bool + '_ {
|
||||
|
|
@ -95,23 +95,21 @@ where
|
|||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn mk_cycle<'tcx, Q>(query: Q, qcx: QueryCtxt<'tcx>, cycle_error: CycleError) -> Q::Value
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
fn mk_cycle<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
cycle_error: CycleError,
|
||||
) -> C::Value {
|
||||
let error = report_cycle(qcx.tcx.sess, &cycle_error);
|
||||
handle_cycle_error(query, qcx, &cycle_error, error)
|
||||
}
|
||||
|
||||
fn handle_cycle_error<'tcx, Q>(
|
||||
query: Q,
|
||||
fn handle_cycle_error<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
cycle_error: &CycleError,
|
||||
error: Diag<'_>,
|
||||
) -> Q::Value
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> C::Value {
|
||||
match query.cycle_error_handling() {
|
||||
CycleErrorHandling::Error => {
|
||||
let guar = error.emit();
|
||||
|
|
@ -205,15 +203,12 @@ where
|
|||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn cycle_error<'tcx, Q>(
|
||||
query: Q,
|
||||
fn cycle_error<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
try_execute: QueryJobId,
|
||||
span: Span,
|
||||
) -> (Q::Value, Option<DepNodeIndex>)
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> (C::Value, Option<DepNodeIndex>) {
|
||||
// Ensure there was no errors collecting all active jobs.
|
||||
// We need the complete map to ensure we find a cycle to break.
|
||||
let query_map = qcx
|
||||
|
|
@ -226,17 +221,14 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn wait_for_query<'tcx, Q>(
|
||||
query: Q,
|
||||
fn wait_for_query<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
span: Span,
|
||||
key: Q::Key,
|
||||
key: C::Key,
|
||||
latch: QueryLatch<'tcx>,
|
||||
current: Option<QueryJobId>,
|
||||
) -> (Q::Value, Option<DepNodeIndex>)
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> (C::Value, Option<DepNodeIndex>) {
|
||||
// For parallel queries, we'll block and wait until the query running
|
||||
// in another thread has completed. Record how long we wait in the
|
||||
// self-profiler.
|
||||
|
|
@ -275,16 +267,13 @@ where
|
|||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn try_execute_query<'tcx, Q, const INCR: bool>(
|
||||
query: Q,
|
||||
fn try_execute_query<'tcx, C: QueryCache, const FLAGS: QueryFlags, const INCR: bool>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
span: Span,
|
||||
key: Q::Key,
|
||||
key: C::Key,
|
||||
dep_node: Option<DepNode>,
|
||||
) -> (Q::Value, Option<DepNodeIndex>)
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> (C::Value, Option<DepNodeIndex>) {
|
||||
let state = query.query_state(qcx);
|
||||
let key_hash = sharded::make_hash(&key);
|
||||
let mut state_lock = state.active.lock_shard_by_hash(key_hash);
|
||||
|
|
@ -315,7 +304,7 @@ where
|
|||
// Drop the lock before we start executing the query
|
||||
drop(state_lock);
|
||||
|
||||
execute_job::<Q, INCR>(query, qcx, state, key, key_hash, id, dep_node)
|
||||
execute_job::<C, FLAGS, INCR>(query, qcx, state, key, key_hash, id, dep_node)
|
||||
}
|
||||
Entry::Occupied(mut entry) => {
|
||||
match &mut entry.get_mut().1 {
|
||||
|
|
@ -344,18 +333,15 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn execute_job<'tcx, Q, const INCR: bool>(
|
||||
query: Q,
|
||||
fn execute_job<'tcx, C: QueryCache, const FLAGS: QueryFlags, const INCR: bool>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
state: &'tcx QueryState<'tcx, Q::Key>,
|
||||
key: Q::Key,
|
||||
state: &'tcx QueryState<'tcx, C::Key>,
|
||||
key: C::Key,
|
||||
key_hash: u64,
|
||||
id: QueryJobId,
|
||||
dep_node: Option<DepNode>,
|
||||
) -> (Q::Value, Option<DepNodeIndex>)
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> (C::Value, Option<DepNodeIndex>) {
|
||||
// Use `JobOwner` so the query will be poisoned if executing it panics.
|
||||
let job_owner = JobOwner { state, key };
|
||||
|
||||
|
|
@ -409,15 +395,12 @@ where
|
|||
|
||||
// Fast path for when incr. comp. is off.
|
||||
#[inline(always)]
|
||||
fn execute_job_non_incr<'tcx, Q>(
|
||||
query: Q,
|
||||
fn execute_job_non_incr<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
key: Q::Key,
|
||||
key: C::Key,
|
||||
job_id: QueryJobId,
|
||||
) -> (Q::Value, DepNodeIndex)
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> (C::Value, DepNodeIndex) {
|
||||
debug_assert!(!qcx.tcx.dep_graph.is_fully_enabled());
|
||||
|
||||
// Fingerprint the key, just to assert that it doesn't
|
||||
|
|
@ -445,17 +428,14 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn execute_job_incr<'tcx, Q>(
|
||||
query: Q,
|
||||
fn execute_job_incr<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
dep_graph_data: &DepGraphData<DepsType>,
|
||||
key: Q::Key,
|
||||
key: C::Key,
|
||||
mut dep_node_opt: Option<DepNode>,
|
||||
job_id: QueryJobId,
|
||||
) -> (Q::Value, DepNodeIndex)
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> (C::Value, DepNodeIndex) {
|
||||
if !query.anon() && !query.eval_always() {
|
||||
// `to_dep_node` is expensive for some `DepKind`s.
|
||||
let dep_node = dep_node_opt.get_or_insert_with(|| query.construct_dep_node(qcx.tcx, &key));
|
||||
|
|
@ -495,16 +475,13 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_load_from_disk_and_cache_in_memory<'tcx, Q>(
|
||||
query: Q,
|
||||
fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
dep_graph_data: &DepGraphData<DepsType>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
key: &Q::Key,
|
||||
key: &C::Key,
|
||||
dep_node: &DepNode,
|
||||
) -> Option<(Q::Value, DepNodeIndex)>
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> Option<(C::Value, DepNodeIndex)> {
|
||||
// Note this function can be called concurrently from the same query
|
||||
// We must ensure that this is handled correctly.
|
||||
|
||||
|
|
@ -598,15 +575,12 @@ where
|
|||
///
|
||||
/// Note: The optimization is only available during incr. comp.
|
||||
#[inline(never)]
|
||||
fn ensure_must_run<'tcx, Q>(
|
||||
query: Q,
|
||||
fn ensure_must_run<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
key: &Q::Key,
|
||||
key: &C::Key,
|
||||
check_cache: bool,
|
||||
) -> (bool, Option<DepNode>)
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> (bool, Option<DepNode>) {
|
||||
if query.eval_always() {
|
||||
return (true, None);
|
||||
}
|
||||
|
|
@ -644,31 +618,25 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn get_query_non_incr<'tcx, Q>(
|
||||
query: Q,
|
||||
pub(super) fn get_query_non_incr<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
span: Span,
|
||||
key: Q::Key,
|
||||
) -> Q::Value
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
key: C::Key,
|
||||
) -> C::Value {
|
||||
debug_assert!(!qcx.tcx.dep_graph.is_fully_enabled());
|
||||
|
||||
ensure_sufficient_stack(|| try_execute_query::<Q, false>(query, qcx, span, key, None).0)
|
||||
ensure_sufficient_stack(|| try_execute_query::<C, FLAGS, false>(query, qcx, span, key, None).0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn get_query_incr<'tcx, Q>(
|
||||
query: Q,
|
||||
pub(super) fn get_query_incr<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
span: Span,
|
||||
key: Q::Key,
|
||||
key: C::Key,
|
||||
mode: QueryMode,
|
||||
) -> Option<Q::Value>
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
) -> Option<C::Value> {
|
||||
debug_assert!(qcx.tcx.dep_graph.is_fully_enabled());
|
||||
|
||||
let dep_node = if let QueryMode::Ensure { check_cache } = mode {
|
||||
|
|
@ -681,18 +649,21 @@ where
|
|||
None
|
||||
};
|
||||
|
||||
let (result, dep_node_index) =
|
||||
ensure_sufficient_stack(|| try_execute_query::<Q, true>(query, qcx, span, key, dep_node));
|
||||
let (result, dep_node_index) = ensure_sufficient_stack(|| {
|
||||
try_execute_query::<C, FLAGS, true>(query, qcx, span, key, dep_node)
|
||||
});
|
||||
if let Some(dep_node_index) = dep_node_index {
|
||||
qcx.tcx.dep_graph.read_index(dep_node_index)
|
||||
}
|
||||
Some(result)
|
||||
}
|
||||
|
||||
pub(super) fn force_query<'tcx, Q>(query: Q, qcx: QueryCtxt<'tcx>, key: Q::Key, dep_node: DepNode)
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
pub(crate) fn force_query<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
key: C::Key,
|
||||
dep_node: DepNode,
|
||||
) {
|
||||
// We may be concurrently trying both execute and force a query.
|
||||
// Ensure that only one of them runs the query.
|
||||
if let Some((_, index)) = query.query_cache(qcx).lookup(&key) {
|
||||
|
|
@ -703,6 +674,6 @@ where
|
|||
debug_assert!(!query.anon());
|
||||
|
||||
ensure_sufficient_stack(|| {
|
||||
try_execute_query::<Q, true>(query, qcx, DUMMY_SP, key, Some(dep_node))
|
||||
try_execute_query::<C, FLAGS, true>(query, qcx, DUMMY_SP, key, Some(dep_node))
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,23 +10,20 @@
|
|||
|
||||
use std::marker::ConstParamTy;
|
||||
|
||||
use rustc_data_structures::stable_hasher::HashStable;
|
||||
use rustc_data_structures::sync::AtomicU64;
|
||||
use rustc_middle::arena::Arena;
|
||||
use rustc_middle::dep_graph::{self, DepKind, DepKindVTable, DepNodeIndex};
|
||||
use rustc_middle::dep_graph::{self, DepKind, DepKindVTable, DepNode, DepNodeIndex};
|
||||
use rustc_middle::queries::{
|
||||
self, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates,
|
||||
};
|
||||
use rustc_middle::query::AsLocalKey;
|
||||
use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
|
||||
use rustc_middle::query::plumbing::{QuerySystem, QuerySystemFns, QueryVTable};
|
||||
use rustc_middle::query::plumbing::{HashResult, QuerySystem, QuerySystemFns, QueryVTable};
|
||||
use rustc_middle::query::values::Value;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_query_system::dep_graph::SerializedDepNodeIndex;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_query_system::query::{
|
||||
CycleError, CycleErrorHandling, HashResult, QueryCache, QueryDispatcher, QueryMap, QueryMode,
|
||||
QueryState,
|
||||
CycleError, CycleErrorHandling, QueryCache, QueryMap, QueryMode, QueryState,
|
||||
};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
|
||||
|
|
@ -52,8 +49,8 @@ struct QueryFlags {
|
|||
is_feedable: bool,
|
||||
}
|
||||
|
||||
/// Combines a [`QueryVTable`] with some additional compile-time booleans
|
||||
/// to implement [`QueryDispatcher`], for use by code in [`rustc_query_system`].
|
||||
/// Combines a [`QueryVTable`] with some additional compile-time booleans.
|
||||
/// "Dispatcher" should be understood as a near-synonym of "vtable".
|
||||
///
|
||||
/// Baking these boolean flags into the type gives a modest but measurable
|
||||
/// improvement to compiler perf and compiler code size; see
|
||||
|
|
@ -75,56 +72,49 @@ impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> Clone
|
|||
}
|
||||
}
|
||||
|
||||
// This is `impl QueryDispatcher for SemiDynamicQueryDispatcher`.
|
||||
impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> QueryDispatcher<'tcx>
|
||||
for SemiDynamicQueryDispatcher<'tcx, C, FLAGS>
|
||||
where
|
||||
for<'a> C::Key: HashStable<StableHashingContext<'a>>,
|
||||
{
|
||||
type Qcx = QueryCtxt<'tcx>;
|
||||
type Key = C::Key;
|
||||
type Value = C::Value;
|
||||
type Cache = C;
|
||||
|
||||
impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> SemiDynamicQueryDispatcher<'tcx, C, FLAGS> {
|
||||
#[inline(always)]
|
||||
fn name(self) -> &'static str {
|
||||
self.vtable.name
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn will_cache_on_disk_for_key(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
|
||||
fn will_cache_on_disk_for_key(self, tcx: TyCtxt<'tcx>, key: &C::Key) -> bool {
|
||||
self.vtable.will_cache_on_disk_for_key_fn.map_or(false, |f| f(tcx, key))
|
||||
}
|
||||
|
||||
// Don't use this method to access query results, instead use the methods on TyCtxt.
|
||||
#[inline(always)]
|
||||
fn query_state(self, qcx: QueryCtxt<'tcx>) -> &'tcx QueryState<'tcx, Self::Key> {
|
||||
fn query_state(self, qcx: QueryCtxt<'tcx>) -> &'tcx QueryState<'tcx, C::Key> {
|
||||
// Safety:
|
||||
// This is just manually doing the subfield referencing through pointer math.
|
||||
unsafe {
|
||||
&*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>)
|
||||
.byte_add(self.vtable.query_state)
|
||||
.cast::<QueryState<'tcx, Self::Key>>()
|
||||
.cast::<QueryState<'tcx, C::Key>>()
|
||||
}
|
||||
}
|
||||
|
||||
// Don't use this method to access query results, instead use the methods on TyCtxt.
|
||||
#[inline(always)]
|
||||
fn query_cache(self, qcx: QueryCtxt<'tcx>) -> &'tcx Self::Cache {
|
||||
fn query_cache(self, qcx: QueryCtxt<'tcx>) -> &'tcx C {
|
||||
// Safety:
|
||||
// This is just manually doing the subfield referencing through pointer math.
|
||||
unsafe {
|
||||
&*(&qcx.tcx.query_system.caches as *const QueryCaches<'tcx>)
|
||||
.byte_add(self.vtable.query_cache)
|
||||
.cast::<Self::Cache>()
|
||||
.cast::<C>()
|
||||
}
|
||||
}
|
||||
|
||||
// Don't use this method to compute query results, instead use the methods on TyCtxt.
|
||||
#[inline(always)]
|
||||
fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
|
||||
fn execute_query(self, tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value {
|
||||
(self.vtable.execute_query)(tcx, key)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
|
||||
fn compute(self, qcx: QueryCtxt<'tcx>, key: C::Key) -> C::Value {
|
||||
(self.vtable.compute_fn)(qcx.tcx, key)
|
||||
}
|
||||
|
||||
|
|
@ -132,10 +122,10 @@ where
|
|||
fn try_load_from_disk(
|
||||
self,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
key: &Self::Key,
|
||||
key: &C::Key,
|
||||
prev_index: SerializedDepNodeIndex,
|
||||
index: DepNodeIndex,
|
||||
) -> Option<Self::Value> {
|
||||
) -> Option<C::Value> {
|
||||
// `?` will return None immediately for queries that never cache to disk.
|
||||
self.vtable.try_load_from_disk_fn?(qcx.tcx, key, prev_index, index)
|
||||
}
|
||||
|
|
@ -144,23 +134,24 @@ where
|
|||
fn is_loadable_from_disk(
|
||||
self,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
key: &Self::Key,
|
||||
key: &C::Key,
|
||||
index: SerializedDepNodeIndex,
|
||||
) -> bool {
|
||||
self.vtable.is_loadable_from_disk_fn.map_or(false, |f| f(qcx.tcx, key, index))
|
||||
}
|
||||
|
||||
/// Synthesize an error value to let compilation continue after a cycle.
|
||||
fn value_from_cycle_error(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cycle_error: &CycleError,
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self::Value {
|
||||
) -> C::Value {
|
||||
(self.vtable.value_from_cycle_error)(tcx, cycle_error, guar)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn format_value(self) -> fn(&Self::Value) -> String {
|
||||
fn format_value(self) -> fn(&C::Value) -> String {
|
||||
self.vtable.format_value
|
||||
}
|
||||
|
||||
|
|
@ -195,13 +186,17 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn hash_result(self) -> HashResult<Self::Value> {
|
||||
fn hash_result(self) -> HashResult<C::Value> {
|
||||
self.vtable.hash_result
|
||||
}
|
||||
|
||||
fn construct_dep_node(self, tcx: TyCtxt<'tcx>, key: &C::Key) -> DepNode {
|
||||
DepNode::construct(tcx, self.dep_kind(), key)
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides access to vtable-like operations for a query
|
||||
/// (by creating a [`QueryDispatcher`]),
|
||||
/// (by creating a [`SemiDynamicQueryDispatcher`]),
|
||||
/// but also keeps track of the "unerased" value type of the query
|
||||
/// (i.e. the actual result type in the query declaration).
|
||||
///
|
||||
|
|
@ -211,17 +206,14 @@ where
|
|||
///
|
||||
/// There is one macro-generated implementation of this trait for each query,
|
||||
/// on the type `rustc_query_impl::query_impl::$name::QueryType`.
|
||||
trait QueryDispatcherUnerased<'tcx> {
|
||||
trait QueryDispatcherUnerased<'tcx, C: QueryCache, const FLAGS: QueryFlags> {
|
||||
type UnerasedValue;
|
||||
type Dispatcher: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>;
|
||||
|
||||
const NAME: &'static &'static str;
|
||||
|
||||
fn query_dispatcher(tcx: TyCtxt<'tcx>) -> Self::Dispatcher;
|
||||
fn query_dispatcher(tcx: TyCtxt<'tcx>) -> SemiDynamicQueryDispatcher<'tcx, C, FLAGS>;
|
||||
|
||||
fn restore_val(
|
||||
value: <Self::Dispatcher as QueryDispatcher<'tcx>>::Value,
|
||||
) -> Self::UnerasedValue;
|
||||
fn restore_val(value: C::Value) -> Self::UnerasedValue;
|
||||
}
|
||||
|
||||
pub fn query_system<'tcx>(
|
||||
|
|
|
|||
|
|
@ -27,17 +27,16 @@ use rustc_middle::ty::print::with_reduced_queries;
|
|||
use rustc_middle::ty::tls::{self, ImplicitCtxt};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_query_system::dep_graph::{DepNodeKey, FingerprintStyle, HasDepContext};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_query_system::query::{
|
||||
QueryCache, QueryContext, QueryDispatcher, QueryJobId, QueryMap, QuerySideEffect,
|
||||
QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra,
|
||||
QueryCache, QueryContext, QueryJobId, QueryMap, QuerySideEffect, QueryStackDeferred,
|
||||
QueryStackFrame, QueryStackFrameExtra,
|
||||
};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
|
||||
use crate::QueryDispatcherUnerased;
|
||||
use crate::error::{QueryOverflow, QueryOverflowNote};
|
||||
use crate::execution::{all_inactive, force_query};
|
||||
use crate::{QueryDispatcherUnerased, QueryFlags, SemiDynamicQueryDispatcher};
|
||||
|
||||
/// Implements [`QueryContext`] for use by [`rustc_query_system`], since that
|
||||
/// crate does not have direct access to [`TyCtxt`].
|
||||
|
|
@ -360,7 +359,7 @@ pub(crate) fn create_deferred_query_stack_frame<'tcx, Cache>(
|
|||
) -> QueryStackFrame<QueryStackDeferred<'tcx>>
|
||||
where
|
||||
Cache: QueryCache,
|
||||
Cache::Key: Key + DynSend + DynSync + for<'a> HashStable<StableHashingContext<'a>> + 'tcx,
|
||||
Cache::Key: Key + DynSend + DynSync,
|
||||
{
|
||||
let kind = vtable.dep_kind;
|
||||
|
||||
|
|
@ -378,13 +377,13 @@ where
|
|||
QueryStackFrame::new(info, kind, hash, def_id, def_id_for_ty_in_cycle)
|
||||
}
|
||||
|
||||
pub(crate) fn encode_query_results<'a, 'tcx, Q>(
|
||||
query: Q::Dispatcher,
|
||||
pub(crate) fn encode_query_results<'a, 'tcx, Q, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
encoder: &mut CacheEncoder<'a, 'tcx>,
|
||||
query_result_index: &mut EncodedDepNodeIndex,
|
||||
) where
|
||||
Q: QueryDispatcherUnerased<'tcx>,
|
||||
Q: QueryDispatcherUnerased<'tcx, C, FLAGS>,
|
||||
Q::UnerasedValue: Encodable<CacheEncoder<'a, 'tcx>>,
|
||||
{
|
||||
let _timer = qcx.tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name());
|
||||
|
|
@ -405,8 +404,8 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>(
|
|||
});
|
||||
}
|
||||
|
||||
pub(crate) fn query_key_hash_verify<'tcx>(
|
||||
query: impl QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
pub(crate) fn query_key_hash_verify<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
) {
|
||||
let _timer = qcx.tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name());
|
||||
|
|
@ -431,13 +430,14 @@ pub(crate) fn query_key_hash_verify<'tcx>(
|
|||
});
|
||||
}
|
||||
|
||||
fn try_load_from_on_disk_cache<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode)
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
fn try_load_from_on_disk_cache<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
dep_node: DepNode,
|
||||
) {
|
||||
debug_assert!(tcx.dep_graph.is_green(&dep_node));
|
||||
|
||||
let key = Q::Key::recover(tcx, &dep_node).unwrap_or_else(|| {
|
||||
let key = C::Key::recover(tcx, &dep_node).unwrap_or_else(|| {
|
||||
panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)
|
||||
});
|
||||
if query.will_cache_on_disk_for_key(tcx, &key) {
|
||||
|
|
@ -477,10 +477,11 @@ where
|
|||
value
|
||||
}
|
||||
|
||||
fn force_from_dep_node<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
|
||||
where
|
||||
Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
fn force_from_dep_node<'tcx, C: QueryCache, const FLAGS: QueryFlags>(
|
||||
query: SemiDynamicQueryDispatcher<'tcx, C, FLAGS>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
dep_node: DepNode,
|
||||
) -> bool {
|
||||
// We must avoid ever having to call `force_from_dep_node()` for a
|
||||
// `DepNode::codegen_unit`:
|
||||
// Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
|
||||
|
|
@ -499,7 +500,7 @@ where
|
|||
"calling force_from_dep_node() on dep_kinds::codegen_unit"
|
||||
);
|
||||
|
||||
if let Some(key) = Q::Key::recover(tcx, &dep_node) {
|
||||
if let Some(key) = C::Key::recover(tcx, &dep_node) {
|
||||
force_query(query, QueryCtxt::new(tcx), key, dep_node);
|
||||
true
|
||||
} else {
|
||||
|
|
@ -507,17 +508,22 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>(
|
||||
is_anon: bool,
|
||||
pub(crate) fn make_dep_kind_vtable_for_query<
|
||||
'tcx,
|
||||
Q,
|
||||
C: QueryCache + 'tcx,
|
||||
const FLAGS: QueryFlags,
|
||||
>(
|
||||
is_eval_always: bool,
|
||||
) -> DepKindVTable<'tcx>
|
||||
where
|
||||
Q: QueryDispatcherUnerased<'tcx>,
|
||||
Q: QueryDispatcherUnerased<'tcx, C, FLAGS>,
|
||||
{
|
||||
let is_anon = FLAGS.is_anon;
|
||||
let fingerprint_style = if is_anon {
|
||||
FingerprintStyle::Opaque
|
||||
} else {
|
||||
<Q::Dispatcher as QueryDispatcher>::Key::fingerprint_style()
|
||||
<C::Key as DepNodeKey<TyCtxt<'tcx>>>::fingerprint_style()
|
||||
};
|
||||
|
||||
if is_anon || !fingerprint_style.reconstructible() {
|
||||
|
|
@ -713,25 +719,26 @@ macro_rules! define_queries {
|
|||
is_feedable: feedable!([$($modifiers)*]),
|
||||
};
|
||||
|
||||
impl<'tcx> QueryDispatcherUnerased<'tcx> for QueryType<'tcx> {
|
||||
impl<'tcx> QueryDispatcherUnerased<'tcx, queries::$name::Storage<'tcx>, FLAGS>
|
||||
for QueryType<'tcx>
|
||||
{
|
||||
type UnerasedValue = queries::$name::Value<'tcx>;
|
||||
type Dispatcher = SemiDynamicQueryDispatcher<
|
||||
'tcx,
|
||||
queries::$name::Storage<'tcx>,
|
||||
FLAGS,
|
||||
>;
|
||||
|
||||
const NAME: &'static &'static str = &stringify!($name);
|
||||
|
||||
#[inline(always)]
|
||||
fn query_dispatcher(tcx: TyCtxt<'tcx>) -> Self::Dispatcher {
|
||||
fn query_dispatcher(tcx: TyCtxt<'tcx>)
|
||||
-> SemiDynamicQueryDispatcher<'tcx, queries::$name::Storage<'tcx>, FLAGS>
|
||||
{
|
||||
SemiDynamicQueryDispatcher {
|
||||
vtable: &tcx.query_system.query_vtables.$name,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn restore_val(value: <Self::Dispatcher as QueryDispatcher<'tcx>>::Value) -> Self::UnerasedValue {
|
||||
fn restore_val(value: <queries::$name::Storage<'tcx> as QueryCache>::Value)
|
||||
-> Self::UnerasedValue
|
||||
{
|
||||
erase::restore_val::<queries::$name::Value<'tcx>>(value)
|
||||
}
|
||||
}
|
||||
|
|
@ -787,7 +794,11 @@ macro_rules! define_queries {
|
|||
encoder: &mut CacheEncoder<'_, 'tcx>,
|
||||
query_result_index: &mut EncodedDepNodeIndex
|
||||
) {
|
||||
$crate::plumbing::encode_query_results::<query_impl::$name::QueryType<'tcx>>(
|
||||
$crate::plumbing::encode_query_results::<
|
||||
query_impl::$name::QueryType<'tcx>,
|
||||
_,
|
||||
_
|
||||
> (
|
||||
query_impl::$name::QueryType::query_dispatcher(tcx),
|
||||
QueryCtxt::new(tcx),
|
||||
encoder,
|
||||
|
|
@ -959,8 +970,7 @@ macro_rules! define_queries {
|
|||
|
||||
$(pub(crate) fn $name<'tcx>() -> DepKindVTable<'tcx> {
|
||||
use $crate::query_impl::$name::QueryType;
|
||||
$crate::plumbing::make_dep_kind_vtable_for_query::<QueryType<'tcx>>(
|
||||
is_anon!([$($modifiers)*]),
|
||||
$crate::plumbing::make_dep_kind_vtable_for_query::<QueryType<'tcx>, _, _>(
|
||||
is_eval_always!([$($modifiers)*]),
|
||||
)
|
||||
})*
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trait_alias)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
pub mod dep_graph;
|
||||
|
|
|
|||
|
|
@ -3,12 +3,17 @@ use std::hash::Hash;
|
|||
use std::sync::OnceLock;
|
||||
|
||||
use rustc_data_structures::sharded::ShardedHashMap;
|
||||
use rustc_data_structures::stable_hasher::HashStable;
|
||||
pub use rustc_data_structures::vec_cache::VecCache;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_index::Idx;
|
||||
use rustc_span::def_id::{DefId, DefIndex};
|
||||
|
||||
use crate::dep_graph::DepNodeIndex;
|
||||
use crate::ich::StableHashingContext;
|
||||
|
||||
/// Traits that all query keys must satisfy.
|
||||
pub trait QueryCacheKey = Hash + Eq + Copy + Debug + for<'a> HashStable<StableHashingContext<'a>>;
|
||||
|
||||
/// Trait for types that serve as an in-memory cache for query results,
|
||||
/// for a given key (argument) type and value (return) type.
|
||||
|
|
@ -16,7 +21,10 @@ use crate::dep_graph::DepNodeIndex;
|
|||
/// Types implementing this trait are associated with actual key/value types
|
||||
/// by the `Cache` associated type of the `rustc_middle::query::Key` trait.
|
||||
pub trait QueryCache: Sized {
|
||||
type Key: Hash + Eq + Copy + Debug;
|
||||
// `Key` and `Value` are `Copy` instead of `Clone` to ensure copying them stays cheap,
|
||||
// but it isn't strictly necessary.
|
||||
// FIXME: Is that comment still true?
|
||||
type Key: QueryCacheKey;
|
||||
type Value: Copy;
|
||||
|
||||
/// Returns the cached value (and other information) associated with the
|
||||
|
|
@ -48,7 +56,7 @@ impl<K, V> Default for DefaultCache<K, V> {
|
|||
|
||||
impl<K, V> QueryCache for DefaultCache<K, V>
|
||||
where
|
||||
K: Eq + Hash + Copy + Debug,
|
||||
K: QueryCacheKey,
|
||||
V: Copy,
|
||||
{
|
||||
type Key = K;
|
||||
|
|
@ -175,7 +183,7 @@ where
|
|||
|
||||
impl<K, V> QueryCache for VecCache<K, V, DepNodeIndex>
|
||||
where
|
||||
K: Idx + Eq + Hash + Copy + Debug,
|
||||
K: Idx + QueryCacheKey,
|
||||
V: Copy,
|
||||
{
|
||||
type Key = K;
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
use super::QueryStackFrameExtra;
|
||||
use crate::dep_graph::{DepKind, DepNode, DepNodeKey, HasDepContext, SerializedDepNodeIndex};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::query::caches::QueryCache;
|
||||
use crate::query::{CycleError, CycleErrorHandling, DepNodeIndex, QueryContext, QueryState};
|
||||
|
||||
pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>;
|
||||
|
||||
/// Unambiguous shorthand for `<This::Qcx as HasDepContext>::DepContext`.
|
||||
#[expect(type_alias_bounds)]
|
||||
type DepContextOf<'tcx, This: QueryDispatcher<'tcx>> =
|
||||
<<This as QueryDispatcher<'tcx>>::Qcx as HasDepContext>::DepContext;
|
||||
|
||||
/// Trait that can be used as a vtable for a single query, providing operations
|
||||
/// and metadata for that query.
|
||||
///
|
||||
/// Implemented by `rustc_query_impl::SemiDynamicQueryDispatcher`, which
|
||||
/// mostly delegates to `rustc_middle::query::plumbing::QueryVTable`.
|
||||
/// Those types are not visible from this `rustc_query_system` crate.
|
||||
///
|
||||
/// "Dispatcher" should be understood as a near-synonym of "vtable".
|
||||
pub trait QueryDispatcher<'tcx>: Copy + 'tcx {
|
||||
fn name(self) -> &'static str;
|
||||
|
||||
/// Query context used by this dispatcher, i.e. `rustc_query_impl::QueryCtxt`.
|
||||
type Qcx: QueryContext<'tcx>;
|
||||
|
||||
// `Key` and `Value` are `Copy` instead of `Clone` to ensure copying them stays cheap,
|
||||
// but it isn't necessary.
|
||||
type Key: DepNodeKey<DepContextOf<'tcx, Self>> + Eq + Hash + Copy + Debug;
|
||||
type Value: Copy;
|
||||
|
||||
type Cache: QueryCache<Key = Self::Key, Value = Self::Value>;
|
||||
|
||||
fn format_value(self) -> fn(&Self::Value) -> String;
|
||||
|
||||
// Don't use this method to access query results, instead use the methods on TyCtxt
|
||||
fn query_state(self, tcx: Self::Qcx) -> &'tcx QueryState<'tcx, Self::Key>;
|
||||
|
||||
// Don't use this method to access query results, instead use the methods on TyCtxt
|
||||
fn query_cache(self, tcx: Self::Qcx) -> &'tcx Self::Cache;
|
||||
|
||||
fn will_cache_on_disk_for_key(self, tcx: DepContextOf<'tcx, Self>, key: &Self::Key) -> bool;
|
||||
|
||||
// Don't use this method to compute query results, instead use the methods on TyCtxt
|
||||
fn execute_query(self, tcx: DepContextOf<'tcx, Self>, k: Self::Key) -> Self::Value;
|
||||
|
||||
fn compute(self, tcx: Self::Qcx, key: Self::Key) -> Self::Value;
|
||||
|
||||
fn try_load_from_disk(
|
||||
self,
|
||||
tcx: Self::Qcx,
|
||||
key: &Self::Key,
|
||||
prev_index: SerializedDepNodeIndex,
|
||||
index: DepNodeIndex,
|
||||
) -> Option<Self::Value>;
|
||||
|
||||
fn is_loadable_from_disk(
|
||||
self,
|
||||
qcx: Self::Qcx,
|
||||
key: &Self::Key,
|
||||
idx: SerializedDepNodeIndex,
|
||||
) -> bool;
|
||||
|
||||
/// Synthesize an error value to let compilation continue after a cycle.
|
||||
fn value_from_cycle_error(
|
||||
self,
|
||||
tcx: DepContextOf<'tcx, Self>,
|
||||
cycle_error: &CycleError<QueryStackFrameExtra>,
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self::Value;
|
||||
|
||||
fn anon(self) -> bool;
|
||||
fn eval_always(self) -> bool;
|
||||
fn depth_limit(self) -> bool;
|
||||
fn feedable(self) -> bool;
|
||||
|
||||
fn dep_kind(self) -> DepKind;
|
||||
fn cycle_error_handling(self) -> CycleErrorHandling;
|
||||
fn hash_result(self) -> HashResult<Self::Value>;
|
||||
|
||||
// Just here for convenience and checking that the key matches the kind, don't override this.
|
||||
fn construct_dep_node(self, tcx: DepContextOf<'tcx, Self>, key: &Self::Key) -> DepNode {
|
||||
DepNode::construct(tcx, self.dep_kind(), key)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,8 +12,9 @@ use rustc_macros::{Decodable, Encodable};
|
|||
use rustc_span::Span;
|
||||
use rustc_span::def_id::DefId;
|
||||
|
||||
pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache};
|
||||
pub use self::dispatcher::{HashResult, QueryDispatcher};
|
||||
pub use self::caches::{
|
||||
DefIdCache, DefaultCache, QueryCache, QueryCacheKey, SingleCache, VecCache,
|
||||
};
|
||||
pub use self::job::{
|
||||
QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryLatch, QueryMap, break_query_cycles,
|
||||
print_query_stack, report_cycle,
|
||||
|
|
@ -22,7 +23,6 @@ pub use self::plumbing::*;
|
|||
use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
|
||||
|
||||
mod caches;
|
||||
mod dispatcher;
|
||||
mod job;
|
||||
mod plumbing;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue