]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_query_impl/src/plumbing.rs
Added docs to internal_macro const
[rust.git] / compiler / rustc_query_impl / src / plumbing.rs
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.
4
5 use crate::{on_disk_cache, queries, Queries};
6 use rustc_middle::dep_graph::{DepKind, 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::{
11     QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects,
12 };
13
14 use rustc_data_structures::sync::Lock;
15 use rustc_data_structures::thin_vec::ThinVec;
16 use rustc_errors::{Diagnostic, Handler};
17 use rustc_serialize::opaque;
18 use rustc_span::def_id::LocalDefId;
19
20 use std::any::Any;
21
22 #[derive(Copy, Clone)]
23 pub struct QueryCtxt<'tcx> {
24     pub tcx: TyCtxt<'tcx>,
25     pub queries: &'tcx Queries<'tcx>,
26 }
27
28 impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
29     type Target = TyCtxt<'tcx>;
30
31     #[inline]
32     fn deref(&self) -> &Self::Target {
33         &self.tcx
34     }
35 }
36
37 impl HasDepContext for QueryCtxt<'tcx> {
38     type DepKind = rustc_middle::dep_graph::DepKind;
39     type DepContext = TyCtxt<'tcx>;
40
41     #[inline]
42     fn dep_context(&self) -> &Self::DepContext {
43         &self.tcx
44     }
45 }
46
47 impl QueryContext for QueryCtxt<'tcx> {
48     fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
49         tls::with_related_context(**self, |icx| icx.query)
50     }
51
52     fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>> {
53         self.queries.try_collect_active_jobs(**self)
54     }
55
56     // Interactions with on_disk_cache
57     fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects {
58         self.queries
59             .on_disk_cache
60             .as_ref()
61             .map(|c| c.load_side_effects(**self, prev_dep_node_index))
62             .unwrap_or_default()
63     }
64
65     fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) {
66         if let Some(c) = self.queries.on_disk_cache.as_ref() {
67             c.store_side_effects(dep_node_index, side_effects)
68         }
69     }
70
71     fn store_side_effects_for_anon_node(
72         &self,
73         dep_node_index: DepNodeIndex,
74         side_effects: QuerySideEffects,
75     ) {
76         if let Some(c) = self.queries.on_disk_cache.as_ref() {
77             c.store_side_effects_for_anon_node(dep_node_index, side_effects)
78         }
79     }
80
81     /// Executes a job by changing the `ImplicitCtxt` to point to the
82     /// new query job while it executes. It returns the diagnostics
83     /// captured during execution and the actual result.
84     #[inline(always)]
85     fn start_query<R>(
86         &self,
87         token: QueryJobId<Self::DepKind>,
88         diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
89         compute: impl FnOnce() -> R,
90     ) -> R {
91         // The `TyCtxt` stored in TLS has the same global interner lifetime
92         // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
93         // when accessing the `ImplicitCtxt`.
94         tls::with_related_context(**self, move |current_icx| {
95             // Update the `ImplicitCtxt` to point to our new query job.
96             let new_icx = ImplicitCtxt {
97                 tcx: **self,
98                 query: Some(token),
99                 diagnostics,
100                 layout_depth: current_icx.layout_depth,
101                 task_deps: current_icx.task_deps,
102             };
103
104             // Use the `ImplicitCtxt` while we execute the query.
105             tls::enter_context(&new_icx, |_| {
106                 rustc_data_structures::stack::ensure_sufficient_stack(compute)
107             })
108         })
109     }
110 }
111
112 impl<'tcx> QueryCtxt<'tcx> {
113     #[inline]
114     pub fn from_tcx(tcx: TyCtxt<'tcx>) -> Self {
115         let queries = tcx.queries.as_any();
116         let queries = unsafe {
117             let queries = std::mem::transmute::<&dyn Any, &dyn Any>(queries);
118             let queries = queries.downcast_ref().unwrap();
119             let queries = std::mem::transmute::<&Queries<'_>, &Queries<'_>>(queries);
120             queries
121         };
122         QueryCtxt { tcx, queries }
123     }
124
125     crate fn on_disk_cache(self) -> Option<&'tcx on_disk_cache::OnDiskCache<'tcx>> {
126         self.queries.on_disk_cache.as_ref()
127     }
128
129     #[cfg(parallel_compiler)]
130     pub unsafe fn deadlock(self, registry: &rustc_rayon_core::Registry) {
131         rustc_query_system::query::deadlock(self, registry)
132     }
133
134     pub(super) fn encode_query_results(
135         self,
136         encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>,
137         query_result_index: &mut on_disk_cache::EncodedDepNodeIndex,
138     ) -> opaque::FileEncodeResult {
139         macro_rules! encode_queries {
140             ($($query:ident,)*) => {
141                 $(
142                     on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>(
143                         self,
144                         encoder,
145                         query_result_index
146                     )?;
147                 )*
148             }
149         }
150
151         rustc_cached_queries!(encode_queries!);
152
153         Ok(())
154     }
155
156     pub fn try_print_query_stack(
157         self,
158         query: Option<QueryJobId<DepKind>>,
159         handler: &Handler,
160         num_frames: Option<usize>,
161     ) -> usize {
162         rustc_query_system::query::print_query_stack(self, query, handler, num_frames)
163     }
164 }
165
166 macro_rules! handle_cycle_error {
167     ([][$tcx: expr, $error:expr]) => {{
168         $error.emit();
169         Value::from_cycle_error($tcx)
170     }};
171     ([(fatal_cycle) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
172         $error.emit();
173         $tcx.sess.abort_if_errors();
174         unreachable!()
175     }};
176     ([(cycle_delay_bug) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
177         $error.delay_as_bug();
178         Value::from_cycle_error($tcx)
179     }};
180     ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
181         handle_cycle_error!([$($modifiers)*][$($args)*])
182     };
183 }
184
185 macro_rules! is_anon {
186     ([]) => {{
187         false
188     }};
189     ([(anon) $($rest:tt)*]) => {{
190         true
191     }};
192     ([$other:tt $($modifiers:tt)*]) => {
193         is_anon!([$($modifiers)*])
194     };
195 }
196
197 macro_rules! is_eval_always {
198     ([]) => {{
199         false
200     }};
201     ([(eval_always) $($rest:tt)*]) => {{
202         true
203     }};
204     ([$other:tt $($modifiers:tt)*]) => {
205         is_eval_always!([$($modifiers)*])
206     };
207 }
208
209 macro_rules! hash_result {
210     ([]) => {{
211         Some(dep_graph::hash_result)
212     }};
213     ([(no_hash) $($rest:tt)*]) => {{
214         None
215     }};
216     ([$other:tt $($modifiers:tt)*]) => {
217         hash_result!([$($modifiers)*])
218     };
219 }
220
221 macro_rules! define_queries {
222     (<$tcx:tt>
223      $($(#[$attr:meta])*
224         [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
225
226         define_queries_struct! {
227             tcx: $tcx,
228             input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
229         }
230
231         mod make_query {
232             use super::*;
233
234             // Create an eponymous constructor for each query.
235             $(#[allow(nonstandard_style)] $(#[$attr])*
236             pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame {
237                 let kind = dep_graph::DepKind::$name;
238                 let name = stringify!($name);
239                 // Disable visible paths printing for performance reasons.
240                 // Showing visible path instead of any path is not that important in production.
241                 let description = ty::print::with_no_visible_paths(
242                     || ty::print::with_forced_impl_filename_line(
243                     // Force filename-line mode to avoid invoking `type_of` query.
244                     || queries::$name::describe(tcx, key)
245                 ));
246                 let description = if tcx.sess.verbose() {
247                     format!("{} [{}]", description, name)
248                 } else {
249                     description
250                 };
251                 let span = if kind == dep_graph::DepKind::def_span {
252                     // The `def_span` query is used to calculate `default_span`,
253                     // so exit to avoid infinite recursion.
254                     None
255                 } else {
256                     Some(key.default_span(*tcx))
257                 };
258                 let def_id = key.key_as_def_id();
259                 let def_kind = def_id
260                     .and_then(|def_id| def_id.as_local())
261                     // Use `tcx.hir().opt_def_kind()` to reduce the chance of
262                     // accidentally triggering an infinite query loop.
263                     .and_then(|def_id| tcx.hir().opt_def_kind(def_id))
264                     .map(|def_kind| $crate::util::def_kind_to_simple_def_kind(def_kind));
265                 let hash = || {
266                     let mut hcx = tcx.create_stable_hashing_context();
267                     let mut hasher = StableHasher::new();
268                     std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher);
269                     key.hash_stable(&mut hcx, &mut hasher);
270                     hasher.finish::<u64>()
271                 };
272
273                 QueryStackFrame::new(name, description, span, def_kind, hash)
274             })*
275         }
276
277         #[allow(nonstandard_style)]
278         pub mod queries {
279             use std::marker::PhantomData;
280
281             $(pub struct $name<$tcx> {
282                 data: PhantomData<&$tcx ()>
283             })*
284         }
285
286         $(impl<$tcx> QueryConfig for queries::$name<$tcx> {
287             type Key = query_keys::$name<$tcx>;
288             type Value = query_values::$name<$tcx>;
289             type Stored = query_stored::$name<$tcx>;
290             const NAME: &'static str = stringify!($name);
291         }
292
293         impl<$tcx> QueryAccessors<QueryCtxt<$tcx>> for queries::$name<$tcx> {
294             const ANON: bool = is_anon!([$($modifiers)*]);
295             const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
296             const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
297             const HASH_RESULT: Option<fn(&mut StableHashingContext<'_>, &Self::Value) -> Fingerprint> = hash_result!([$($modifiers)*]);
298
299             type Cache = query_storage::$name<$tcx>;
300
301             #[inline(always)]
302             fn query_state<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryState<crate::dep_graph::DepKind, Self::Key>
303                 where QueryCtxt<$tcx>: 'a
304             {
305                 &tcx.queries.$name
306             }
307
308             #[inline(always)]
309             fn query_cache<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryCacheStore<Self::Cache>
310                 where 'tcx:'a
311             {
312                 &tcx.query_caches.$name
313             }
314
315             #[inline]
316             fn compute_fn(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
317                 fn(TyCtxt<'tcx>, Self::Key) -> Self::Value
318             {
319                 if key.query_crate_is_local() {
320                     tcx.queries.local_providers.$name
321                 } else {
322                     tcx.queries.extern_providers.$name
323                 }
324             }
325
326             fn handle_cycle_error(
327                 tcx: QueryCtxt<'tcx>,
328                 mut error: DiagnosticBuilder<'_>,
329             ) -> Self::Value {
330                 handle_cycle_error!([$($modifiers)*][tcx, error])
331             }
332         })*
333
334         #[allow(nonstandard_style)]
335         pub mod query_callbacks {
336             use super::*;
337             use rustc_middle::dep_graph::DepNode;
338             use rustc_middle::ty::query::query_keys;
339             use rustc_query_system::dep_graph::DepNodeParams;
340             use rustc_query_system::query::{force_query, QueryDescription};
341             use rustc_query_system::dep_graph::FingerprintStyle;
342
343             // We use this for most things when incr. comp. is turned off.
344             pub fn Null() -> DepKindStruct {
345                 DepKindStruct {
346                     is_anon: false,
347                     is_eval_always: false,
348                     fingerprint_style: FingerprintStyle::Unit,
349                     force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)),
350                     try_load_from_on_disk_cache: None,
351                 }
352             }
353
354             pub fn TraitSelect() -> DepKindStruct {
355                 DepKindStruct {
356                     is_anon: true,
357                     is_eval_always: false,
358                     fingerprint_style: FingerprintStyle::Unit,
359                     force_from_dep_node: None,
360                     try_load_from_on_disk_cache: None,
361                 }
362             }
363
364             pub fn CompileCodegenUnit() -> DepKindStruct {
365                 DepKindStruct {
366                     is_anon: false,
367                     is_eval_always: false,
368                     fingerprint_style: FingerprintStyle::Opaque,
369                     force_from_dep_node: None,
370                     try_load_from_on_disk_cache: None,
371                 }
372             }
373
374             pub fn CompileMonoItem() -> DepKindStruct {
375                 DepKindStruct {
376                     is_anon: false,
377                     is_eval_always: false,
378                     fingerprint_style: FingerprintStyle::Opaque,
379                     force_from_dep_node: None,
380                     try_load_from_on_disk_cache: None,
381                 }
382             }
383
384             $(pub fn $name()-> DepKindStruct {
385                 let is_anon = is_anon!([$($modifiers)*]);
386                 let is_eval_always = is_eval_always!([$($modifiers)*]);
387
388                 let fingerprint_style =
389                     <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::fingerprint_style();
390
391                 if is_anon || !fingerprint_style.reconstructible() {
392                     return DepKindStruct {
393                         is_anon,
394                         is_eval_always,
395                         fingerprint_style,
396                         force_from_dep_node: None,
397                         try_load_from_on_disk_cache: None,
398                     }
399                 }
400
401                 #[inline(always)]
402                 fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option<query_keys::$name<'tcx>> {
403                     <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, &dep_node)
404                 }
405
406                 fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool {
407                     if let Some(key) = recover(tcx, dep_node) {
408                         let tcx = QueryCtxt::from_tcx(tcx);
409                         force_query::<queries::$name<'_>, _>(tcx, key, dep_node);
410                         true
411                     } else {
412                         false
413                     }
414                 }
415
416                 fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) {
417                     debug_assert!(tcx.dep_graph.is_green(&dep_node));
418
419                     let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
420                     let tcx = QueryCtxt::from_tcx(tcx);
421                     if queries::$name::cache_on_disk(tcx, &key, None) {
422                         let _ = tcx.$name(key);
423                     }
424                 }
425
426                 DepKindStruct {
427                     is_anon,
428                     is_eval_always,
429                     fingerprint_style,
430                     force_from_dep_node: Some(force_from_dep_node),
431                     try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache),
432                 }
433             })*
434         }
435
436         pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] {
437             arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
438         }
439     }
440 }
441
442 // FIXME(eddyb) this macro (and others?) use `$tcx` and `'tcx` interchangeably.
443 // We should either not take `$tcx` at all and use `'tcx` everywhere, or use
444 // `$tcx` everywhere (even if that isn't necessary due to lack of hygiene).
445 macro_rules! define_queries_struct {
446     (tcx: $tcx:tt,
447      input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
448         pub struct Queries<$tcx> {
449             local_providers: Box<Providers>,
450             extern_providers: Box<Providers>,
451
452             pub on_disk_cache: Option<OnDiskCache<$tcx>>,
453
454             $($(#[$attr])*  $name: QueryState<
455                 crate::dep_graph::DepKind,
456                 query_keys::$name<$tcx>,
457             >,)*
458         }
459
460         impl<$tcx> Queries<$tcx> {
461             pub fn new(
462                 local_providers: Providers,
463                 extern_providers: Providers,
464                 on_disk_cache: Option<OnDiskCache<$tcx>>,
465             ) -> Self {
466                 Queries {
467                     local_providers: Box::new(local_providers),
468                     extern_providers: Box::new(extern_providers),
469                     on_disk_cache,
470                     $($name: Default::default()),*
471                 }
472             }
473
474             pub(crate) fn try_collect_active_jobs(
475                 &$tcx self,
476                 tcx: TyCtxt<$tcx>,
477             ) -> Option<QueryMap<crate::dep_graph::DepKind>> {
478                 let tcx = QueryCtxt { tcx, queries: self };
479                 let mut jobs = QueryMap::default();
480
481                 $(
482                     self.$name.try_collect_active_jobs(
483                         tcx,
484                         dep_graph::DepKind::$name,
485                         make_query::$name,
486                         &mut jobs,
487                     )?;
488                 )*
489
490                 Some(jobs)
491             }
492         }
493
494         impl QueryEngine<'tcx> for Queries<'tcx> {
495             fn as_any(&'tcx self) -> &'tcx dyn std::any::Any {
496                 let this = unsafe { std::mem::transmute::<&Queries<'_>, &Queries<'_>>(self) };
497                 this as _
498             }
499
500             fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool {
501                 let qcx = QueryCtxt { tcx, queries: self };
502                 tcx.dep_graph.try_mark_green(qcx, dep_node).is_some()
503             }
504
505             $($(#[$attr])*
506             #[inline(always)]
507             fn $name(
508                 &'tcx self,
509                 tcx: TyCtxt<$tcx>,
510                 span: Span,
511                 key: query_keys::$name<$tcx>,
512                 lookup: QueryLookup,
513                 mode: QueryMode,
514             ) -> Option<query_stored::$name<$tcx>> {
515                 let qcx = QueryCtxt { tcx, queries: self };
516                 get_query::<queries::$name<$tcx>, _>(qcx, span, key, lookup, mode)
517             })*
518         }
519     };
520 }
521
522 fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
523     if def_id.is_top_level_module() {
524         "top-level module".to_string()
525     } else {
526         format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
527     }
528 }
529
530 rustc_query_description! {}