rustc_query_system/query/
mod.rs

1mod plumbing;
2pub use self::plumbing::*;
3
4mod job;
5pub use self::job::{
6    QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack,
7    report_cycle,
8};
9
10mod caches;
11pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache};
12
13mod config;
14use rustc_data_structures::stable_hasher::Hash64;
15use rustc_data_structures::sync::Lock;
16use rustc_errors::DiagInner;
17use rustc_hir::def::DefKind;
18use rustc_macros::{Decodable, Encodable};
19use rustc_span::Span;
20use rustc_span::def_id::DefId;
21use thin_vec::ThinVec;
22
23pub use self::config::{HashResult, QueryConfig};
24use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
25
26/// Description of a frame in the query stack.
27///
28/// This is mostly used in case of cycles for error reporting.
29#[derive(Clone, Debug)]
30pub struct QueryStackFrame {
31    pub description: String,
32    span: Option<Span>,
33    pub def_id: Option<DefId>,
34    pub def_kind: Option<DefKind>,
35    /// A def-id that is extracted from a `Ty` in a query key
36    pub def_id_for_ty_in_cycle: Option<DefId>,
37    pub dep_kind: DepKind,
38    /// This hash is used to deterministically pick
39    /// a query to remove cycles in the parallel compiler.
40    hash: Hash64,
41}
42
43impl QueryStackFrame {
44    #[inline]
45    pub fn new(
46        description: String,
47        span: Option<Span>,
48        def_id: Option<DefId>,
49        def_kind: Option<DefKind>,
50        dep_kind: DepKind,
51        def_id_for_ty_in_cycle: Option<DefId>,
52        hash: impl FnOnce() -> Hash64,
53    ) -> Self {
54        Self { description, span, def_id, def_kind, def_id_for_ty_in_cycle, dep_kind, hash: hash() }
55    }
56
57    // FIXME(eddyb) Get more valid `Span`s on queries.
58    #[inline]
59    pub fn default_span(&self, span: Span) -> Span {
60        if !span.is_dummy() {
61            return span;
62        }
63        self.span.unwrap_or(span)
64    }
65}
66
67/// Tracks 'side effects' for a particular query.
68/// This struct is saved to disk along with the query result,
69/// and loaded from disk if we mark the query as green.
70/// This allows us to 'replay' changes to global state
71/// that would otherwise only occur if we actually
72/// executed the query method.
73#[derive(Debug, Clone, Default, Encodable, Decodable)]
74pub struct QuerySideEffects {
75    /// Stores any diagnostics emitted during query execution.
76    /// These diagnostics will be re-emitted if we mark
77    /// the query as green.
78    pub(super) diagnostics: ThinVec<DiagInner>,
79}
80
81impl QuerySideEffects {
82    /// Returns true if there might be side effects.
83    #[inline]
84    pub fn maybe_any(&self) -> bool {
85        let QuerySideEffects { diagnostics } = self;
86        // Use `has_capacity` so that the destructor for `self.diagnostics` can be skipped
87        // if `maybe_any` is known to be false.
88        diagnostics.has_capacity()
89    }
90    pub fn append(&mut self, other: QuerySideEffects) {
91        let QuerySideEffects { diagnostics } = self;
92        diagnostics.extend(other.diagnostics);
93    }
94}
95
96pub trait QueryContext: HasDepContext {
97    fn next_job_id(self) -> QueryJobId;
98
99    /// Get the query information from the TLS context.
100    fn current_query_job(self) -> Option<QueryJobId>;
101
102    fn collect_active_jobs(self) -> QueryMap;
103
104    /// Load side effects associated to the node in the previous session.
105    fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
106
107    /// Register diagnostics for the given node, for use in next session.
108    fn store_side_effects(self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects);
109
110    /// Register diagnostics for the given node, for use in next session.
111    fn store_side_effects_for_anon_node(
112        self,
113        dep_node_index: DepNodeIndex,
114        side_effects: QuerySideEffects,
115    );
116
117    /// Executes a job by changing the `ImplicitCtxt` to point to the
118    /// new query job while it executes. It returns the diagnostics
119    /// captured during execution and the actual result.
120    fn start_query<R>(
121        self,
122        token: QueryJobId,
123        depth_limit: bool,
124        diagnostics: Option<&Lock<ThinVec<DiagInner>>>,
125        compute: impl FnOnce() -> R,
126    ) -> R;
127
128    fn depth_limit_error(self, job: QueryJobId);
129}