]>
Commit | Line | Data |
---|---|---|
9ffffee4 FG |
1 | use super::{GlobalCtxt, TyCtxt}; |
2 | ||
3 | use crate::dep_graph::TaskDepsRef; | |
4 | use crate::ty::query; | |
5 | use rustc_data_structures::sync::{self, Lock}; | |
6 | use rustc_errors::Diagnostic; | |
353b0b11 FG |
7 | #[cfg(not(parallel_compiler))] |
8 | use std::cell::Cell; | |
9ffffee4 FG |
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<query::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> { | |
40 | 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 | ||
353b0b11 | 52 | // Import the thread-local variable from Rayon, which is preserved for Rayon jobs. |
9ffffee4 | 53 | #[cfg(parallel_compiler)] |
353b0b11 | 54 | use rayon_core::tlv::TLV; |
9ffffee4 | 55 | |
353b0b11 | 56 | // Otherwise define our own |
9ffffee4 | 57 | #[cfg(not(parallel_compiler))] |
353b0b11 FG |
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()) }; | |
9ffffee4 FG |
61 | } |
62 | ||
63 | #[inline] | |
64 | fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () { | |
65 | context as *const _ as *const () | |
66 | } | |
67 | ||
68 | #[inline] | |
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] | |
75 | pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R | |
76 | where | |
77 | F: FnOnce() -> R, | |
78 | { | |
353b0b11 FG |
79 | TLV.with(|tlv| { |
80 | let old = tlv.replace(erase(context)); | |
81 | let _reset = rustc_data_structures::OnDrop(move || tlv.set(old)); | |
82 | f() | |
83 | }) | |
9ffffee4 FG |
84 | } |
85 | ||
86 | /// Allows access to the current `ImplicitCtxt` in a closure if one is available. | |
87 | #[inline] | |
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 | { | |
353b0b11 | 92 | let context = TLV.get(); |
9ffffee4 FG |
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 `Sync`. | |
98 | sync::assert_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] | |
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] | |
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] | |
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] | |
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 | } |