diff options
author | Dmitry <[email protected]> | 2020-08-14 19:32:05 +0100 |
---|---|---|
committer | Dmitry <[email protected]> | 2020-08-14 19:32:05 +0100 |
commit | 178c3e135a2a249692f7784712492e7884ae0c00 (patch) | |
tree | ac6b769dbf7162150caa0c1624786a4dd79ff3be /crates/hir_ty/src/traits | |
parent | 06ff8e6c760ff05f10e868b5d1f9d79e42fbb49c (diff) | |
parent | c2594daf2974dbd4ce3d9b7ec72481764abaceb5 (diff) |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'crates/hir_ty/src/traits')
-rw-r--r-- | crates/hir_ty/src/traits/chalk.rs | 589 | ||||
-rw-r--r-- | crates/hir_ty/src/traits/chalk/interner.rs | 383 | ||||
-rw-r--r-- | crates/hir_ty/src/traits/chalk/mapping.rs | 787 | ||||
-rw-r--r-- | crates/hir_ty/src/traits/chalk/tls.rs | 358 |
4 files changed, 2117 insertions, 0 deletions
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs new file mode 100644 index 000000000..17c83b6a4 --- /dev/null +++ b/crates/hir_ty/src/traits/chalk.rs | |||
@@ -0,0 +1,589 @@ | |||
1 | //! Conversion code from/to Chalk. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use log::debug; | ||
5 | |||
6 | use chalk_ir::{fold::shift::Shift, CanonicalVarKinds, GenericArg, TypeName}; | ||
7 | use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; | ||
8 | |||
9 | use base_db::{salsa::InternKey, CrateId}; | ||
10 | use hir_def::{ | ||
11 | lang_item::{lang_attr, LangItemTarget}, | ||
12 | AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, | ||
13 | }; | ||
14 | |||
15 | use super::ChalkContext; | ||
16 | use crate::{ | ||
17 | db::HirDatabase, | ||
18 | display::HirDisplay, | ||
19 | method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, | ||
20 | utils::generics, | ||
21 | CallableDefId, DebruijnIndex, FnSig, GenericPredicate, Substs, Ty, TypeCtor, | ||
22 | }; | ||
23 | use mapping::{ | ||
24 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, | ||
25 | }; | ||
26 | |||
27 | pub use self::interner::*; | ||
28 | |||
29 | pub(super) mod tls; | ||
30 | mod interner; | ||
31 | mod mapping; | ||
32 | |||
33 | pub(super) trait ToChalk { | ||
34 | type Chalk; | ||
35 | fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk; | ||
36 | fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self; | ||
37 | } | ||
38 | |||
39 | pub(super) fn from_chalk<T, ChalkT>(db: &dyn HirDatabase, chalk: ChalkT) -> T | ||
40 | where | ||
41 | T: ToChalk<Chalk = ChalkT>, | ||
42 | { | ||
43 | T::from_chalk(db, chalk) | ||
44 | } | ||
45 | |||
46 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | ||
47 | fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { | ||
48 | self.db.associated_ty_data(id) | ||
49 | } | ||
50 | fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> { | ||
51 | self.db.trait_datum(self.krate, trait_id) | ||
52 | } | ||
53 | fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> { | ||
54 | self.db.struct_datum(self.krate, struct_id) | ||
55 | } | ||
56 | fn adt_repr(&self, _struct_id: AdtId) -> rust_ir::AdtRepr { | ||
57 | rust_ir::AdtRepr { repr_c: false, repr_packed: false } | ||
58 | } | ||
59 | fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { | ||
60 | self.db.impl_datum(self.krate, impl_id) | ||
61 | } | ||
62 | |||
63 | fn fn_def_datum( | ||
64 | &self, | ||
65 | fn_def_id: chalk_ir::FnDefId<Interner>, | ||
66 | ) -> Arc<rust_ir::FnDefDatum<Interner>> { | ||
67 | self.db.fn_def_datum(self.krate, fn_def_id) | ||
68 | } | ||
69 | |||
70 | fn impls_for_trait( | ||
71 | &self, | ||
72 | trait_id: TraitId, | ||
73 | parameters: &[GenericArg<Interner>], | ||
74 | binders: &CanonicalVarKinds<Interner>, | ||
75 | ) -> Vec<ImplId> { | ||
76 | debug!("impls_for_trait {:?}", trait_id); | ||
77 | let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); | ||
78 | |||
79 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone()); | ||
80 | |||
81 | fn binder_kind(ty: &Ty, binders: &CanonicalVarKinds<Interner>) -> Option<chalk_ir::TyKind> { | ||
82 | if let Ty::Bound(bv) = ty { | ||
83 | let binders = binders.as_slice(&Interner); | ||
84 | if bv.debruijn == DebruijnIndex::INNERMOST { | ||
85 | if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind { | ||
86 | return Some(tk); | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | None | ||
91 | } | ||
92 | |||
93 | let self_ty_fp = TyFingerprint::for_impl(&ty); | ||
94 | let fps: &[TyFingerprint] = match binder_kind(&ty, binders) { | ||
95 | Some(chalk_ir::TyKind::Integer) => &ALL_INT_FPS, | ||
96 | Some(chalk_ir::TyKind::Float) => &ALL_FLOAT_FPS, | ||
97 | _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]), | ||
98 | }; | ||
99 | |||
100 | // Note: Since we're using impls_for_trait, only impls where the trait | ||
101 | // can be resolved should ever reach Chalk. `impl_datum` relies on that | ||
102 | // and will panic if the trait can't be resolved. | ||
103 | let in_deps = self.db.trait_impls_in_deps(self.krate); | ||
104 | let in_self = self.db.trait_impls_in_crate(self.krate); | ||
105 | let impl_maps = [in_deps, in_self]; | ||
106 | |||
107 | let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); | ||
108 | |||
109 | let result: Vec<_> = if fps.is_empty() { | ||
110 | debug!("Unrestricted search for {:?} impls...", trait_); | ||
111 | impl_maps | ||
112 | .iter() | ||
113 | .flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk)) | ||
114 | .collect() | ||
115 | } else { | ||
116 | impl_maps | ||
117 | .iter() | ||
118 | .flat_map(|crate_impl_defs| { | ||
119 | fps.iter().flat_map(move |fp| { | ||
120 | crate_impl_defs.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) | ||
121 | }) | ||
122 | }) | ||
123 | .collect() | ||
124 | }; | ||
125 | |||
126 | debug!("impls_for_trait returned {} impls", result.len()); | ||
127 | result | ||
128 | } | ||
129 | fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: AdtId) -> bool { | ||
130 | debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); | ||
131 | false // FIXME | ||
132 | } | ||
133 | fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> { | ||
134 | self.db.associated_ty_value(self.krate, id) | ||
135 | } | ||
136 | |||
137 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<Interner>> { | ||
138 | vec![] | ||
139 | } | ||
140 | fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec<ImplId> { | ||
141 | // We don't do coherence checking (yet) | ||
142 | unimplemented!() | ||
143 | } | ||
144 | fn interner(&self) -> &Interner { | ||
145 | &Interner | ||
146 | } | ||
147 | fn well_known_trait_id( | ||
148 | &self, | ||
149 | well_known_trait: rust_ir::WellKnownTrait, | ||
150 | ) -> Option<chalk_ir::TraitId<Interner>> { | ||
151 | let lang_attr = lang_attr_from_well_known_trait(well_known_trait); | ||
152 | let trait_ = match self.db.lang_item(self.krate, lang_attr.into()) { | ||
153 | Some(LangItemTarget::TraitId(trait_)) => trait_, | ||
154 | _ => return None, | ||
155 | }; | ||
156 | Some(trait_.to_chalk(self.db)) | ||
157 | } | ||
158 | |||
159 | fn program_clauses_for_env( | ||
160 | &self, | ||
161 | environment: &chalk_ir::Environment<Interner>, | ||
162 | ) -> chalk_ir::ProgramClauses<Interner> { | ||
163 | self.db.program_clauses_for_chalk_env(self.krate, environment.clone()) | ||
164 | } | ||
165 | |||
166 | fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> { | ||
167 | let interned_id = crate::db::InternedOpaqueTyId::from(id); | ||
168 | let full_id = self.db.lookup_intern_impl_trait_id(interned_id); | ||
169 | let (func, idx) = match full_id { | ||
170 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx), | ||
171 | }; | ||
172 | let datas = | ||
173 | self.db.return_type_impl_traits(func).expect("impl trait id without impl traits"); | ||
174 | let data = &datas.value.impl_traits[idx as usize]; | ||
175 | let bound = OpaqueTyDatumBound { | ||
176 | bounds: make_binders( | ||
177 | data.bounds | ||
178 | .value | ||
179 | .iter() | ||
180 | .cloned() | ||
181 | .filter(|b| !b.is_error()) | ||
182 | .map(|b| b.to_chalk(self.db)) | ||
183 | .collect(), | ||
184 | 1, | ||
185 | ), | ||
186 | where_clauses: make_binders(vec![], 0), | ||
187 | }; | ||
188 | let num_vars = datas.num_binders; | ||
189 | Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) }) | ||
190 | } | ||
191 | |||
192 | fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { | ||
193 | // FIXME: actually provide the hidden type; it is relevant for auto traits | ||
194 | Ty::Unknown.to_chalk(self.db) | ||
195 | } | ||
196 | |||
197 | fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool { | ||
198 | // FIXME: implement actual object safety | ||
199 | true | ||
200 | } | ||
201 | |||
202 | fn closure_kind( | ||
203 | &self, | ||
204 | _closure_id: chalk_ir::ClosureId<Interner>, | ||
205 | _substs: &chalk_ir::Substitution<Interner>, | ||
206 | ) -> rust_ir::ClosureKind { | ||
207 | // Fn is the closure kind that implements all three traits | ||
208 | rust_ir::ClosureKind::Fn | ||
209 | } | ||
210 | fn closure_inputs_and_output( | ||
211 | &self, | ||
212 | _closure_id: chalk_ir::ClosureId<Interner>, | ||
213 | substs: &chalk_ir::Substitution<Interner>, | ||
214 | ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> { | ||
215 | let sig_ty: Ty = | ||
216 | from_chalk(self.db, substs.at(&Interner, 0).assert_ty_ref(&Interner).clone()); | ||
217 | let sig = FnSig::from_fn_ptr_substs( | ||
218 | &sig_ty.substs().expect("first closure param should be fn ptr"), | ||
219 | false, | ||
220 | ); | ||
221 | let io = rust_ir::FnDefInputsAndOutputDatum { | ||
222 | argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(self.db)).collect(), | ||
223 | return_type: sig.ret().clone().to_chalk(self.db), | ||
224 | }; | ||
225 | make_binders(io.shifted_in(&Interner), 0) | ||
226 | } | ||
227 | fn closure_upvars( | ||
228 | &self, | ||
229 | _closure_id: chalk_ir::ClosureId<Interner>, | ||
230 | _substs: &chalk_ir::Substitution<Interner>, | ||
231 | ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> { | ||
232 | let ty = Ty::unit().to_chalk(self.db); | ||
233 | make_binders(ty, 0) | ||
234 | } | ||
235 | fn closure_fn_substitution( | ||
236 | &self, | ||
237 | _closure_id: chalk_ir::ClosureId<Interner>, | ||
238 | _substs: &chalk_ir::Substitution<Interner>, | ||
239 | ) -> chalk_ir::Substitution<Interner> { | ||
240 | Substs::empty().to_chalk(self.db) | ||
241 | } | ||
242 | |||
243 | fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String { | ||
244 | let id = from_chalk(self.db, trait_id); | ||
245 | self.db.trait_data(id).name.to_string() | ||
246 | } | ||
247 | // FIXME: lookup names | ||
248 | fn adt_name(&self, struct_id: chalk_ir::AdtId<Interner>) -> String { | ||
249 | let datum = self.db.struct_datum(self.krate, struct_id); | ||
250 | format!("{:?}", datum.name(&Interner)) | ||
251 | } | ||
252 | fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String { | ||
253 | format!("Assoc_{}", assoc_ty_id.0) | ||
254 | } | ||
255 | fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String { | ||
256 | format!("Opaque_{}", opaque_ty_id.0) | ||
257 | } | ||
258 | fn fn_def_name(&self, fn_def_id: chalk_ir::FnDefId<Interner>) -> String { | ||
259 | format!("fn_{}", fn_def_id.0) | ||
260 | } | ||
261 | } | ||
262 | |||
263 | pub(crate) fn program_clauses_for_chalk_env_query( | ||
264 | db: &dyn HirDatabase, | ||
265 | krate: CrateId, | ||
266 | environment: chalk_ir::Environment<Interner>, | ||
267 | ) -> chalk_ir::ProgramClauses<Interner> { | ||
268 | chalk_solve::program_clauses_for_env(&ChalkContext { db, krate }, &environment) | ||
269 | } | ||
270 | |||
271 | pub(crate) fn associated_ty_data_query( | ||
272 | db: &dyn HirDatabase, | ||
273 | id: AssocTypeId, | ||
274 | ) -> Arc<AssociatedTyDatum> { | ||
275 | debug!("associated_ty_data {:?}", id); | ||
276 | let type_alias: TypeAliasId = from_chalk(db, id); | ||
277 | let trait_ = match type_alias.lookup(db.upcast()).container { | ||
278 | AssocContainerId::TraitId(t) => t, | ||
279 | _ => panic!("associated type not in trait"), | ||
280 | }; | ||
281 | |||
282 | // Lower bounds -- we could/should maybe move this to a separate query in `lower` | ||
283 | let type_alias_data = db.type_alias_data(type_alias); | ||
284 | let generic_params = generics(db.upcast(), type_alias.into()); | ||
285 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
286 | let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); | ||
287 | let ctx = crate::TyLoweringContext::new(db, &resolver) | ||
288 | .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); | ||
289 | let self_ty = Ty::Bound(crate::BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)); | ||
290 | let bounds = type_alias_data | ||
291 | .bounds | ||
292 | .iter() | ||
293 | .flat_map(|bound| GenericPredicate::from_type_bound(&ctx, bound, self_ty.clone())) | ||
294 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) | ||
295 | .map(|bound| make_binders(bound.shifted_in(&Interner), 0)) | ||
296 | .collect(); | ||
297 | |||
298 | let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); | ||
299 | let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; | ||
300 | let datum = AssociatedTyDatum { | ||
301 | trait_id: trait_.to_chalk(db), | ||
302 | id, | ||
303 | name: type_alias, | ||
304 | binders: make_binders(bound_data, generic_params.len()), | ||
305 | }; | ||
306 | Arc::new(datum) | ||
307 | } | ||
308 | |||
309 | pub(crate) fn trait_datum_query( | ||
310 | db: &dyn HirDatabase, | ||
311 | krate: CrateId, | ||
312 | trait_id: TraitId, | ||
313 | ) -> Arc<TraitDatum> { | ||
314 | debug!("trait_datum {:?}", trait_id); | ||
315 | let trait_: hir_def::TraitId = from_chalk(db, trait_id); | ||
316 | let trait_data = db.trait_data(trait_); | ||
317 | debug!("trait {:?} = {:?}", trait_id, trait_data.name); | ||
318 | let generic_params = generics(db.upcast(), trait_.into()); | ||
319 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
320 | let flags = rust_ir::TraitFlags { | ||
321 | auto: trait_data.auto, | ||
322 | upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate, | ||
323 | non_enumerable: true, | ||
324 | coinductive: false, // only relevant for Chalk testing | ||
325 | // FIXME: set these flags correctly | ||
326 | marker: false, | ||
327 | fundamental: false, | ||
328 | }; | ||
329 | let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); | ||
330 | let associated_ty_ids = | ||
331 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); | ||
332 | let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; | ||
333 | let well_known = | ||
334 | lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); | ||
335 | let trait_datum = TraitDatum { | ||
336 | id: trait_id, | ||
337 | binders: make_binders(trait_datum_bound, bound_vars.len()), | ||
338 | flags, | ||
339 | associated_ty_ids, | ||
340 | well_known, | ||
341 | }; | ||
342 | Arc::new(trait_datum) | ||
343 | } | ||
344 | |||
345 | fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> { | ||
346 | Some(match name { | ||
347 | "sized" => WellKnownTrait::Sized, | ||
348 | "copy" => WellKnownTrait::Copy, | ||
349 | "clone" => WellKnownTrait::Clone, | ||
350 | "drop" => WellKnownTrait::Drop, | ||
351 | "fn_once" => WellKnownTrait::FnOnce, | ||
352 | "fn_mut" => WellKnownTrait::FnMut, | ||
353 | "fn" => WellKnownTrait::Fn, | ||
354 | "unsize" => WellKnownTrait::Unsize, | ||
355 | _ => return None, | ||
356 | }) | ||
357 | } | ||
358 | |||
359 | fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str { | ||
360 | match attr { | ||
361 | WellKnownTrait::Sized => "sized", | ||
362 | WellKnownTrait::Copy => "copy", | ||
363 | WellKnownTrait::Clone => "clone", | ||
364 | WellKnownTrait::Drop => "drop", | ||
365 | WellKnownTrait::FnOnce => "fn_once", | ||
366 | WellKnownTrait::FnMut => "fn_mut", | ||
367 | WellKnownTrait::Fn => "fn", | ||
368 | WellKnownTrait::Unsize => "unsize", | ||
369 | } | ||
370 | } | ||
371 | |||
372 | pub(crate) fn struct_datum_query( | ||
373 | db: &dyn HirDatabase, | ||
374 | krate: CrateId, | ||
375 | struct_id: AdtId, | ||
376 | ) -> Arc<StructDatum> { | ||
377 | debug!("struct_datum {:?}", struct_id); | ||
378 | let type_ctor: TypeCtor = from_chalk(db, TypeName::Adt(struct_id)); | ||
379 | debug!("struct {:?} = {:?}", struct_id, type_ctor); | ||
380 | let num_params = type_ctor.num_ty_params(db); | ||
381 | let upstream = type_ctor.krate(db) != Some(krate); | ||
382 | let where_clauses = type_ctor | ||
383 | .as_generic_def() | ||
384 | .map(|generic_def| { | ||
385 | let generic_params = generics(db.upcast(), generic_def); | ||
386 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
387 | convert_where_clauses(db, generic_def, &bound_vars) | ||
388 | }) | ||
389 | .unwrap_or_else(Vec::new); | ||
390 | let flags = rust_ir::AdtFlags { | ||
391 | upstream, | ||
392 | // FIXME set fundamental and phantom_data flags correctly | ||
393 | fundamental: false, | ||
394 | phantom_data: false, | ||
395 | }; | ||
396 | // FIXME provide enum variants properly (for auto traits) | ||
397 | let variant = rust_ir::AdtVariantDatum { | ||
398 | fields: Vec::new(), // FIXME add fields (only relevant for auto traits), | ||
399 | }; | ||
400 | let struct_datum_bound = rust_ir::AdtDatumBound { variants: vec![variant], where_clauses }; | ||
401 | let struct_datum = StructDatum { | ||
402 | // FIXME set ADT kind | ||
403 | kind: rust_ir::AdtKind::Struct, | ||
404 | id: struct_id, | ||
405 | binders: make_binders(struct_datum_bound, num_params), | ||
406 | flags, | ||
407 | }; | ||
408 | Arc::new(struct_datum) | ||
409 | } | ||
410 | |||
411 | pub(crate) fn impl_datum_query( | ||
412 | db: &dyn HirDatabase, | ||
413 | krate: CrateId, | ||
414 | impl_id: ImplId, | ||
415 | ) -> Arc<ImplDatum> { | ||
416 | let _p = profile::span("impl_datum"); | ||
417 | debug!("impl_datum {:?}", impl_id); | ||
418 | let impl_: hir_def::ImplId = from_chalk(db, impl_id); | ||
419 | impl_def_datum(db, krate, impl_id, impl_) | ||
420 | } | ||
421 | |||
422 | fn impl_def_datum( | ||
423 | db: &dyn HirDatabase, | ||
424 | krate: CrateId, | ||
425 | chalk_id: ImplId, | ||
426 | impl_id: hir_def::ImplId, | ||
427 | ) -> Arc<ImplDatum> { | ||
428 | let trait_ref = db | ||
429 | .impl_trait(impl_id) | ||
430 | // ImplIds for impls where the trait ref can't be resolved should never reach Chalk | ||
431 | .expect("invalid impl passed to Chalk") | ||
432 | .value; | ||
433 | let impl_data = db.impl_data(impl_id); | ||
434 | |||
435 | let generic_params = generics(db.upcast(), impl_id.into()); | ||
436 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
437 | let trait_ = trait_ref.trait_; | ||
438 | let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate { | ||
439 | rust_ir::ImplType::Local | ||
440 | } else { | ||
441 | rust_ir::ImplType::External | ||
442 | }; | ||
443 | let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars); | ||
444 | let negative = impl_data.is_negative; | ||
445 | debug!( | ||
446 | "impl {:?}: {}{} where {:?}", | ||
447 | chalk_id, | ||
448 | if negative { "!" } else { "" }, | ||
449 | trait_ref.display(db), | ||
450 | where_clauses | ||
451 | ); | ||
452 | let trait_ref = trait_ref.to_chalk(db); | ||
453 | |||
454 | let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; | ||
455 | |||
456 | let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses }; | ||
457 | let trait_data = db.trait_data(trait_); | ||
458 | let associated_ty_value_ids = impl_data | ||
459 | .items | ||
460 | .iter() | ||
461 | .filter_map(|item| match item { | ||
462 | AssocItemId::TypeAliasId(type_alias) => Some(*type_alias), | ||
463 | _ => None, | ||
464 | }) | ||
465 | .filter(|&type_alias| { | ||
466 | // don't include associated types that don't exist in the trait | ||
467 | let name = &db.type_alias_data(type_alias).name; | ||
468 | trait_data.associated_type_by_name(name).is_some() | ||
469 | }) | ||
470 | .map(|type_alias| TypeAliasAsValue(type_alias).to_chalk(db)) | ||
471 | .collect(); | ||
472 | debug!("impl_datum: {:?}", impl_datum_bound); | ||
473 | let impl_datum = ImplDatum { | ||
474 | binders: make_binders(impl_datum_bound, bound_vars.len()), | ||
475 | impl_type, | ||
476 | polarity, | ||
477 | associated_ty_value_ids, | ||
478 | }; | ||
479 | Arc::new(impl_datum) | ||
480 | } | ||
481 | |||
482 | pub(crate) fn associated_ty_value_query( | ||
483 | db: &dyn HirDatabase, | ||
484 | krate: CrateId, | ||
485 | id: AssociatedTyValueId, | ||
486 | ) -> Arc<AssociatedTyValue> { | ||
487 | let type_alias: TypeAliasAsValue = from_chalk(db, id); | ||
488 | type_alias_associated_ty_value(db, krate, type_alias.0) | ||
489 | } | ||
490 | |||
491 | fn type_alias_associated_ty_value( | ||
492 | db: &dyn HirDatabase, | ||
493 | _krate: CrateId, | ||
494 | type_alias: TypeAliasId, | ||
495 | ) -> Arc<AssociatedTyValue> { | ||
496 | let type_alias_data = db.type_alias_data(type_alias); | ||
497 | let impl_id = match type_alias.lookup(db.upcast()).container { | ||
498 | AssocContainerId::ImplId(it) => it, | ||
499 | _ => panic!("assoc ty value should be in impl"), | ||
500 | }; | ||
501 | |||
502 | let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist").value; // we don't return any assoc ty values if the impl'd trait can't be resolved | ||
503 | |||
504 | let assoc_ty = db | ||
505 | .trait_data(trait_ref.trait_) | ||
506 | .associated_type_by_name(&type_alias_data.name) | ||
507 | .expect("assoc ty value should not exist"); // validated when building the impl data as well | ||
508 | let ty = db.ty(type_alias.into()); | ||
509 | let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; | ||
510 | let value = rust_ir::AssociatedTyValue { | ||
511 | impl_id: impl_id.to_chalk(db), | ||
512 | associated_ty_id: assoc_ty.to_chalk(db), | ||
513 | value: make_binders(value_bound, ty.num_binders), | ||
514 | }; | ||
515 | Arc::new(value) | ||
516 | } | ||
517 | |||
518 | pub(crate) fn fn_def_datum_query( | ||
519 | db: &dyn HirDatabase, | ||
520 | _krate: CrateId, | ||
521 | fn_def_id: FnDefId, | ||
522 | ) -> Arc<FnDefDatum> { | ||
523 | let callable_def: CallableDefId = from_chalk(db, fn_def_id); | ||
524 | let generic_params = generics(db.upcast(), callable_def.into()); | ||
525 | let sig = db.callable_item_signature(callable_def); | ||
526 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
527 | let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); | ||
528 | let bound = rust_ir::FnDefDatumBound { | ||
529 | // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway | ||
530 | inputs_and_output: make_binders( | ||
531 | rust_ir::FnDefInputsAndOutputDatum { | ||
532 | argument_types: sig | ||
533 | .value | ||
534 | .params() | ||
535 | .iter() | ||
536 | .map(|ty| ty.clone().to_chalk(db)) | ||
537 | .collect(), | ||
538 | return_type: sig.value.ret().clone().to_chalk(db), | ||
539 | } | ||
540 | .shifted_in(&Interner), | ||
541 | 0, | ||
542 | ), | ||
543 | where_clauses, | ||
544 | }; | ||
545 | let datum = FnDefDatum { | ||
546 | id: fn_def_id, | ||
547 | abi: (), | ||
548 | safety: chalk_ir::Safety::Safe, | ||
549 | variadic: sig.value.is_varargs, | ||
550 | binders: make_binders(bound, sig.num_binders), | ||
551 | }; | ||
552 | Arc::new(datum) | ||
553 | } | ||
554 | |||
555 | impl From<FnDefId> for crate::db::InternedCallableDefId { | ||
556 | fn from(fn_def_id: FnDefId) -> Self { | ||
557 | InternKey::from_intern_id(fn_def_id.0) | ||
558 | } | ||
559 | } | ||
560 | |||
561 | impl From<crate::db::InternedCallableDefId> for FnDefId { | ||
562 | fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self { | ||
563 | chalk_ir::FnDefId(callable_def_id.as_intern_id()) | ||
564 | } | ||
565 | } | ||
566 | |||
567 | impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId { | ||
568 | fn from(id: OpaqueTyId) -> Self { | ||
569 | InternKey::from_intern_id(id.0) | ||
570 | } | ||
571 | } | ||
572 | |||
573 | impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId { | ||
574 | fn from(id: crate::db::InternedOpaqueTyId) -> Self { | ||
575 | chalk_ir::OpaqueTyId(id.as_intern_id()) | ||
576 | } | ||
577 | } | ||
578 | |||
579 | impl From<chalk_ir::ClosureId<Interner>> for crate::db::ClosureId { | ||
580 | fn from(id: chalk_ir::ClosureId<Interner>) -> Self { | ||
581 | Self::from_intern_id(id.0) | ||
582 | } | ||
583 | } | ||
584 | |||
585 | impl From<crate::db::ClosureId> for chalk_ir::ClosureId<Interner> { | ||
586 | fn from(id: crate::db::ClosureId) -> Self { | ||
587 | chalk_ir::ClosureId(id.as_intern_id()) | ||
588 | } | ||
589 | } | ||
diff --git a/crates/hir_ty/src/traits/chalk/interner.rs b/crates/hir_ty/src/traits/chalk/interner.rs new file mode 100644 index 000000000..fc0f9c201 --- /dev/null +++ b/crates/hir_ty/src/traits/chalk/interner.rs | |||
@@ -0,0 +1,383 @@ | |||
1 | //! Implementation of the Chalk `Interner` trait, which allows customizing the | ||
2 | //! representation of the various objects Chalk deals with (types, goals etc.). | ||
3 | |||
4 | use super::tls; | ||
5 | use base_db::salsa::InternId; | ||
6 | use chalk_ir::{GenericArg, Goal, GoalData}; | ||
7 | use hir_def::TypeAliasId; | ||
8 | use std::{fmt, sync::Arc}; | ||
9 | |||
10 | #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] | ||
11 | pub struct Interner; | ||
12 | |||
13 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; | ||
14 | pub type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>; | ||
15 | pub type TraitId = chalk_ir::TraitId<Interner>; | ||
16 | pub type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>; | ||
17 | pub type AdtId = chalk_ir::AdtId<Interner>; | ||
18 | pub type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>; | ||
19 | pub type ImplId = chalk_ir::ImplId<Interner>; | ||
20 | pub type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>; | ||
21 | pub type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interner>; | ||
22 | pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>; | ||
23 | pub type FnDefId = chalk_ir::FnDefId<Interner>; | ||
24 | pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>; | ||
25 | pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; | ||
26 | pub type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>; | ||
27 | |||
28 | impl chalk_ir::interner::Interner for Interner { | ||
29 | type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc? | ||
30 | type InternedLifetime = chalk_ir::LifetimeData<Self>; | ||
31 | type InternedConst = Arc<chalk_ir::ConstData<Self>>; | ||
32 | type InternedConcreteConst = (); | ||
33 | type InternedGenericArg = chalk_ir::GenericArgData<Self>; | ||
34 | type InternedGoal = Arc<GoalData<Self>>; | ||
35 | type InternedGoals = Vec<Goal<Self>>; | ||
36 | type InternedSubstitution = Vec<GenericArg<Self>>; | ||
37 | type InternedProgramClause = chalk_ir::ProgramClauseData<Self>; | ||
38 | type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; | ||
39 | type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; | ||
40 | type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; | ||
41 | type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; | ||
42 | type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>; | ||
43 | type DefId = InternId; | ||
44 | type InternedAdtId = hir_def::AdtId; | ||
45 | type Identifier = TypeAliasId; | ||
46 | type FnAbi = (); | ||
47 | |||
48 | fn debug_adt_id(type_kind_id: AdtId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
49 | tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) | ||
50 | } | ||
51 | |||
52 | fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
53 | tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) | ||
54 | } | ||
55 | |||
56 | fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
57 | tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) | ||
58 | } | ||
59 | |||
60 | fn debug_alias( | ||
61 | alias: &chalk_ir::AliasTy<Interner>, | ||
62 | fmt: &mut fmt::Formatter<'_>, | ||
63 | ) -> Option<fmt::Result> { | ||
64 | tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt))) | ||
65 | } | ||
66 | |||
67 | fn debug_projection_ty( | ||
68 | proj: &chalk_ir::ProjectionTy<Interner>, | ||
69 | fmt: &mut fmt::Formatter<'_>, | ||
70 | ) -> Option<fmt::Result> { | ||
71 | tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) | ||
72 | } | ||
73 | |||
74 | fn debug_opaque_ty( | ||
75 | opaque_ty: &chalk_ir::OpaqueTy<Interner>, | ||
76 | fmt: &mut fmt::Formatter<'_>, | ||
77 | ) -> Option<fmt::Result> { | ||
78 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt))) | ||
79 | } | ||
80 | |||
81 | fn debug_opaque_ty_id( | ||
82 | opaque_ty_id: chalk_ir::OpaqueTyId<Self>, | ||
83 | fmt: &mut fmt::Formatter<'_>, | ||
84 | ) -> Option<fmt::Result> { | ||
85 | tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt))) | ||
86 | } | ||
87 | |||
88 | fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
89 | tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) | ||
90 | } | ||
91 | |||
92 | fn debug_lifetime( | ||
93 | lifetime: &chalk_ir::Lifetime<Interner>, | ||
94 | fmt: &mut fmt::Formatter<'_>, | ||
95 | ) -> Option<fmt::Result> { | ||
96 | tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt))) | ||
97 | } | ||
98 | |||
99 | fn debug_generic_arg( | ||
100 | parameter: &GenericArg<Interner>, | ||
101 | fmt: &mut fmt::Formatter<'_>, | ||
102 | ) -> Option<fmt::Result> { | ||
103 | tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt))) | ||
104 | } | ||
105 | |||
106 | fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | ||
107 | tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt))) | ||
108 | } | ||
109 | |||
110 | fn debug_goals( | ||
111 | goals: &chalk_ir::Goals<Interner>, | ||
112 | fmt: &mut fmt::Formatter<'_>, | ||
113 | ) -> Option<fmt::Result> { | ||
114 | tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt))) | ||
115 | } | ||
116 | |||
117 | fn debug_program_clause_implication( | ||
118 | pci: &chalk_ir::ProgramClauseImplication<Interner>, | ||
119 | fmt: &mut fmt::Formatter<'_>, | ||
120 | ) -> Option<fmt::Result> { | ||
121 | tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt))) | ||
122 | } | ||
123 | |||
124 | fn debug_application_ty( | ||
125 | application_ty: &chalk_ir::ApplicationTy<Interner>, | ||
126 | fmt: &mut fmt::Formatter<'_>, | ||
127 | ) -> Option<fmt::Result> { | ||
128 | tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt))) | ||
129 | } | ||
130 | |||
131 | fn debug_substitution( | ||
132 | substitution: &chalk_ir::Substitution<Interner>, | ||
133 | fmt: &mut fmt::Formatter<'_>, | ||
134 | ) -> Option<fmt::Result> { | ||
135 | tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt))) | ||
136 | } | ||
137 | |||
138 | fn debug_separator_trait_ref( | ||
139 | separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, | ||
140 | fmt: &mut fmt::Formatter<'_>, | ||
141 | ) -> Option<fmt::Result> { | ||
142 | tls::with_current_program(|prog| { | ||
143 | Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt)) | ||
144 | }) | ||
145 | } | ||
146 | |||
147 | fn debug_fn_def_id( | ||
148 | fn_def_id: chalk_ir::FnDefId<Self>, | ||
149 | fmt: &mut fmt::Formatter<'_>, | ||
150 | ) -> Option<fmt::Result> { | ||
151 | tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) | ||
152 | } | ||
153 | fn debug_const( | ||
154 | constant: &chalk_ir::Const<Self>, | ||
155 | fmt: &mut fmt::Formatter<'_>, | ||
156 | ) -> Option<fmt::Result> { | ||
157 | tls::with_current_program(|prog| Some(prog?.debug_const(constant, fmt))) | ||
158 | } | ||
159 | fn debug_variable_kinds( | ||
160 | variable_kinds: &chalk_ir::VariableKinds<Self>, | ||
161 | fmt: &mut fmt::Formatter<'_>, | ||
162 | ) -> Option<fmt::Result> { | ||
163 | tls::with_current_program(|prog| Some(prog?.debug_variable_kinds(variable_kinds, fmt))) | ||
164 | } | ||
165 | fn debug_variable_kinds_with_angles( | ||
166 | variable_kinds: &chalk_ir::VariableKinds<Self>, | ||
167 | fmt: &mut fmt::Formatter<'_>, | ||
168 | ) -> Option<fmt::Result> { | ||
169 | tls::with_current_program(|prog| { | ||
170 | Some(prog?.debug_variable_kinds_with_angles(variable_kinds, fmt)) | ||
171 | }) | ||
172 | } | ||
173 | fn debug_canonical_var_kinds( | ||
174 | canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Self>, | ||
175 | fmt: &mut fmt::Formatter<'_>, | ||
176 | ) -> Option<fmt::Result> { | ||
177 | tls::with_current_program(|prog| { | ||
178 | Some(prog?.debug_canonical_var_kinds(canonical_var_kinds, fmt)) | ||
179 | }) | ||
180 | } | ||
181 | fn debug_program_clause( | ||
182 | clause: &chalk_ir::ProgramClause<Self>, | ||
183 | fmt: &mut fmt::Formatter<'_>, | ||
184 | ) -> Option<fmt::Result> { | ||
185 | tls::with_current_program(|prog| Some(prog?.debug_program_clause(clause, fmt))) | ||
186 | } | ||
187 | fn debug_program_clauses( | ||
188 | clauses: &chalk_ir::ProgramClauses<Self>, | ||
189 | fmt: &mut fmt::Formatter<'_>, | ||
190 | ) -> Option<fmt::Result> { | ||
191 | tls::with_current_program(|prog| Some(prog?.debug_program_clauses(clauses, fmt))) | ||
192 | } | ||
193 | fn debug_quantified_where_clauses( | ||
194 | clauses: &chalk_ir::QuantifiedWhereClauses<Self>, | ||
195 | fmt: &mut fmt::Formatter<'_>, | ||
196 | ) -> Option<fmt::Result> { | ||
197 | tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt))) | ||
198 | } | ||
199 | |||
200 | fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { | ||
201 | Box::new(ty) | ||
202 | } | ||
203 | |||
204 | fn ty_data<'a>(&self, ty: &'a Box<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> { | ||
205 | ty | ||
206 | } | ||
207 | |||
208 | fn intern_lifetime( | ||
209 | &self, | ||
210 | lifetime: chalk_ir::LifetimeData<Self>, | ||
211 | ) -> chalk_ir::LifetimeData<Self> { | ||
212 | lifetime | ||
213 | } | ||
214 | |||
215 | fn lifetime_data<'a>( | ||
216 | &self, | ||
217 | lifetime: &'a chalk_ir::LifetimeData<Self>, | ||
218 | ) -> &'a chalk_ir::LifetimeData<Self> { | ||
219 | lifetime | ||
220 | } | ||
221 | |||
222 | fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Arc<chalk_ir::ConstData<Self>> { | ||
223 | Arc::new(constant) | ||
224 | } | ||
225 | |||
226 | fn const_data<'a>( | ||
227 | &self, | ||
228 | constant: &'a Arc<chalk_ir::ConstData<Self>>, | ||
229 | ) -> &'a chalk_ir::ConstData<Self> { | ||
230 | constant | ||
231 | } | ||
232 | |||
233 | fn const_eq(&self, _ty: &Box<chalk_ir::TyData<Self>>, _c1: &(), _c2: &()) -> bool { | ||
234 | true | ||
235 | } | ||
236 | |||
237 | fn intern_generic_arg( | ||
238 | &self, | ||
239 | parameter: chalk_ir::GenericArgData<Self>, | ||
240 | ) -> chalk_ir::GenericArgData<Self> { | ||
241 | parameter | ||
242 | } | ||
243 | |||
244 | fn generic_arg_data<'a>( | ||
245 | &self, | ||
246 | parameter: &'a chalk_ir::GenericArgData<Self>, | ||
247 | ) -> &'a chalk_ir::GenericArgData<Self> { | ||
248 | parameter | ||
249 | } | ||
250 | |||
251 | fn intern_goal(&self, goal: GoalData<Self>) -> Arc<GoalData<Self>> { | ||
252 | Arc::new(goal) | ||
253 | } | ||
254 | |||
255 | fn intern_goals<E>( | ||
256 | &self, | ||
257 | data: impl IntoIterator<Item = Result<Goal<Self>, E>>, | ||
258 | ) -> Result<Self::InternedGoals, E> { | ||
259 | data.into_iter().collect() | ||
260 | } | ||
261 | |||
262 | fn goal_data<'a>(&self, goal: &'a Arc<GoalData<Self>>) -> &'a GoalData<Self> { | ||
263 | goal | ||
264 | } | ||
265 | |||
266 | fn goals_data<'a>(&self, goals: &'a Vec<Goal<Interner>>) -> &'a [Goal<Interner>] { | ||
267 | goals | ||
268 | } | ||
269 | |||
270 | fn intern_substitution<E>( | ||
271 | &self, | ||
272 | data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>, | ||
273 | ) -> Result<Vec<GenericArg<Self>>, E> { | ||
274 | data.into_iter().collect() | ||
275 | } | ||
276 | |||
277 | fn substitution_data<'a>( | ||
278 | &self, | ||
279 | substitution: &'a Vec<GenericArg<Self>>, | ||
280 | ) -> &'a [GenericArg<Self>] { | ||
281 | substitution | ||
282 | } | ||
283 | |||
284 | fn intern_program_clause( | ||
285 | &self, | ||
286 | data: chalk_ir::ProgramClauseData<Self>, | ||
287 | ) -> chalk_ir::ProgramClauseData<Self> { | ||
288 | data | ||
289 | } | ||
290 | |||
291 | fn program_clause_data<'a>( | ||
292 | &self, | ||
293 | clause: &'a chalk_ir::ProgramClauseData<Self>, | ||
294 | ) -> &'a chalk_ir::ProgramClauseData<Self> { | ||
295 | clause | ||
296 | } | ||
297 | |||
298 | fn intern_program_clauses<E>( | ||
299 | &self, | ||
300 | data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, | ||
301 | ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> { | ||
302 | data.into_iter().collect() | ||
303 | } | ||
304 | |||
305 | fn program_clauses_data<'a>( | ||
306 | &self, | ||
307 | clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>, | ||
308 | ) -> &'a [chalk_ir::ProgramClause<Self>] { | ||
309 | &clauses | ||
310 | } | ||
311 | |||
312 | fn intern_quantified_where_clauses<E>( | ||
313 | &self, | ||
314 | data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, | ||
315 | ) -> Result<Self::InternedQuantifiedWhereClauses, E> { | ||
316 | data.into_iter().collect() | ||
317 | } | ||
318 | |||
319 | fn quantified_where_clauses_data<'a>( | ||
320 | &self, | ||
321 | clauses: &'a Self::InternedQuantifiedWhereClauses, | ||
322 | ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] { | ||
323 | clauses | ||
324 | } | ||
325 | |||
326 | fn intern_generic_arg_kinds<E>( | ||
327 | &self, | ||
328 | data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>, | ||
329 | ) -> Result<Self::InternedVariableKinds, E> { | ||
330 | data.into_iter().collect() | ||
331 | } | ||
332 | |||
333 | fn variable_kinds_data<'a>( | ||
334 | &self, | ||
335 | parameter_kinds: &'a Self::InternedVariableKinds, | ||
336 | ) -> &'a [chalk_ir::VariableKind<Self>] { | ||
337 | ¶meter_kinds | ||
338 | } | ||
339 | |||
340 | fn intern_canonical_var_kinds<E>( | ||
341 | &self, | ||
342 | data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>, | ||
343 | ) -> Result<Self::InternedCanonicalVarKinds, E> { | ||
344 | data.into_iter().collect() | ||
345 | } | ||
346 | |||
347 | fn canonical_var_kinds_data<'a>( | ||
348 | &self, | ||
349 | canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, | ||
350 | ) -> &'a [chalk_ir::CanonicalVarKind<Self>] { | ||
351 | &canonical_var_kinds | ||
352 | } | ||
353 | |||
354 | fn intern_constraints<E>( | ||
355 | &self, | ||
356 | data: impl IntoIterator<Item = Result<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>, E>>, | ||
357 | ) -> Result<Self::InternedConstraints, E> { | ||
358 | data.into_iter().collect() | ||
359 | } | ||
360 | |||
361 | fn constraints_data<'a>( | ||
362 | &self, | ||
363 | constraints: &'a Self::InternedConstraints, | ||
364 | ) -> &'a [chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] { | ||
365 | constraints | ||
366 | } | ||
367 | fn debug_closure_id( | ||
368 | _fn_def_id: chalk_ir::ClosureId<Self>, | ||
369 | _fmt: &mut fmt::Formatter<'_>, | ||
370 | ) -> Option<fmt::Result> { | ||
371 | None | ||
372 | } | ||
373 | fn debug_constraints( | ||
374 | _clauses: &chalk_ir::Constraints<Self>, | ||
375 | _fmt: &mut fmt::Formatter<'_>, | ||
376 | ) -> Option<fmt::Result> { | ||
377 | None | ||
378 | } | ||
379 | } | ||
380 | |||
381 | impl chalk_ir::interner::HasInterner for Interner { | ||
382 | type Interner = Self; | ||
383 | } | ||
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs new file mode 100644 index 000000000..fe62f3fa7 --- /dev/null +++ b/crates/hir_ty/src/traits/chalk/mapping.rs | |||
@@ -0,0 +1,787 @@ | |||
1 | //! This module contains the implementations of the `ToChalk` trait, which | ||
2 | //! handles conversion between our data types and their corresponding types in | ||
3 | //! Chalk (in both directions); plus some helper functions for more specialized | ||
4 | //! conversions. | ||
5 | |||
6 | use chalk_ir::{ | ||
7 | cast::Cast, fold::shift::Shift, interner::HasInterner, PlaceholderIndex, Scalar, TypeName, | ||
8 | UniverseIndex, | ||
9 | }; | ||
10 | use chalk_solve::rust_ir; | ||
11 | |||
12 | use base_db::salsa::InternKey; | ||
13 | use hir_def::{type_ref::Mutability, AssocContainerId, GenericDefId, Lookup, TypeAliasId}; | ||
14 | |||
15 | use crate::{ | ||
16 | db::HirDatabase, | ||
17 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, | ||
18 | traits::{Canonical, Obligation}, | ||
19 | ApplicationTy, CallableDefId, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, | ||
20 | ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor, | ||
21 | }; | ||
22 | |||
23 | use super::interner::*; | ||
24 | use super::*; | ||
25 | |||
26 | impl ToChalk for Ty { | ||
27 | type Chalk = chalk_ir::Ty<Interner>; | ||
28 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { | ||
29 | match self { | ||
30 | Ty::Apply(apply_ty) => match apply_ty.ctor { | ||
31 | TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), | ||
32 | TypeCtor::Array => array_to_chalk(db, apply_ty.parameters), | ||
33 | TypeCtor::FnPtr { num_args: _, is_varargs } => { | ||
34 | let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); | ||
35 | chalk_ir::TyData::Function(chalk_ir::FnPointer { | ||
36 | num_binders: 0, | ||
37 | abi: (), | ||
38 | safety: chalk_ir::Safety::Safe, | ||
39 | variadic: is_varargs, | ||
40 | substitution, | ||
41 | }) | ||
42 | .intern(&Interner) | ||
43 | } | ||
44 | _ => { | ||
45 | let name = apply_ty.ctor.to_chalk(db); | ||
46 | let substitution = apply_ty.parameters.to_chalk(db); | ||
47 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
48 | } | ||
49 | }, | ||
50 | Ty::Projection(proj_ty) => { | ||
51 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | ||
52 | let substitution = proj_ty.parameters.to_chalk(db); | ||
53 | chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { | ||
54 | associated_ty_id, | ||
55 | substitution, | ||
56 | }) | ||
57 | .cast(&Interner) | ||
58 | .intern(&Interner) | ||
59 | } | ||
60 | Ty::Placeholder(id) => { | ||
61 | let interned_id = db.intern_type_param_id(id); | ||
62 | PlaceholderIndex { | ||
63 | ui: UniverseIndex::ROOT, | ||
64 | idx: interned_id.as_intern_id().as_usize(), | ||
65 | } | ||
66 | .to_ty::<Interner>(&Interner) | ||
67 | } | ||
68 | Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner), | ||
69 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), | ||
70 | Ty::Dyn(predicates) => { | ||
71 | let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter( | ||
72 | &Interner, | ||
73 | predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)), | ||
74 | ); | ||
75 | let bounded_ty = chalk_ir::DynTy { | ||
76 | bounds: make_binders(where_clauses, 1), | ||
77 | lifetime: FAKE_PLACEHOLDER.to_lifetime(&Interner), | ||
78 | }; | ||
79 | chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) | ||
80 | } | ||
81 | Ty::Opaque(opaque_ty) => { | ||
82 | let opaque_ty_id = opaque_ty.opaque_ty_id.to_chalk(db); | ||
83 | let substitution = opaque_ty.parameters.to_chalk(db); | ||
84 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { | ||
85 | opaque_ty_id, | ||
86 | substitution, | ||
87 | })) | ||
88 | .intern(&Interner) | ||
89 | } | ||
90 | Ty::Unknown => { | ||
91 | let substitution = chalk_ir::Substitution::empty(&Interner); | ||
92 | let name = TypeName::Error; | ||
93 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self { | ||
98 | match chalk.data(&Interner).clone() { | ||
99 | chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { | ||
100 | TypeName::Error => Ty::Unknown, | ||
101 | TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution), | ||
102 | TypeName::Array => array_from_chalk(db, apply_ty.substitution), | ||
103 | _ => { | ||
104 | let ctor = from_chalk(db, apply_ty.name); | ||
105 | let parameters = from_chalk(db, apply_ty.substitution); | ||
106 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
107 | } | ||
108 | }, | ||
109 | chalk_ir::TyData::Placeholder(idx) => { | ||
110 | assert_eq!(idx.ui, UniverseIndex::ROOT); | ||
111 | let interned_id = crate::db::GlobalTypeParamId::from_intern_id( | ||
112 | crate::salsa::InternId::from(idx.idx), | ||
113 | ); | ||
114 | Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) | ||
115 | } | ||
116 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => { | ||
117 | let associated_ty = from_chalk(db, proj.associated_ty_id); | ||
118 | let parameters = from_chalk(db, proj.substitution); | ||
119 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | ||
120 | } | ||
121 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => { | ||
122 | let impl_trait_id = from_chalk(db, opaque_ty.opaque_ty_id); | ||
123 | let parameters = from_chalk(db, opaque_ty.substitution); | ||
124 | Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) | ||
125 | } | ||
126 | chalk_ir::TyData::Function(chalk_ir::FnPointer { | ||
127 | num_binders, | ||
128 | variadic, | ||
129 | substitution, | ||
130 | .. | ||
131 | }) => { | ||
132 | assert_eq!(num_binders, 0); | ||
133 | let parameters: Substs = from_chalk( | ||
134 | db, | ||
135 | substitution.shifted_out(&Interner).expect("fn ptr should have no binders"), | ||
136 | ); | ||
137 | Ty::Apply(ApplicationTy { | ||
138 | ctor: TypeCtor::FnPtr { | ||
139 | num_args: (parameters.len() - 1) as u16, | ||
140 | is_varargs: variadic, | ||
141 | }, | ||
142 | parameters, | ||
143 | }) | ||
144 | } | ||
145 | chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), | ||
146 | chalk_ir::TyData::InferenceVar(_iv, _kind) => Ty::Unknown, | ||
147 | chalk_ir::TyData::Dyn(where_clauses) => { | ||
148 | assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); | ||
149 | let predicates = where_clauses | ||
150 | .bounds | ||
151 | .skip_binders() | ||
152 | .iter(&Interner) | ||
153 | .map(|c| from_chalk(db, c.clone())) | ||
154 | .collect(); | ||
155 | Ty::Dyn(predicates) | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | const FAKE_PLACEHOLDER: PlaceholderIndex = | ||
162 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX }; | ||
163 | |||
164 | /// We currently don't model lifetimes, but Chalk does. So, we have to insert a | ||
165 | /// fake lifetime here, because Chalks built-in logic may expect it to be there. | ||
166 | fn ref_to_chalk( | ||
167 | db: &dyn HirDatabase, | ||
168 | mutability: Mutability, | ||
169 | subst: Substs, | ||
170 | ) -> chalk_ir::Ty<Interner> { | ||
171 | let arg = subst[0].clone().to_chalk(db); | ||
172 | let lifetime = FAKE_PLACEHOLDER.to_lifetime(&Interner); | ||
173 | chalk_ir::ApplicationTy { | ||
174 | name: TypeName::Ref(mutability.to_chalk(db)), | ||
175 | substitution: chalk_ir::Substitution::from_iter( | ||
176 | &Interner, | ||
177 | vec![lifetime.cast(&Interner), arg.cast(&Interner)], | ||
178 | ), | ||
179 | } | ||
180 | .intern(&Interner) | ||
181 | } | ||
182 | |||
183 | /// Here we remove the lifetime from the type we got from Chalk. | ||
184 | fn ref_from_chalk( | ||
185 | db: &dyn HirDatabase, | ||
186 | mutability: chalk_ir::Mutability, | ||
187 | subst: chalk_ir::Substitution<Interner>, | ||
188 | ) -> Ty { | ||
189 | let tys = subst | ||
190 | .iter(&Interner) | ||
191 | .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone()))) | ||
192 | .collect(); | ||
193 | Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys)) | ||
194 | } | ||
195 | |||
196 | /// We currently don't model constants, but Chalk does. So, we have to insert a | ||
197 | /// fake constant here, because Chalks built-in logic may expect it to be there. | ||
198 | fn array_to_chalk(db: &dyn HirDatabase, subst: Substs) -> chalk_ir::Ty<Interner> { | ||
199 | let arg = subst[0].clone().to_chalk(db); | ||
200 | let usize_ty = chalk_ir::ApplicationTy { | ||
201 | name: TypeName::Scalar(Scalar::Uint(chalk_ir::UintTy::Usize)), | ||
202 | substitution: chalk_ir::Substitution::empty(&Interner), | ||
203 | } | ||
204 | .intern(&Interner); | ||
205 | let const_ = FAKE_PLACEHOLDER.to_const(&Interner, usize_ty); | ||
206 | chalk_ir::ApplicationTy { | ||
207 | name: TypeName::Array, | ||
208 | substitution: chalk_ir::Substitution::from_iter( | ||
209 | &Interner, | ||
210 | vec![arg.cast(&Interner), const_.cast(&Interner)], | ||
211 | ), | ||
212 | } | ||
213 | .intern(&Interner) | ||
214 | } | ||
215 | |||
216 | /// Here we remove the const from the type we got from Chalk. | ||
217 | fn array_from_chalk(db: &dyn HirDatabase, subst: chalk_ir::Substitution<Interner>) -> Ty { | ||
218 | let tys = subst | ||
219 | .iter(&Interner) | ||
220 | .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone()))) | ||
221 | .collect(); | ||
222 | Ty::apply(TypeCtor::Array, Substs(tys)) | ||
223 | } | ||
224 | |||
225 | impl ToChalk for Substs { | ||
226 | type Chalk = chalk_ir::Substitution<Interner>; | ||
227 | |||
228 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> { | ||
229 | chalk_ir::Substitution::from_iter(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db))) | ||
230 | } | ||
231 | |||
232 | fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs { | ||
233 | let tys = parameters | ||
234 | .iter(&Interner) | ||
235 | .map(|p| match p.ty(&Interner) { | ||
236 | Some(ty) => from_chalk(db, ty.clone()), | ||
237 | None => unimplemented!(), | ||
238 | }) | ||
239 | .collect(); | ||
240 | Substs(tys) | ||
241 | } | ||
242 | } | ||
243 | |||
244 | impl ToChalk for TraitRef { | ||
245 | type Chalk = chalk_ir::TraitRef<Interner>; | ||
246 | |||
247 | fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> { | ||
248 | let trait_id = self.trait_.to_chalk(db); | ||
249 | let substitution = self.substs.to_chalk(db); | ||
250 | chalk_ir::TraitRef { trait_id, substitution } | ||
251 | } | ||
252 | |||
253 | fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self { | ||
254 | let trait_ = from_chalk(db, trait_ref.trait_id); | ||
255 | let substs = from_chalk(db, trait_ref.substitution); | ||
256 | TraitRef { trait_, substs } | ||
257 | } | ||
258 | } | ||
259 | |||
260 | impl ToChalk for hir_def::TraitId { | ||
261 | type Chalk = TraitId; | ||
262 | |||
263 | fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId { | ||
264 | chalk_ir::TraitId(self.as_intern_id()) | ||
265 | } | ||
266 | |||
267 | fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId { | ||
268 | InternKey::from_intern_id(trait_id.0) | ||
269 | } | ||
270 | } | ||
271 | |||
272 | impl ToChalk for OpaqueTyId { | ||
273 | type Chalk = chalk_ir::OpaqueTyId<Interner>; | ||
274 | |||
275 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::OpaqueTyId<Interner> { | ||
276 | db.intern_impl_trait_id(self).into() | ||
277 | } | ||
278 | |||
279 | fn from_chalk( | ||
280 | db: &dyn HirDatabase, | ||
281 | opaque_ty_id: chalk_ir::OpaqueTyId<Interner>, | ||
282 | ) -> OpaqueTyId { | ||
283 | db.lookup_intern_impl_trait_id(opaque_ty_id.into()) | ||
284 | } | ||
285 | } | ||
286 | |||
287 | impl ToChalk for TypeCtor { | ||
288 | type Chalk = TypeName<Interner>; | ||
289 | |||
290 | fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> { | ||
291 | match self { | ||
292 | TypeCtor::AssociatedType(type_alias) => { | ||
293 | let type_id = type_alias.to_chalk(db); | ||
294 | TypeName::AssociatedType(type_id) | ||
295 | } | ||
296 | |||
297 | TypeCtor::OpaqueType(impl_trait_id) => { | ||
298 | let id = impl_trait_id.to_chalk(db); | ||
299 | TypeName::OpaqueType(id) | ||
300 | } | ||
301 | |||
302 | TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), | ||
303 | TypeCtor::Char => TypeName::Scalar(Scalar::Char), | ||
304 | TypeCtor::Int(int_ty) => TypeName::Scalar(int_ty_to_chalk(int_ty)), | ||
305 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 }) => { | ||
306 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) | ||
307 | } | ||
308 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 }) => { | ||
309 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) | ||
310 | } | ||
311 | |||
312 | TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()), | ||
313 | TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)), | ||
314 | TypeCtor::Slice => TypeName::Slice, | ||
315 | TypeCtor::Array => TypeName::Array, | ||
316 | TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)), | ||
317 | TypeCtor::Str => TypeName::Str, | ||
318 | TypeCtor::FnDef(callable_def) => { | ||
319 | let id = callable_def.to_chalk(db); | ||
320 | TypeName::FnDef(id) | ||
321 | } | ||
322 | TypeCtor::Never => TypeName::Never, | ||
323 | |||
324 | TypeCtor::Closure { def, expr } => { | ||
325 | let closure_id = db.intern_closure((def, expr)); | ||
326 | TypeName::Closure(closure_id.into()) | ||
327 | } | ||
328 | |||
329 | TypeCtor::Adt(adt_id) => TypeName::Adt(chalk_ir::AdtId(adt_id)), | ||
330 | |||
331 | TypeCtor::FnPtr { .. } => { | ||
332 | // This should not be reached, since Chalk doesn't represent | ||
333 | // function pointers with TypeName | ||
334 | unreachable!() | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | |||
339 | fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor { | ||
340 | match type_name { | ||
341 | TypeName::Adt(struct_id) => TypeCtor::Adt(struct_id.0), | ||
342 | TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), | ||
343 | TypeName::OpaqueType(opaque_type_id) => { | ||
344 | TypeCtor::OpaqueType(from_chalk(db, opaque_type_id)) | ||
345 | } | ||
346 | |||
347 | TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, | ||
348 | TypeName::Scalar(Scalar::Char) => TypeCtor::Char, | ||
349 | TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(IntTy { | ||
350 | signedness: Signedness::Signed, | ||
351 | bitness: bitness_from_chalk_int(int_ty), | ||
352 | }), | ||
353 | TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(IntTy { | ||
354 | signedness: Signedness::Unsigned, | ||
355 | bitness: bitness_from_chalk_uint(uint_ty), | ||
356 | }), | ||
357 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => { | ||
358 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 }) | ||
359 | } | ||
360 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => { | ||
361 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 }) | ||
362 | } | ||
363 | TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 }, | ||
364 | TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)), | ||
365 | TypeName::Slice => TypeCtor::Slice, | ||
366 | TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)), | ||
367 | TypeName::Str => TypeCtor::Str, | ||
368 | TypeName::Never => TypeCtor::Never, | ||
369 | |||
370 | TypeName::FnDef(fn_def_id) => { | ||
371 | let callable_def = from_chalk(db, fn_def_id); | ||
372 | TypeCtor::FnDef(callable_def) | ||
373 | } | ||
374 | TypeName::Array => TypeCtor::Array, | ||
375 | |||
376 | TypeName::Closure(id) => { | ||
377 | let id: crate::db::ClosureId = id.into(); | ||
378 | let (def, expr) = db.lookup_intern_closure(id); | ||
379 | TypeCtor::Closure { def, expr } | ||
380 | } | ||
381 | |||
382 | TypeName::Error => { | ||
383 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor | ||
384 | unreachable!() | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | |||
390 | fn bitness_from_chalk_uint(uint_ty: chalk_ir::UintTy) -> IntBitness { | ||
391 | use chalk_ir::UintTy; | ||
392 | |||
393 | match uint_ty { | ||
394 | UintTy::Usize => IntBitness::Xsize, | ||
395 | UintTy::U8 => IntBitness::X8, | ||
396 | UintTy::U16 => IntBitness::X16, | ||
397 | UintTy::U32 => IntBitness::X32, | ||
398 | UintTy::U64 => IntBitness::X64, | ||
399 | UintTy::U128 => IntBitness::X128, | ||
400 | } | ||
401 | } | ||
402 | |||
403 | fn bitness_from_chalk_int(int_ty: chalk_ir::IntTy) -> IntBitness { | ||
404 | use chalk_ir::IntTy; | ||
405 | |||
406 | match int_ty { | ||
407 | IntTy::Isize => IntBitness::Xsize, | ||
408 | IntTy::I8 => IntBitness::X8, | ||
409 | IntTy::I16 => IntBitness::X16, | ||
410 | IntTy::I32 => IntBitness::X32, | ||
411 | IntTy::I64 => IntBitness::X64, | ||
412 | IntTy::I128 => IntBitness::X128, | ||
413 | } | ||
414 | } | ||
415 | |||
416 | fn int_ty_to_chalk(int_ty: IntTy) -> Scalar { | ||
417 | use chalk_ir::{IntTy, UintTy}; | ||
418 | |||
419 | match int_ty.signedness { | ||
420 | Signedness::Signed => Scalar::Int(match int_ty.bitness { | ||
421 | IntBitness::Xsize => IntTy::Isize, | ||
422 | IntBitness::X8 => IntTy::I8, | ||
423 | IntBitness::X16 => IntTy::I16, | ||
424 | IntBitness::X32 => IntTy::I32, | ||
425 | IntBitness::X64 => IntTy::I64, | ||
426 | IntBitness::X128 => IntTy::I128, | ||
427 | }), | ||
428 | Signedness::Unsigned => Scalar::Uint(match int_ty.bitness { | ||
429 | IntBitness::Xsize => UintTy::Usize, | ||
430 | IntBitness::X8 => UintTy::U8, | ||
431 | IntBitness::X16 => UintTy::U16, | ||
432 | IntBitness::X32 => UintTy::U32, | ||
433 | IntBitness::X64 => UintTy::U64, | ||
434 | IntBitness::X128 => UintTy::U128, | ||
435 | }), | ||
436 | } | ||
437 | } | ||
438 | |||
439 | impl ToChalk for Mutability { | ||
440 | type Chalk = chalk_ir::Mutability; | ||
441 | fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk { | ||
442 | match self { | ||
443 | Mutability::Shared => chalk_ir::Mutability::Not, | ||
444 | Mutability::Mut => chalk_ir::Mutability::Mut, | ||
445 | } | ||
446 | } | ||
447 | fn from_chalk(_db: &dyn HirDatabase, chalk: Self::Chalk) -> Self { | ||
448 | match chalk { | ||
449 | chalk_ir::Mutability::Mut => Mutability::Mut, | ||
450 | chalk_ir::Mutability::Not => Mutability::Shared, | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | |||
455 | impl ToChalk for hir_def::ImplId { | ||
456 | type Chalk = ImplId; | ||
457 | |||
458 | fn to_chalk(self, _db: &dyn HirDatabase) -> ImplId { | ||
459 | chalk_ir::ImplId(self.as_intern_id()) | ||
460 | } | ||
461 | |||
462 | fn from_chalk(_db: &dyn HirDatabase, impl_id: ImplId) -> hir_def::ImplId { | ||
463 | InternKey::from_intern_id(impl_id.0) | ||
464 | } | ||
465 | } | ||
466 | |||
467 | impl ToChalk for CallableDefId { | ||
468 | type Chalk = FnDefId; | ||
469 | |||
470 | fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { | ||
471 | db.intern_callable_def(self).into() | ||
472 | } | ||
473 | |||
474 | fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId { | ||
475 | db.lookup_intern_callable_def(fn_def_id.into()) | ||
476 | } | ||
477 | } | ||
478 | |||
479 | impl ToChalk for TypeAliasId { | ||
480 | type Chalk = AssocTypeId; | ||
481 | |||
482 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId { | ||
483 | chalk_ir::AssocTypeId(self.as_intern_id()) | ||
484 | } | ||
485 | |||
486 | fn from_chalk(_db: &dyn HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { | ||
487 | InternKey::from_intern_id(type_alias_id.0) | ||
488 | } | ||
489 | } | ||
490 | |||
491 | pub struct TypeAliasAsValue(pub TypeAliasId); | ||
492 | |||
493 | impl ToChalk for TypeAliasAsValue { | ||
494 | type Chalk = AssociatedTyValueId; | ||
495 | |||
496 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssociatedTyValueId { | ||
497 | rust_ir::AssociatedTyValueId(self.0.as_intern_id()) | ||
498 | } | ||
499 | |||
500 | fn from_chalk( | ||
501 | _db: &dyn HirDatabase, | ||
502 | assoc_ty_value_id: AssociatedTyValueId, | ||
503 | ) -> TypeAliasAsValue { | ||
504 | TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0)) | ||
505 | } | ||
506 | } | ||
507 | |||
508 | impl ToChalk for GenericPredicate { | ||
509 | type Chalk = chalk_ir::QuantifiedWhereClause<Interner>; | ||
510 | |||
511 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> { | ||
512 | match self { | ||
513 | GenericPredicate::Implemented(trait_ref) => { | ||
514 | let chalk_trait_ref = trait_ref.to_chalk(db); | ||
515 | let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner); | ||
516 | make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0) | ||
517 | } | ||
518 | GenericPredicate::Projection(projection_pred) => { | ||
519 | let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner); | ||
520 | let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner); | ||
521 | let alias = chalk_ir::AliasTy::Projection(projection); | ||
522 | make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0) | ||
523 | } | ||
524 | GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), | ||
525 | } | ||
526 | } | ||
527 | |||
528 | fn from_chalk( | ||
529 | db: &dyn HirDatabase, | ||
530 | where_clause: chalk_ir::QuantifiedWhereClause<Interner>, | ||
531 | ) -> GenericPredicate { | ||
532 | // we don't produce any where clauses with binders and can't currently deal with them | ||
533 | match where_clause | ||
534 | .skip_binders() | ||
535 | .shifted_out(&Interner) | ||
536 | .expect("unexpected bound vars in where clause") | ||
537 | { | ||
538 | chalk_ir::WhereClause::Implemented(tr) => { | ||
539 | GenericPredicate::Implemented(from_chalk(db, tr)) | ||
540 | } | ||
541 | chalk_ir::WhereClause::AliasEq(projection_eq) => { | ||
542 | let projection_ty = from_chalk( | ||
543 | db, | ||
544 | match projection_eq.alias { | ||
545 | chalk_ir::AliasTy::Projection(p) => p, | ||
546 | _ => unimplemented!(), | ||
547 | }, | ||
548 | ); | ||
549 | let ty = from_chalk(db, projection_eq.ty); | ||
550 | GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty }) | ||
551 | } | ||
552 | |||
553 | chalk_ir::WhereClause::LifetimeOutlives(_) => { | ||
554 | // we shouldn't get these from Chalk | ||
555 | panic!("encountered LifetimeOutlives from Chalk") | ||
556 | } | ||
557 | |||
558 | chalk_ir::WhereClause::TypeOutlives(_) => { | ||
559 | // we shouldn't get these from Chalk | ||
560 | panic!("encountered TypeOutlives from Chalk") | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | |||
566 | impl ToChalk for ProjectionTy { | ||
567 | type Chalk = chalk_ir::ProjectionTy<Interner>; | ||
568 | |||
569 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> { | ||
570 | chalk_ir::ProjectionTy { | ||
571 | associated_ty_id: self.associated_ty.to_chalk(db), | ||
572 | substitution: self.parameters.to_chalk(db), | ||
573 | } | ||
574 | } | ||
575 | |||
576 | fn from_chalk( | ||
577 | db: &dyn HirDatabase, | ||
578 | projection_ty: chalk_ir::ProjectionTy<Interner>, | ||
579 | ) -> ProjectionTy { | ||
580 | ProjectionTy { | ||
581 | associated_ty: from_chalk(db, projection_ty.associated_ty_id), | ||
582 | parameters: from_chalk(db, projection_ty.substitution), | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | |||
587 | impl ToChalk for ProjectionPredicate { | ||
588 | type Chalk = chalk_ir::AliasEq<Interner>; | ||
589 | |||
590 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { | ||
591 | chalk_ir::AliasEq { | ||
592 | alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)), | ||
593 | ty: self.ty.to_chalk(db), | ||
594 | } | ||
595 | } | ||
596 | |||
597 | fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { | ||
598 | unimplemented!() | ||
599 | } | ||
600 | } | ||
601 | |||
602 | impl ToChalk for Obligation { | ||
603 | type Chalk = chalk_ir::DomainGoal<Interner>; | ||
604 | |||
605 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> { | ||
606 | match self { | ||
607 | Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner), | ||
608 | Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner), | ||
609 | } | ||
610 | } | ||
611 | |||
612 | fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self { | ||
613 | unimplemented!() | ||
614 | } | ||
615 | } | ||
616 | |||
617 | impl<T> ToChalk for Canonical<T> | ||
618 | where | ||
619 | T: ToChalk, | ||
620 | T::Chalk: HasInterner<Interner = Interner>, | ||
621 | { | ||
622 | type Chalk = chalk_ir::Canonical<T::Chalk>; | ||
623 | |||
624 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | ||
625 | let kinds = self | ||
626 | .kinds | ||
627 | .iter() | ||
628 | .map(|k| match k { | ||
629 | TyKind::General => chalk_ir::TyKind::General, | ||
630 | TyKind::Integer => chalk_ir::TyKind::Integer, | ||
631 | TyKind::Float => chalk_ir::TyKind::Float, | ||
632 | }) | ||
633 | .map(|tk| { | ||
634 | chalk_ir::CanonicalVarKind::new( | ||
635 | chalk_ir::VariableKind::Ty(tk), | ||
636 | chalk_ir::UniverseIndex::ROOT, | ||
637 | ) | ||
638 | }); | ||
639 | let value = self.value.to_chalk(db); | ||
640 | chalk_ir::Canonical { | ||
641 | value, | ||
642 | binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds), | ||
643 | } | ||
644 | } | ||
645 | |||
646 | fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | ||
647 | let kinds = canonical | ||
648 | .binders | ||
649 | .iter(&Interner) | ||
650 | .map(|k| match k.kind { | ||
651 | chalk_ir::VariableKind::Ty(tk) => match tk { | ||
652 | chalk_ir::TyKind::General => TyKind::General, | ||
653 | chalk_ir::TyKind::Integer => TyKind::Integer, | ||
654 | chalk_ir::TyKind::Float => TyKind::Float, | ||
655 | }, | ||
656 | chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"), | ||
657 | chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"), | ||
658 | }) | ||
659 | .collect(); | ||
660 | Canonical { kinds, value: from_chalk(db, canonical.value) } | ||
661 | } | ||
662 | } | ||
663 | |||
664 | impl ToChalk for Arc<TraitEnvironment> { | ||
665 | type Chalk = chalk_ir::Environment<Interner>; | ||
666 | |||
667 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Environment<Interner> { | ||
668 | let mut clauses = Vec::new(); | ||
669 | for pred in &self.predicates { | ||
670 | if pred.is_error() { | ||
671 | // for env, we just ignore errors | ||
672 | continue; | ||
673 | } | ||
674 | let program_clause: chalk_ir::ProgramClause<Interner> = | ||
675 | pred.clone().to_chalk(db).cast(&Interner); | ||
676 | clauses.push(program_clause.into_from_env_clause(&Interner)); | ||
677 | } | ||
678 | chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses) | ||
679 | } | ||
680 | |||
681 | fn from_chalk( | ||
682 | _db: &dyn HirDatabase, | ||
683 | _env: chalk_ir::Environment<Interner>, | ||
684 | ) -> Arc<TraitEnvironment> { | ||
685 | unimplemented!() | ||
686 | } | ||
687 | } | ||
688 | |||
689 | impl<T: ToChalk> ToChalk for InEnvironment<T> | ||
690 | where | ||
691 | T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>, | ||
692 | { | ||
693 | type Chalk = chalk_ir::InEnvironment<T::Chalk>; | ||
694 | |||
695 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { | ||
696 | chalk_ir::InEnvironment { | ||
697 | environment: self.environment.to_chalk(db), | ||
698 | goal: self.value.to_chalk(db), | ||
699 | } | ||
700 | } | ||
701 | |||
702 | fn from_chalk( | ||
703 | db: &dyn HirDatabase, | ||
704 | in_env: chalk_ir::InEnvironment<T::Chalk>, | ||
705 | ) -> InEnvironment<T> { | ||
706 | InEnvironment { | ||
707 | environment: from_chalk(db, in_env.environment), | ||
708 | value: from_chalk(db, in_env.goal), | ||
709 | } | ||
710 | } | ||
711 | } | ||
712 | |||
713 | pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> | ||
714 | where | ||
715 | T: HasInterner<Interner = Interner>, | ||
716 | { | ||
717 | chalk_ir::Binders::new( | ||
718 | chalk_ir::VariableKinds::from_iter( | ||
719 | &Interner, | ||
720 | std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)).take(num_vars), | ||
721 | ), | ||
722 | value, | ||
723 | ) | ||
724 | } | ||
725 | |||
726 | pub(super) fn convert_where_clauses( | ||
727 | db: &dyn HirDatabase, | ||
728 | def: GenericDefId, | ||
729 | substs: &Substs, | ||
730 | ) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> { | ||
731 | let generic_predicates = db.generic_predicates(def); | ||
732 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
733 | for pred in generic_predicates.iter() { | ||
734 | if pred.value.is_error() { | ||
735 | // skip errored predicates completely | ||
736 | continue; | ||
737 | } | ||
738 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
739 | } | ||
740 | result | ||
741 | } | ||
742 | |||
743 | pub(super) fn generic_predicate_to_inline_bound( | ||
744 | db: &dyn HirDatabase, | ||
745 | pred: &GenericPredicate, | ||
746 | self_ty: &Ty, | ||
747 | ) -> Option<rust_ir::InlineBound<Interner>> { | ||
748 | // An InlineBound is like a GenericPredicate, except the self type is left out. | ||
749 | // We don't have a special type for this, but Chalk does. | ||
750 | match pred { | ||
751 | GenericPredicate::Implemented(trait_ref) => { | ||
752 | if &trait_ref.substs[0] != self_ty { | ||
753 | // we can only convert predicates back to type bounds if they | ||
754 | // have the expected self type | ||
755 | return None; | ||
756 | } | ||
757 | let args_no_self = trait_ref.substs[1..] | ||
758 | .iter() | ||
759 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
760 | .collect(); | ||
761 | let trait_bound = | ||
762 | rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; | ||
763 | Some(rust_ir::InlineBound::TraitBound(trait_bound)) | ||
764 | } | ||
765 | GenericPredicate::Projection(proj) => { | ||
766 | if &proj.projection_ty.parameters[0] != self_ty { | ||
767 | return None; | ||
768 | } | ||
769 | let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container { | ||
770 | AssocContainerId::TraitId(t) => t, | ||
771 | _ => panic!("associated type not in trait"), | ||
772 | }; | ||
773 | let args_no_self = proj.projection_ty.parameters[1..] | ||
774 | .iter() | ||
775 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | ||
776 | .collect(); | ||
777 | let alias_eq_bound = rust_ir::AliasEqBound { | ||
778 | value: proj.ty.clone().to_chalk(db), | ||
779 | trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, | ||
780 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), | ||
781 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | ||
782 | }; | ||
783 | Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) | ||
784 | } | ||
785 | GenericPredicate::Error => None, | ||
786 | } | ||
787 | } | ||
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. | ||
2 | use std::fmt; | ||
3 | |||
4 | use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication, TypeName}; | ||
5 | use itertools::Itertools; | ||
6 | |||
7 | use super::{from_chalk, Interner}; | ||
8 | use crate::{db::HirDatabase, CallableDefId, TypeCtor}; | ||
9 | use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId}; | ||
10 | |||
11 | pub use unsafe_tls::{set_current_program, with_current_program}; | ||
12 | |||
13 | pub struct DebugContext<'a>(&'a dyn HirDatabase); | ||
14 | |||
15 | impl 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 {}", ¶ms[0], trait_data.name,)?; | ||
162 | if params.len() > 1 { | ||
163 | write!( | ||
164 | fmt, | ||
165 | "<{}>", | ||
166 | ¶ms[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 | |||
327 | mod 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 | } | ||