rustc_middle/ty/context/
tls.rs1use std::{mem, ptr};
2
3use rustc_data_structures::sync::{self, Lock};
4use rustc_errors::DiagInner;
5use thin_vec::ThinVec;
6
7use super::{GlobalCtxt, TyCtxt};
8use crate::dep_graph::TaskDepsRef;
9use crate::query::plumbing::QueryJobId;
10
11#[derive(Clone)]
17pub struct ImplicitCtxt<'a, 'tcx> {
18 pub tcx: TyCtxt<'tcx>,
20
21 pub query: Option<QueryJobId>,
24
25 pub diagnostics: Option<&'a Lock<ThinVec<DiagInner>>>,
28
29 pub query_depth: usize,
31
32 pub task_deps: TaskDepsRef<'a>,
35}
36
37impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
38 pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
39 let tcx = TyCtxt { gcx };
40 ImplicitCtxt {
41 tcx,
42 query: None,
43 diagnostics: None,
44 query_depth: 0,
45 task_deps: TaskDepsRef::Ignore,
46 }
47 }
48}
49
50use rayon_core::tlv::TLV;
52
53#[inline]
54fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
55 context as *const _ as *const ()
56}
57
58#[inline]
59unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
60 unsafe { &*(context as *const ImplicitCtxt<'a, 'tcx>) }
61}
62
63#[inline]
65pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
66where
67 F: FnOnce() -> R,
68{
69 TLV.with(|tlv| {
70 let old = tlv.replace(erase(context));
71 let _reset = rustc_data_structures::defer(move || tlv.set(old));
72 f()
73 })
74}
75
76#[inline]
78#[track_caller]
79pub fn with_context_opt<F, R>(f: F) -> R
80where
81 F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
82{
83 let context = TLV.get();
84 if context.is_null() {
85 f(None)
86 } else {
87 sync::assert_dyn_sync::<ImplicitCtxt<'_, '_>>();
90
91 unsafe { f(Some(downcast(context))) }
92 }
93}
94
95#[inline]
98pub fn with_context<F, R>(f: F) -> R
99where
100 F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
101{
102 with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
103}
104
105#[inline]
111pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
112where
113 F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
114{
115 with_context(|context| {
116 assert!(ptr::eq(
118 context.tcx.gcx as *const _ as *const (),
119 tcx.gcx as *const _ as *const ()
120 ));
121
122 let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) };
123
124 f(context)
125 })
126}
127
128#[inline]
131pub fn with<F, R>(f: F) -> R
132where
133 F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
134{
135 with_context(|context| f(context.tcx))
136}
137
138#[inline]
141#[track_caller]
142pub fn with_opt<F, R>(f: F) -> R
143where
144 F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
145{
146 with_context_opt(
147 #[track_caller]
148 |opt_context| f(opt_context.map(|context| context.tcx)),
149 )
150}