aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/traits/chalk/tls.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/traits/chalk/tls.rs')
-rw-r--r--crates/hir_ty/src/traits/chalk/tls.rs358
1 files changed, 358 insertions, 0 deletions
diff --git a/crates/hir_ty/src/traits/chalk/tls.rs b/crates/hir_ty/src/traits/chalk/tls.rs
new file mode 100644
index 000000000..db915625c
--- /dev/null
+++ b/crates/hir_ty/src/traits/chalk/tls.rs
@@ -0,0 +1,358 @@
1//! Implementation of Chalk debug helper functions using TLS.
2use std::fmt;
3
4use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication, TypeName};
5use itertools::Itertools;
6
7use super::{from_chalk, Interner};
8use crate::{db::HirDatabase, CallableDefId, TypeCtor};
9use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId};
10
11pub use unsafe_tls::{set_current_program, with_current_program};
12
13pub struct DebugContext<'a>(&'a dyn HirDatabase);
14
15impl DebugContext<'_> {
16 pub fn debug_struct_id(
17 &self,
18 id: super::AdtId,
19 f: &mut fmt::Formatter<'_>,
20 ) -> Result<(), fmt::Error> {
21 let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Adt(id));
22 match type_ctor {
23 TypeCtor::Bool => write!(f, "bool")?,
24 TypeCtor::Char => write!(f, "char")?,
25 TypeCtor::Int(t) => write!(f, "{}", t)?,
26 TypeCtor::Float(t) => write!(f, "{}", t)?,
27 TypeCtor::Str => write!(f, "str")?,
28 TypeCtor::Slice => write!(f, "slice")?,
29 TypeCtor::Array => write!(f, "array")?,
30 TypeCtor::RawPtr(m) => write!(f, "*{}", m.as_keyword_for_ptr())?,
31 TypeCtor::Ref(m) => write!(f, "&{}", m.as_keyword_for_ref())?,
32 TypeCtor::Never => write!(f, "!")?,
33 TypeCtor::Tuple { .. } => {
34 write!(f, "()")?;
35 }
36 TypeCtor::FnPtr { .. } => {
37 write!(f, "fn")?;
38 }
39 TypeCtor::FnDef(def) => {
40 let name = match def {
41 CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(),
42 CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(),
43 CallableDefId::EnumVariantId(e) => {
44 let enum_data = self.0.enum_data(e.parent);
45 enum_data.variants[e.local_id].name.clone()
46 }
47 };
48 match def {
49 CallableDefId::FunctionId(_) => write!(f, "{{fn {}}}", name)?,
50 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
51 write!(f, "{{ctor {}}}", name)?
52 }
53 }
54 }
55 TypeCtor::Adt(def_id) => {
56 let name = match def_id {
57 AdtId::StructId(it) => self.0.struct_data(it).name.clone(),
58 AdtId::UnionId(it) => self.0.union_data(it).name.clone(),
59 AdtId::EnumId(it) => self.0.enum_data(it).name.clone(),
60 };
61 write!(f, "{}", name)?;
62 }
63 TypeCtor::AssociatedType(type_alias) => {
64 let trait_ = match type_alias.lookup(self.0.upcast()).container {
65 AssocContainerId::TraitId(it) => it,
66 _ => panic!("not an associated type"),
67 };
68 let trait_name = self.0.trait_data(trait_).name.clone();
69 let name = self.0.type_alias_data(type_alias).name.clone();
70 write!(f, "{}::{}", trait_name, name)?;
71 }
72 TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id {
73 crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
74 write!(f, "{{impl trait {} of {:?}}}", idx, func)?;
75 }
76 },
77 TypeCtor::Closure { def, expr } => {
78 write!(f, "{{closure {:?} in ", expr.into_raw())?;
79 match def {
80 DefWithBodyId::FunctionId(func) => {
81 write!(f, "fn {}", self.0.function_data(func).name)?
82 }
83 DefWithBodyId::StaticId(s) => {
84 if let Some(name) = self.0.static_data(s).name.as_ref() {
85 write!(f, "body of static {}", name)?;
86 } else {
87 write!(f, "body of unnamed static {:?}", s)?;
88 }
89 }
90 DefWithBodyId::ConstId(c) => {
91 if let Some(name) = self.0.const_data(c).name.as_ref() {
92 write!(f, "body of const {}", name)?;
93 } else {
94 write!(f, "body of unnamed const {:?}", c)?;
95 }
96 }
97 };
98 write!(f, "}}")?;
99 }
100 }
101 Ok(())
102 }
103
104 pub fn debug_trait_id(
105 &self,
106 id: super::TraitId,
107 fmt: &mut fmt::Formatter<'_>,
108 ) -> Result<(), fmt::Error> {
109 let trait_: hir_def::TraitId = from_chalk(self.0, id);
110 let trait_data = self.0.trait_data(trait_);
111 write!(fmt, "{}", trait_data.name)
112 }
113
114 pub fn debug_assoc_type_id(
115 &self,
116 id: super::AssocTypeId,
117 fmt: &mut fmt::Formatter<'_>,
118 ) -> Result<(), fmt::Error> {
119 let type_alias: TypeAliasId = from_chalk(self.0, id);
120 let type_alias_data = self.0.type_alias_data(type_alias);
121 let trait_ = match type_alias.lookup(self.0.upcast()).container {
122 AssocContainerId::TraitId(t) => t,
123 _ => panic!("associated type not in trait"),
124 };
125 let trait_data = self.0.trait_data(trait_);
126 write!(fmt, "{}::{}", trait_data.name, type_alias_data.name)
127 }
128
129 pub fn debug_opaque_ty_id(
130 &self,
131 opaque_ty_id: chalk_ir::OpaqueTyId<Interner>,
132 fmt: &mut fmt::Formatter<'_>,
133 ) -> Result<(), fmt::Error> {
134 fmt.debug_struct("OpaqueTyId").field("index", &opaque_ty_id.0).finish()
135 }
136
137 pub fn debug_alias(
138 &self,
139 alias_ty: &AliasTy<Interner>,
140 fmt: &mut fmt::Formatter<'_>,
141 ) -> Result<(), fmt::Error> {
142 match alias_ty {
143 AliasTy::Projection(projection_ty) => self.debug_projection_ty(projection_ty, fmt),
144 AliasTy::Opaque(opaque_ty) => self.debug_opaque_ty(opaque_ty, fmt),
145 }
146 }
147
148 pub fn debug_projection_ty(
149 &self,
150 projection_ty: &chalk_ir::ProjectionTy<Interner>,
151 fmt: &mut fmt::Formatter<'_>,
152 ) -> Result<(), fmt::Error> {
153 let type_alias: TypeAliasId = from_chalk(self.0, projection_ty.associated_ty_id);
154 let type_alias_data = self.0.type_alias_data(type_alias);
155 let trait_ = match type_alias.lookup(self.0.upcast()).container {
156 AssocContainerId::TraitId(t) => t,
157 _ => panic!("associated type not in trait"),
158 };
159 let trait_data = self.0.trait_data(trait_);
160 let params = projection_ty.substitution.as_slice(&Interner);
161 write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
162 if params.len() > 1 {
163 write!(
164 fmt,
165 "<{}>",
166 &params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
167 )?;
168 }
169 write!(fmt, ">::{}", type_alias_data.name)
170 }
171
172 pub fn debug_opaque_ty(
173 &self,
174 opaque_ty: &chalk_ir::OpaqueTy<Interner>,
175 fmt: &mut fmt::Formatter<'_>,
176 ) -> Result<(), fmt::Error> {
177 write!(fmt, "{:?}", opaque_ty.opaque_ty_id)
178 }
179
180 pub fn debug_ty(
181 &self,
182 ty: &chalk_ir::Ty<Interner>,
183 fmt: &mut fmt::Formatter<'_>,
184 ) -> Result<(), fmt::Error> {
185 write!(fmt, "{:?}", ty.data(&Interner))
186 }
187
188 pub fn debug_lifetime(
189 &self,
190 lifetime: &Lifetime<Interner>,
191 fmt: &mut fmt::Formatter<'_>,
192 ) -> Result<(), fmt::Error> {
193 write!(fmt, "{:?}", lifetime.data(&Interner))
194 }
195
196 pub fn debug_generic_arg(
197 &self,
198 parameter: &GenericArg<Interner>,
199 fmt: &mut fmt::Formatter<'_>,
200 ) -> Result<(), fmt::Error> {
201 write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())
202 }
203
204 pub fn debug_goal(
205 &self,
206 goal: &Goal<Interner>,
207 fmt: &mut fmt::Formatter<'_>,
208 ) -> Result<(), fmt::Error> {
209 let goal_data = goal.data(&Interner);
210 write!(fmt, "{:?}", goal_data)
211 }
212
213 pub fn debug_goals(
214 &self,
215 goals: &Goals<Interner>,
216 fmt: &mut fmt::Formatter<'_>,
217 ) -> Result<(), fmt::Error> {
218 write!(fmt, "{:?}", goals.debug(&Interner))
219 }
220
221 pub fn debug_program_clause_implication(
222 &self,
223 pci: &ProgramClauseImplication<Interner>,
224 fmt: &mut fmt::Formatter<'_>,
225 ) -> Result<(), fmt::Error> {
226 write!(fmt, "{:?}", pci.debug(&Interner))
227 }
228
229 pub fn debug_application_ty(
230 &self,
231 application_ty: &chalk_ir::ApplicationTy<Interner>,
232 fmt: &mut fmt::Formatter<'_>,
233 ) -> Result<(), fmt::Error> {
234 write!(fmt, "{:?}", application_ty.debug(&Interner))
235 }
236
237 pub fn debug_substitution(
238 &self,
239 substitution: &chalk_ir::Substitution<Interner>,
240 fmt: &mut fmt::Formatter<'_>,
241 ) -> Result<(), fmt::Error> {
242 write!(fmt, "{:?}", substitution.debug(&Interner))
243 }
244
245 pub fn debug_separator_trait_ref(
246 &self,
247 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
248 fmt: &mut fmt::Formatter<'_>,
249 ) -> Result<(), fmt::Error> {
250 write!(fmt, "{:?}", separator_trait_ref.debug(&Interner))
251 }
252
253 pub fn debug_fn_def_id(
254 &self,
255 fn_def_id: chalk_ir::FnDefId<Interner>,
256 fmt: &mut fmt::Formatter<'_>,
257 ) -> Result<(), fmt::Error> {
258 let def: CallableDefId = from_chalk(self.0, fn_def_id);
259 let name = match def {
260 CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(),
261 CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(),
262 CallableDefId::EnumVariantId(e) => {
263 let enum_data = self.0.enum_data(e.parent);
264 enum_data.variants[e.local_id].name.clone()
265 }
266 };
267 match def {
268 CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name),
269 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
270 write!(fmt, "{{ctor {}}}", name)
271 }
272 }
273 }
274
275 pub fn debug_const(
276 &self,
277 _constant: &chalk_ir::Const<Interner>,
278 fmt: &mut fmt::Formatter<'_>,
279 ) -> fmt::Result {
280 write!(fmt, "const")
281 }
282
283 pub fn debug_variable_kinds(
284 &self,
285 variable_kinds: &chalk_ir::VariableKinds<Interner>,
286 fmt: &mut fmt::Formatter<'_>,
287 ) -> fmt::Result {
288 write!(fmt, "{:?}", variable_kinds.as_slice(&Interner))
289 }
290 pub fn debug_variable_kinds_with_angles(
291 &self,
292 variable_kinds: &chalk_ir::VariableKinds<Interner>,
293 fmt: &mut fmt::Formatter<'_>,
294 ) -> fmt::Result {
295 write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner))
296 }
297 pub fn debug_canonical_var_kinds(
298 &self,
299 canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Interner>,
300 fmt: &mut fmt::Formatter<'_>,
301 ) -> fmt::Result {
302 write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner))
303 }
304 pub fn debug_program_clause(
305 &self,
306 clause: &chalk_ir::ProgramClause<Interner>,
307 fmt: &mut fmt::Formatter<'_>,
308 ) -> fmt::Result {
309 write!(fmt, "{:?}", clause.data(&Interner))
310 }
311 pub fn debug_program_clauses(
312 &self,
313 clauses: &chalk_ir::ProgramClauses<Interner>,
314 fmt: &mut fmt::Formatter<'_>,
315 ) -> fmt::Result {
316 write!(fmt, "{:?}", clauses.as_slice(&Interner))
317 }
318 pub fn debug_quantified_where_clauses(
319 &self,
320 clauses: &chalk_ir::QuantifiedWhereClauses<Interner>,
321 fmt: &mut fmt::Formatter<'_>,
322 ) -> fmt::Result {
323 write!(fmt, "{:?}", clauses.as_slice(&Interner))
324 }
325}
326
327mod unsafe_tls {
328 use super::DebugContext;
329 use crate::db::HirDatabase;
330 use scoped_tls::scoped_thread_local;
331
332 scoped_thread_local!(static PROGRAM: DebugContext);
333
334 pub fn with_current_program<R>(
335 op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R,
336 ) -> R {
337 if PROGRAM.is_set() {
338 PROGRAM.with(|prog| op(Some(prog)))
339 } else {
340 op(None)
341 }
342 }
343
344 pub fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R
345 where
346 OP: FnOnce() -> R,
347 {
348 let ctx = DebugContext(p);
349 // we're transmuting the lifetime in the DebugContext to static. This is
350 // fine because we only keep the reference for the lifetime of this
351 // function, *and* the only way to access the context is through
352 // `with_current_program`, which hides the lifetime through the `for`
353 // type.
354 let static_p: &DebugContext<'static> =
355 unsafe { std::mem::transmute::<&DebugContext, &DebugContext<'static>>(&ctx) };
356 PROGRAM.set(static_p, || op())
357 }
358}