rustc_query_system/query/
mod.rs

1mod plumbing;
2use std::fmt::Debug;
3use std::marker::PhantomData;
4use std::mem::transmute;
5use std::sync::Arc;
6
7pub use self::plumbing::*;
8
9mod job;
10pub use self::job::{
11    QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack,
12    report_cycle,
13};
14
15mod caches;
16pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache};
17
18mod config;
19use rustc_data_structures::jobserver::Proxy;
20use rustc_data_structures::sync::{DynSend, DynSync};
21use rustc_errors::DiagInner;
22use rustc_hashes::Hash64;
23use rustc_hir::def::DefKind;
24use rustc_macros::{Decodable, Encodable};
25use rustc_span::Span;
26use rustc_span::def_id::DefId;
27
28pub use self::config::{HashResult, QueryConfig};
29use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
30
31/// Description of a frame in the query stack.
32///
33/// This is mostly used in case of cycles for error reporting.
34#[derive(Clone, Debug)]
35pub struct QueryStackFrame<I> {
36    /// This field initially stores a `QueryStackDeferred` during collection,
37    /// but can later be changed to `QueryStackFrameExtra` containing concrete information
38    /// by calling `lift`. This is done so that collecting query does not need to invoke
39    /// queries, instead `lift` will call queries in a more appropriate location.
40    pub info: I,
41
42    pub dep_kind: DepKind,
43    /// This hash is used to deterministically pick
44    /// a query to remove cycles in the parallel compiler.
45    hash: Hash64,
46    pub def_id: Option<DefId>,
47    /// A def-id that is extracted from a `Ty` in a query key
48    pub def_id_for_ty_in_cycle: Option<DefId>,
49}
50
51impl<I> QueryStackFrame<I> {
52    #[inline]
53    pub fn new(
54        info: I,
55        dep_kind: DepKind,
56        hash: impl FnOnce() -> Hash64,
57        def_id: Option<DefId>,
58        def_id_for_ty_in_cycle: Option<DefId>,
59    ) -> Self {
60        Self { info, def_id, dep_kind, hash: hash(), def_id_for_ty_in_cycle }
61    }
62
63    fn lift<Qcx: QueryContext<QueryInfo = I>>(
64        &self,
65        qcx: Qcx,
66    ) -> QueryStackFrame<QueryStackFrameExtra> {
67        QueryStackFrame {
68            info: qcx.lift_query_info(&self.info),
69            dep_kind: self.dep_kind,
70            hash: self.hash,
71            def_id: self.def_id,
72            def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle,
73        }
74    }
75}
76
77#[derive(Clone, Debug)]
78pub struct QueryStackFrameExtra {
79    pub description: String,
80    span: Option<Span>,
81    pub def_kind: Option<DefKind>,
82}
83
84impl QueryStackFrameExtra {
85    #[inline]
86    pub fn new(description: String, span: Option<Span>, def_kind: Option<DefKind>) -> Self {
87        Self { description, span, def_kind }
88    }
89
90    // FIXME(eddyb) Get more valid `Span`s on queries.
91    #[inline]
92    pub fn default_span(&self, span: Span) -> Span {
93        if !span.is_dummy() {
94            return span;
95        }
96        self.span.unwrap_or(span)
97    }
98}
99
100/// Track a 'side effect' for a particular query.
101/// This is used to hold a closure which can create `QueryStackFrameExtra`.
102#[derive(Clone)]
103pub struct QueryStackDeferred<'tcx> {
104    _dummy: PhantomData<&'tcx ()>,
105
106    // `extract` may contain references to 'tcx, but we can't tell drop checking that it won't
107    // access it in the destructor.
108    extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend>,
109}
110
111impl<'tcx> QueryStackDeferred<'tcx> {
112    pub fn new<C: Copy + DynSync + DynSend + 'tcx>(
113        context: C,
114        extract: fn(C) -> QueryStackFrameExtra,
115    ) -> Self {
116        let extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend + 'tcx> =
117            Arc::new(move || extract(context));
118        // SAFETY: The `extract` closure does not access 'tcx in its destructor as the only
119        // captured variable is `context` which is Copy and cannot have a destructor.
120        Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } }
121    }
122
123    pub fn extract(&self) -> QueryStackFrameExtra {
124        (self.extract)()
125    }
126}
127
128impl<'tcx> Debug for QueryStackDeferred<'tcx> {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        f.write_str("QueryStackDeferred")
131    }
132}
133
134/// Tracks 'side effects' for a particular query.
135/// This struct is saved to disk along with the query result,
136/// and loaded from disk if we mark the query as green.
137/// This allows us to 'replay' changes to global state
138/// that would otherwise only occur if we actually
139/// executed the query method.
140///
141/// Each side effect gets an unique dep node index which is added
142/// as a dependency of the query which had the effect.
143#[derive(Debug, Encodable, Decodable)]
144pub enum QuerySideEffect {
145    /// Stores a diagnostic emitted during query execution.
146    /// This diagnostic will be re-emitted if we mark
147    /// the query as green, as that query will have the side
148    /// effect dep node as a dependency.
149    Diagnostic(DiagInner),
150}
151
152pub trait QueryContext: HasDepContext {
153    type QueryInfo: Clone;
154
155    /// Gets a jobserver reference which is used to release then acquire
156    /// a token while waiting on a query.
157    fn jobserver_proxy(&self) -> &Proxy;
158
159    fn next_job_id(self) -> QueryJobId;
160
161    /// Get the query information from the TLS context.
162    fn current_query_job(self) -> Option<QueryJobId>;
163
164    fn collect_active_jobs(self) -> Result<QueryMap<Self::QueryInfo>, QueryMap<Self::QueryInfo>>;
165
166    fn lift_query_info(self, info: &Self::QueryInfo) -> QueryStackFrameExtra;
167
168    /// Load a side effect associated to the node in the previous session.
169    fn load_side_effect(
170        self,
171        prev_dep_node_index: SerializedDepNodeIndex,
172    ) -> Option<QuerySideEffect>;
173
174    /// Register a side effect for the given node, for use in next session.
175    fn store_side_effect(self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect);
176
177    /// Executes a job by changing the `ImplicitCtxt` to point to the
178    /// new query job while it executes.
179    fn start_query<R>(self, token: QueryJobId, depth_limit: bool, compute: impl FnOnce() -> R)
180    -> R;
181
182    fn depth_limit_error(self, job: QueryJobId);
183}