]> git.lizzy.rs Git - rust.git/blob - src/librustc_middle/ty/query/plumbing.rs
d6d4335e9388d7bdaf653b2ea0a0f210225f7edd
[rust.git] / src / librustc_middle / ty / query / 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::dep_graph::DepGraph;
6 use crate::ty::query::Query;
7 use crate::ty::tls::{self, ImplicitCtxt};
8 use crate::ty::{self, TyCtxt};
9 use rustc_query_system::query::QueryContext;
10 use rustc_query_system::query::{CycleError, QueryJobId, QueryJobInfo};
11
12 use rustc_data_structures::fx::FxHashMap;
13 use rustc_data_structures::sync::Lock;
14 use rustc_data_structures::thin_vec::ThinVec;
15 use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, Handler, Level};
16 use rustc_span::def_id::DefId;
17 use rustc_span::Span;
18
19 impl QueryContext for TyCtxt<'tcx> {
20     type Query = Query<'tcx>;
21
22     fn incremental_verify_ich(&self) -> bool {
23         self.sess.opts.debugging_opts.incremental_verify_ich
24     }
25     fn verbose(&self) -> bool {
26         self.sess.verbose()
27     }
28
29     fn def_path_str(&self, def_id: DefId) -> String {
30         TyCtxt::def_path_str(*self, def_id)
31     }
32
33     fn dep_graph(&self) -> &DepGraph {
34         &self.dep_graph
35     }
36
37     fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
38         tls::with_related_context(*self, |icx| icx.query)
39     }
40
41     fn try_collect_active_jobs(
42         &self,
43     ) -> Option<FxHashMap<QueryJobId<Self::DepKind>, QueryJobInfo<Self>>> {
44         self.queries.try_collect_active_jobs()
45     }
46
47     /// Executes a job by changing the `ImplicitCtxt` to point to the
48     /// new query job while it executes. It returns the diagnostics
49     /// captured during execution and the actual result.
50     #[inline(always)]
51     fn start_query<R>(
52         &self,
53         token: QueryJobId<Self::DepKind>,
54         diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
55         compute: impl FnOnce(Self) -> R,
56     ) -> R {
57         // The `TyCtxt` stored in TLS has the same global interner lifetime
58         // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
59         // when accessing the `ImplicitCtxt`.
60         tls::with_related_context(*self, move |current_icx| {
61             // Update the `ImplicitCtxt` to point to our new query job.
62             let new_icx = ImplicitCtxt {
63                 tcx: *self,
64                 query: Some(token),
65                 diagnostics,
66                 layout_depth: current_icx.layout_depth,
67                 task_deps: current_icx.task_deps,
68             };
69
70             // Use the `ImplicitCtxt` while we execute the query.
71             tls::enter_context(&new_icx, |_| compute(*self))
72         })
73     }
74 }
75
76 impl<'tcx> TyCtxt<'tcx> {
77     #[inline(never)]
78     #[cold]
79     pub(super) fn report_cycle(
80         self,
81         CycleError { usage, cycle: stack }: CycleError<Query<'tcx>>,
82     ) -> DiagnosticBuilder<'tcx> {
83         assert!(!stack.is_empty());
84
85         let fix_span = |span: Span, query: &Query<'tcx>| {
86             self.sess.source_map().guess_head_span(query.default_span(self, span))
87         };
88
89         // Disable naming impls with types in this path, since that
90         // sometimes cycles itself, leading to extra cycle errors.
91         // (And cycle errors around impls tend to occur during the
92         // collect/coherence phases anyhow.)
93         ty::print::with_forced_impl_filename_line(|| {
94             let span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
95             let mut err = struct_span_err!(
96                 self.sess,
97                 span,
98                 E0391,
99                 "cycle detected when {}",
100                 stack[0].query.describe(self)
101             );
102
103             for i in 1..stack.len() {
104                 let query = &stack[i].query;
105                 let span = fix_span(stack[(i + 1) % stack.len()].span, query);
106                 err.span_note(span, &format!("...which requires {}...", query.describe(self)));
107             }
108
109             err.note(&format!(
110                 "...which again requires {}, completing the cycle",
111                 stack[0].query.describe(self)
112             ));
113
114             if let Some((span, query)) = usage {
115                 err.span_note(
116                     fix_span(span, &query),
117                     &format!("cycle used when {}", query.describe(self)),
118                 );
119             }
120
121             err
122         })
123     }
124
125     pub fn try_print_query_stack(handler: &Handler) {
126         eprintln!("query stack during panic:");
127
128         // Be careful reyling on global state here: this code is called from
129         // a panic hook, which means that the global `Handler` may be in a weird
130         // state if it was responsible for triggering the panic.
131         ty::tls::with_context_opt(|icx| {
132             if let Some(icx) = icx {
133                 let query_map = icx.tcx.queries.try_collect_active_jobs();
134
135                 let mut current_query = icx.query;
136                 let mut i = 0;
137
138                 while let Some(query) = current_query {
139                     let query_info =
140                         if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) {
141                             info
142                         } else {
143                             break;
144                         };
145                     let mut diag = Diagnostic::new(
146                         Level::FailureNote,
147                         &format!(
148                             "#{} [{}] {}",
149                             i,
150                             query_info.info.query.name(),
151                             query_info.info.query.describe(icx.tcx)
152                         ),
153                     );
154                     diag.span =
155                         icx.tcx.sess.source_map().guess_head_span(query_info.info.span).into();
156                     handler.force_print_diagnostic(diag);
157
158                     current_query = query_info.job.parent;
159                     i += 1;
160                 }
161             }
162         });
163
164         eprintln!("end of query stack");
165     }
166 }
167
168 macro_rules! handle_cycle_error {
169     ([][$tcx: expr, $error:expr]) => {{
170         $tcx.report_cycle($error).emit();
171         Value::from_cycle_error($tcx)
172     }};
173     ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{
174         $tcx.report_cycle($error).emit();
175         $tcx.sess.abort_if_errors();
176         unreachable!()
177     }};
178     ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{
179         $tcx.report_cycle($error).delay_as_bug();
180         Value::from_cycle_error($tcx)
181     }};
182     ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
183         handle_cycle_error!([$($($modifiers)*)*][$($args)*])
184     };
185 }
186
187 macro_rules! is_anon {
188     ([]) => {{
189         false
190     }};
191     ([anon $($rest:tt)*]) => {{
192         true
193     }};
194     ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
195         is_anon!([$($($modifiers)*)*])
196     };
197 }
198
199 macro_rules! is_eval_always {
200     ([]) => {{
201         false
202     }};
203     ([eval_always $($rest:tt)*]) => {{
204         true
205     }};
206     ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
207         is_eval_always!([$($($modifiers)*)*])
208     };
209 }
210
211 macro_rules! query_storage {
212     ([][$K:ty, $V:ty]) => {
213         <<$K as Key>::CacheSelector as CacheSelector<$K, $V>>::Cache
214     };
215     ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => {
216         <$ty as CacheSelector<$K, $V>>::Cache
217     };
218     ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
219         query_storage!([$($($modifiers)*)*][$($args)*])
220     };
221 }
222
223 macro_rules! hash_result {
224     ([][$hcx:expr, $result:expr]) => {{
225         dep_graph::hash_result($hcx, &$result)
226     }};
227     ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{
228         None
229     }};
230     ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
231         hash_result!([$($($modifiers)*)*][$($args)*])
232     };
233 }
234
235 macro_rules! define_queries {
236     (<$tcx:tt> $($category:tt {
237         $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*
238     },)*) => {
239         define_queries_inner! { <$tcx>
240             $($( $(#[$attr])* category<$category> [$($modifiers)*] fn $name: $node($($K)*) -> $V,)*)*
241         }
242     }
243 }
244
245 macro_rules! query_helper_param_ty {
246     (DefId) => { impl IntoQueryParam<DefId> };
247     ($K:ty) => { $K };
248 }
249
250 macro_rules! define_queries_inner {
251     (<$tcx:tt>
252      $($(#[$attr:meta])* category<$category:tt>
253         [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*) => {
254
255         use std::mem;
256         use crate::{
257             rustc_data_structures::stable_hasher::HashStable,
258             rustc_data_structures::stable_hasher::StableHasher,
259             ich::StableHashingContext
260         };
261         use rustc_data_structures::profiling::ProfileCategory;
262
263         define_queries_struct! {
264             tcx: $tcx,
265             input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
266         }
267
268         #[allow(nonstandard_style)]
269         #[derive(Clone, Debug)]
270         pub enum Query<$tcx> {
271             $($(#[$attr])* $name($($K)*)),*
272         }
273
274         impl<$tcx> Query<$tcx> {
275             pub fn name(&self) -> &'static str {
276                 match *self {
277                     $(Query::$name(_) => stringify!($name),)*
278                 }
279             }
280
281             pub fn describe(&self, tcx: TyCtxt<$tcx>) -> Cow<'static, str> {
282                 let (r, name) = match *self {
283                     $(Query::$name(key) => {
284                         (queries::$name::describe(tcx, key), stringify!($name))
285                     })*
286                 };
287                 if tcx.sess.verbose() {
288                     format!("{} [{}]", r, name).into()
289                 } else {
290                     r
291                 }
292             }
293
294             // FIXME(eddyb) Get more valid `Span`s on queries.
295             pub fn default_span(&self, tcx: TyCtxt<$tcx>, span: Span) -> Span {
296                 if !span.is_dummy() {
297                     return span;
298                 }
299                 // The `def_span` query is used to calculate `default_span`,
300                 // so exit to avoid infinite recursion.
301                 if let Query::def_span(..) = *self {
302                     return span
303                 }
304                 match *self {
305                     $(Query::$name(key) => key.default_span(tcx),)*
306                 }
307             }
308         }
309
310         impl<'a, $tcx> HashStable<StableHashingContext<'a>> for Query<$tcx> {
311             fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
312                 mem::discriminant(self).hash_stable(hcx, hasher);
313                 match *self {
314                     $(Query::$name(key) => key.hash_stable(hcx, hasher),)*
315                 }
316             }
317         }
318
319         pub mod queries {
320             use std::marker::PhantomData;
321
322             $(#[allow(nonstandard_style)]
323             pub struct $name<$tcx> {
324                 data: PhantomData<&$tcx ()>
325             })*
326         }
327
328         $(impl<$tcx> QueryConfig<TyCtxt<$tcx>> for queries::$name<$tcx> {
329             type Key = $($K)*;
330             type Value = $V;
331             type Stored = <
332                 query_storage!([$($modifiers)*][$($K)*, $V])
333                 as QueryStorage
334             >::Stored;
335             const NAME: &'static str = stringify!($name);
336             const CATEGORY: ProfileCategory = $category;
337         }
338
339         impl<$tcx> QueryAccessors<TyCtxt<$tcx>> for queries::$name<$tcx> {
340             const ANON: bool = is_anon!([$($modifiers)*]);
341             const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
342             const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$node;
343
344             type Cache = query_storage!([$($modifiers)*][$($K)*, $V]);
345
346             #[inline(always)]
347             fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<TyCtxt<$tcx>, Self::Cache> {
348                 &tcx.queries.$name
349             }
350
351             #[inline]
352             fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
353                 let provider = tcx.queries.providers.get(key.query_crate())
354                     // HACK(eddyb) it's possible crates may be loaded after
355                     // the query engine is created, and because crate loading
356                     // is not yet integrated with the query engine, such crates
357                     // would be missing appropriate entries in `providers`.
358                     .unwrap_or(&tcx.queries.fallback_extern_providers)
359                     .$name;
360                 provider(tcx, key)
361             }
362
363             fn hash_result(
364                 _hcx: &mut StableHashingContext<'_>,
365                 _result: &Self::Value
366             ) -> Option<Fingerprint> {
367                 hash_result!([$($modifiers)*][_hcx, _result])
368             }
369
370             fn handle_cycle_error(
371                 tcx: TyCtxt<'tcx>,
372                 error: CycleError<Query<'tcx>>
373             ) -> Self::Value {
374                 handle_cycle_error!([$($modifiers)*][tcx, error])
375             }
376         })*
377
378         #[derive(Copy, Clone)]
379         pub struct TyCtxtEnsure<'tcx> {
380             pub tcx: TyCtxt<'tcx>,
381         }
382
383         impl TyCtxtEnsure<$tcx> {
384             $($(#[$attr])*
385             #[inline(always)]
386             pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
387                 ensure_query::<queries::$name<'_>, _>(self.tcx, key.into_query_param())
388             })*
389         }
390
391         #[derive(Copy, Clone)]
392         pub struct TyCtxtAt<'tcx> {
393             pub tcx: TyCtxt<'tcx>,
394             pub span: Span,
395         }
396
397         impl Deref for TyCtxtAt<'tcx> {
398             type Target = TyCtxt<'tcx>;
399             #[inline(always)]
400             fn deref(&self) -> &Self::Target {
401                 &self.tcx
402             }
403         }
404
405         impl TyCtxt<$tcx> {
406             /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
407             /// are executed instead of just returning their results.
408             #[inline(always)]
409             pub fn ensure(self) -> TyCtxtEnsure<$tcx> {
410                 TyCtxtEnsure {
411                     tcx: self,
412                 }
413             }
414
415             /// Returns a transparent wrapper for `TyCtxt` which uses
416             /// `span` as the location of queries performed through it.
417             #[inline(always)]
418             pub fn at(self, span: Span) -> TyCtxtAt<$tcx> {
419                 TyCtxtAt {
420                     tcx: self,
421                     span
422                 }
423             }
424
425             $($(#[$attr])*
426             #[inline(always)]
427             pub fn $name(self, key: query_helper_param_ty!($($K)*))
428                 -> <queries::$name<$tcx> as QueryConfig<TyCtxt<$tcx>>>::Stored
429             {
430                 self.at(DUMMY_SP).$name(key.into_query_param())
431             })*
432
433             /// All self-profiling events generated by the query engine use
434             /// virtual `StringId`s for their `event_id`. This method makes all
435             /// those virtual `StringId`s point to actual strings.
436             ///
437             /// If we are recording only summary data, the ids will point to
438             /// just the query names. If we are recording query keys too, we
439             /// allocate the corresponding strings here.
440             pub fn alloc_self_profile_query_strings(self) {
441                 use crate::ty::query::profiling_support::{
442                     alloc_self_profile_query_strings_for_query_cache,
443                     QueryKeyStringCache,
444                 };
445
446                 if !self.prof.enabled() {
447                     return;
448                 }
449
450                 let mut string_cache = QueryKeyStringCache::new();
451
452                 $({
453                     alloc_self_profile_query_strings_for_query_cache(
454                         self,
455                         stringify!($name),
456                         &self.queries.$name,
457                         &mut string_cache,
458                     );
459                 })*
460             }
461         }
462
463         impl TyCtxtAt<$tcx> {
464             $($(#[$attr])*
465             #[inline(always)]
466             pub fn $name(self, key: query_helper_param_ty!($($K)*))
467                 -> <queries::$name<$tcx> as QueryConfig<TyCtxt<$tcx>>>::Stored
468             {
469                 get_query::<queries::$name<'_>, _>(self.tcx, self.span, key.into_query_param())
470             })*
471         }
472
473         define_provider_struct! {
474             tcx: $tcx,
475             input: ($(([$($modifiers)*] [$name] [$($K)*] [$V]))*)
476         }
477
478         impl<$tcx> Copy for Providers<$tcx> {}
479         impl<$tcx> Clone for Providers<$tcx> {
480             fn clone(&self) -> Self { *self }
481         }
482     }
483 }
484
485 macro_rules! define_queries_struct {
486     (tcx: $tcx:tt,
487      input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
488         pub struct Queries<$tcx> {
489             /// This provides access to the incrimental comilation on-disk cache for query results.
490             /// Do not access this directly. It is only meant to be used by
491             /// `DepGraph::try_mark_green()` and the query infrastructure.
492             pub(crate) on_disk_cache: OnDiskCache<'tcx>,
493
494             providers: IndexVec<CrateNum, Providers<$tcx>>,
495             fallback_extern_providers: Box<Providers<$tcx>>,
496
497             $($(#[$attr])*  $name: QueryState<
498                 TyCtxt<$tcx>,
499                 <queries::$name<$tcx> as QueryAccessors<TyCtxt<'tcx>>>::Cache,
500             >,)*
501         }
502
503         impl<$tcx> Queries<$tcx> {
504             pub(crate) fn new(
505                 providers: IndexVec<CrateNum, Providers<$tcx>>,
506                 fallback_extern_providers: Providers<$tcx>,
507                 on_disk_cache: OnDiskCache<'tcx>,
508             ) -> Self {
509                 Queries {
510                     providers,
511                     fallback_extern_providers: Box::new(fallback_extern_providers),
512                     on_disk_cache,
513                     $($name: Default::default()),*
514                 }
515             }
516
517             pub(crate) fn try_collect_active_jobs(
518                 &self
519             ) -> Option<FxHashMap<QueryJobId<crate::dep_graph::DepKind>, QueryJobInfo<TyCtxt<'tcx>>>> {
520                 let mut jobs = FxHashMap::default();
521
522                 $(
523                     self.$name.try_collect_active_jobs(
524                         <queries::$name<'tcx> as QueryAccessors<TyCtxt<'tcx>>>::DEP_KIND,
525                         Query::$name,
526                         &mut jobs,
527                     )?;
528                 )*
529
530                 Some(jobs)
531             }
532         }
533     };
534 }
535
536 macro_rules! define_provider_struct {
537     (tcx: $tcx:tt,
538      input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => {
539         pub struct Providers<$tcx> {
540             $(pub $name: fn(TyCtxt<$tcx>, $K) -> $R,)*
541         }
542
543         impl<$tcx> Default for Providers<$tcx> {
544             fn default() -> Self {
545                 $(fn $name<$tcx>(_: TyCtxt<$tcx>, key: $K) -> $R {
546                     bug!("`tcx.{}({:?})` unsupported by its crate",
547                          stringify!($name), key);
548                 })*
549                 Providers { $($name),* }
550             }
551         }
552     };
553 }