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