1use std::{mem, ptr};
23use rustc_data_structures::sync;
45use super::{GlobalCtxt, TyCtxt};
6use crate::dep_graph::TaskDepsRef;
7use crate::query::plumbing::QueryJobId;
89/// This is the implicit state of rustc. It contains the current
10/// `TyCtxt` and query. It is updated when creating a local interner or
11/// executing a new query. Whenever there's a `TyCtxt` value available
12/// you should also have access to an `ImplicitCtxt` through the functions
13/// in this module.
14#[derive(#[automatically_derived]
impl<'a, 'tcx> ::core::clone::Clone for ImplicitCtxt<'a, 'tcx> {
#[inline]
fn clone(&self) -> ImplicitCtxt<'a, 'tcx> {
ImplicitCtxt {
tcx: ::core::clone::Clone::clone(&self.tcx),
query: ::core::clone::Clone::clone(&self.query),
query_depth: ::core::clone::Clone::clone(&self.query_depth),
task_deps: ::core::clone::Clone::clone(&self.task_deps),
}
}
}Clone)]
15pub struct ImplicitCtxt<'a, 'tcx> {
16/// The current `TyCtxt`.
17pub tcx: TyCtxt<'tcx>,
1819/// The current query job, if any. This is updated by `JobOwner::start` in
20 /// `ty::query::plumbing` when executing a query.
21pub query: Option<QueryJobId>,
2223/// Used to prevent queries from calling too deeply.
24pub query_depth: usize,
2526/// The current dep graph task. This is used to add dependencies to queries
27 /// when executing them.
28pub task_deps: TaskDepsRef<'a>,
29}
3031impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
32pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
33let tcx = TyCtxt { gcx };
34ImplicitCtxt { tcx, query: None, query_depth: 0, task_deps: TaskDepsRef::Ignore }
35 }
36}
3738// Import the thread-local variable from Rayon, which is preserved for Rayon jobs.
39use rustc_thread_pool::tlv::TLV;
4041#[inline]
42fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
43contextas *const _ as *const ()
44}
4546#[inline]
47unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
48unsafe { &*(contextas *const ImplicitCtxt<'a, 'tcx>) }
49}
5051/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
52#[inline]
53pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
54where
55F: FnOnce() -> R,
56{
57TLV.with(|tlv| {
58let old = tlv.replace(erase(context));
59let _reset = rustc_data_structures::defer(move || tlv.set(old));
60f()
61 })
62}
6364/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
65#[inline]
66#[track_caller]
67pub fn with_context_opt<F, R>(f: F) -> R
68where
69F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
70{
71let context = TLV.get();
72if context.is_null() {
73f(None)
74 } else {
75// We could get an `ImplicitCtxt` pointer from another thread.
76 // Ensure that `ImplicitCtxt` is `DynSync`.
77sync::assert_dyn_sync::<ImplicitCtxt<'_, '_>>();
7879unsafe { f(Some(downcast(context))) }
80 }
81}
8283/// Allows access to the current `ImplicitCtxt`.
84/// Panics if there is no `ImplicitCtxt` available.
85#[inline]
86pub fn with_context<F, R>(f: F) -> R
87where
88F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
89{
90with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
91}
9293/// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
94/// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
95/// as the `TyCtxt` passed in.
96/// This will panic if you pass it a `TyCtxt` which is different from the current
97/// `ImplicitCtxt`'s `tcx` field.
98#[inline]
99pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
100where
101F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
102{
103with_context(|context| {
104// The two gcx have different invariant lifetimes, so we need to erase them for the comparison.
105if !ptr::eq(context.tcx.gcx as *const _ as *const (),
tcx.gcx as *const _ as *const ()) {
::core::panicking::panic("assertion failed: ptr::eq(context.tcx.gcx as *const _ as *const (),\n tcx.gcx as *const _ as *const ())")
};assert!(ptr::eq(
106 context.tcx.gcx as *const _ as *const (),
107 tcx.gcx as *const _ as *const ()
108 ));
109110let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) };
111112f(context)
113 })
114}
115116/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
117/// Panics if there is no `ImplicitCtxt` available.
118#[inline]
119pub fn with<F, R>(f: F) -> R
120where
121F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
122{
123with_context(|context| f(context.tcx))
124}
125126/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
127/// The closure is passed None if there is no `ImplicitCtxt` available.
128#[inline]
129#[track_caller]
130pub fn with_opt<F, R>(f: F) -> R
131where
132F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
133{
134with_context_opt(
135#[track_caller]
136|opt_context| f(opt_context.map(|context| context.tcx)),
137 )
138}