diff options
Diffstat (limited to 'crates/ra_hir_ty/src/traits/chalk.rs')
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 906 |
1 files changed, 906 insertions, 0 deletions
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs new file mode 100644 index 000000000..810e8c21a --- /dev/null +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -0,0 +1,906 @@ | |||
1 | //! Conversion code from/to Chalk. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use log::debug; | ||
5 | |||
6 | use chalk_ir::{ | ||
7 | cast::Cast, family::ChalkIr, Identifier, Parameter, PlaceholderIndex, TypeId, TypeKindId, | ||
8 | TypeName, UniverseIndex, | ||
9 | }; | ||
10 | use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; | ||
11 | use ra_db::CrateId; | ||
12 | |||
13 | use hir_def::{ | ||
14 | expr::Expr, lang_item::LangItemTarget, resolver::HasResolver, AssocItemId, AstItemDef, | ||
15 | ContainerId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId, | ||
16 | }; | ||
17 | use hir_expand::name; | ||
18 | |||
19 | use ra_db::salsa::{InternId, InternKey}; | ||
20 | |||
21 | use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; | ||
22 | use crate::{ | ||
23 | db::HirDatabase, | ||
24 | display::HirDisplay, | ||
25 | {ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk}, | ||
26 | }; | ||
27 | |||
28 | /// This represents a trait whose name we could not resolve. | ||
29 | const UNKNOWN_TRAIT: chalk_ir::TraitId = | ||
30 | chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() }); | ||
31 | |||
32 | pub(super) trait ToChalk { | ||
33 | type Chalk; | ||
34 | fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk; | ||
35 | fn from_chalk(db: &impl HirDatabase, chalk: Self::Chalk) -> Self; | ||
36 | } | ||
37 | |||
38 | pub(super) fn from_chalk<T, ChalkT>(db: &impl HirDatabase, chalk: ChalkT) -> T | ||
39 | where | ||
40 | T: ToChalk<Chalk = ChalkT>, | ||
41 | { | ||
42 | T::from_chalk(db, chalk) | ||
43 | } | ||
44 | |||
45 | impl ToChalk for Ty { | ||
46 | type Chalk = chalk_ir::Ty<ChalkIr>; | ||
47 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty<ChalkIr> { | ||
48 | match self { | ||
49 | Ty::Apply(apply_ty) => { | ||
50 | let name = match apply_ty.ctor { | ||
51 | TypeCtor::AssociatedType(type_alias) => { | ||
52 | let type_id = type_alias.to_chalk(db); | ||
53 | TypeName::AssociatedType(type_id) | ||
54 | } | ||
55 | _ => { | ||
56 | // other TypeCtors get interned and turned into a chalk StructId | ||
57 | let struct_id = apply_ty.ctor.to_chalk(db); | ||
58 | TypeName::TypeKindId(struct_id.into()) | ||
59 | } | ||
60 | }; | ||
61 | let parameters = apply_ty.parameters.to_chalk(db); | ||
62 | chalk_ir::ApplicationTy { name, parameters }.cast().intern() | ||
63 | } | ||
64 | Ty::Projection(proj_ty) => { | ||
65 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | ||
66 | let parameters = proj_ty.parameters.to_chalk(db); | ||
67 | chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast().intern() | ||
68 | } | ||
69 | Ty::Param { idx, .. } => { | ||
70 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::<ChalkIr>() | ||
71 | } | ||
72 | Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(), | ||
73 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), | ||
74 | Ty::Dyn(predicates) => { | ||
75 | let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); | ||
76 | chalk_ir::TyData::Dyn(make_binders(where_clauses, 1)).intern() | ||
77 | } | ||
78 | Ty::Opaque(predicates) => { | ||
79 | let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); | ||
80 | chalk_ir::TyData::Opaque(make_binders(where_clauses, 1)).intern() | ||
81 | } | ||
82 | Ty::Unknown => { | ||
83 | let parameters = Vec::new(); | ||
84 | let name = TypeName::Error; | ||
85 | chalk_ir::ApplicationTy { name, parameters }.cast().intern() | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<ChalkIr>) -> Self { | ||
90 | match chalk.data().clone() { | ||
91 | chalk_ir::TyData::Apply(apply_ty) => { | ||
92 | // FIXME this is kind of hacky due to the fact that | ||
93 | // TypeName::Placeholder is a Ty::Param on our side | ||
94 | match apply_ty.name { | ||
95 | TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { | ||
96 | let ctor = from_chalk(db, struct_id); | ||
97 | let parameters = from_chalk(db, apply_ty.parameters); | ||
98 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
99 | } | ||
100 | TypeName::AssociatedType(type_id) => { | ||
101 | let ctor = TypeCtor::AssociatedType(from_chalk(db, type_id)); | ||
102 | let parameters = from_chalk(db, apply_ty.parameters); | ||
103 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
104 | } | ||
105 | TypeName::Error => Ty::Unknown, | ||
106 | // FIXME handle TypeKindId::Trait/Type here | ||
107 | TypeName::TypeKindId(_) => unimplemented!(), | ||
108 | TypeName::Placeholder(idx) => { | ||
109 | assert_eq!(idx.ui, UniverseIndex::ROOT); | ||
110 | Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | chalk_ir::TyData::Projection(proj) => { | ||
115 | let associated_ty = from_chalk(db, proj.associated_ty_id); | ||
116 | let parameters = from_chalk(db, proj.parameters); | ||
117 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | ||
118 | } | ||
119 | chalk_ir::TyData::ForAll(_) => unimplemented!(), | ||
120 | chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx as u32), | ||
121 | chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, | ||
122 | chalk_ir::TyData::Dyn(where_clauses) => { | ||
123 | assert_eq!(where_clauses.binders.len(), 1); | ||
124 | let predicates = | ||
125 | where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); | ||
126 | Ty::Dyn(predicates) | ||
127 | } | ||
128 | chalk_ir::TyData::Opaque(where_clauses) => { | ||
129 | assert_eq!(where_clauses.binders.len(), 1); | ||
130 | let predicates = | ||
131 | where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); | ||
132 | Ty::Opaque(predicates) | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | impl ToChalk for Substs { | ||
139 | type Chalk = Vec<chalk_ir::Parameter<ChalkIr>>; | ||
140 | |||
141 | fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter<ChalkIr>> { | ||
142 | self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect() | ||
143 | } | ||
144 | |||
145 | fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter<ChalkIr>>) -> Substs { | ||
146 | let tys = parameters | ||
147 | .into_iter() | ||
148 | .map(|p| match p { | ||
149 | chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), | ||
150 | chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), | ||
151 | }) | ||
152 | .collect(); | ||
153 | Substs(tys) | ||
154 | } | ||
155 | } | ||
156 | |||
157 | impl ToChalk for TraitRef { | ||
158 | type Chalk = chalk_ir::TraitRef<ChalkIr>; | ||
159 | |||
160 | fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef<ChalkIr> { | ||
161 | let trait_id = self.trait_.to_chalk(db); | ||
162 | let parameters = self.substs.to_chalk(db); | ||
163 | chalk_ir::TraitRef { trait_id, parameters } | ||
164 | } | ||
165 | |||
166 | fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef<ChalkIr>) -> Self { | ||
167 | let trait_ = from_chalk(db, trait_ref.trait_id); | ||
168 | let substs = from_chalk(db, trait_ref.parameters); | ||
169 | TraitRef { trait_, substs } | ||
170 | } | ||
171 | } | ||
172 | |||
173 | impl ToChalk for TraitId { | ||
174 | type Chalk = chalk_ir::TraitId; | ||
175 | |||
176 | fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId { | ||
177 | chalk_ir::TraitId(id_to_chalk(self)) | ||
178 | } | ||
179 | |||
180 | fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> TraitId { | ||
181 | id_from_chalk(trait_id.0) | ||
182 | } | ||
183 | } | ||
184 | |||
185 | impl ToChalk for TypeCtor { | ||
186 | type Chalk = chalk_ir::StructId; | ||
187 | |||
188 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::StructId { | ||
189 | db.intern_type_ctor(self).into() | ||
190 | } | ||
191 | |||
192 | fn from_chalk(db: &impl HirDatabase, struct_id: chalk_ir::StructId) -> TypeCtor { | ||
193 | db.lookup_intern_type_ctor(struct_id.into()) | ||
194 | } | ||
195 | } | ||
196 | |||
197 | impl ToChalk for Impl { | ||
198 | type Chalk = chalk_ir::ImplId; | ||
199 | |||
200 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { | ||
201 | db.intern_chalk_impl(self).into() | ||
202 | } | ||
203 | |||
204 | fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { | ||
205 | db.lookup_intern_chalk_impl(impl_id.into()) | ||
206 | } | ||
207 | } | ||
208 | |||
209 | impl ToChalk for TypeAliasId { | ||
210 | type Chalk = chalk_ir::TypeId; | ||
211 | |||
212 | fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId { | ||
213 | chalk_ir::TypeId(id_to_chalk(self)) | ||
214 | } | ||
215 | |||
216 | fn from_chalk(_db: &impl HirDatabase, type_alias_id: chalk_ir::TypeId) -> TypeAliasId { | ||
217 | id_from_chalk(type_alias_id.0) | ||
218 | } | ||
219 | } | ||
220 | |||
221 | impl ToChalk for AssocTyValue { | ||
222 | type Chalk = chalk_rust_ir::AssociatedTyValueId; | ||
223 | |||
224 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::AssociatedTyValueId { | ||
225 | db.intern_assoc_ty_value(self).into() | ||
226 | } | ||
227 | |||
228 | fn from_chalk( | ||
229 | db: &impl HirDatabase, | ||
230 | assoc_ty_value_id: chalk_rust_ir::AssociatedTyValueId, | ||
231 | ) -> AssocTyValue { | ||
232 | db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into()) | ||
233 | } | ||
234 | } | ||
235 | |||
236 | impl ToChalk for GenericPredicate { | ||
237 | type Chalk = chalk_ir::QuantifiedWhereClause<ChalkIr>; | ||
238 | |||
239 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause<ChalkIr> { | ||
240 | match self { | ||
241 | GenericPredicate::Implemented(trait_ref) => { | ||
242 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) | ||
243 | } | ||
244 | GenericPredicate::Projection(projection_pred) => make_binders( | ||
245 | chalk_ir::WhereClause::ProjectionEq(chalk_ir::ProjectionEq { | ||
246 | projection: projection_pred.projection_ty.to_chalk(db), | ||
247 | ty: projection_pred.ty.to_chalk(db), | ||
248 | }), | ||
249 | 0, | ||
250 | ), | ||
251 | GenericPredicate::Error => { | ||
252 | let impossible_trait_ref = chalk_ir::TraitRef { | ||
253 | trait_id: UNKNOWN_TRAIT, | ||
254 | parameters: vec![Ty::Unknown.to_chalk(db).cast()], | ||
255 | }; | ||
256 | make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0) | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | fn from_chalk( | ||
262 | db: &impl HirDatabase, | ||
263 | where_clause: chalk_ir::QuantifiedWhereClause<ChalkIr>, | ||
264 | ) -> GenericPredicate { | ||
265 | match where_clause.value { | ||
266 | chalk_ir::WhereClause::Implemented(tr) => { | ||
267 | if tr.trait_id == UNKNOWN_TRAIT { | ||
268 | // FIXME we need an Error enum on the Chalk side to avoid this | ||
269 | return GenericPredicate::Error; | ||
270 | } | ||
271 | GenericPredicate::Implemented(from_chalk(db, tr)) | ||
272 | } | ||
273 | chalk_ir::WhereClause::ProjectionEq(projection_eq) => { | ||
274 | let projection_ty = from_chalk(db, projection_eq.projection); | ||
275 | let ty = from_chalk(db, projection_eq.ty); | ||
276 | GenericPredicate::Projection(super::ProjectionPredicate { projection_ty, ty }) | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | impl ToChalk for ProjectionTy { | ||
283 | type Chalk = chalk_ir::ProjectionTy<ChalkIr>; | ||
284 | |||
285 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy<ChalkIr> { | ||
286 | chalk_ir::ProjectionTy { | ||
287 | associated_ty_id: self.associated_ty.to_chalk(db), | ||
288 | parameters: self.parameters.to_chalk(db), | ||
289 | } | ||
290 | } | ||
291 | |||
292 | fn from_chalk( | ||
293 | db: &impl HirDatabase, | ||
294 | projection_ty: chalk_ir::ProjectionTy<ChalkIr>, | ||
295 | ) -> ProjectionTy { | ||
296 | ProjectionTy { | ||
297 | associated_ty: from_chalk(db, projection_ty.associated_ty_id), | ||
298 | parameters: from_chalk(db, projection_ty.parameters), | ||
299 | } | ||
300 | } | ||
301 | } | ||
302 | |||
303 | impl ToChalk for super::ProjectionPredicate { | ||
304 | type Chalk = chalk_ir::Normalize<ChalkIr>; | ||
305 | |||
306 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize<ChalkIr> { | ||
307 | chalk_ir::Normalize { | ||
308 | projection: self.projection_ty.to_chalk(db), | ||
309 | ty: self.ty.to_chalk(db), | ||
310 | } | ||
311 | } | ||
312 | |||
313 | fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize<ChalkIr>) -> Self { | ||
314 | unimplemented!() | ||
315 | } | ||
316 | } | ||
317 | |||
318 | impl ToChalk for Obligation { | ||
319 | type Chalk = chalk_ir::DomainGoal<ChalkIr>; | ||
320 | |||
321 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal<ChalkIr> { | ||
322 | match self { | ||
323 | Obligation::Trait(tr) => tr.to_chalk(db).cast(), | ||
324 | Obligation::Projection(pr) => pr.to_chalk(db).cast(), | ||
325 | } | ||
326 | } | ||
327 | |||
328 | fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal<ChalkIr>) -> Self { | ||
329 | unimplemented!() | ||
330 | } | ||
331 | } | ||
332 | |||
333 | impl<T> ToChalk for Canonical<T> | ||
334 | where | ||
335 | T: ToChalk, | ||
336 | { | ||
337 | type Chalk = chalk_ir::Canonical<T::Chalk>; | ||
338 | |||
339 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | ||
340 | let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT); | ||
341 | let value = self.value.to_chalk(db); | ||
342 | let canonical = chalk_ir::Canonical { value, binders: vec![parameter; self.num_vars] }; | ||
343 | canonical | ||
344 | } | ||
345 | |||
346 | fn from_chalk(db: &impl HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { | ||
347 | Canonical { num_vars: canonical.binders.len(), value: from_chalk(db, canonical.value) } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | impl ToChalk for Arc<super::TraitEnvironment> { | ||
352 | type Chalk = chalk_ir::Environment<ChalkIr>; | ||
353 | |||
354 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment<ChalkIr> { | ||
355 | let mut clauses = Vec::new(); | ||
356 | for pred in &self.predicates { | ||
357 | if pred.is_error() { | ||
358 | // for env, we just ignore errors | ||
359 | continue; | ||
360 | } | ||
361 | let program_clause: chalk_ir::ProgramClause<ChalkIr> = pred.clone().to_chalk(db).cast(); | ||
362 | clauses.push(program_clause.into_from_env_clause()); | ||
363 | } | ||
364 | chalk_ir::Environment::new().add_clauses(clauses) | ||
365 | } | ||
366 | |||
367 | fn from_chalk( | ||
368 | _db: &impl HirDatabase, | ||
369 | _env: chalk_ir::Environment<ChalkIr>, | ||
370 | ) -> Arc<super::TraitEnvironment> { | ||
371 | unimplemented!() | ||
372 | } | ||
373 | } | ||
374 | |||
375 | impl<T: ToChalk> ToChalk for super::InEnvironment<T> | ||
376 | where | ||
377 | T::Chalk: chalk_ir::family::HasTypeFamily<TypeFamily = ChalkIr>, | ||
378 | { | ||
379 | type Chalk = chalk_ir::InEnvironment<T::Chalk>; | ||
380 | |||
381 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { | ||
382 | chalk_ir::InEnvironment { | ||
383 | environment: self.environment.to_chalk(db), | ||
384 | goal: self.value.to_chalk(db), | ||
385 | } | ||
386 | } | ||
387 | |||
388 | fn from_chalk( | ||
389 | db: &impl HirDatabase, | ||
390 | in_env: chalk_ir::InEnvironment<T::Chalk>, | ||
391 | ) -> super::InEnvironment<T> { | ||
392 | super::InEnvironment { | ||
393 | environment: from_chalk(db, in_env.environment), | ||
394 | value: from_chalk(db, in_env.goal), | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | |||
399 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | ||
400 | chalk_ir::Binders { | ||
401 | value, | ||
402 | binders: std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars).collect(), | ||
403 | } | ||
404 | } | ||
405 | |||
406 | fn convert_where_clauses( | ||
407 | db: &impl HirDatabase, | ||
408 | def: GenericDefId, | ||
409 | substs: &Substs, | ||
410 | ) -> Vec<chalk_ir::QuantifiedWhereClause<ChalkIr>> { | ||
411 | let generic_predicates = db.generic_predicates(def); | ||
412 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
413 | for pred in generic_predicates.iter() { | ||
414 | if pred.is_error() { | ||
415 | // HACK: Return just the single predicate (which is always false | ||
416 | // anyway), otherwise Chalk can easily get into slow situations | ||
417 | return vec![pred.clone().subst(substs).to_chalk(db)]; | ||
418 | } | ||
419 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
420 | } | ||
421 | result | ||
422 | } | ||
423 | |||
424 | impl<'a, DB> chalk_solve::RustIrDatabase<ChalkIr> for ChalkContext<'a, DB> | ||
425 | where | ||
426 | DB: HirDatabase, | ||
427 | { | ||
428 | fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum<ChalkIr>> { | ||
429 | self.db.associated_ty_data(id) | ||
430 | } | ||
431 | fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum<ChalkIr>> { | ||
432 | self.db.trait_datum(self.krate, trait_id) | ||
433 | } | ||
434 | fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum<ChalkIr>> { | ||
435 | self.db.struct_datum(self.krate, struct_id) | ||
436 | } | ||
437 | fn impl_datum(&self, impl_id: chalk_ir::ImplId) -> Arc<ImplDatum<ChalkIr>> { | ||
438 | self.db.impl_datum(self.krate, impl_id) | ||
439 | } | ||
440 | fn impls_for_trait( | ||
441 | &self, | ||
442 | trait_id: chalk_ir::TraitId, | ||
443 | parameters: &[Parameter<ChalkIr>], | ||
444 | ) -> Vec<chalk_ir::ImplId> { | ||
445 | debug!("impls_for_trait {:?}", trait_id); | ||
446 | if trait_id == UNKNOWN_TRAIT { | ||
447 | return Vec::new(); | ||
448 | } | ||
449 | let trait_: TraitId = from_chalk(self.db, trait_id); | ||
450 | let mut result: Vec<_> = self | ||
451 | .db | ||
452 | .impls_for_trait(self.krate, trait_.into()) | ||
453 | .iter() | ||
454 | .copied() | ||
455 | .map(|it| Impl::ImplBlock(it.into())) | ||
456 | .map(|impl_| impl_.to_chalk(self.db)) | ||
457 | .collect(); | ||
458 | |||
459 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); | ||
460 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { | ||
461 | for &fn_trait in | ||
462 | [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() | ||
463 | { | ||
464 | if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) { | ||
465 | if trait_ == actual_trait { | ||
466 | let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait }; | ||
467 | result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db)); | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | |||
473 | debug!("impls_for_trait returned {} impls", result.len()); | ||
474 | result | ||
475 | } | ||
476 | fn impl_provided_for( | ||
477 | &self, | ||
478 | auto_trait_id: chalk_ir::TraitId, | ||
479 | struct_id: chalk_ir::StructId, | ||
480 | ) -> bool { | ||
481 | debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); | ||
482 | false // FIXME | ||
483 | } | ||
484 | fn type_name(&self, _id: TypeKindId) -> Identifier { | ||
485 | unimplemented!() | ||
486 | } | ||
487 | fn associated_ty_value( | ||
488 | &self, | ||
489 | id: chalk_rust_ir::AssociatedTyValueId, | ||
490 | ) -> Arc<AssociatedTyValue<ChalkIr>> { | ||
491 | self.db.associated_ty_value(self.krate.into(), id) | ||
492 | } | ||
493 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<ChalkIr>> { | ||
494 | vec![] | ||
495 | } | ||
496 | fn local_impls_to_coherence_check( | ||
497 | &self, | ||
498 | _trait_id: chalk_ir::TraitId, | ||
499 | ) -> Vec<chalk_ir::ImplId> { | ||
500 | // We don't do coherence checking (yet) | ||
501 | unimplemented!() | ||
502 | } | ||
503 | } | ||
504 | |||
505 | pub(crate) fn associated_ty_data_query( | ||
506 | db: &impl HirDatabase, | ||
507 | id: TypeId, | ||
508 | ) -> Arc<AssociatedTyDatum<ChalkIr>> { | ||
509 | debug!("associated_ty_data {:?}", id); | ||
510 | let type_alias: TypeAliasId = from_chalk(db, id); | ||
511 | let trait_ = match type_alias.lookup(db).container { | ||
512 | ContainerId::TraitId(t) => t, | ||
513 | _ => panic!("associated type not in trait"), | ||
514 | }; | ||
515 | let generic_params = db.generic_params(type_alias.into()); | ||
516 | let bound_data = chalk_rust_ir::AssociatedTyDatumBound { | ||
517 | // FIXME add bounds and where clauses | ||
518 | bounds: vec![], | ||
519 | where_clauses: vec![], | ||
520 | }; | ||
521 | let datum = AssociatedTyDatum { | ||
522 | trait_id: trait_.to_chalk(db), | ||
523 | id, | ||
524 | name: lalrpop_intern::intern(&db.type_alias_data(type_alias).name.to_string()), | ||
525 | binders: make_binders(bound_data, generic_params.count_params_including_parent()), | ||
526 | }; | ||
527 | Arc::new(datum) | ||
528 | } | ||
529 | |||
530 | pub(crate) fn trait_datum_query( | ||
531 | db: &impl HirDatabase, | ||
532 | krate: CrateId, | ||
533 | trait_id: chalk_ir::TraitId, | ||
534 | ) -> Arc<TraitDatum<ChalkIr>> { | ||
535 | debug!("trait_datum {:?}", trait_id); | ||
536 | if trait_id == UNKNOWN_TRAIT { | ||
537 | let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses: Vec::new() }; | ||
538 | |||
539 | let flags = chalk_rust_ir::TraitFlags { | ||
540 | auto: false, | ||
541 | marker: false, | ||
542 | upstream: true, | ||
543 | fundamental: false, | ||
544 | non_enumerable: true, | ||
545 | coinductive: false, | ||
546 | }; | ||
547 | return Arc::new(TraitDatum { | ||
548 | id: trait_id, | ||
549 | binders: make_binders(trait_datum_bound, 1), | ||
550 | flags, | ||
551 | associated_ty_ids: vec![], | ||
552 | }); | ||
553 | } | ||
554 | let trait_: TraitId = from_chalk(db, trait_id); | ||
555 | let trait_data = db.trait_data(trait_); | ||
556 | debug!("trait {:?} = {:?}", trait_id, trait_data.name); | ||
557 | let generic_params = db.generic_params(trait_.into()); | ||
558 | let bound_vars = Substs::bound_vars(&generic_params); | ||
559 | let flags = chalk_rust_ir::TraitFlags { | ||
560 | auto: trait_data.auto, | ||
561 | upstream: trait_.module(db).krate != krate, | ||
562 | non_enumerable: true, | ||
563 | coinductive: false, // only relevant for Chalk testing | ||
564 | // FIXME set these flags correctly | ||
565 | marker: false, | ||
566 | fundamental: false, | ||
567 | }; | ||
568 | let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); | ||
569 | let associated_ty_ids = | ||
570 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); | ||
571 | let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; | ||
572 | let trait_datum = TraitDatum { | ||
573 | id: trait_id, | ||
574 | binders: make_binders(trait_datum_bound, bound_vars.len()), | ||
575 | flags, | ||
576 | associated_ty_ids, | ||
577 | }; | ||
578 | Arc::new(trait_datum) | ||
579 | } | ||
580 | |||
581 | pub(crate) fn struct_datum_query( | ||
582 | db: &impl HirDatabase, | ||
583 | krate: CrateId, | ||
584 | struct_id: chalk_ir::StructId, | ||
585 | ) -> Arc<StructDatum<ChalkIr>> { | ||
586 | debug!("struct_datum {:?}", struct_id); | ||
587 | let type_ctor: TypeCtor = from_chalk(db, struct_id); | ||
588 | debug!("struct {:?} = {:?}", struct_id, type_ctor); | ||
589 | let num_params = type_ctor.num_ty_params(db); | ||
590 | let upstream = type_ctor.krate(db) != Some(krate); | ||
591 | let where_clauses = type_ctor | ||
592 | .as_generic_def() | ||
593 | .map(|generic_def| { | ||
594 | let generic_params = db.generic_params(generic_def.into()); | ||
595 | let bound_vars = Substs::bound_vars(&generic_params); | ||
596 | convert_where_clauses(db, generic_def, &bound_vars) | ||
597 | }) | ||
598 | .unwrap_or_else(Vec::new); | ||
599 | let flags = chalk_rust_ir::StructFlags { | ||
600 | upstream, | ||
601 | // FIXME set fundamental flag correctly | ||
602 | fundamental: false, | ||
603 | }; | ||
604 | let struct_datum_bound = chalk_rust_ir::StructDatumBound { | ||
605 | fields: Vec::new(), // FIXME add fields (only relevant for auto traits) | ||
606 | where_clauses, | ||
607 | }; | ||
608 | let struct_datum = | ||
609 | StructDatum { id: struct_id, binders: make_binders(struct_datum_bound, num_params), flags }; | ||
610 | Arc::new(struct_datum) | ||
611 | } | ||
612 | |||
613 | pub(crate) fn impl_datum_query( | ||
614 | db: &impl HirDatabase, | ||
615 | krate: CrateId, | ||
616 | impl_id: chalk_ir::ImplId, | ||
617 | ) -> Arc<ImplDatum<ChalkIr>> { | ||
618 | let _p = ra_prof::profile("impl_datum"); | ||
619 | debug!("impl_datum {:?}", impl_id); | ||
620 | let impl_: Impl = from_chalk(db, impl_id); | ||
621 | match impl_ { | ||
622 | Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), | ||
623 | Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), | ||
624 | } | ||
625 | .unwrap_or_else(invalid_impl_datum) | ||
626 | } | ||
627 | |||
628 | fn impl_block_datum( | ||
629 | db: &impl HirDatabase, | ||
630 | krate: CrateId, | ||
631 | chalk_id: chalk_ir::ImplId, | ||
632 | impl_id: ImplId, | ||
633 | ) -> Option<Arc<ImplDatum<ChalkIr>>> { | ||
634 | let impl_data = db.impl_data(impl_id); | ||
635 | let resolver = impl_id.resolver(db); | ||
636 | let target_ty = Ty::from_hir(db, &resolver, &impl_data.target_type); | ||
637 | |||
638 | // `CoerseUnsized` has one generic parameter for the target type. | ||
639 | let trait_ref = | ||
640 | TraitRef::from_hir(db, &resolver, impl_data.target_trait.as_ref()?, Some(target_ty))?; | ||
641 | |||
642 | let generic_params = db.generic_params(impl_id.into()); | ||
643 | let bound_vars = Substs::bound_vars(&generic_params); | ||
644 | let trait_ref = trait_ref.subst(&bound_vars); | ||
645 | let trait_ = trait_ref.trait_; | ||
646 | let impl_type = if impl_id.module(db).krate == krate { | ||
647 | chalk_rust_ir::ImplType::Local | ||
648 | } else { | ||
649 | chalk_rust_ir::ImplType::External | ||
650 | }; | ||
651 | let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars); | ||
652 | let negative = impl_data.is_negative; | ||
653 | debug!( | ||
654 | "impl {:?}: {}{} where {:?}", | ||
655 | chalk_id, | ||
656 | if negative { "!" } else { "" }, | ||
657 | trait_ref.display(db), | ||
658 | where_clauses | ||
659 | ); | ||
660 | let trait_ref = trait_ref.to_chalk(db); | ||
661 | |||
662 | let polarity = if negative { | ||
663 | chalk_rust_ir::Polarity::Negative | ||
664 | } else { | ||
665 | chalk_rust_ir::Polarity::Positive | ||
666 | }; | ||
667 | |||
668 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses }; | ||
669 | let trait_data = db.trait_data(trait_); | ||
670 | let associated_ty_value_ids = impl_data | ||
671 | .items | ||
672 | .iter() | ||
673 | .filter_map(|item| match item { | ||
674 | AssocItemId::TypeAliasId(type_alias) => Some(*type_alias), | ||
675 | _ => None, | ||
676 | }) | ||
677 | .filter(|&type_alias| { | ||
678 | // don't include associated types that don't exist in the trait | ||
679 | let name = &db.type_alias_data(type_alias).name; | ||
680 | trait_data.associated_type_by_name(name).is_some() | ||
681 | }) | ||
682 | .map(|type_alias| AssocTyValue::TypeAlias(type_alias).to_chalk(db)) | ||
683 | .collect(); | ||
684 | debug!("impl_datum: {:?}", impl_datum_bound); | ||
685 | let impl_datum = ImplDatum { | ||
686 | binders: make_binders(impl_datum_bound, bound_vars.len()), | ||
687 | impl_type, | ||
688 | polarity, | ||
689 | associated_ty_value_ids, | ||
690 | }; | ||
691 | Some(Arc::new(impl_datum)) | ||
692 | } | ||
693 | |||
694 | fn invalid_impl_datum() -> Arc<ImplDatum<ChalkIr>> { | ||
695 | let trait_ref = chalk_ir::TraitRef { | ||
696 | trait_id: UNKNOWN_TRAIT, | ||
697 | parameters: vec![chalk_ir::TyData::BoundVar(0).cast().intern().cast()], | ||
698 | }; | ||
699 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses: Vec::new() }; | ||
700 | let impl_datum = ImplDatum { | ||
701 | binders: make_binders(impl_datum_bound, 1), | ||
702 | impl_type: chalk_rust_ir::ImplType::External, | ||
703 | polarity: chalk_rust_ir::Polarity::Positive, | ||
704 | associated_ty_value_ids: Vec::new(), | ||
705 | }; | ||
706 | Arc::new(impl_datum) | ||
707 | } | ||
708 | |||
709 | fn closure_fn_trait_impl_datum( | ||
710 | db: &impl HirDatabase, | ||
711 | krate: CrateId, | ||
712 | data: super::ClosureFnTraitImplData, | ||
713 | ) -> Option<Arc<ImplDatum<ChalkIr>>> { | ||
714 | // for some closure |X, Y| -> Z: | ||
715 | // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } | ||
716 | |||
717 | let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait | ||
718 | |||
719 | // validate FnOnce trait, since we need it in the assoc ty value definition | ||
720 | // and don't want to return a valid value only to find out later that FnOnce | ||
721 | // is broken | ||
722 | let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; | ||
723 | let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?; | ||
724 | |||
725 | let num_args: u16 = match &db.body(data.def.into())[data.expr] { | ||
726 | Expr::Lambda { args, .. } => args.len() as u16, | ||
727 | _ => { | ||
728 | log::warn!("closure for closure type {:?} not found", data); | ||
729 | 0 | ||
730 | } | ||
731 | }; | ||
732 | |||
733 | let arg_ty = Ty::apply( | ||
734 | TypeCtor::Tuple { cardinality: num_args }, | ||
735 | Substs::builder(num_args as usize).fill_with_bound_vars(0).build(), | ||
736 | ); | ||
737 | let sig_ty = Ty::apply( | ||
738 | TypeCtor::FnPtr { num_args }, | ||
739 | Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(), | ||
740 | ); | ||
741 | |||
742 | let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); | ||
743 | |||
744 | let trait_ref = TraitRef { | ||
745 | trait_: trait_.into(), | ||
746 | substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(), | ||
747 | }; | ||
748 | |||
749 | let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db); | ||
750 | |||
751 | let impl_type = chalk_rust_ir::ImplType::External; | ||
752 | |||
753 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { | ||
754 | trait_ref: trait_ref.to_chalk(db), | ||
755 | where_clauses: Vec::new(), | ||
756 | }; | ||
757 | let impl_datum = ImplDatum { | ||
758 | binders: make_binders(impl_datum_bound, num_args as usize + 1), | ||
759 | impl_type, | ||
760 | polarity: chalk_rust_ir::Polarity::Positive, | ||
761 | associated_ty_value_ids: vec![output_ty_id], | ||
762 | }; | ||
763 | Some(Arc::new(impl_datum)) | ||
764 | } | ||
765 | |||
766 | pub(crate) fn associated_ty_value_query( | ||
767 | db: &impl HirDatabase, | ||
768 | krate: CrateId, | ||
769 | id: chalk_rust_ir::AssociatedTyValueId, | ||
770 | ) -> Arc<chalk_rust_ir::AssociatedTyValue<ChalkIr>> { | ||
771 | let data: AssocTyValue = from_chalk(db, id); | ||
772 | match data { | ||
773 | AssocTyValue::TypeAlias(type_alias) => { | ||
774 | type_alias_associated_ty_value(db, krate, type_alias) | ||
775 | } | ||
776 | AssocTyValue::ClosureFnTraitImplOutput(data) => { | ||
777 | closure_fn_trait_output_assoc_ty_value(db, krate, data) | ||
778 | } | ||
779 | } | ||
780 | } | ||
781 | |||
782 | fn type_alias_associated_ty_value( | ||
783 | db: &impl HirDatabase, | ||
784 | _krate: CrateId, | ||
785 | type_alias: TypeAliasId, | ||
786 | ) -> Arc<AssociatedTyValue<ChalkIr>> { | ||
787 | let type_alias_data = db.type_alias_data(type_alias); | ||
788 | let impl_id = match type_alias.lookup(db).container { | ||
789 | ContainerId::ImplId(it) => it, | ||
790 | _ => panic!("assoc ty value should be in impl"), | ||
791 | }; | ||
792 | |||
793 | let impl_data = db.impl_data(impl_id); | ||
794 | let resolver = impl_id.resolver(db); | ||
795 | let target_ty = Ty::from_hir(db, &resolver, &impl_data.target_type); | ||
796 | let target_trait = impl_data | ||
797 | .target_trait | ||
798 | .as_ref() | ||
799 | .and_then(|trait_ref| TraitRef::from_hir(db, &resolver, &trait_ref, Some(target_ty))) | ||
800 | .expect("assoc ty value should not exist"); // we don't return any assoc ty values if the impl'd trait can't be resolved | ||
801 | |||
802 | let assoc_ty = db | ||
803 | .trait_data(target_trait.trait_) | ||
804 | .associated_type_by_name(&type_alias_data.name) | ||
805 | .expect("assoc ty value should not exist"); // validated when building the impl data as well | ||
806 | let generic_params = db.generic_params(impl_id.into()); | ||
807 | let bound_vars = Substs::bound_vars(&generic_params); | ||
808 | let ty = db.ty(type_alias.into()).subst(&bound_vars); | ||
809 | let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) }; | ||
810 | let value = chalk_rust_ir::AssociatedTyValue { | ||
811 | impl_id: Impl::ImplBlock(impl_id.into()).to_chalk(db), | ||
812 | associated_ty_id: assoc_ty.to_chalk(db), | ||
813 | value: make_binders(value_bound, bound_vars.len()), | ||
814 | }; | ||
815 | Arc::new(value) | ||
816 | } | ||
817 | |||
818 | fn closure_fn_trait_output_assoc_ty_value( | ||
819 | db: &impl HirDatabase, | ||
820 | krate: CrateId, | ||
821 | data: super::ClosureFnTraitImplData, | ||
822 | ) -> Arc<AssociatedTyValue<ChalkIr>> { | ||
823 | let impl_id = Impl::ClosureFnTraitImpl(data.clone()).to_chalk(db); | ||
824 | |||
825 | let num_args: u16 = match &db.body(data.def.into())[data.expr] { | ||
826 | Expr::Lambda { args, .. } => args.len() as u16, | ||
827 | _ => { | ||
828 | log::warn!("closure for closure type {:?} not found", data); | ||
829 | 0 | ||
830 | } | ||
831 | }; | ||
832 | |||
833 | let output_ty = Ty::Bound(num_args.into()); | ||
834 | |||
835 | let fn_once_trait = | ||
836 | get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist"); | ||
837 | |||
838 | let output_ty_id = db | ||
839 | .trait_data(fn_once_trait) | ||
840 | .associated_type_by_name(&name::OUTPUT_TYPE) | ||
841 | .expect("assoc ty value should not exist"); | ||
842 | |||
843 | let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) }; | ||
844 | |||
845 | let value = chalk_rust_ir::AssociatedTyValue { | ||
846 | associated_ty_id: output_ty_id.to_chalk(db), | ||
847 | impl_id, | ||
848 | value: make_binders(value_bound, num_args as usize + 1), | ||
849 | }; | ||
850 | Arc::new(value) | ||
851 | } | ||
852 | |||
853 | fn get_fn_trait( | ||
854 | db: &impl HirDatabase, | ||
855 | krate: CrateId, | ||
856 | fn_trait: super::FnTrait, | ||
857 | ) -> Option<TraitId> { | ||
858 | let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; | ||
859 | match target { | ||
860 | LangItemTarget::TraitId(t) => Some(t), | ||
861 | _ => None, | ||
862 | } | ||
863 | } | ||
864 | |||
865 | fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { | ||
866 | T::from_intern_id(InternId::from(chalk_id.index)) | ||
867 | } | ||
868 | fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId { | ||
869 | chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() } | ||
870 | } | ||
871 | |||
872 | impl From<chalk_ir::StructId> for crate::TypeCtorId { | ||
873 | fn from(struct_id: chalk_ir::StructId) -> Self { | ||
874 | id_from_chalk(struct_id.0) | ||
875 | } | ||
876 | } | ||
877 | |||
878 | impl From<crate::TypeCtorId> for chalk_ir::StructId { | ||
879 | fn from(type_ctor_id: crate::TypeCtorId) -> Self { | ||
880 | chalk_ir::StructId(id_to_chalk(type_ctor_id)) | ||
881 | } | ||
882 | } | ||
883 | |||
884 | impl From<chalk_ir::ImplId> for crate::traits::GlobalImplId { | ||
885 | fn from(impl_id: chalk_ir::ImplId) -> Self { | ||
886 | id_from_chalk(impl_id.0) | ||
887 | } | ||
888 | } | ||
889 | |||
890 | impl From<crate::traits::GlobalImplId> for chalk_ir::ImplId { | ||
891 | fn from(impl_id: crate::traits::GlobalImplId) -> Self { | ||
892 | chalk_ir::ImplId(id_to_chalk(impl_id)) | ||
893 | } | ||
894 | } | ||
895 | |||
896 | impl From<chalk_rust_ir::AssociatedTyValueId> for crate::traits::AssocTyValueId { | ||
897 | fn from(id: chalk_rust_ir::AssociatedTyValueId) -> Self { | ||
898 | id_from_chalk(id.0) | ||
899 | } | ||
900 | } | ||
901 | |||
902 | impl From<crate::traits::AssocTyValueId> for chalk_rust_ir::AssociatedTyValueId { | ||
903 | fn from(assoc_ty_value_id: crate::traits::AssocTyValueId) -> Self { | ||
904 | chalk_rust_ir::AssociatedTyValueId(id_to_chalk(assoc_ty_value_id)) | ||
905 | } | ||
906 | } | ||