rustc_middle/ty/context/
tls.rs
1use std::{mem, ptr};
2
3use rustc_data_structures::sync;
4
5use super::{GlobalCtxt, TyCtxt};
6use crate::dep_graph::TaskDepsRef;
7use crate::query::plumbing::QueryJobId;
8
9#[derive(Clone)]
15pub struct ImplicitCtxt<'a, 'tcx> {
16 pub tcx: TyCtxt<'tcx>,
18
19 pub query: Option<QueryJobId>,
22
23 pub query_depth: usize,
25
26 pub task_deps: TaskDepsRef<'a>,
29}
30
31impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
32 pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
33 let tcx = TyCtxt { gcx };
34 ImplicitCtxt { tcx, query: None, query_depth: 0, task_deps: TaskDepsRef::Ignore }
35 }
36}
37
38use rayon_core::tlv::TLV;
40
41#[inline]
42fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
43 context as *const _ as *const ()
44}
45
46#[inline]
47unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
48 unsafe { &*(context as *const ImplicitCtxt<'a, 'tcx>) }
49}
50
51#[inline]
53pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
54where
55 F: FnOnce() -> R,
56{
57 TLV.with(|tlv| {
58 let old = tlv.replace(erase(context));
59 let _reset = rustc_data_structures::defer(move || tlv.set(old));
60 f()
61 })
62}
63
64#[inline]
66#[track_caller]
67pub fn with_context_opt<F, R>(f: F) -> R
68where
69 F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
70{
71 let context = TLV.get();
72 if context.is_null() {
73 f(None)
74 } else {
75 sync::assert_dyn_sync::<ImplicitCtxt<'_, '_>>();
78
79 unsafe { f(Some(downcast(context))) }
80 }
81}
82
83#[inline]
86pub fn with_context<F, R>(f: F) -> R
87where
88 F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
89{
90 with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
91}
92
93#[inline]
99pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
100where
101 F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
102{
103 with_context(|context| {
104 assert!(ptr::eq(
106 context.tcx.gcx as *const _ as *const (),
107 tcx.gcx as *const _ as *const ()
108 ));
109
110 let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) };
111
112 f(context)
113 })
114}
115
116#[inline]
119pub fn with<F, R>(f: F) -> R
120where
121 F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
122{
123 with_context(|context| f(context.tcx))
124}
125
126#[inline]
129#[track_caller]
130pub fn with_opt<F, R>(f: F) -> R
131where
132 F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
133{
134 with_context_opt(
135 #[track_caller]
136 |opt_context| f(opt_context.map(|context| context.tcx)),
137 )
138}