1 //! Conversion code from/to Chalk.
7 cast::Cast, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId, TypeKindId, TypeName,
10 use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
12 use ra_db::salsa::{InternId, InternKey};
13 use test_utils::tested_by;
15 use super::{Canonical, ChalkContext, Obligation};
19 ty::display::HirDisplay,
21 ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
23 Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias,
26 /// This represents a trait whose name we could not resolve.
27 const UNKNOWN_TRAIT: chalk_ir::TraitId =
28 chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() });
30 pub(super) trait ToChalk {
32 fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk;
33 fn from_chalk(db: &impl HirDatabase, chalk: Self::Chalk) -> Self;
36 pub(super) fn from_chalk<T, ChalkT>(db: &impl HirDatabase, chalk: ChalkT) -> T
38 T: ToChalk<Chalk = ChalkT>,
40 T::from_chalk(db, chalk)
44 type Chalk = chalk_ir::Ty;
45 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty {
47 Ty::Apply(apply_ty) => {
48 let struct_id = apply_ty.ctor.to_chalk(db);
49 let name = TypeName::TypeKindId(struct_id.into());
50 let parameters = apply_ty.parameters.to_chalk(db);
51 chalk_ir::ApplicationTy { name, parameters }.cast()
53 Ty::Param { idx, .. } => {
54 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty()
56 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize),
57 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
58 // FIXME this is clearly incorrect, but probably not too incorrect
59 // and I'm not sure what to actually do with Ty::Unknown
60 // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
62 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty()
66 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self {
68 chalk_ir::Ty::Apply(apply_ty) => {
70 TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => {
71 let ctor = from_chalk(db, struct_id);
72 let parameters = from_chalk(db, apply_ty.parameters);
73 Ty::Apply(ApplicationTy { ctor, parameters })
75 // FIXME handle TypeKindId::Trait/Type here
76 TypeName::TypeKindId(_) => unimplemented!(),
77 TypeName::AssociatedType(_) => unimplemented!(),
78 TypeName::Placeholder(idx) => {
79 assert_eq!(idx.ui, UniverseIndex::ROOT);
80 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
84 chalk_ir::Ty::Projection(_) => unimplemented!(),
85 chalk_ir::Ty::UnselectedProjection(_) => unimplemented!(),
86 chalk_ir::Ty::ForAll(_) => unimplemented!(),
87 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
88 chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"),
93 impl ToChalk for Substs {
94 type Chalk = Vec<chalk_ir::Parameter>;
96 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter> {
97 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect()
100 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs {
104 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
105 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
112 impl ToChalk for TraitRef {
113 type Chalk = chalk_ir::TraitRef;
115 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef {
116 let trait_id = self.trait_.to_chalk(db);
117 let parameters = self.substs.to_chalk(db);
118 chalk_ir::TraitRef { trait_id, parameters }
121 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self {
122 let trait_ = from_chalk(db, trait_ref.trait_id);
123 let substs = from_chalk(db, trait_ref.parameters);
124 TraitRef { trait_, substs }
128 impl ToChalk for Trait {
129 type Chalk = chalk_ir::TraitId;
131 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId {
135 fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> Trait {
136 Trait { id: trait_id.into() }
140 impl ToChalk for TypeCtor {
141 type Chalk = chalk_ir::StructId;
143 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::StructId {
144 db.intern_type_ctor(self).into()
147 fn from_chalk(db: &impl HirDatabase, struct_id: chalk_ir::StructId) -> TypeCtor {
148 db.lookup_intern_type_ctor(struct_id.into())
152 impl ToChalk for ImplBlock {
153 type Chalk = chalk_ir::ImplId;
155 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId {
156 db.intern_impl_block(self).into()
159 fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock {
160 db.lookup_intern_impl_block(impl_id.into())
164 impl ToChalk for TypeAlias {
165 type Chalk = chalk_ir::TypeId;
167 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId {
171 fn from_chalk(_db: &impl HirDatabase, impl_id: chalk_ir::TypeId) -> TypeAlias {
172 TypeAlias { id: impl_id.into() }
176 impl ToChalk for GenericPredicate {
177 type Chalk = chalk_ir::QuantifiedWhereClause;
179 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause {
181 GenericPredicate::Implemented(trait_ref) => {
182 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
184 GenericPredicate::Error => {
185 let impossible_trait_ref = chalk_ir::TraitRef {
186 trait_id: UNKNOWN_TRAIT,
187 parameters: vec![Ty::Unknown.to_chalk(db).cast()],
189 make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0)
195 _db: &impl HirDatabase,
196 _where_clause: chalk_ir::QuantifiedWhereClause,
197 ) -> GenericPredicate {
198 // This should never need to be called
203 impl ToChalk for ProjectionTy {
204 type Chalk = chalk_ir::ProjectionTy;
206 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy {
207 chalk_ir::ProjectionTy {
208 associated_ty_id: self.associated_ty.to_chalk(db),
209 parameters: self.parameters.to_chalk(db),
213 fn from_chalk(db: &impl HirDatabase, projection_ty: chalk_ir::ProjectionTy) -> ProjectionTy {
215 associated_ty: from_chalk(db, projection_ty.associated_ty_id),
216 parameters: from_chalk(db, projection_ty.parameters),
221 impl ToChalk for super::ProjectionPredicate {
222 type Chalk = chalk_ir::Normalize;
224 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize {
225 chalk_ir::Normalize {
226 projection: self.projection_ty.to_chalk(db),
227 ty: self.ty.to_chalk(db),
231 fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self {
236 impl ToChalk for Obligation {
237 type Chalk = chalk_ir::DomainGoal;
239 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal {
241 Obligation::Trait(tr) => tr.to_chalk(db).cast(),
242 Obligation::Projection(pr) => pr.to_chalk(db).cast(),
246 fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self {
251 impl<T> ToChalk for Canonical<T>
255 type Chalk = chalk_ir::Canonical<T::Chalk>;
257 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
258 let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT);
259 let value = self.value.to_chalk(db);
260 let canonical = chalk_ir::Canonical { value, binders: vec![parameter; self.num_vars] };
264 fn from_chalk(db: &impl HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
265 Canonical { num_vars: canonical.binders.len(), value: from_chalk(db, canonical.value) }
269 impl ToChalk for Arc<super::TraitEnvironment> {
270 type Chalk = Arc<chalk_ir::Environment>;
272 fn to_chalk(self, db: &impl HirDatabase) -> Arc<chalk_ir::Environment> {
273 let mut clauses = Vec::new();
274 for pred in &self.predicates {
276 // for env, we just ignore errors
279 clauses.push(pred.clone().to_chalk(db).cast());
281 chalk_ir::Environment::new().add_clauses(clauses)
285 _db: &impl HirDatabase,
286 _env: Arc<chalk_ir::Environment>,
287 ) -> Arc<super::TraitEnvironment> {
292 impl<T: ToChalk> ToChalk for super::InEnvironment<T> {
293 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
295 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
296 chalk_ir::InEnvironment {
297 environment: self.environment.to_chalk(db),
298 goal: self.value.to_chalk(db),
303 db: &impl HirDatabase,
304 in_env: chalk_ir::InEnvironment<T::Chalk>,
305 ) -> super::InEnvironment<T> {
306 super::InEnvironment {
307 environment: from_chalk(db, in_env.environment),
308 value: from_chalk(db, in_env.goal),
313 fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
316 binders: std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars).collect(),
320 fn is_non_enumerable_trait(db: &impl HirDatabase, trait_: Trait) -> bool {
321 let name = trait_.name(db).unwrap_or_else(crate::Name::missing).to_string();
328 fn convert_where_clauses(
329 db: &impl HirDatabase,
332 ) -> Vec<chalk_ir::QuantifiedWhereClause> {
333 let generic_predicates = db.generic_predicates(def);
334 let mut result = Vec::with_capacity(generic_predicates.len());
335 for pred in generic_predicates.iter() {
337 // HACK: Return just the single predicate (which is always false
338 // anyway), otherwise Chalk can easily get into slow situations
339 return vec![pred.clone().subst(substs).to_chalk(db)];
341 result.push(pred.clone().subst(substs).to_chalk(db));
346 impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
350 fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum> {
351 self.db.associated_ty_data(id)
353 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> {
354 self.db.trait_datum(self.krate, trait_id)
356 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
357 self.db.struct_datum(self.krate, struct_id)
359 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
360 self.db.impl_datum(self.krate, impl_id)
362 fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> {
363 debug!("impls_for_trait {:?}", trait_id);
364 if trait_id == UNKNOWN_TRAIT {
367 let trait_: Trait = from_chalk(self.db, trait_id);
368 let result: Vec<_> = self
370 .impls_for_trait(self.krate, trait_)
372 .map(|impl_block| impl_block.to_chalk(self.db))
374 debug!("impls_for_trait returned {} impls", result.len());
377 fn impl_provided_for(
379 auto_trait_id: chalk_ir::TraitId,
380 struct_id: chalk_ir::StructId,
382 debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id);
385 fn type_name(&self, _id: TypeKindId) -> Identifier {
388 fn split_projection<'p>(
390 projection: &'p chalk_ir::ProjectionTy,
391 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) {
392 debug!("split_projection {:?}", projection);
395 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> {
396 debug!("custom_clauses");
399 fn all_structs(&self) -> Vec<chalk_ir::StructId> {
400 debug!("all_structs");
406 pub(crate) fn associated_ty_data_query(
407 db: &impl HirDatabase,
409 ) -> Arc<AssociatedTyDatum> {
410 debug!("associated_ty_data {:?}", id);
411 let type_alias: TypeAlias = from_chalk(db, id);
412 let trait_ = match type_alias.container(db) {
413 Some(crate::Container::Trait(t)) => t,
414 _ => panic!("associated type not in trait"),
416 let generic_params = type_alias.generic_params(db);
417 let parameter_kinds = generic_params
418 .params_including_parent()
420 .map(|p| chalk_ir::ParameterKind::Ty(lalrpop_intern::intern(&p.name.to_string())))
422 let datum = AssociatedTyDatum {
423 trait_id: trait_.to_chalk(db),
425 name: lalrpop_intern::intern(&type_alias.name(db).to_string()),
427 // FIXME add bounds and where clauses
429 where_clauses: vec![],
434 pub(crate) fn trait_datum_query(
435 db: &impl HirDatabase,
437 trait_id: chalk_ir::TraitId,
438 ) -> Arc<TraitDatum> {
439 debug!("trait_datum {:?}", trait_id);
440 if trait_id == UNKNOWN_TRAIT {
441 let trait_datum_bound = chalk_rust_ir::TraitDatumBound {
442 trait_ref: chalk_ir::TraitRef {
443 trait_id: UNKNOWN_TRAIT,
444 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()],
446 associated_ty_ids: Vec::new(),
447 where_clauses: Vec::new(),
448 flags: chalk_rust_ir::TraitFlags {
449 non_enumerable: false,
456 return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1) });
458 let trait_: Trait = from_chalk(db, trait_id);
459 debug!("trait {:?} = {:?}", trait_id, trait_.name(db));
460 let generic_params = trait_.generic_params(db);
461 let bound_vars = Substs::bound_vars(&generic_params);
462 let trait_ref = trait_.trait_ref(db).subst(&bound_vars).to_chalk(db);
463 let flags = chalk_rust_ir::TraitFlags {
464 auto: trait_.is_auto(db),
465 upstream: trait_.module(db).krate(db) != Some(krate),
466 non_enumerable: is_non_enumerable_trait(db, trait_),
467 // FIXME set these flags correctly
471 let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
472 let associated_ty_ids = trait_
475 .filter_map(|trait_item| match trait_item {
476 crate::traits::TraitItem::TypeAlias(type_alias) => Some(type_alias),
479 .map(|type_alias| type_alias.to_chalk(db))
481 let trait_datum_bound =
482 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids };
483 let trait_datum = TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()) };
484 Arc::new(trait_datum)
487 pub(crate) fn struct_datum_query(
488 db: &impl HirDatabase,
490 struct_id: chalk_ir::StructId,
491 ) -> Arc<StructDatum> {
492 debug!("struct_datum {:?}", struct_id);
493 let type_ctor = from_chalk(db, struct_id);
494 debug!("struct {:?} = {:?}", struct_id, type_ctor);
495 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor
496 // FIXME extract this to a method on Ty
497 let (num_params, where_clauses, upstream) = match type_ctor {
503 | TypeCtor::Str => (0, vec![], true),
504 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => {
507 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, vec![], true),
508 TypeCtor::Tuple { cardinality } => (cardinality as usize, vec![], true),
509 TypeCtor::FnDef(callable) => {
510 tested_by!(trait_resolution_on_fn_type);
511 let upstream = match callable {
512 CallableDef::Function(f) => f.module(db).krate(db),
513 CallableDef::Struct(s) => s.module(db).krate(db),
514 CallableDef::EnumVariant(v) => v.parent_enum(db).module(db).krate(db),
516 let generic_def: GenericDef = callable.into();
517 let generic_params = generic_def.generic_params(db);
518 let bound_vars = Substs::bound_vars(&generic_params);
519 let where_clauses = convert_where_clauses(db, generic_def, &bound_vars);
520 (generic_params.count_params_including_parent(), where_clauses, upstream)
522 TypeCtor::Adt(adt) => {
523 let generic_params = adt.generic_params(db);
524 let bound_vars = Substs::bound_vars(&generic_params);
525 let where_clauses = convert_where_clauses(db, adt.into(), &bound_vars);
527 generic_params.count_params_including_parent(),
529 adt.krate(db) != Some(krate),
533 let flags = chalk_rust_ir::StructFlags {
535 // FIXME set fundamental flag correctly
538 let self_ty = chalk_ir::ApplicationTy {
539 name: TypeName::TypeKindId(type_ctor.to_chalk(db).into()),
540 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(),
542 let struct_datum_bound = chalk_rust_ir::StructDatumBound {
544 fields: Vec::new(), // FIXME add fields (only relevant for auto traits)
548 let struct_datum = StructDatum { binders: make_binders(struct_datum_bound, num_params) };
549 Arc::new(struct_datum)
552 pub(crate) fn impl_datum_query(
553 db: &impl HirDatabase,
556 ) -> Arc<ImplDatum> {
557 let _p = ra_prof::profile("impl_datum");
558 debug!("impl_datum {:?}", impl_id);
559 let impl_block: ImplBlock = from_chalk(db, impl_id);
560 let generic_params = impl_block.generic_params(db);
561 let bound_vars = Substs::bound_vars(&generic_params);
562 let trait_ref = impl_block
563 .target_trait_ref(db)
564 .expect("FIXME handle unresolved impl block trait ref")
566 let impl_type = if impl_block.module().krate(db) == Some(krate) {
567 chalk_rust_ir::ImplType::Local
569 chalk_rust_ir::ImplType::External
571 let where_clauses = convert_where_clauses(db, impl_block.into(), &bound_vars);
572 let negative = impl_block.is_negative(db);
574 "impl {:?}: {}{} where {:?}",
576 if negative { "!" } else { "" },
577 trait_ref.display(db),
580 let trait_ = trait_ref.trait_;
581 let trait_ref = trait_ref.to_chalk(db);
582 let associated_ty_values = impl_block
585 .filter_map(|item| match item {
586 ImplItem::TypeAlias(t) => Some(t),
590 let assoc_ty = trait_.associated_type_by_name(db, t.name(db))?;
591 let ty = db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars);
592 Some(chalk_rust_ir::AssociatedTyValue {
594 associated_ty_id: assoc_ty.to_chalk(db),
595 value: chalk_ir::Binders {
596 value: chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) },
597 binders: vec![], // we don't support GATs yet
603 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
604 trait_ref: if negative {
605 chalk_rust_ir::PolarizedTraitRef::Negative(trait_ref)
607 chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref)
610 associated_ty_values,
613 debug!("impl_datum: {:?}", impl_datum_bound);
614 let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, bound_vars.len()) };
618 fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
619 T::from_intern_id(InternId::from(chalk_id.index))
621 fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId {
622 chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() }
625 impl From<chalk_ir::TraitId> for crate::ids::TraitId {
626 fn from(trait_id: chalk_ir::TraitId) -> Self {
627 id_from_chalk(trait_id.0)
631 impl From<crate::ids::TraitId> for chalk_ir::TraitId {
632 fn from(trait_id: crate::ids::TraitId) -> Self {
633 chalk_ir::TraitId(id_to_chalk(trait_id))
637 impl From<chalk_ir::TypeId> for crate::ids::TypeAliasId {
638 fn from(type_id: chalk_ir::TypeId) -> Self {
639 id_from_chalk(type_id.0)
643 impl From<crate::ids::TypeAliasId> for chalk_ir::TypeId {
644 fn from(type_id: crate::ids::TypeAliasId) -> Self {
645 chalk_ir::TypeId(id_to_chalk(type_id))
649 impl From<chalk_ir::StructId> for crate::ids::TypeCtorId {
650 fn from(struct_id: chalk_ir::StructId) -> Self {
651 id_from_chalk(struct_id.0)
655 impl From<crate::ids::TypeCtorId> for chalk_ir::StructId {
656 fn from(type_ctor_id: crate::ids::TypeCtorId) -> Self {
657 chalk_ir::StructId(id_to_chalk(type_ctor_id))
661 impl From<chalk_ir::ImplId> for crate::ids::GlobalImplId {
662 fn from(impl_id: chalk_ir::ImplId) -> Self {
663 id_from_chalk(impl_id.0)
667 impl From<crate::ids::GlobalImplId> for chalk_ir::ImplId {
668 fn from(impl_id: crate::ids::GlobalImplId) -> Self {
669 chalk_ir::ImplId(id_to_chalk(impl_id))