use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use eko::thread::ThreadLocal;
use crate::rustc_data_structures::sync;
use super::{GlobalCtxt, TyCtxt};
use crate::rustc_middle::dep_graph::TaskDepsRef;
use crate::rustc_middle::query::QueryJobId;
pub struct ImplicitCtxt<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
pub query: Option<QueryJobId>,
pub query_depth: usize,
pub task_deps: TaskDepsRef<'a>,
}
impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
let tcx = TyCtxt { gcx };
ImplicitCtxt { tcx, query: None, query_depth: 0, task_deps: TaskDepsRef::Ignore }
}
}
static TLV: ThreadLocal<core::cell::Cell<*const ()>> = ThreadLocal::new();
#[inline]
fn tlv_init() -> core::cell::Cell<*const ()> {
core::cell::Cell::new(core::ptr::null())
}
#[inline]
fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
context as *const _ as *const ()
}
#[inline]
unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
unsafe { &*(context as *const ImplicitCtxt<'a, 'tcx>) }
}
#[inline]
pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
where
F: FnOnce() -> R,
{
TLV.with(tlv_init, |tlv| {
let old = tlv.replace(erase(context));
let _reset = crate::rustc_data_structures::defer(move || tlv.set(old));
f()
})
.expect("out of thread-local keys: cannot store the ImplicitCtxt")
}
#[inline]
#[track_caller]
pub fn with_context_opt<F, R>(f: F) -> R
where
F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
{
let context = TLV.with(tlv_init, |tlv| tlv.get()).unwrap_or(core::ptr::null());
if context.is_null() {
f(None)
} else {
sync::assert_dyn_sync::<ImplicitCtxt<'_, '_>>();
unsafe { f(Some(downcast(context))) }
}
}
#[inline]
pub fn with_context<F, R>(f: F) -> R
where
F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
{
with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
}
#[inline]
pub fn with<F, R>(f: F) -> R
where
F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
{
with_context(|context| f(context.tcx))
}
#[inline]
#[track_caller]
pub fn with_opt<F, R>(f: F) -> R
where
F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
{
with_context_opt(
|opt_context| f(opt_context.map(|context| context.tcx)),
)
}