• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::{GlobalCtxt, TyCtxt};
2 
3 use crate::dep_graph::TaskDepsRef;
4 use crate::query::plumbing::QueryJobId;
5 use rustc_data_structures::sync::{self, Lock};
6 use rustc_errors::Diagnostic;
7 #[cfg(not(parallel_compiler))]
8 use std::cell::Cell;
9 use std::mem;
10 use std::ptr;
11 use thin_vec::ThinVec;
12 
13 /// This is the implicit state of rustc. It contains the current
14 /// `TyCtxt` and query. It is updated when creating a local interner or
15 /// executing a new query. Whenever there's a `TyCtxt` value available
16 /// you should also have access to an `ImplicitCtxt` through the functions
17 /// in this module.
18 #[derive(Clone)]
19 pub struct ImplicitCtxt<'a, 'tcx> {
20     /// The current `TyCtxt`.
21     pub tcx: TyCtxt<'tcx>,
22 
23     /// The current query job, if any. This is updated by `JobOwner::start` in
24     /// `ty::query::plumbing` when executing a query.
25     pub query: Option<QueryJobId>,
26 
27     /// Where to store diagnostics for the current query job, if any.
28     /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
29     pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
30 
31     /// Used to prevent queries from calling too deeply.
32     pub query_depth: usize,
33 
34     /// The current dep graph task. This is used to add dependencies to queries
35     /// when executing them.
36     pub task_deps: TaskDepsRef<'a>,
37 }
38 
39 impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self40     pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
41         let tcx = TyCtxt { gcx };
42         ImplicitCtxt {
43             tcx,
44             query: None,
45             diagnostics: None,
46             query_depth: 0,
47             task_deps: TaskDepsRef::Ignore,
48         }
49     }
50 }
51 
52 // Import the thread-local variable from Rayon, which is preserved for Rayon jobs.
53 #[cfg(parallel_compiler)]
54 use rayon_core::tlv::TLV;
55 
56 // Otherwise define our own
57 #[cfg(not(parallel_compiler))]
58 thread_local! {
59     /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
60     static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
61 }
62 
63 #[inline]
erase(context: &ImplicitCtxt<'_, '_>) -> *const ()64 fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
65     context as *const _ as *const ()
66 }
67 
68 #[inline]
downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx>69 unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
70     &*(context as *const ImplicitCtxt<'a, 'tcx>)
71 }
72 
73 /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
74 #[inline]
enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R where F: FnOnce() -> R,75 pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
76 where
77     F: FnOnce() -> R,
78 {
79     TLV.with(|tlv| {
80         let old = tlv.replace(erase(context));
81         let _reset = rustc_data_structures::defer(move || tlv.set(old));
82         f()
83     })
84 }
85 
86 /// Allows access to the current `ImplicitCtxt` in a closure if one is available.
87 #[inline]
with_context_opt<F, R>(f: F) -> R where F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,88 pub fn with_context_opt<F, R>(f: F) -> R
89 where
90     F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
91 {
92     let context = TLV.get();
93     if context.is_null() {
94         f(None)
95     } else {
96         // We could get an `ImplicitCtxt` pointer from another thread.
97         // Ensure that `ImplicitCtxt` is `DynSync`.
98         sync::assert_dyn_sync::<ImplicitCtxt<'_, '_>>();
99 
100         unsafe { f(Some(downcast(context))) }
101     }
102 }
103 
104 /// Allows access to the current `ImplicitCtxt`.
105 /// Panics if there is no `ImplicitCtxt` available.
106 #[inline]
with_context<F, R>(f: F) -> R where F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,107 pub fn with_context<F, R>(f: F) -> R
108 where
109     F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
110 {
111     with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
112 }
113 
114 /// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
115 /// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
116 /// as the `TyCtxt` passed in.
117 /// This will panic if you pass it a `TyCtxt` which is different from the current
118 /// `ImplicitCtxt`'s `tcx` field.
119 #[inline]
with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R where F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,120 pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
121 where
122     F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
123 {
124     with_context(|context| {
125         // The two gcx have different invariant lifetimes, so we need to erase them for the comparison.
126         assert!(ptr::eq(
127             context.tcx.gcx as *const _ as *const (),
128             tcx.gcx as *const _ as *const ()
129         ));
130 
131         let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) };
132 
133         f(context)
134     })
135 }
136 
137 /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
138 /// Panics if there is no `ImplicitCtxt` available.
139 #[inline]
with<F, R>(f: F) -> R where F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,140 pub fn with<F, R>(f: F) -> R
141 where
142     F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
143 {
144     with_context(|context| f(context.tcx))
145 }
146 
147 /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
148 /// The closure is passed None if there is no `ImplicitCtxt` available.
149 #[inline]
with_opt<F, R>(f: F) -> R where F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,150 pub fn with_opt<F, R>(f: F) -> R
151 where
152     F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
153 {
154     with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
155 }
156