about summary refs log tree commit diff
path: root/compiler/rustc_query_system/src/query/mod.rs
blob: d9ee65328313f20c146be4032dabcf32085cf6fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
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<I> {
    /// 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<DefId>,
    /// A def-id that is extracted from a `Ty` in a query key
    pub def_id_for_ty_in_cycle: Option<DefId>,
}

impl<I> QueryStackFrame<I> {
    #[inline]
    pub fn new(
        info: I,
        dep_kind: DepKind,
        hash: impl FnOnce() -> Hash64,
        def_id: Option<DefId>,
        def_id_for_ty_in_cycle: Option<DefId>,
    ) -> Self {
        Self { info, def_id, dep_kind, hash: hash(), def_id_for_ty_in_cycle }
    }

    fn lift<Qcx: QueryContext<QueryInfo = I>>(
        &self,
        qcx: Qcx,
    ) -> QueryStackFrame<QueryStackFrameExtra> {
        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<Span>,
    pub def_kind: Option<DefKind>,
}

impl QueryStackFrameExtra {
    #[inline]
    pub fn new(description: String, span: Option<Span>, def_kind: Option<DefKind>) -> 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<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend>,
}

impl<'tcx> QueryStackDeferred<'tcx> {
    /// SAFETY: `extract` may not access 'tcx in its destructor.
    pub unsafe fn new(
        extract: Arc<dyn Fn() -> 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<QueryJobId>;

    fn collect_active_jobs(self) -> Result<QueryMap<Self::QueryInfo>, QueryMap<Self::QueryInfo>>;

    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<QuerySideEffect>;

    /// 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<R>(self, token: QueryJobId, depth_limit: bool, compute: impl FnOnce() -> R)
    -> R;

    fn depth_limit_error(self, job: QueryJobId);
}