Rename trait QueryConfig to QueryDispatcher

This commit is contained in:
Zalathar 2026-01-25 13:55:02 +11:00
parent 89d7695040
commit 2c9175d73d
5 changed files with 82 additions and 55 deletions

View file

@ -21,7 +21,7 @@ use rustc_query_system::Value;
use rustc_query_system::dep_graph::SerializedDepNodeIndex;
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{
CycleError, CycleErrorHandling, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode,
CycleError, CycleErrorHandling, HashResult, QueryCache, QueryDispatcher, QueryMap, QueryMode,
QueryStackDeferred, QueryState, get_query_incr, get_query_non_incr,
};
use rustc_span::{ErrorGuaranteed, Span};
@ -36,7 +36,13 @@ pub use crate::plumbing::{QueryCtxt, query_key_hash_verify_all};
mod profiling_support;
pub use self::profiling_support::alloc_self_profile_query_strings;
struct DynamicConfig<
/// Combines a [`QueryVTable`] with some additional compile-time booleans
/// to implement [`QueryDispatcher`], for use by code in [`rustc_query_system`].
///
/// Baking these boolean flags into the type gives a modest but measurable
/// improvement to compiler perf and compiler code size; see
/// <https://github.com/rust-lang/rust/pull/151633>.
struct SemiDynamicQueryDispatcher<
'tcx,
C: QueryCache,
const ANON: bool,
@ -46,20 +52,23 @@ struct DynamicConfig<
vtable: &'tcx QueryVTable<'tcx, C>,
}
// Manually implement Copy/Clone, because deriving would put trait bounds on the cache type.
impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Copy
for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
{
}
impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Clone
for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
{
fn clone(&self) -> Self {
*self
}
}
// This is `impl QueryDispatcher for SemiDynamicQueryDispatcher`.
impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool>
QueryConfig<QueryCtxt<'tcx>> for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
QueryDispatcher<QueryCtxt<'tcx>>
for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
where
for<'a> C::Key: HashStable<StableHashingContext<'a>>,
{
@ -193,17 +202,28 @@ where
}
}
/// This is implemented per query. It allows restoring query values from their erased state
/// and constructing a QueryConfig.
trait QueryConfigRestored<'tcx> {
type RestoredValue;
type Config: QueryConfig<QueryCtxt<'tcx>>;
/// Provides access to vtable-like operations for a query
/// (by creating a [`QueryDispatcher`]),
/// but also keeps track of the "unerased" value type of the query
/// (i.e. the actual result type in the query declaration).
///
/// This trait allows some per-query code to be defined in generic functions
/// with a trait bound, instead of having to be defined inline within a macro
/// expansion.
///
/// 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> {
type UnerasedValue;
type Dispatcher: QueryDispatcher<QueryCtxt<'tcx>>;
const NAME: &'static &'static str;
fn config(tcx: TyCtxt<'tcx>) -> Self::Config;
fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value)
-> Self::RestoredValue;
fn query_dispatcher(tcx: TyCtxt<'tcx>) -> Self::Dispatcher;
fn restore_val(
value: <Self::Dispatcher as QueryDispatcher<QueryCtxt<'tcx>>>::Value,
) -> Self::UnerasedValue;
}
pub fn query_system<'a>(

View file

@ -27,14 +27,14 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{
QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect,
QueryCache, QueryContext, QueryDispatcher, QueryJobId, QueryMap, QuerySideEffect,
QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra, force_query,
};
use rustc_query_system::{QueryOverflow, QueryOverflowNote};
use rustc_serialize::{Decodable, Encodable};
use rustc_span::def_id::LOCAL_CRATE;
use crate::QueryConfigRestored;
use crate::QueryDispatcherUnerased;
/// Implements [`QueryContext`] for use by [`rustc_query_system`], since that
/// crate does not have direct access to [`TyCtxt`].
@ -387,13 +387,13 @@ pub(crate) fn create_query_frame<
}
pub(crate) fn encode_query_results<'a, 'tcx, Q>(
query: Q::Config,
query: Q::Dispatcher,
qcx: QueryCtxt<'tcx>,
encoder: &mut CacheEncoder<'a, 'tcx>,
query_result_index: &mut EncodedDepNodeIndex,
) where
Q: super::QueryConfigRestored<'tcx>,
Q::RestoredValue: Encodable<CacheEncoder<'a, 'tcx>>,
Q: QueryDispatcherUnerased<'tcx>,
Q::UnerasedValue: Encodable<CacheEncoder<'a, 'tcx>>,
{
let _timer = qcx.tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name());
@ -408,13 +408,13 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>(
// Encode the type check tables with the `SerializedDepNodeIndex`
// as tag.
encoder.encode_tagged(dep_node, &Q::restore(*value));
encoder.encode_tagged(dep_node, &Q::restore_val(*value));
}
});
}
pub(crate) fn query_key_hash_verify<'tcx>(
query: impl QueryConfig<QueryCtxt<'tcx>>,
query: impl QueryDispatcher<QueryCtxt<'tcx>>,
qcx: QueryCtxt<'tcx>,
) {
let _timer = qcx.tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name());
@ -442,7 +442,7 @@ 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: QueryConfig<QueryCtxt<'tcx>>,
Q: QueryDispatcher<QueryCtxt<'tcx>>,
{
debug_assert!(tcx.dep_graph.is_green(&dep_node));
@ -488,7 +488,7 @@ where
fn force_from_dep_node<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
where
Q: QueryConfig<QueryCtxt<'tcx>>,
Q: QueryDispatcher<QueryCtxt<'tcx>>,
{
// We must avoid ever having to call `force_from_dep_node()` for a
// `DepNode::codegen_unit`:
@ -521,9 +521,10 @@ pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>(
is_eval_always: bool,
) -> DepKindVTable<'tcx>
where
Q: QueryConfigRestored<'tcx>,
Q: QueryDispatcherUnerased<'tcx>,
{
let fingerprint_style = <Q::Config as QueryConfig<QueryCtxt<'tcx>>>::Key::fingerprint_style();
let fingerprint_style =
<Q::Dispatcher as QueryDispatcher<QueryCtxt<'tcx>>>::Key::fingerprint_style();
if is_anon || !fingerprint_style.reconstructible() {
return DepKindVTable {
@ -541,10 +542,10 @@ where
is_eval_always,
fingerprint_style,
force_from_dep_node: Some(|tcx, dep_node, _| {
force_from_dep_node(Q::config(tcx), tcx, dep_node)
force_from_dep_node(Q::query_dispatcher(tcx), tcx, dep_node)
}),
try_load_from_on_disk_cache: Some(|tcx, dep_node| {
try_load_from_on_disk_cache(Q::config(tcx), tcx, dep_node)
try_load_from_on_disk_cache(Q::query_dispatcher(tcx), tcx, dep_node)
}),
name: Q::NAME,
}
@ -613,7 +614,7 @@ macro_rules! define_queries {
#[cfg(debug_assertions)]
let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
get_query_incr(
QueryType::config(tcx),
QueryType::query_dispatcher(tcx),
QueryCtxt::new(tcx),
span,
key,
@ -633,7 +634,7 @@ macro_rules! define_queries {
__mode: QueryMode,
) -> Option<Erase<queries::$name::Value<'tcx>>> {
Some(get_query_non_incr(
QueryType::config(tcx),
QueryType::query_dispatcher(tcx),
QueryCtxt::new(tcx),
span,
key,
@ -710,9 +711,9 @@ macro_rules! define_queries {
data: PhantomData<&'tcx ()>
}
impl<'tcx> QueryConfigRestored<'tcx> for QueryType<'tcx> {
type RestoredValue = queries::$name::Value<'tcx>;
type Config = DynamicConfig<
impl<'tcx> QueryDispatcherUnerased<'tcx> for QueryType<'tcx> {
type UnerasedValue = queries::$name::Value<'tcx>;
type Dispatcher = SemiDynamicQueryDispatcher<
'tcx,
queries::$name::Storage<'tcx>,
{ is_anon!([$($modifiers)*]) },
@ -723,14 +724,14 @@ macro_rules! define_queries {
const NAME: &'static &'static str = &stringify!($name);
#[inline(always)]
fn config(tcx: TyCtxt<'tcx>) -> Self::Config {
DynamicConfig {
fn query_dispatcher(tcx: TyCtxt<'tcx>) -> Self::Dispatcher {
SemiDynamicQueryDispatcher {
vtable: &tcx.query_system.query_vtables.$name,
}
}
#[inline(always)]
fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue {
fn restore_val(value: <Self::Dispatcher as QueryDispatcher<QueryCtxt<'tcx>>>::Value) -> Self::UnerasedValue {
restore::<queries::$name::Value<'tcx>>(value)
}
}
@ -782,7 +783,7 @@ macro_rules! define_queries {
query_result_index: &mut EncodedDepNodeIndex
) {
$crate::plumbing::encode_query_results::<query_impl::$name::QueryType<'tcx>>(
query_impl::$name::QueryType::config(tcx),
query_impl::$name::QueryType::query_dispatcher(tcx),
QueryCtxt::new(tcx),
encoder,
query_result_index,
@ -792,7 +793,7 @@ macro_rules! define_queries {
pub(crate) fn query_key_hash_verify<'tcx>(tcx: TyCtxt<'tcx>) {
$crate::plumbing::query_key_hash_verify(
query_impl::$name::QueryType::config(tcx),
query_impl::$name::QueryType::query_dispatcher(tcx),
QueryCtxt::new(tcx),
)
}

View file

@ -1,5 +1,3 @@
//! Query configuration and description traits.
use std::fmt::Debug;
use std::hash::Hash;
@ -14,7 +12,15 @@ use crate::query::{CycleError, CycleErrorHandling, DepNodeIndex, QueryContext, Q
pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>;
pub trait QueryConfig<Qcx: QueryContext>: Copy {
/// 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<Qcx: QueryContext>: Copy {
fn name(self) -> &'static str;
// `Key` and `Value` are `Copy` instead of `Clone` to ensure copying them stays cheap,

View file

@ -13,7 +13,7 @@ use rustc_span::Span;
use rustc_span::def_id::DefId;
pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache};
pub use self::config::{HashResult, QueryConfig};
pub use self::dispatcher::{HashResult, QueryDispatcher};
pub use self::job::{
QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack,
report_cycle,
@ -22,7 +22,7 @@ pub use self::plumbing::*;
use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
mod caches;
mod config;
mod dispatcher;
mod job;
mod plumbing;

View file

@ -18,7 +18,7 @@ use rustc_errors::{Diag, FatalError, StashKey};
use rustc_span::{DUMMY_SP, Span};
use tracing::instrument;
use super::{QueryConfig, QueryStackFrameExtra};
use super::{QueryDispatcher, QueryStackFrameExtra};
use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams};
use crate::ich::StableHashingContext;
use crate::query::caches::QueryCache;
@ -126,7 +126,7 @@ where
#[inline(never)]
fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError) -> Q::Value
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
@ -140,7 +140,7 @@ fn handle_cycle_error<Q, Qcx>(
error: Diag<'_>,
) -> Q::Value
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
match query.cycle_error_handling() {
@ -279,7 +279,7 @@ fn cycle_error<Q, Qcx>(
span: Span,
) -> (Q::Value, Option<DepNodeIndex>)
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
// Ensure there was no errors collecting all active jobs.
@ -300,7 +300,7 @@ fn wait_for_query<Q, Qcx>(
current: Option<QueryJobId>,
) -> (Q::Value, Option<DepNodeIndex>)
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
// For parallel queries, we'll block and wait until the query running
@ -349,7 +349,7 @@ fn try_execute_query<Q, Qcx, const INCR: bool>(
dep_node: Option<DepNode>,
) -> (Q::Value, Option<DepNodeIndex>)
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
let state = query.query_state(qcx);
@ -421,7 +421,7 @@ fn execute_job<Q, Qcx, const INCR: bool>(
dep_node: Option<DepNode>,
) -> (Q::Value, Option<DepNodeIndex>)
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
// Use `JobOwner` so the query will be poisoned if executing it panics.
@ -491,7 +491,7 @@ fn execute_job_non_incr<Q, Qcx>(
job_id: QueryJobId,
) -> (Q::Value, DepNodeIndex)
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled());
@ -530,7 +530,7 @@ fn execute_job_incr<Q, Qcx>(
job_id: QueryJobId,
) -> (Q::Value, DepNodeIndex)
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
if !query.anon() && !query.eval_always() {
@ -585,7 +585,7 @@ fn try_load_from_disk_and_cache_in_memory<Q, Qcx>(
dep_node: &DepNode,
) -> Option<(Q::Value, DepNodeIndex)>
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
// Note this function can be called concurrently from the same query
@ -771,7 +771,7 @@ fn ensure_must_run<Q, Qcx>(
check_cache: bool,
) -> (bool, Option<DepNode>)
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
if query.eval_always() {
@ -819,7 +819,7 @@ pub enum QueryMode {
#[inline(always)]
pub fn get_query_non_incr<Q, Qcx>(query: Q, qcx: Qcx, span: Span, key: Q::Key) -> Q::Value
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled());
@ -836,7 +836,7 @@ pub fn get_query_incr<Q, Qcx>(
mode: QueryMode,
) -> Option<Q::Value>
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
debug_assert!(qcx.dep_context().dep_graph().is_fully_enabled());
@ -862,7 +862,7 @@ where
pub fn force_query<Q, Qcx>(query: Q, qcx: Qcx, key: Q::Key, dep_node: DepNode)
where
Q: QueryConfig<Qcx>,
Q: QueryDispatcher<Qcx>,
Qcx: QueryContext,
{
// We may be concurrently trying both execute and force a query.