diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index abb02caef25d8..04a3ceb0918af 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -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 = Option, &V) -> Fingerprint>; + /// Stores function pointers and other metadata for a particular query. /// /// Used indirectly by query plumbing in `rustc_query_system` via a trait, diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index e58e626a7dfae..ba442d8a0081d 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -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: &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) -where - Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>, -{ +) -> (C::Value, Option) { // 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, -) -> (Q::Value, Option) -where - Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>, -{ +) -> (C::Value, Option) { // 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, -) -> (Q::Value, Option) -where - Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>, -{ +) -> (C::Value, Option) { 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::(query, qcx, state, key, key_hash, id, dep_node) + execute_job::(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, -) -> (Q::Value, Option) -where - Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>, -{ +) -> (C::Value, Option) { // 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, - key: Q::Key, + key: C::Key, mut dep_node_opt: Option, 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, 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) -where - Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>, -{ +) -> (bool, Option) { 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::(query, qcx, span, key, None).0) + ensure_sufficient_stack(|| try_execute_query::(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 -where - Q: QueryDispatcher<'tcx, Qcx = QueryCtxt<'tcx>>, -{ +) -> Option { 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::(query, qcx, span, key, dep_node)); + let (result, dep_node_index) = ensure_sufficient_stack(|| { + try_execute_query::(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::(query, qcx, DUMMY_SP, key, Some(dep_node)) + try_execute_query::(query, qcx, DUMMY_SP, key, Some(dep_node)) }); } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 228d0070b55b6..a33bdd22a7970 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -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>, -{ - 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::>() + .cast::>() } } + // 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::() + .cast::() } } + // 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 { + ) -> Option { // `?` 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 { + fn hash_result(self) -> HashResult { 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: >::Value, - ) -> Self::UnerasedValue; + fn restore_val(value: C::Value) -> Self::UnerasedValue; } pub fn query_system<'tcx>( diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 676d01be3385b..776d720f500bd 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -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> where Cache: QueryCache, - Cache::Key: Key + DynSend + DynSync + for<'a> HashStable> + '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>, { 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 { - ::Key::fingerprint_style() + >>::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: >::Value) -> Self::UnerasedValue { + fn restore_val(value: as QueryCache>::Value) + -> Self::UnerasedValue + { erase::restore_val::>(value) } } @@ -787,7 +794,11 @@ macro_rules! define_queries { encoder: &mut CacheEncoder<'_, 'tcx>, query_result_index: &mut EncodedDepNodeIndex ) { - $crate::plumbing::encode_query_results::>( + $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::>( - is_anon!([$($modifiers)*]), + $crate::plumbing::make_dep_kind_vtable_for_query::, _, _>( is_eval_always!([$($modifiers)*]), ) })* diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 7f6426e395f9b..fc63df3595c41 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -2,6 +2,7 @@ #![allow(internal_features)] #![feature(assert_matches)] #![feature(min_specialization)] +#![feature(trait_alias)] // tidy-alphabetical-end pub mod dep_graph; diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index 67ad767d4d318..eea1c5872290d 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -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>; /// 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 Default for DefaultCache { impl QueryCache for DefaultCache where - K: Eq + Hash + Copy + Debug, + K: QueryCacheKey, V: Copy, { type Key = K; @@ -175,7 +183,7 @@ where impl QueryCache for VecCache where - K: Idx + Eq + Hash + Copy + Debug, + K: Idx + QueryCacheKey, V: Copy, { type Key = K; diff --git a/compiler/rustc_query_system/src/query/dispatcher.rs b/compiler/rustc_query_system/src/query/dispatcher.rs deleted file mode 100644 index 840b09024ffa9..0000000000000 --- a/compiler/rustc_query_system/src/query/dispatcher.rs +++ /dev/null @@ -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 = Option, &V) -> Fingerprint>; - -/// Unambiguous shorthand for `::DepContext`. -#[expect(type_alias_bounds)] -type DepContextOf<'tcx, This: 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> + Eq + Hash + Copy + Debug; - type Value: Copy; - - type Cache: QueryCache; - - 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; - - 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, - 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; - - // 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) - } -} diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 29a572b726f0c..f4a3fda7e3727 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -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;