aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/traits/chalk/mapping.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/traits/chalk/mapping.rs')
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs787
1 files changed, 787 insertions, 0 deletions
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}