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:
bors 2026-02-09 09:34:09 +00:00
commit c6936c309a
8 changed files with 160 additions and 266 deletions

View file

@ -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,

View file

@ -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))
});
}

View file

@ -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>(

View file

@ -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)*]),
)
})*

View file

@ -2,6 +2,7 @@
#![allow(internal_features)]
#![feature(assert_matches)]
#![feature(min_specialization)]
#![feature(trait_alias)]
// tidy-alphabetical-end
pub mod dep_graph;

View file

@ -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;

View file

@ -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)
}
}

View file

@ -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;