aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/traits/chalk.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-05-04 19:07:09 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-05-04 19:07:09 +0100
commit9c49f6c36e1e097f938946811d1e2f5eb70edca9 (patch)
tree544bfd290a08475b1d5250bcc5e0717779b53758 /crates/ra_hir/src/ty/traits/chalk.rs
parentb6ffb1d2a3bcc94e41c95c7a086117e11ce487e5 (diff)
parenta4eb1a546c7623f65823c5e249cd3c6d8c90fd8c (diff)
Merge #1216
1216: Basic Chalk integration r=matklad a=flodiebold This replaces the ad-hoc `implements` check by Chalk. It doesn't yet any new functionality (e.g. where clauses aren't passed to Chalk yet). The tests that exist actually work, but it needs some refactoring, currently crashes when running analysis on the RA repo, and depends on rust-lang/chalk#216 which isn't merged yet :smile: The main work here is converting stuff back and forth and providing Chalk with the information it needs, and the canonicalization logic. Since canonicalization depends a lot on the inference table, I don't think we can currently reuse the logic from Chalk, so we need to implement it ourselves; it's not actually that complicated anyway ;) I realized that we need a `Ty::Bound` variant separate from `Ty::Param` -- these are two different things, and I think type parameters inside a function actually need to be represented in Chalk as `Placeholder` types. ~~Currently this crashes in the 'real' world because we don't yet do canonicalization when filtering method candidates. Proper canonicalization needs the inference table (to collapse different inference variables that have already been unified), but we need to be able to call the method candidate selection from the completion code... So I'm currently thinking how to best handle that :smile:~~ Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty/traits/chalk.rs')
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs333
1 files changed, 333 insertions, 0 deletions
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
new file mode 100644
index 000000000..8b77d21b4
--- /dev/null
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -0,0 +1,333 @@
1//! Conversion code from/to Chalk.
2use std::sync::Arc;
3
4use log::debug;
5
6use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName};
7use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum};
8
9use ra_db::salsa::{InternId, InternKey};
10
11use crate::{
12 Trait, HasGenericParams, ImplBlock,
13 db::HirDatabase,
14 ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs},
15};
16use super::ChalkContext;
17
18pub(super) trait ToChalk {
19 type Chalk;
20 fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk;
21 fn from_chalk(db: &impl HirDatabase, chalk: Self::Chalk) -> Self;
22}
23
24pub(super) fn from_chalk<T, ChalkT>(db: &impl HirDatabase, chalk: ChalkT) -> T
25where
26 T: ToChalk<Chalk = ChalkT>,
27{
28 T::from_chalk(db, chalk)
29}
30
31impl ToChalk for Ty {
32 type Chalk = chalk_ir::Ty;
33 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty {
34 match self {
35 Ty::Apply(apply_ty) => {
36 let struct_id = apply_ty.ctor.to_chalk(db);
37 let name = TypeName::TypeKindId(struct_id.into());
38 let parameters = apply_ty.parameters.to_chalk(db);
39 chalk_ir::ApplicationTy { name, parameters }.cast()
40 }
41 Ty::Param { idx, .. } => {
42 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty()
43 }
44 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize),
45 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
46 // FIXME this is clearly incorrect, but probably not too incorrect
47 // and I'm not sure what to actually do with Ty::Unknown
48 Ty::Unknown => PlaceholderIndex { ui: UniverseIndex::ROOT, idx: 0 }.to_ty(),
49 }
50 }
51 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self {
52 match chalk {
53 chalk_ir::Ty::Apply(apply_ty) => {
54 match apply_ty.name {
55 TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => {
56 let ctor = from_chalk(db, struct_id);
57 let parameters = from_chalk(db, apply_ty.parameters);
58 Ty::Apply(ApplicationTy { ctor, parameters })
59 }
60 // FIXME handle TypeKindId::Trait/Type here
61 TypeName::TypeKindId(_) => unimplemented!(),
62 TypeName::AssociatedType(_) => unimplemented!(),
63 TypeName::Placeholder(idx) => {
64 assert_eq!(idx.ui, UniverseIndex::ROOT);
65 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
66 }
67 }
68 }
69 chalk_ir::Ty::Projection(_) => unimplemented!(),
70 chalk_ir::Ty::UnselectedProjection(_) => unimplemented!(),
71 chalk_ir::Ty::ForAll(_) => unimplemented!(),
72 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
73 chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"),
74 }
75 }
76}
77
78impl ToChalk for Substs {
79 type Chalk = Vec<chalk_ir::Parameter>;
80
81 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter> {
82 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect()
83 }
84
85 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs {
86 parameters
87 .into_iter()
88 .map(|p| match p {
89 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
90 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
91 })
92 .collect::<Vec<_>>()
93 .into()
94 }
95}
96
97impl ToChalk for TraitRef {
98 type Chalk = chalk_ir::TraitRef;
99
100 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef {
101 let trait_id = self.trait_.to_chalk(db);
102 let parameters = self.substs.to_chalk(db);
103 chalk_ir::TraitRef { trait_id, parameters }
104 }
105
106 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self {
107 let trait_ = from_chalk(db, trait_ref.trait_id);
108 let substs = from_chalk(db, trait_ref.parameters);
109 TraitRef { trait_, substs }
110 }
111}
112
113impl ToChalk for Trait {
114 type Chalk = chalk_ir::TraitId;
115
116 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId {
117 self.id.into()
118 }
119
120 fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> Trait {
121 Trait { id: trait_id.into() }
122 }
123}
124
125impl ToChalk for TypeCtor {
126 type Chalk = chalk_ir::StructId;
127
128 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::StructId {
129 db.intern_type_ctor(self).into()
130 }
131
132 fn from_chalk(db: &impl HirDatabase, struct_id: chalk_ir::StructId) -> TypeCtor {
133 db.lookup_intern_type_ctor(struct_id.into())
134 }
135}
136
137impl ToChalk for ImplBlock {
138 type Chalk = chalk_ir::ImplId;
139
140 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId {
141 db.intern_impl_block(self).into()
142 }
143
144 fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock {
145 db.lookup_intern_impl_block(impl_id.into())
146 }
147}
148
149fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
150 chalk_ir::Binders {
151 value,
152 binders: std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars).collect(),
153 }
154}
155
156impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
157where
158 DB: HirDatabase,
159{
160 fn associated_ty_data(&self, _ty: TypeId) -> Arc<AssociatedTyDatum> {
161 unimplemented!()
162 }
163 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> {
164 debug!("trait_datum {:?}", trait_id);
165 let trait_: Trait = from_chalk(self.db, trait_id);
166 let generic_params = trait_.generic_params(self.db);
167 let bound_vars = Substs::bound_vars(&generic_params);
168 let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db);
169 let flags = chalk_rust_ir::TraitFlags {
170 // FIXME set these flags correctly
171 auto: false,
172 marker: false,
173 upstream: trait_.module(self.db).krate(self.db) != Some(self.krate),
174 fundamental: false,
175 };
176 let where_clauses = Vec::new(); // FIXME add where clauses
177 let associated_ty_ids = Vec::new(); // FIXME add associated tys
178 let trait_datum_bound =
179 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids };
180 let trait_datum = TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()) };
181 Arc::new(trait_datum)
182 }
183 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
184 debug!("struct_datum {:?}", struct_id);
185 let type_ctor = from_chalk(self.db, struct_id);
186 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor
187 // FIXME extract this to a method on Ty
188 let (num_params, upstream) = match type_ctor {
189 TypeCtor::Bool
190 | TypeCtor::Char
191 | TypeCtor::Int(_)
192 | TypeCtor::Float(_)
193 | TypeCtor::Never
194 | TypeCtor::Str => (0, true),
195 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => (1, true),
196 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, true),
197 TypeCtor::Tuple { cardinality } => (cardinality as usize, true),
198 TypeCtor::FnDef(_) => unimplemented!(),
199 TypeCtor::Adt(adt) => {
200 let generic_params = adt.generic_params(self.db);
201 (
202 generic_params.count_params_including_parent(),
203 adt.krate(self.db) != Some(self.krate),
204 )
205 }
206 };
207 let flags = chalk_rust_ir::StructFlags {
208 upstream,
209 // FIXME set fundamental flag correctly
210 fundamental: false,
211 };
212 let where_clauses = Vec::new(); // FIXME add where clauses
213 let self_ty = chalk_ir::ApplicationTy {
214 name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()),
215 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(),
216 };
217 let struct_datum_bound = chalk_rust_ir::StructDatumBound {
218 self_ty,
219 fields: Vec::new(), // FIXME add fields (only relevant for auto traits)
220 where_clauses,
221 flags,
222 };
223 let struct_datum = StructDatum { binders: make_binders(struct_datum_bound, num_params) };
224 Arc::new(struct_datum)
225 }
226 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
227 debug!("impl_datum {:?}", impl_id);
228 let impl_block: ImplBlock = from_chalk(self.db, impl_id);
229 let generic_params = impl_block.generic_params(self.db);
230 let bound_vars = Substs::bound_vars(&generic_params);
231 let trait_ref = impl_block
232 .target_trait_ref(self.db)
233 .expect("FIXME handle unresolved impl block trait ref")
234 .subst(&bound_vars);
235 let impl_type = if impl_block.module().krate(self.db) == Some(self.krate) {
236 chalk_rust_ir::ImplType::Local
237 } else {
238 chalk_rust_ir::ImplType::External
239 };
240 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
241 // FIXME handle negative impls (impl !Sync for Foo)
242 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)),
243 where_clauses: Vec::new(), // FIXME add where clauses
244 associated_ty_values: Vec::new(), // FIXME add associated type values
245 impl_type,
246 };
247 let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, bound_vars.len()) };
248 Arc::new(impl_datum)
249 }
250 fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> {
251 debug!("impls_for_trait {:?}", trait_id);
252 let trait_ = from_chalk(self.db, trait_id);
253 self.db
254 .impls_for_trait(self.krate, trait_)
255 .iter()
256 // FIXME temporary hack -- as long as we're not lowering where clauses
257 // correctly, ignore impls with them completely so as to not treat
258 // impl<T> Trait for T where T: ... as a blanket impl on all types
259 .filter(|impl_block| impl_block.generic_params(self.db).where_predicates.is_empty())
260 .map(|impl_block| impl_block.to_chalk(self.db))
261 .collect()
262 }
263 fn impl_provided_for(
264 &self,
265 auto_trait_id: chalk_ir::TraitId,
266 struct_id: chalk_ir::StructId,
267 ) -> bool {
268 debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id);
269 false // FIXME
270 }
271 fn type_name(&self, _id: TypeKindId) -> Identifier {
272 unimplemented!()
273 }
274 fn split_projection<'p>(
275 &self,
276 projection: &'p ProjectionTy,
277 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) {
278 debug!("split_projection {:?}", projection);
279 unimplemented!()
280 }
281 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> {
282 debug!("custom_clauses");
283 vec![]
284 }
285 fn all_structs(&self) -> Vec<chalk_ir::StructId> {
286 debug!("all_structs");
287 // FIXME
288 vec![]
289 }
290}
291
292fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
293 T::from_intern_id(InternId::from(chalk_id.index))
294}
295fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId {
296 chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() }
297}
298
299impl From<chalk_ir::TraitId> for crate::ids::TraitId {
300 fn from(trait_id: chalk_ir::TraitId) -> Self {
301 id_from_chalk(trait_id.0)
302 }
303}
304
305impl From<crate::ids::TraitId> for chalk_ir::TraitId {
306 fn from(trait_id: crate::ids::TraitId) -> Self {
307 chalk_ir::TraitId(id_to_chalk(trait_id))
308 }
309}
310
311impl From<chalk_ir::StructId> for crate::ids::TypeCtorId {
312 fn from(struct_id: chalk_ir::StructId) -> Self {
313 id_from_chalk(struct_id.0)
314 }
315}
316
317impl From<crate::ids::TypeCtorId> for chalk_ir::StructId {
318 fn from(type_ctor_id: crate::ids::TypeCtorId) -> Self {
319 chalk_ir::StructId(id_to_chalk(type_ctor_id))
320 }
321}
322
323impl From<chalk_ir::ImplId> for crate::ids::GlobalImplId {
324 fn from(impl_id: chalk_ir::ImplId) -> Self {
325 id_from_chalk(impl_id.0)
326 }
327}
328
329impl From<crate::ids::GlobalImplId> for chalk_ir::ImplId {
330 fn from(impl_id: crate::ids::GlobalImplId) -> Self {
331 chalk_ir::ImplId(id_to_chalk(impl_id))
332 }
333}