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