aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/traits
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/traits')
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs900
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.
2use std::sync::Arc;
3
4use log::debug;
5
6use chalk_ir::{
7 cast::Cast, family::ChalkIr, Identifier, Parameter, PlaceholderIndex, TypeId, TypeKindId,
8 TypeName, UniverseIndex,
9};
10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
11use ra_db::CrateId;
12
13use hir_def::{
14 expr::Expr, lang_item::LangItemTarget, AssocItemId, AstItemDef, ContainerId, GenericDefId,
15 ImplId, Lookup, TraitId, TypeAliasId,
16};
17use hir_expand::name;
18
19use ra_db::salsa::{InternId, InternKey};
20
21use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
22use 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.
28const UNKNOWN_TRAIT: chalk_ir::TraitId =
29 chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() });
30
31pub(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
37pub(super) fn from_chalk<T, ChalkT>(db: &impl HirDatabase, chalk: ChalkT) -> T
38where
39 T: ToChalk<Chalk = ChalkT>,
40{
41 T::from_chalk(db, chalk)
42}
43
44impl 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
137impl 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
156impl 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
172impl 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
184impl 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
196impl 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
208impl 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
220impl 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
235impl 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
281impl 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
302impl 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
317impl 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
332impl<T> ToChalk for Canonical<T>
333where
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
350impl 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
374impl<T: ToChalk> ToChalk for super::InEnvironment<T>
375where
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
398fn 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
405fn 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
423impl<'a, DB> chalk_solve::RustIrDatabase<ChalkIr> for ChalkContext<'a, DB>
424where
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
504pub(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
529pub(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
580pub(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
612pub(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
627fn 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
691fn 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
706fn 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
763pub(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
779fn 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
812fn 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
847fn 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
859fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
860 T::from_intern_id(InternId::from(chalk_id.index))
861}
862fn 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
866impl 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
872impl 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
878impl 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
884impl 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
890impl 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
896impl 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}