aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/traits/chalk.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/traits/chalk.rs')
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs906
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.
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, resolver::HasResolver, AssocItemId, AstItemDef,
15 ContainerId, GenericDefId, 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,
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.
29const UNKNOWN_TRAIT: chalk_ir::TraitId =
30 chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() });
31
32pub(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
38pub(super) fn from_chalk<T, ChalkT>(db: &impl HirDatabase, chalk: ChalkT) -> T
39where
40 T: ToChalk<Chalk = ChalkT>,
41{
42 T::from_chalk(db, chalk)
43}
44
45impl 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
138impl 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
157impl 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
173impl 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
185impl 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
197impl 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
209impl 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
221impl 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
236impl 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
282impl 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
303impl 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
318impl 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
333impl<T> ToChalk for Canonical<T>
334where
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
351impl 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
375impl<T: ToChalk> ToChalk for super::InEnvironment<T>
376where
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
399fn 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
406fn 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
424impl<'a, DB> chalk_solve::RustIrDatabase<ChalkIr> for ChalkContext<'a, DB>
425where
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
505pub(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
530pub(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
581pub(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
613pub(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
628fn 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
694fn 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
709fn 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
766pub(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
782fn 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
818fn 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
853fn 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
865fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
866 T::from_intern_id(InternId::from(chalk_id.index))
867}
868fn 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
872impl 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
878impl 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
884impl 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
890impl 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
896impl 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
902impl 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}