mod plumbing; use std::fmt::Debug; use std::marker::PhantomData; use std::mem::transmute; use std::sync::Arc; pub use self::plumbing::*; mod job; pub use self::job::{ QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack, report_cycle, }; mod caches; pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; mod config; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::DiagInner; use rustc_hashes::Hash64; use rustc_hir::def::DefKind; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; use rustc_span::def_id::DefId; pub use self::config::{HashResult, QueryConfig}; use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; /// Description of a frame in the query stack. /// /// This is mostly used in case of cycles for error reporting. #[derive(Clone, Debug)] pub struct QueryStackFrame { /// This field initially stores a `QueryStackDeferred` during collection, /// but can later be changed to `QueryStackFrameExtra` containing concrete information /// by calling `lift`. This is done so that collecting query does not need to invoke /// queries, instead `lift` will call queries in a more appropriate location. pub info: I, pub dep_kind: DepKind, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. hash: Hash64, pub def_id: Option, /// A def-id that is extracted from a `Ty` in a query key pub def_id_for_ty_in_cycle: Option, } impl QueryStackFrame { #[inline] pub fn new( info: I, dep_kind: DepKind, hash: impl FnOnce() -> Hash64, def_id: Option, def_id_for_ty_in_cycle: Option, ) -> Self { Self { info, def_id, dep_kind, hash: hash(), def_id_for_ty_in_cycle } } fn lift>( &self, qcx: Qcx, ) -> QueryStackFrame { QueryStackFrame { info: qcx.lift_query_info(&self.info), dep_kind: self.dep_kind, hash: self.hash, def_id: self.def_id, def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle, } } } #[derive(Clone, Debug)] pub struct QueryStackFrameExtra { pub description: String, span: Option, pub def_kind: Option, } impl QueryStackFrameExtra { #[inline] pub fn new(description: String, span: Option, def_kind: Option) -> Self { Self { description, span, def_kind } } // FIXME(eddyb) Get more valid `Span`s on queries. #[inline] pub fn default_span(&self, span: Span) -> Span { if !span.is_dummy() { return span; } self.span.unwrap_or(span) } } /// Track a 'side effect' for a particular query. /// This is used to hold a closure which can create `QueryStackFrameExtra`. #[derive(Clone)] pub struct QueryStackDeferred<'tcx> { _dummy: PhantomData<&'tcx ()>, // `extract` may contain references to 'tcx, but we can't tell drop checking that it won't // access it in the destructor. extract: Arc QueryStackFrameExtra + DynSync + DynSend>, } impl<'tcx> QueryStackDeferred<'tcx> { /// SAFETY: `extract` may not access 'tcx in its destructor. pub unsafe fn new( extract: Arc QueryStackFrameExtra + DynSync + DynSend + 'tcx>, ) -> Self { Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } } } pub fn extract(&self) -> QueryStackFrameExtra { (self.extract)() } } impl<'tcx> Debug for QueryStackDeferred<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("QueryStackDeferred") } } /// Tracks 'side effects' for a particular query. /// This struct is saved to disk along with the query result, /// and loaded from disk if we mark the query as green. /// This allows us to 'replay' changes to global state /// that would otherwise only occur if we actually /// executed the query method. /// /// Each side effect gets an unique dep node index which is added /// as a dependency of the query which had the effect. #[derive(Debug, Encodable, Decodable)] pub enum QuerySideEffect { /// Stores a diagnostic emitted during query execution. /// This diagnostic will be re-emitted if we mark /// the query as green, as that query will have the side /// effect dep node as a dependency. Diagnostic(DiagInner), } pub trait QueryContext: HasDepContext { type QueryInfo: Clone; fn next_job_id(self) -> QueryJobId; /// Get the query information from the TLS context. fn current_query_job(self) -> Option; fn collect_active_jobs(self) -> Result, QueryMap>; fn lift_query_info(self, info: &Self::QueryInfo) -> QueryStackFrameExtra; /// Load a side effect associated to the node in the previous session. fn load_side_effect( self, prev_dep_node_index: SerializedDepNodeIndex, ) -> Option; /// Register a side effect for the given node, for use in next session. fn store_side_effect(self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect); /// Executes a job by changing the `ImplicitCtxt` to point to the /// new query job while it executes. fn start_query(self, token: QueryJobId, depth_limit: bool, compute: impl FnOnce() -> R) -> R; fn depth_limit_error(self, job: QueryJobId); }