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