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::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}
;
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
;
19 impl QueryContext
for TyCtxt
<'tcx
> {
20 type Query
= Query
<'tcx
>;
22 fn incremental_verify_ich(&self) -> bool
{
23 self.sess
.opts
.debugging_opts
.incremental_verify_ich
25 fn verbose(&self) -> bool
{
29 fn def_path_str(&self, def_id
: DefId
) -> String
{
30 TyCtxt
::def_path_str(*self, def_id
)
33 fn dep_graph(&self) -> &DepGraph
{
37 fn current_query_job(&self) -> Option
<QueryJobId
<Self::DepKind
>> {
38 tls
::with_related_context(*self, |icx
| icx
.query
)
41 fn try_collect_active_jobs(
43 ) -> Option
<FxHashMap
<QueryJobId
<Self::DepKind
>, QueryJobInfo
<Self>>> {
44 self.queries
.try_collect_active_jobs()
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.
53 token
: QueryJobId
<Self::DepKind
>,
54 diagnostics
: Option
<&Lock
<ThinVec
<Diagnostic
>>>,
55 compute
: impl FnOnce(Self) -> 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
{
66 layout_depth
: current_icx
.layout_depth
,
67 task_deps
: current_icx
.task_deps
,
70 // Use the `ImplicitCtxt` while we execute the query.
71 tls
::enter_context(&new_icx
, |_
| {
72 rustc_data_structures
::stack
::ensure_sufficient_stack(|| compute(*self))
78 impl<'tcx
> TyCtxt
<'tcx
> {
81 pub(super) fn report_cycle(
83 CycleError { usage, cycle: stack }
: CycleError
<Query
<'tcx
>>,
84 ) -> DiagnosticBuilder
<'tcx
> {
85 assert
!(!stack
.is_empty());
87 let fix_span
= |span
: Span
, query
: &Query
<'tcx
>| {
88 self.sess
.source_map().guess_head_span(query
.default_span(self, span
))
91 // Disable naming impls with types in this path, since that
92 // sometimes cycles itself, leading to extra cycle errors.
93 // (And cycle errors around impls tend to occur during the
94 // collect/coherence phases anyhow.)
95 ty
::print
::with_forced_impl_filename_line(|| {
96 let span
= fix_span(stack
[1 % stack
.len()].span
, &stack
[0].query
);
97 let mut err
= struct_span_err
!(
101 "cycle detected when {}",
102 stack
[0].query
.describe(self)
105 for i
in 1..stack
.len() {
106 let query
= &stack
[i
].query
;
107 let span
= fix_span(stack
[(i
+ 1) % stack
.len()].span
, query
);
108 err
.span_note(span
, &format
!("...which requires {}...", query
.describe(self)));
112 "...which again requires {}, completing the cycle",
113 stack
[0].query
.describe(self)
116 if let Some((span
, query
)) = usage
{
118 fix_span(span
, &query
),
119 &format
!("cycle used when {}", query
.describe(self)),
127 pub fn try_print_query_stack(handler
: &Handler
) {
128 eprintln
!("query stack during panic:");
130 // Be careful reyling on global state here: this code is called from
131 // a panic hook, which means that the global `Handler` may be in a weird
132 // state if it was responsible for triggering the panic.
133 ty
::tls
::with_context_opt(|icx
| {
134 if let Some(icx
) = icx
{
135 let query_map
= icx
.tcx
.queries
.try_collect_active_jobs();
137 let mut current_query
= icx
.query
;
140 while let Some(query
) = current_query
{
142 if let Some(info
) = query_map
.as_ref().and_then(|map
| map
.get(&query
)) {
147 let mut diag
= Diagnostic
::new(
152 query_info
.info
.query
.name(),
153 query_info
.info
.query
.describe(icx
.tcx
)
157 icx
.tcx
.sess
.source_map().guess_head_span(query_info
.info
.span
).into();
158 handler
.force_print_diagnostic(diag
);
160 current_query
= query_info
.job
.parent
;
166 eprintln
!("end of query stack");
170 macro_rules
! handle_cycle_error
{
171 ([][$tcx
: expr
, $error
:expr
]) => {{
172 $tcx
.report_cycle($error
).emit();
173 Value
::from_cycle_error($tcx
)
175 ([fatal_cycle $
($rest
:tt
)*][$tcx
:expr
, $error
:expr
]) => {{
176 $tcx
.report_cycle($error
).emit();
177 $tcx
.sess
.abort_if_errors();
180 ([cycle_delay_bug $
($rest
:tt
)*][$tcx
:expr
, $error
:expr
]) => {{
181 $tcx
.report_cycle($error
).delay_as_bug();
182 Value
::from_cycle_error($tcx
)
184 ([$other
:ident $
(($
($other_args
:tt
)*))* $
(, $
($modifiers
:tt
)*)*][$
($args
:tt
)*]) => {
185 handle_cycle_error
!([$
($
($modifiers
)*)*][$
($args
)*])
189 macro_rules
! is_anon
{
193 ([anon $
($rest
:tt
)*]) => {{
196 ([$other
:ident $
(($
($other_args
:tt
)*))* $
(, $
($modifiers
:tt
)*)*]) => {
197 is_anon
!([$
($
($modifiers
)*)*])
201 macro_rules
! is_eval_always
{
205 ([eval_always $
($rest
:tt
)*]) => {{
208 ([$other
:ident $
(($
($other_args
:tt
)*))* $
(, $
($modifiers
:tt
)*)*]) => {
209 is_eval_always
!([$
($
($modifiers
)*)*])
213 macro_rules
! query_storage
{
214 ([][$K
:ty
, $V
:ty
]) => {
215 <<$K
as Key
>::CacheSelector
as CacheSelector
<$K
, $V
>>::Cache
217 ([storage($ty
:ty
) $
($rest
:tt
)*][$K
:ty
, $V
:ty
]) => {
218 <$ty
as CacheSelector
<$K
, $V
>>::Cache
220 ([$other
:ident $
(($
($other_args
:tt
)*))* $
(, $
($modifiers
:tt
)*)*][$
($args
:tt
)*]) => {
221 query_storage
!([$
($
($modifiers
)*)*][$
($args
)*])
225 macro_rules
! hash_result
{
226 ([][$hcx
:expr
, $result
:expr
]) => {{
227 dep_graph
::hash_result($hcx
, &$result
)
229 ([no_hash $
($rest
:tt
)*][$hcx
:expr
, $result
:expr
]) => {{
232 ([$other
:ident $
(($
($other_args
:tt
)*))* $
(, $
($modifiers
:tt
)*)*][$
($args
:tt
)*]) => {
233 hash_result
!([$
($
($modifiers
)*)*][$
($args
)*])
237 macro_rules
! define_queries
{
238 (<$tcx
:tt
> $
($category
:tt
{
239 $
($
(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*
241 define_queries_inner
! { <$tcx
>
242 $
($
( $
(#[$attr])* category<$category> [$($modifiers)*] fn $name: $node($($K)*) -> $V,)*)*
247 macro_rules
! query_helper_param_ty
{
248 (DefId
) => { impl IntoQueryParam<DefId> }
;
252 macro_rules
! define_queries_inner
{
254 $
($
(#[$attr:meta])* category<$category:tt>
255 [$
($modifiers
:tt
)*] fn $name
:ident
: $node
:ident($
($K
:tt
)*) -> $V
:ty
,)*) => {
259 rustc_data_structures
::stable_hasher
::HashStable
,
260 rustc_data_structures
::stable_hasher
::StableHasher
,
261 ich
::StableHashingContext
263 use rustc_data_structures
::profiling
::ProfileCategory
;
265 define_queries_struct
! {
267 input
: ($
(([$
($modifiers
)*] [$
($attr
)*] [$name
]))*)
270 #[allow(nonstandard_style)]
271 #[derive(Clone, Debug)]
272 pub enum Query
<$tcx
> {
273 $
($
(#[$attr])* $name($($K)*)),*
276 impl<$tcx
> Query
<$tcx
> {
277 pub fn name(&self) -> &'
static str {
279 $
(Query
::$
name(_
) => stringify
!($name
),)*
283 pub fn describe(&self, tcx
: TyCtxt
<$tcx
>) -> Cow
<'
static, str> {
284 let (r
, name
) = match *self {
285 $
(Query
::$
name(key
) => {
286 (queries
::$name
::describe(tcx
, key
), stringify
!($name
))
289 if tcx
.sess
.verbose() {
290 format
!("{} [{}]", r
, name
).into()
296 // FIXME(eddyb) Get more valid `Span`s on queries.
297 pub fn default_span(&self, tcx
: TyCtxt
<$tcx
>, span
: Span
) -> Span
{
298 if !span
.is_dummy() {
301 // The `def_span` query is used to calculate `default_span`,
302 // so exit to avoid infinite recursion.
303 if let Query
::def_span(..) = *self {
307 $
(Query
::$
name(key
) => key
.default_span(tcx
),)*
312 impl<'a
, $tcx
> HashStable
<StableHashingContext
<'a
>> for Query
<$tcx
> {
313 fn hash_stable(&self, hcx
: &mut StableHashingContext
<'a
>, hasher
: &mut StableHasher
) {
314 mem
::discriminant(self).hash_stable(hcx
, hasher
);
316 $
(Query
::$
name(key
) => key
.hash_stable(hcx
, hasher
),)*
321 #[allow(nonstandard_style)]
323 use std
::marker
::PhantomData
;
325 $
(pub struct $name
<$tcx
> {
326 data
: PhantomData
<&$
tcx ()>
330 // HACK(eddyb) this is like the `impl QueryConfig for queries::$name`
331 // below, but using type aliases instead of associated types, to bypass
332 // the limitations around normalizing under HRTB - for example, this:
333 // `for<'tcx> fn(...) -> <queries::$name<'tcx> as QueryConfig<TyCtxt<'tcx>>>::Value`
334 // doesn't currently normalize to `for<'tcx> fn(...) -> query_values::$name<'tcx>`.
335 // This is primarily used by the `provide!` macro in `rustc_metadata`.
336 #[allow(nonstandard_style, unused_lifetimes)]
340 $
(pub type $name
<$tcx
> = $
($K
)*;)*
342 #[allow(nonstandard_style, unused_lifetimes)]
343 pub mod query_values
{
346 $
(pub type $name
<$tcx
> = $V
;)*
349 $
(impl<$tcx
> QueryConfig
<TyCtxt
<$tcx
>> for queries
::$name
<$tcx
> {
353 query_storage
!([$
($modifiers
)*][$
($K
)*, $V
])
356 const NAME
: &'
static str = stringify
!($name
);
357 const CATEGORY
: ProfileCategory
= $category
;
360 impl<$tcx
> QueryAccessors
<TyCtxt
<$tcx
>> for queries
::$name
<$tcx
> {
361 const ANON
: bool
= is_anon
!([$
($modifiers
)*]);
362 const EVAL_ALWAYS
: bool
= is_eval_always
!([$
($modifiers
)*]);
363 const DEP_KIND
: dep_graph
::DepKind
= dep_graph
::DepKind
::$node
;
365 type Cache
= query_storage
!([$
($modifiers
)*][$
($K
)*, $V
]);
368 fn query_state
<'a
>(tcx
: TyCtxt
<$tcx
>) -> &'a QueryState
<TyCtxt
<$tcx
>, Self::Cache
> {
373 fn compute(tcx
: TyCtxt
<'tcx
>, key
: Self::Key
) -> Self::Value
{
374 let provider
= tcx
.queries
.providers
.get(key
.query_crate())
375 // HACK(eddyb) it's possible crates may be loaded after
376 // the query engine is created, and because crate loading
377 // is not yet integrated with the query engine, such crates
378 // would be missing appropriate entries in `providers`.
379 .unwrap_or(&tcx
.queries
.fallback_extern_providers
)
385 _hcx
: &mut StableHashingContext
<'_
>,
386 _result
: &Self::Value
387 ) -> Option
<Fingerprint
> {
388 hash_result
!([$
($modifiers
)*][_hcx
, _result
])
391 fn handle_cycle_error(
393 error
: CycleError
<Query
<'tcx
>>
395 handle_cycle_error
!([$
($modifiers
)*][tcx
, error
])
399 #[derive(Copy, Clone)]
400 pub struct TyCtxtEnsure
<'tcx
> {
401 pub tcx
: TyCtxt
<'tcx
>,
404 impl TyCtxtEnsure
<$tcx
> {
407 pub fn $
name(self, key
: query_helper_param_ty
!($
($K
)*)) {
408 ensure_query
::<queries
::$name
<'_
>, _
>(self.tcx
, key
.into_query_param())
412 #[derive(Copy, Clone)]
413 pub struct TyCtxtAt
<'tcx
> {
414 pub tcx
: TyCtxt
<'tcx
>,
418 impl Deref
for TyCtxtAt
<'tcx
> {
419 type Target
= TyCtxt
<'tcx
>;
421 fn deref(&self) -> &Self::Target
{
427 /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
428 /// are executed instead of just returning their results.
430 pub fn ensure(self) -> TyCtxtEnsure
<$tcx
> {
436 /// Returns a transparent wrapper for `TyCtxt` which uses
437 /// `span` as the location of queries performed through it.
439 pub fn at(self, span
: Span
) -> TyCtxtAt
<$tcx
> {
449 pub fn $
name(self, key
: query_helper_param_ty
!($
($K
)*))
450 -> <queries
::$name
<$tcx
> as QueryConfig
<TyCtxt
<$tcx
>>>::Stored
452 self.at(DUMMY_SP
).$
name(key
.into_query_param())
455 /// All self-profiling events generated by the query engine use
456 /// virtual `StringId`s for their `event_id`. This method makes all
457 /// those virtual `StringId`s point to actual strings.
459 /// If we are recording only summary data, the ids will point to
460 /// just the query names. If we are recording query keys too, we
461 /// allocate the corresponding strings here.
462 pub fn alloc_self_profile_query_strings(self) {
463 use crate::ty
::query
::profiling_support
::{
464 alloc_self_profile_query_strings_for_query_cache
,
468 if !self.prof
.enabled() {
472 let mut string_cache
= QueryKeyStringCache
::new();
475 alloc_self_profile_query_strings_for_query_cache(
485 impl TyCtxtAt
<$tcx
> {
488 pub fn $
name(self, key
: query_helper_param_ty
!($
($K
)*))
489 -> <queries
::$name
<$tcx
> as QueryConfig
<TyCtxt
<$tcx
>>>::Stored
491 get_query
::<queries
::$name
<'_
>, _
>(self.tcx
, self.span
, key
.into_query_param())
495 define_provider_struct
! {
497 input
: ($
(([$
($modifiers
)*] [$name
] [$
($K
)*] [$V
]))*)
500 impl Copy
for Providers {}
501 impl Clone
for Providers
{
502 fn clone(&self) -> Self { *self }
507 // FIXME(eddyb) this macro (and others?) use `$tcx` and `'tcx` interchangeably.
508 // We should either not take `$tcx` at all and use `'tcx` everywhere, or use
509 // `$tcx` everywhere (even if that isn't necessary due to lack of hygiene).
510 macro_rules
! define_queries_struct
{
512 input
: ($
(([$
($modifiers
:tt
)*] [$
($attr
:tt
)*] [$name
:ident
]))*)) => {
513 pub struct Queries
<$tcx
> {
514 /// This provides access to the incrimental comilation on-disk cache for query results.
515 /// Do not access this directly. It is only meant to be used by
516 /// `DepGraph::try_mark_green()` and the query infrastructure.
517 pub(crate) on_disk_cache
: OnDiskCache
<'tcx
>,
519 providers
: IndexVec
<CrateNum
, Providers
>,
520 fallback_extern_providers
: Box
<Providers
>,
522 $
($
(#[$attr])* $name: QueryState<
524 <queries
::$name
<$tcx
> as QueryAccessors
<TyCtxt
<'tcx
>>>::Cache
,
528 impl<$tcx
> Queries
<$tcx
> {
530 providers
: IndexVec
<CrateNum
, Providers
>,
531 fallback_extern_providers
: Providers
,
532 on_disk_cache
: OnDiskCache
<'tcx
>,
536 fallback_extern_providers
: Box
::new(fallback_extern_providers
),
538 $
($name
: Default
::default()),*
542 pub(crate) fn try_collect_active_jobs(
544 ) -> Option
<FxHashMap
<QueryJobId
<crate::dep_graph
::DepKind
>, QueryJobInfo
<TyCtxt
<'tcx
>>>> {
545 let mut jobs
= FxHashMap
::default();
548 self.$name
.try_collect_active_jobs(
549 <queries
::$name
<'tcx
> as QueryAccessors
<TyCtxt
<'tcx
>>>::DEP_KIND
,
561 macro_rules
! define_provider_struct
{
563 input
: ($
(([$
($modifiers
:tt
)*] [$name
:ident
] [$K
:ty
] [$R
:ty
]))*)) => {
564 pub struct Providers
{
565 $
(pub $name
: for<$tcx
> fn(TyCtxt
<$tcx
>, $K
) -> $R
,)*
568 impl Default
for Providers
{
569 fn default() -> Self {
570 $
(fn $name
<$tcx
>(_
: TyCtxt
<$tcx
>, key
: $K
) -> $R
{
571 bug
!("`tcx.{}({:?})` unsupported by its crate",
572 stringify
!($name
), key
);
574 Providers { $($name),* }