diff options
Diffstat (limited to 'crates/hir_ty/src/mapping.rs')
-rw-r--r-- | crates/hir_ty/src/mapping.rs | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/crates/hir_ty/src/mapping.rs b/crates/hir_ty/src/mapping.rs new file mode 100644 index 000000000..4d3c41b2c --- /dev/null +++ b/crates/hir_ty/src/mapping.rs | |||
@@ -0,0 +1,125 @@ | |||
1 | //! This module contains the implementations of the `ToChalk` trait, which | ||
2 | //! handles conversion between our data types and their corresponding types in | ||
3 | //! Chalk (in both directions); plus some helper functions for more specialized | ||
4 | //! conversions. | ||
5 | |||
6 | use chalk_ir::{DebruijnIndex, cast::Cast, fold::Shift}; | ||
7 | use chalk_solve::rust_ir; | ||
8 | |||
9 | use base_db::salsa::InternKey; | ||
10 | use hir_def::{GenericDefId, TypeAliasId}; | ||
11 | |||
12 | use crate::{AliasEq, AliasTy, CallableDefId, FnDefId, Interner, ProjectionTyExt, QuantifiedWhereClause, Substitution, Ty, WhereClause, chalk_db::{self, ToChalk}, db::HirDatabase}; | ||
13 | |||
14 | impl ToChalk for hir_def::TraitId { | ||
15 | type Chalk = chalk_db::TraitId; | ||
16 | |||
17 | fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::TraitId { | ||
18 | chalk_ir::TraitId(self.as_intern_id()) | ||
19 | } | ||
20 | |||
21 | fn from_chalk(_db: &dyn HirDatabase, trait_id: chalk_db::TraitId) -> hir_def::TraitId { | ||
22 | InternKey::from_intern_id(trait_id.0) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | impl ToChalk for hir_def::ImplId { | ||
27 | type Chalk = chalk_db::ImplId; | ||
28 | |||
29 | fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::ImplId { | ||
30 | chalk_ir::ImplId(self.as_intern_id()) | ||
31 | } | ||
32 | |||
33 | fn from_chalk(_db: &dyn HirDatabase, impl_id: chalk_db::ImplId) -> hir_def::ImplId { | ||
34 | InternKey::from_intern_id(impl_id.0) | ||
35 | } | ||
36 | } | ||
37 | |||
38 | impl ToChalk for CallableDefId { | ||
39 | type Chalk = FnDefId; | ||
40 | |||
41 | fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { | ||
42 | db.intern_callable_def(self).into() | ||
43 | } | ||
44 | |||
45 | fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId { | ||
46 | db.lookup_intern_callable_def(fn_def_id.into()) | ||
47 | } | ||
48 | } | ||
49 | |||
50 | pub(crate) struct TypeAliasAsValue(pub(crate) TypeAliasId); | ||
51 | |||
52 | impl ToChalk for TypeAliasAsValue { | ||
53 | type Chalk = chalk_db::AssociatedTyValueId; | ||
54 | |||
55 | fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::AssociatedTyValueId { | ||
56 | rust_ir::AssociatedTyValueId(self.0.as_intern_id()) | ||
57 | } | ||
58 | |||
59 | fn from_chalk( | ||
60 | _db: &dyn HirDatabase, | ||
61 | assoc_ty_value_id: chalk_db::AssociatedTyValueId, | ||
62 | ) -> TypeAliasAsValue { | ||
63 | TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0)) | ||
64 | } | ||
65 | } | ||
66 | |||
67 | pub(super) fn convert_where_clauses( | ||
68 | db: &dyn HirDatabase, | ||
69 | def: GenericDefId, | ||
70 | substs: &Substitution, | ||
71 | ) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> { | ||
72 | let generic_predicates = db.generic_predicates(def); | ||
73 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
74 | for pred in generic_predicates.iter() { | ||
75 | result.push(pred.clone().substitute(&Interner, substs)); | ||
76 | } | ||
77 | result | ||
78 | } | ||
79 | |||
80 | pub(super) fn generic_predicate_to_inline_bound( | ||
81 | db: &dyn HirDatabase, | ||
82 | pred: &QuantifiedWhereClause, | ||
83 | self_ty: &Ty, | ||
84 | ) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> { | ||
85 | // An InlineBound is like a GenericPredicate, except the self type is left out. | ||
86 | // We don't have a special type for this, but Chalk does. | ||
87 | let self_ty_shifted_in = self_ty.clone().shifted_in_from(&Interner, DebruijnIndex::ONE); | ||
88 | let (pred, binders) = pred.as_ref().into_value_and_skipped_binders(); | ||
89 | match pred { | ||
90 | WhereClause::Implemented(trait_ref) => { | ||
91 | if trait_ref.self_type_parameter(&Interner) != self_ty_shifted_in { | ||
92 | // we can only convert predicates back to type bounds if they | ||
93 | // have the expected self type | ||
94 | return None; | ||
95 | } | ||
96 | let args_no_self = trait_ref.substitution.as_slice(&Interner)[1..] | ||
97 | .iter() | ||
98 | .map(|ty| ty.clone().cast(&Interner)) | ||
99 | .collect(); | ||
100 | let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self }; | ||
101 | Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound))) | ||
102 | } | ||
103 | WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { | ||
104 | if projection_ty.self_type_parameter(&Interner) != self_ty_shifted_in { | ||
105 | return None; | ||
106 | } | ||
107 | let trait_ = projection_ty.trait_(db); | ||
108 | let args_no_self = projection_ty.substitution.as_slice(&Interner)[1..] | ||
109 | .iter() | ||
110 | .map(|ty| ty.clone().cast(&Interner)) | ||
111 | .collect(); | ||
112 | let alias_eq_bound = rust_ir::AliasEqBound { | ||
113 | value: ty.clone(), | ||
114 | trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, | ||
115 | associated_ty_id: projection_ty.associated_ty_id, | ||
116 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | ||
117 | }; | ||
118 | Some(chalk_ir::Binders::new( | ||
119 | binders, | ||
120 | rust_ir::InlineBound::AliasEqBound(alias_eq_bound), | ||
121 | )) | ||
122 | } | ||
123 | _ => None, | ||
124 | } | ||
125 | } | ||