aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/tls.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/tls.rs')
-rw-r--r--crates/hir_ty/src/tls.rs277
1 files changed, 277 insertions, 0 deletions
diff --git a/crates/hir_ty/src/tls.rs b/crates/hir_ty/src/tls.rs
new file mode 100644
index 000000000..87c671a42
--- /dev/null
+++ b/crates/hir_ty/src/tls.rs
@@ -0,0 +1,277 @@
1//! Implementation of Chalk debug helper functions using TLS.
2use std::fmt;
3
4use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication};
5use itertools::Itertools;
6
7use crate::{
8 chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
9 CallableDefId, Interner,
10};
11use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
12
13pub(crate) use unsafe_tls::{set_current_program, with_current_program};
14
15pub(crate) struct DebugContext<'a>(&'a dyn HirDatabase);
16
17impl DebugContext<'_> {
18 pub(crate) fn debug_struct_id(
19 &self,
20 id: chalk_db::AdtId,
21 f: &mut fmt::Formatter<'_>,
22 ) -> Result<(), fmt::Error> {
23 let name = match id.0 {
24 AdtId::StructId(it) => self.0.struct_data(it).name.clone(),
25 AdtId::UnionId(it) => self.0.union_data(it).name.clone(),
26 AdtId::EnumId(it) => self.0.enum_data(it).name.clone(),
27 };
28 write!(f, "{}", name)
29 }
30
31 pub(crate) fn debug_trait_id(
32 &self,
33 id: chalk_db::TraitId,
34 fmt: &mut fmt::Formatter<'_>,
35 ) -> Result<(), fmt::Error> {
36 let trait_: hir_def::TraitId = from_chalk_trait_id(id);
37 let trait_data = self.0.trait_data(trait_);
38 write!(fmt, "{}", trait_data.name)
39 }
40
41 pub(crate) fn debug_assoc_type_id(
42 &self,
43 id: chalk_db::AssocTypeId,
44 fmt: &mut fmt::Formatter<'_>,
45 ) -> Result<(), fmt::Error> {
46 let type_alias: TypeAliasId = from_assoc_type_id(id);
47 let type_alias_data = self.0.type_alias_data(type_alias);
48 let trait_ = match type_alias.lookup(self.0.upcast()).container {
49 AssocContainerId::TraitId(t) => t,
50 _ => panic!("associated type not in trait"),
51 };
52 let trait_data = self.0.trait_data(trait_);
53 write!(fmt, "{}::{}", trait_data.name, type_alias_data.name)
54 }
55
56 pub(crate) fn debug_opaque_ty_id(
57 &self,
58 opaque_ty_id: chalk_ir::OpaqueTyId<Interner>,
59 fmt: &mut fmt::Formatter<'_>,
60 ) -> Result<(), fmt::Error> {
61 fmt.debug_struct("OpaqueTyId").field("index", &opaque_ty_id.0).finish()
62 }
63
64 pub(crate) fn debug_alias(
65 &self,
66 alias_ty: &AliasTy<Interner>,
67 fmt: &mut fmt::Formatter<'_>,
68 ) -> Result<(), fmt::Error> {
69 match alias_ty {
70 AliasTy::Projection(projection_ty) => self.debug_projection_ty(projection_ty, fmt),
71 AliasTy::Opaque(opaque_ty) => self.debug_opaque_ty(opaque_ty, fmt),
72 }
73 }
74
75 pub(crate) fn debug_projection_ty(
76 &self,
77 projection_ty: &chalk_ir::ProjectionTy<Interner>,
78 fmt: &mut fmt::Formatter<'_>,
79 ) -> Result<(), fmt::Error> {
80 let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
81 let type_alias_data = self.0.type_alias_data(type_alias);
82 let trait_ = match type_alias.lookup(self.0.upcast()).container {
83 AssocContainerId::TraitId(t) => t,
84 _ => panic!("associated type not in trait"),
85 };
86 let trait_data = self.0.trait_data(trait_);
87 let params = projection_ty.substitution.as_slice(&Interner);
88 write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
89 if params.len() > 1 {
90 write!(
91 fmt,
92 "<{}>",
93 &params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
94 )?;
95 }
96 write!(fmt, ">::{}", type_alias_data.name)
97 }
98
99 pub(crate) fn debug_opaque_ty(
100 &self,
101 opaque_ty: &chalk_ir::OpaqueTy<Interner>,
102 fmt: &mut fmt::Formatter<'_>,
103 ) -> Result<(), fmt::Error> {
104 write!(fmt, "{:?}", opaque_ty.opaque_ty_id)
105 }
106
107 pub(crate) fn debug_ty(
108 &self,
109 ty: &chalk_ir::Ty<Interner>,
110 fmt: &mut fmt::Formatter<'_>,
111 ) -> Result<(), fmt::Error> {
112 write!(fmt, "{:?}", ty.data(&Interner))
113 }
114
115 pub(crate) fn debug_lifetime(
116 &self,
117 lifetime: &Lifetime<Interner>,
118 fmt: &mut fmt::Formatter<'_>,
119 ) -> Result<(), fmt::Error> {
120 write!(fmt, "{:?}", lifetime.data(&Interner))
121 }
122
123 pub(crate) fn debug_generic_arg(
124 &self,
125 parameter: &GenericArg<Interner>,
126 fmt: &mut fmt::Formatter<'_>,
127 ) -> Result<(), fmt::Error> {
128 write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())
129 }
130
131 pub(crate) fn debug_goal(
132 &self,
133 goal: &Goal<Interner>,
134 fmt: &mut fmt::Formatter<'_>,
135 ) -> Result<(), fmt::Error> {
136 let goal_data = goal.data(&Interner);
137 write!(fmt, "{:?}", goal_data)
138 }
139
140 pub(crate) fn debug_goals(
141 &self,
142 goals: &Goals<Interner>,
143 fmt: &mut fmt::Formatter<'_>,
144 ) -> Result<(), fmt::Error> {
145 write!(fmt, "{:?}", goals.debug(&Interner))
146 }
147
148 pub(crate) fn debug_program_clause_implication(
149 &self,
150 pci: &ProgramClauseImplication<Interner>,
151 fmt: &mut fmt::Formatter<'_>,
152 ) -> Result<(), fmt::Error> {
153 write!(fmt, "{:?}", pci.debug(&Interner))
154 }
155
156 pub(crate) fn debug_substitution(
157 &self,
158 substitution: &chalk_ir::Substitution<Interner>,
159 fmt: &mut fmt::Formatter<'_>,
160 ) -> Result<(), fmt::Error> {
161 write!(fmt, "{:?}", substitution.debug(&Interner))
162 }
163
164 pub(crate) fn debug_separator_trait_ref(
165 &self,
166 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
167 fmt: &mut fmt::Formatter<'_>,
168 ) -> Result<(), fmt::Error> {
169 write!(fmt, "{:?}", separator_trait_ref.debug(&Interner))
170 }
171
172 pub(crate) fn debug_fn_def_id(
173 &self,
174 fn_def_id: chalk_ir::FnDefId<Interner>,
175 fmt: &mut fmt::Formatter<'_>,
176 ) -> Result<(), fmt::Error> {
177 let def: CallableDefId = from_chalk(self.0, fn_def_id);
178 let name = match def {
179 CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(),
180 CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(),
181 CallableDefId::EnumVariantId(e) => {
182 let enum_data = self.0.enum_data(e.parent);
183 enum_data.variants[e.local_id].name.clone()
184 }
185 };
186 match def {
187 CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name),
188 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
189 write!(fmt, "{{ctor {}}}", name)
190 }
191 }
192 }
193
194 pub(crate) fn debug_const(
195 &self,
196 _constant: &chalk_ir::Const<Interner>,
197 fmt: &mut fmt::Formatter<'_>,
198 ) -> fmt::Result {
199 write!(fmt, "const")
200 }
201
202 pub(crate) fn debug_variable_kinds(
203 &self,
204 variable_kinds: &chalk_ir::VariableKinds<Interner>,
205 fmt: &mut fmt::Formatter<'_>,
206 ) -> fmt::Result {
207 write!(fmt, "{:?}", variable_kinds.as_slice(&Interner))
208 }
209 pub(crate) fn debug_variable_kinds_with_angles(
210 &self,
211 variable_kinds: &chalk_ir::VariableKinds<Interner>,
212 fmt: &mut fmt::Formatter<'_>,
213 ) -> fmt::Result {
214 write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner))
215 }
216 pub(crate) fn debug_canonical_var_kinds(
217 &self,
218 canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Interner>,
219 fmt: &mut fmt::Formatter<'_>,
220 ) -> fmt::Result {
221 write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner))
222 }
223 pub(crate) fn debug_program_clause(
224 &self,
225 clause: &chalk_ir::ProgramClause<Interner>,
226 fmt: &mut fmt::Formatter<'_>,
227 ) -> fmt::Result {
228 write!(fmt, "{:?}", clause.data(&Interner))
229 }
230 pub(crate) fn debug_program_clauses(
231 &self,
232 clauses: &chalk_ir::ProgramClauses<Interner>,
233 fmt: &mut fmt::Formatter<'_>,
234 ) -> fmt::Result {
235 write!(fmt, "{:?}", clauses.as_slice(&Interner))
236 }
237 pub(crate) fn debug_quantified_where_clauses(
238 &self,
239 clauses: &chalk_ir::QuantifiedWhereClauses<Interner>,
240 fmt: &mut fmt::Formatter<'_>,
241 ) -> fmt::Result {
242 write!(fmt, "{:?}", clauses.as_slice(&Interner))
243 }
244}
245
246mod unsafe_tls {
247 use super::DebugContext;
248 use crate::db::HirDatabase;
249 use scoped_tls::scoped_thread_local;
250
251 scoped_thread_local!(static PROGRAM: DebugContext);
252
253 pub(crate) fn with_current_program<R>(
254 op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R,
255 ) -> R {
256 if PROGRAM.is_set() {
257 PROGRAM.with(|prog| op(Some(prog)))
258 } else {
259 op(None)
260 }
261 }
262
263 pub(crate) fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R
264 where
265 OP: FnOnce() -> R,
266 {
267 let ctx = DebugContext(p);
268 // we're transmuting the lifetime in the DebugContext to static. This is
269 // fine because we only keep the reference for the lifetime of this
270 // function, *and* the only way to access the context is through
271 // `with_current_program`, which hides the lifetime through the `for`
272 // type.
273 let static_p: &DebugContext<'static> =
274 unsafe { std::mem::transmute::<&DebugContext, &DebugContext<'static>>(&ctx) };
275 PROGRAM.set(static_p, || op())
276 }
277}