1 //! The implementation of the query system itself. This defines the macros that
2 //! generate the actual methods on tcx which find and execute the provider,
3 //! manage the caches, and so forth.
5 use crate::{on_disk_cache, queries, Queries}
;
6 use rustc_middle
::dep_graph
::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}
;
7 use rustc_middle
::ty
::tls
::{self, ImplicitCtxt}
;
8 use rustc_middle
::ty
::{self, TyCtxt}
;
9 use rustc_query_system
::dep_graph
::HasDepContext
;
10 use rustc_query_system
::query
::{QueryContext, QueryDescription, QueryJobId, QueryMap}
;
12 use rustc_data_structures
::sync
::Lock
;
13 use rustc_data_structures
::thin_vec
::ThinVec
;
14 use rustc_errors
::{Diagnostic, Handler}
;
15 use rustc_serialize
::opaque
;
16 use rustc_span
::def_id
::LocalDefId
;
20 #[derive(Copy, Clone)]
21 pub struct QueryCtxt
<'tcx
> {
22 pub tcx
: TyCtxt
<'tcx
>,
23 pub queries
: &'tcx Queries
<'tcx
>,
26 impl<'tcx
> std
::ops
::Deref
for QueryCtxt
<'tcx
> {
27 type Target
= TyCtxt
<'tcx
>;
30 fn deref(&self) -> &Self::Target
{
35 impl HasDepContext
for QueryCtxt
<'tcx
> {
36 type DepKind
= rustc_middle
::dep_graph
::DepKind
;
37 type StableHashingContext
= rustc_middle
::ich
::StableHashingContext
<'tcx
>;
38 type DepContext
= TyCtxt
<'tcx
>;
41 fn dep_context(&self) -> &Self::DepContext
{
46 impl QueryContext
for QueryCtxt
<'tcx
> {
47 fn current_query_job(&self) -> Option
<QueryJobId
<Self::DepKind
>> {
48 tls
::with_related_context(**self, |icx
| icx
.query
)
51 fn try_collect_active_jobs(&self) -> Option
<QueryMap
<Self::DepKind
>> {
52 self.queries
.try_collect_active_jobs(**self)
55 fn try_load_from_on_disk_cache(&self, dep_node
: &DepNode
) {
56 let cb
= &super::QUERY_CALLBACKS
[dep_node
.kind
as usize];
57 (cb
.try_load_from_on_disk_cache
)(*self, dep_node
)
60 fn try_force_from_dep_node(&self, dep_node
: &DepNode
) -> bool
{
61 debug
!("try_force_from_dep_node({:?}) --- trying to force", dep_node
);
63 // We must avoid ever having to call `force_from_dep_node()` for a
64 // `DepNode::codegen_unit`:
65 // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
66 // would always end up having to evaluate the first caller of the
67 // `codegen_unit` query that *is* reconstructible. This might very well be
68 // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
69 // to re-trigger calling the `codegen_unit` query with the right key. At
70 // that point we would already have re-done all the work we are trying to
71 // avoid doing in the first place.
72 // The solution is simple: Just explicitly call the `codegen_unit` query for
73 // each CGU, right after partitioning. This way `try_mark_green` will always
74 // hit the cache instead of having to go through `force_from_dep_node`.
75 // This assertion makes sure, we actually keep applying the solution above.
77 dep_node
.kind
!= DepKind
::codegen_unit
,
78 "calling force_from_dep_node() on DepKind::codegen_unit"
81 let cb
= &super::QUERY_CALLBACKS
[dep_node
.kind
as usize];
82 (cb
.force_from_dep_node
)(*self, dep_node
)
85 // Interactions with on_disk_cache
86 fn load_diagnostics(&self, prev_dep_node_index
: SerializedDepNodeIndex
) -> Vec
<Diagnostic
> {
90 .map(|c
| c
.load_diagnostics(**self, prev_dep_node_index
))
94 fn store_diagnostics(&self, dep_node_index
: DepNodeIndex
, diagnostics
: ThinVec
<Diagnostic
>) {
95 if let Some(c
) = self.queries
.on_disk_cache
.as_ref() {
96 c
.store_diagnostics(dep_node_index
, diagnostics
)
100 fn store_diagnostics_for_anon_node(
102 dep_node_index
: DepNodeIndex
,
103 diagnostics
: ThinVec
<Diagnostic
>,
105 if let Some(c
) = self.queries
.on_disk_cache
.as_ref() {
106 c
.store_diagnostics_for_anon_node(dep_node_index
, diagnostics
)
110 /// Executes a job by changing the `ImplicitCtxt` to point to the
111 /// new query job while it executes. It returns the diagnostics
112 /// captured during execution and the actual result.
116 token
: QueryJobId
<Self::DepKind
>,
117 diagnostics
: Option
<&Lock
<ThinVec
<Diagnostic
>>>,
118 compute
: impl FnOnce() -> R
,
120 // The `TyCtxt` stored in TLS has the same global interner lifetime
121 // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
122 // when accessing the `ImplicitCtxt`.
123 tls
::with_related_context(**self, move |current_icx
| {
124 // Update the `ImplicitCtxt` to point to our new query job.
125 let new_icx
= ImplicitCtxt
{
129 layout_depth
: current_icx
.layout_depth
,
130 task_deps
: current_icx
.task_deps
,
133 // Use the `ImplicitCtxt` while we execute the query.
134 tls
::enter_context(&new_icx
, |_
| {
135 rustc_data_structures
::stack
::ensure_sufficient_stack(compute
)
141 impl<'tcx
> QueryCtxt
<'tcx
> {
143 pub fn from_tcx(tcx
: TyCtxt
<'tcx
>) -> Self {
144 let queries
= tcx
.queries
.as_any();
145 let queries
= unsafe {
146 let queries
= std
::mem
::transmute
::<&dyn Any
, &dyn Any
>(queries
);
147 let queries
= queries
.downcast_ref().unwrap();
148 let queries
= std
::mem
::transmute
::<&Queries
<'_
>, &Queries
<'_
>>(queries
);
151 QueryCtxt { tcx, queries }
154 crate fn on_disk_cache(self) -> Option
<&'tcx on_disk_cache
::OnDiskCache
<'tcx
>> {
155 self.queries
.on_disk_cache
.as_ref()
158 #[cfg(parallel_compiler)]
159 pub unsafe fn deadlock(self, registry
: &rustc_rayon_core
::Registry
) {
160 rustc_query_system
::query
::deadlock(self, registry
)
163 pub(super) fn encode_query_results(
165 encoder
: &mut on_disk_cache
::CacheEncoder
<'a
, 'tcx
, opaque
::FileEncoder
>,
166 query_result_index
: &mut on_disk_cache
::EncodedQueryResultIndex
,
167 ) -> opaque
::FileEncodeResult
{
168 macro_rules
! encode_queries
{
169 ($
($query
:ident
,)*) => {
171 on_disk_cache
::encode_query_results
::<_
, super::queries
::$query
<'_
>>(
180 rustc_cached_queries
!(encode_queries
!);
185 pub fn try_print_query_stack(
187 query
: Option
<QueryJobId
<DepKind
>>,
189 num_frames
: Option
<usize>,
191 rustc_query_system
::query
::print_query_stack(self, query
, handler
, num_frames
)
195 /// This struct stores metadata about each Query.
197 /// Information is retrieved by indexing the `QUERIES` array using the integer value
198 /// of the `DepKind`. Overall, this allows to implement `QueryContext` using this manual
199 /// jump table instead of large matches.
200 pub struct QueryStruct
{
201 /// The red/green evaluation system will try to mark a specific DepNode in the
202 /// dependency graph as green by recursively trying to mark the dependencies of
203 /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
204 /// where we don't know if it is red or green and we therefore actually have
205 /// to recompute its value in order to find out. Since the only piece of
206 /// information that we have at that point is the `DepNode` we are trying to
207 /// re-evaluate, we need some way to re-run a query from just that. This is what
208 /// `force_from_dep_node()` implements.
210 /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
211 /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
212 /// is usually constructed by computing a stable hash of the query-key that the
213 /// `DepNode` corresponds to. Consequently, it is not in general possible to go
214 /// back from hash to query-key (since hash functions are not reversible). For
215 /// this reason `force_from_dep_node()` is expected to fail from time to time
216 /// because we just cannot find out, from the `DepNode` alone, what the
217 /// corresponding query-key is and therefore cannot re-run the query.
219 /// The system deals with this case letting `try_mark_green` fail which forces
220 /// the root query to be re-evaluated.
222 /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
223 /// Fortunately, we can use some contextual information that will allow us to
224 /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
225 /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
226 /// valid `DefPathHash`. Since we also always build a huge table that maps every
227 /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
228 /// everything we need to re-run the query.
230 /// Take the `mir_promoted` query as an example. Like many other queries, it
231 /// just has a single parameter: the `DefId` of the item it will compute the
232 /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
233 /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
234 /// is actually a `DefPathHash`, and can therefore just look up the corresponding
235 /// `DefId` in `tcx.def_path_hash_to_def_id`.
237 /// When you implement a new query, it will likely have a corresponding new
238 /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
239 /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
240 /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
241 /// add it to the "We don't have enough information to reconstruct..." group in
243 pub(crate) force_from_dep_node
: fn(tcx
: QueryCtxt
<'_
>, dep_node
: &DepNode
) -> bool
,
245 /// Invoke a query to put the on-disk cached value in memory.
246 pub(crate) try_load_from_on_disk_cache
: fn(QueryCtxt
<'_
>, &DepNode
),
249 macro_rules
! handle_cycle_error
{
250 ([][$tcx
: expr
, $error
:expr
]) => {{
252 Value
::from_cycle_error($tcx
)
254 ([fatal_cycle $
($rest
:tt
)*][$tcx
:expr
, $error
:expr
]) => {{
256 $tcx
.sess
.abort_if_errors();
259 ([cycle_delay_bug $
($rest
:tt
)*][$tcx
:expr
, $error
:expr
]) => {{
260 $error
.delay_as_bug();
261 Value
::from_cycle_error($tcx
)
263 ([$other
:ident $
(($
($other_args
:tt
)*))* $
(, $
($modifiers
:tt
)*)*][$
($args
:tt
)*]) => {
264 handle_cycle_error
!([$
($
($modifiers
)*)*][$
($args
)*])
268 macro_rules
! is_anon
{
272 ([anon $
($rest
:tt
)*]) => {{
275 ([$other
:ident $
(($
($other_args
:tt
)*))* $
(, $
($modifiers
:tt
)*)*]) => {
276 is_anon
!([$
($
($modifiers
)*)*])
280 macro_rules
! is_eval_always
{
284 ([eval_always $
($rest
:tt
)*]) => {{
287 ([$other
:ident $
(($
($other_args
:tt
)*))* $
(, $
($modifiers
:tt
)*)*]) => {
288 is_eval_always
!([$
($
($modifiers
)*)*])
292 macro_rules
! hash_result
{
293 ([][$hcx
:expr
, $result
:expr
]) => {{
294 dep_graph
::hash_result($hcx
, &$result
)
296 ([no_hash $
($rest
:tt
)*][$hcx
:expr
, $result
:expr
]) => {{
299 ([$other
:ident $
(($
($other_args
:tt
)*))* $
(, $
($modifiers
:tt
)*)*][$
($args
:tt
)*]) => {
300 hash_result
!([$
($
($modifiers
)*)*][$
($args
)*])
304 macro_rules
! define_queries
{
307 [$
($modifiers
:tt
)*] fn $name
:ident($
($K
:tt
)*) -> $V
:ty
,)*) => {
309 define_queries_struct
! {
311 input
: ($
(([$
($modifiers
)*] [$
($attr
)*] [$name
]))*)
317 // Create an eponymous constructor for each query.
318 $
(#[allow(nonstandard_style)] $(#[$attr])*
319 pub fn $name
<$tcx
>(tcx
: QueryCtxt
<$tcx
>, key
: query_keys
::$name
<$tcx
>) -> QueryStackFrame
{
320 let kind
= dep_graph
::DepKind
::$name
;
321 let name
= stringify
!($name
);
322 let description
= ty
::print
::with_forced_impl_filename_line(
323 // Force filename-line mode to avoid invoking `type_of` query.
324 || queries
::$name
::describe(tcx
, key
)
326 let description
= if tcx
.sess
.verbose() {
327 format
!("{} [{}]", description
, name
)
331 let span
= if kind
== dep_graph
::DepKind
::def_span
{
332 // The `def_span` query is used to calculate `default_span`,
333 // so exit to avoid infinite recursion.
336 Some(key
.default_span(*tcx
))
339 let mut hcx
= tcx
.create_stable_hashing_context();
340 let mut hasher
= StableHasher
::new();
341 std
::mem
::discriminant(&kind
).hash_stable(&mut hcx
, &mut hasher
);
342 key
.hash_stable(&mut hcx
, &mut hasher
);
343 hasher
.finish
::<u64>()
346 QueryStackFrame
::new(name
, description
, span
, hash
)
350 #[allow(nonstandard_style)]
352 use std
::marker
::PhantomData
;
354 $
(pub struct $name
<$tcx
> {
355 data
: PhantomData
<&$
tcx ()>
359 $
(impl<$tcx
> QueryConfig
for queries
::$name
<$tcx
> {
360 type Key
= query_keys
::$name
<$tcx
>;
361 type Value
= query_values
::$name
<$tcx
>;
362 type Stored
= query_stored
::$name
<$tcx
>;
363 const NAME
: &'
static str = stringify
!($name
);
366 impl<$tcx
> QueryAccessors
<QueryCtxt
<$tcx
>> for queries
::$name
<$tcx
> {
367 const ANON
: bool
= is_anon
!([$
($modifiers
)*]);
368 const EVAL_ALWAYS
: bool
= is_eval_always
!([$
($modifiers
)*]);
369 const DEP_KIND
: dep_graph
::DepKind
= dep_graph
::DepKind
::$name
;
371 type Cache
= query_storage
::$name
<$tcx
>;
374 fn query_state
<'a
>(tcx
: QueryCtxt
<$tcx
>) -> &'a QueryState
<crate::dep_graph
::DepKind
, Self::Key
>
375 where QueryCtxt
<$tcx
>: 'a
381 fn query_cache
<'a
>(tcx
: QueryCtxt
<$tcx
>) -> &'a QueryCacheStore
<Self::Cache
>
384 &tcx
.query_caches
.$name
388 fn compute_fn(tcx
: QueryCtxt
<'tcx
>, key
: &Self::Key
) ->
389 fn(TyCtxt
<'tcx
>, Self::Key
) -> Self::Value
391 if key
.query_crate_is_local() {
392 tcx
.queries
.local_providers
.$name
394 tcx
.queries
.extern_providers
.$name
399 _hcx
: &mut StableHashingContext
<'_
>,
400 _result
: &Self::Value
401 ) -> Option
<Fingerprint
> {
402 hash_result
!([$
($modifiers
)*][_hcx
, _result
])
405 fn handle_cycle_error(
406 tcx
: QueryCtxt
<'tcx
>,
407 mut error
: DiagnosticBuilder
<'_
>,
409 handle_cycle_error
!([$
($modifiers
)*][tcx
, error
])
413 #[allow(non_upper_case_globals)]
414 pub mod query_callbacks
{
416 use rustc_middle
::dep_graph
::DepNode
;
417 use rustc_middle
::ty
::query
::query_keys
;
418 use rustc_query_system
::dep_graph
::DepNodeParams
;
419 use rustc_query_system
::query
::{force_query, QueryDescription}
;
421 // We use this for most things when incr. comp. is turned off.
422 pub const Null
: QueryStruct
= QueryStruct
{
423 force_from_dep_node
: |_
, dep_node
| bug
!("force_from_dep_node: encountered {:?}", dep_node
),
424 try_load_from_on_disk_cache
: |_
, _
| {}
,
427 pub const TraitSelect
: QueryStruct
= QueryStruct
{
428 force_from_dep_node
: |_
, _
| false,
429 try_load_from_on_disk_cache
: |_
, _
| {}
,
432 pub const CompileCodegenUnit
: QueryStruct
= QueryStruct
{
433 force_from_dep_node
: |_
, _
| false,
434 try_load_from_on_disk_cache
: |_
, _
| {}
,
437 pub const CompileMonoItem
: QueryStruct
= QueryStruct
{
438 force_from_dep_node
: |_
, _
| false,
439 try_load_from_on_disk_cache
: |_
, _
| {}
,
442 $
(pub const $name
: QueryStruct
= {
443 const is_anon
: bool
= is_anon
!([$
($modifiers
)*]);
446 fn can_reconstruct_query_key() -> bool
{
447 <query_keys
::$name
<'_
> as DepNodeParams
<TyCtxt
<'_
>>>
448 ::can_reconstruct_query_key()
451 fn recover
<'tcx
>(tcx
: TyCtxt
<'tcx
>, dep_node
: &DepNode
) -> Option
<query_keys
::$name
<'tcx
>> {
452 <query_keys
::$name
<'_
> as DepNodeParams
<TyCtxt
<'_
>>>::recover(tcx
, dep_node
)
455 fn force_from_dep_node(tcx
: QueryCtxt
<'_
>, dep_node
: &DepNode
) -> bool
{
456 force_query
::<queries
::$name
<'_
>, _
>(tcx
, dep_node
)
459 fn try_load_from_on_disk_cache(tcx
: QueryCtxt
<'_
>, dep_node
: &DepNode
) {
464 if !can_reconstruct_query_key() {
468 debug_assert
!(tcx
.dep_graph
.is_green(dep_node
));
470 let key
= recover(*tcx
, dep_node
).unwrap_or_else(|| panic
!("Failed to recover key for {:?} with hash {}", dep_node
, dep_node
.hash
));
471 if queries
::$name
::cache_on_disk(tcx
, &key
, None
) {
472 let _
= tcx
.$
name(key
);
478 try_load_from_on_disk_cache
,
483 static QUERY_CALLBACKS
: &[QueryStruct
] = &make_dep_kind_array
!(query_callbacks
);
487 // FIXME(eddyb) this macro (and others?) use `$tcx` and `'tcx` interchangeably.
488 // We should either not take `$tcx` at all and use `'tcx` everywhere, or use
489 // `$tcx` everywhere (even if that isn't necessary due to lack of hygiene).
490 macro_rules
! define_queries_struct
{
492 input
: ($
(([$
($modifiers
:tt
)*] [$
($attr
:tt
)*] [$name
:ident
]))*)) => {
493 pub struct Queries
<$tcx
> {
494 local_providers
: Box
<Providers
>,
495 extern_providers
: Box
<Providers
>,
497 pub on_disk_cache
: Option
<OnDiskCache
<$tcx
>>,
499 $
($
(#[$attr])* $name: QueryState<
500 crate::dep_graph
::DepKind
,
501 query_keys
::$name
<$tcx
>,
505 impl<$tcx
> Queries
<$tcx
> {
507 local_providers
: Providers
,
508 extern_providers
: Providers
,
509 on_disk_cache
: Option
<OnDiskCache
<$tcx
>>,
512 local_providers
: Box
::new(local_providers
),
513 extern_providers
: Box
::new(extern_providers
),
515 $
($name
: Default
::default()),*
519 pub(crate) fn try_collect_active_jobs(
522 ) -> Option
<QueryMap
<crate::dep_graph
::DepKind
>> {
523 let tcx
= QueryCtxt { tcx, queries: self }
;
524 let mut jobs
= QueryMap
::default();
527 self.$name
.try_collect_active_jobs(
529 dep_graph
::DepKind
::$name
,
539 impl QueryEngine
<'tcx
> for Queries
<'tcx
> {
540 fn as_any(&'tcx
self) -> &'tcx
dyn std
::any
::Any
{
541 let this
= unsafe { std::mem::transmute::<&Queries<'_>, &Queries<'_>>(self) }
;
545 fn try_mark_green(&'tcx
self, tcx
: TyCtxt
<'tcx
>, dep_node
: &dep_graph
::DepNode
) -> bool
{
546 let qcx
= QueryCtxt { tcx, queries: self }
;
547 tcx
.dep_graph
.try_mark_green(qcx
, dep_node
).is_some()
556 key
: query_keys
::$name
<$tcx
>,
559 ) -> Option
<query_stored
::$name
<$tcx
>> {
560 let qcx
= QueryCtxt { tcx, queries: self }
;
561 get_query
::<queries
::$name
<$tcx
>, _
>(qcx
, span
, key
, lookup
, mode
)
567 fn describe_as_module(def_id
: LocalDefId
, tcx
: TyCtxt
<'_
>) -> String
{
568 if def_id
.is_top_level_module() {
569 "top-level module".to_string()
571 format
!("module `{}`", tcx
.def_path_str(def_id
.to_def_id()))
575 rustc_query_description
! {}