diff options
Diffstat (limited to 'crates/ra_hir/src/ty/traits')
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 132 |
1 files changed, 122 insertions, 10 deletions
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 34e623931..f229b1aef 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -12,7 +12,7 @@ use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; | |||
12 | use ra_db::salsa::{InternId, InternKey}; | 12 | use ra_db::salsa::{InternId, InternKey}; |
13 | use test_utils::tested_by; | 13 | use test_utils::tested_by; |
14 | 14 | ||
15 | use super::{Canonical, ChalkContext, Obligation}; | 15 | use super::{Canonical, ChalkContext, Impl, Obligation}; |
16 | use crate::{ | 16 | use crate::{ |
17 | db::HirDatabase, | 17 | db::HirDatabase, |
18 | generics::GenericDef, | 18 | generics::GenericDef, |
@@ -111,7 +111,7 @@ impl ToChalk for Ty { | |||
111 | } | 111 | } |
112 | chalk_ir::Ty::ForAll(_) => unimplemented!(), | 112 | chalk_ir::Ty::ForAll(_) => unimplemented!(), |
113 | chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), | 113 | chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), |
114 | chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"), | 114 | chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown, |
115 | } | 115 | } |
116 | } | 116 | } |
117 | } | 117 | } |
@@ -175,15 +175,15 @@ impl ToChalk for TypeCtor { | |||
175 | } | 175 | } |
176 | } | 176 | } |
177 | 177 | ||
178 | impl ToChalk for ImplBlock { | 178 | impl ToChalk for Impl { |
179 | type Chalk = chalk_ir::ImplId; | 179 | type Chalk = chalk_ir::ImplId; |
180 | 180 | ||
181 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { | 181 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { |
182 | db.intern_impl_block(self).into() | 182 | db.intern_impl(self).into() |
183 | } | 183 | } |
184 | 184 | ||
185 | fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock { | 185 | fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { |
186 | db.lookup_intern_impl_block(impl_id.into()) | 186 | db.lookup_intern_impl(impl_id.into()) |
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
@@ -388,19 +388,36 @@ where | |||
388 | fn impls_for_trait( | 388 | fn impls_for_trait( |
389 | &self, | 389 | &self, |
390 | trait_id: chalk_ir::TraitId, | 390 | trait_id: chalk_ir::TraitId, |
391 | _parameters: &[Parameter], | 391 | parameters: &[Parameter], |
392 | ) -> Vec<ImplId> { | 392 | ) -> Vec<ImplId> { |
393 | debug!("impls_for_trait {:?}", trait_id); | 393 | debug!("impls_for_trait {:?}", trait_id); |
394 | if trait_id == UNKNOWN_TRAIT { | 394 | if trait_id == UNKNOWN_TRAIT { |
395 | return Vec::new(); | 395 | return Vec::new(); |
396 | } | 396 | } |
397 | let trait_: Trait = from_chalk(self.db, trait_id); | 397 | let trait_: Trait = from_chalk(self.db, trait_id); |
398 | let result: Vec<_> = self | 398 | let mut result: Vec<_> = self |
399 | .db | 399 | .db |
400 | .impls_for_trait(self.krate, trait_) | 400 | .impls_for_trait(self.krate, trait_) |
401 | .iter() | 401 | .iter() |
402 | .map(|impl_block| impl_block.to_chalk(self.db)) | 402 | .copied() |
403 | .map(Impl::ImplBlock) | ||
404 | .map(|impl_| impl_.to_chalk(self.db)) | ||
403 | .collect(); | 405 | .collect(); |
406 | |||
407 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); | ||
408 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { | ||
409 | for fn_trait in | ||
410 | [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter().copied() | ||
411 | { | ||
412 | if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) { | ||
413 | if trait_ == actual_trait { | ||
414 | let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait }; | ||
415 | result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db)); | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | |||
404 | debug!("impls_for_trait returned {} impls", result.len()); | 421 | debug!("impls_for_trait returned {} impls", result.len()); |
405 | result | 422 | result |
406 | } | 423 | } |
@@ -602,7 +619,21 @@ pub(crate) fn impl_datum_query( | |||
602 | ) -> Arc<ImplDatum> { | 619 | ) -> Arc<ImplDatum> { |
603 | let _p = ra_prof::profile("impl_datum"); | 620 | let _p = ra_prof::profile("impl_datum"); |
604 | debug!("impl_datum {:?}", impl_id); | 621 | debug!("impl_datum {:?}", impl_id); |
605 | let impl_block: ImplBlock = from_chalk(db, impl_id); | 622 | let impl_: Impl = from_chalk(db, impl_id); |
623 | match impl_ { | ||
624 | Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), | ||
625 | Impl::ClosureFnTraitImpl(data) => { | ||
626 | closure_fn_trait_impl_datum(db, krate, impl_id, data).unwrap_or_else(invalid_impl_datum) | ||
627 | } | ||
628 | } | ||
629 | } | ||
630 | |||
631 | fn impl_block_datum( | ||
632 | db: &impl HirDatabase, | ||
633 | krate: Crate, | ||
634 | impl_id: ImplId, | ||
635 | impl_block: ImplBlock, | ||
636 | ) -> Arc<ImplDatum> { | ||
606 | let generic_params = impl_block.generic_params(db); | 637 | let generic_params = impl_block.generic_params(db); |
607 | let bound_vars = Substs::bound_vars(&generic_params); | 638 | let bound_vars = Substs::bound_vars(&generic_params); |
608 | let trait_ref = impl_block | 639 | let trait_ref = impl_block |
@@ -661,6 +692,87 @@ pub(crate) fn impl_datum_query( | |||
661 | Arc::new(impl_datum) | 692 | Arc::new(impl_datum) |
662 | } | 693 | } |
663 | 694 | ||
695 | fn invalid_impl_datum() -> Arc<ImplDatum> { | ||
696 | let trait_ref = chalk_ir::TraitRef { | ||
697 | trait_id: UNKNOWN_TRAIT, | ||
698 | parameters: vec![chalk_ir::Ty::BoundVar(0).cast()], | ||
699 | }; | ||
700 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { | ||
701 | trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref), | ||
702 | where_clauses: Vec::new(), | ||
703 | associated_ty_values: Vec::new(), | ||
704 | impl_type: chalk_rust_ir::ImplType::External, | ||
705 | }; | ||
706 | let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, 1) }; | ||
707 | Arc::new(impl_datum) | ||
708 | } | ||
709 | |||
710 | fn closure_fn_trait_impl_datum( | ||
711 | db: &impl HirDatabase, | ||
712 | krate: Crate, | ||
713 | impl_id: ImplId, | ||
714 | data: super::ClosureFnTraitImplData, | ||
715 | ) -> Option<Arc<ImplDatum>> { | ||
716 | // for some closure |X, Y| -> Z: | ||
717 | // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } | ||
718 | |||
719 | let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; | ||
720 | let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait | ||
721 | |||
722 | let num_args: u16 = match &db.body_hir(data.def)[data.expr] { | ||
723 | crate::expr::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 | (0..num_args).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(), | ||
733 | ); | ||
734 | let output_ty = Ty::Bound(num_args.into()); | ||
735 | let sig_ty = Ty::apply( | ||
736 | TypeCtor::FnPtr { num_args }, | ||
737 | (0..num_args + 1).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(), | ||
738 | ); | ||
739 | |||
740 | let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); | ||
741 | |||
742 | let trait_ref = TraitRef { trait_, substs: vec![self_ty, arg_ty].into() }; | ||
743 | |||
744 | let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?; | ||
745 | |||
746 | let output_ty_value = chalk_rust_ir::AssociatedTyValue { | ||
747 | associated_ty_id: output_ty_id.to_chalk(db), | ||
748 | impl_id, | ||
749 | value: make_binders( | ||
750 | chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) }, | ||
751 | 0, | ||
752 | ), | ||
753 | }; | ||
754 | |||
755 | let impl_type = chalk_rust_ir::ImplType::External; | ||
756 | |||
757 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { | ||
758 | trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(db)), | ||
759 | where_clauses: Vec::new(), | ||
760 | associated_ty_values: vec![output_ty_value], | ||
761 | impl_type, | ||
762 | }; | ||
763 | let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, num_args as usize + 1) }; | ||
764 | Some(Arc::new(impl_datum)) | ||
765 | } | ||
766 | |||
767 | fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> { | ||
768 | let lang_items = db.lang_items(krate); | ||
769 | let target = lang_items.target(fn_trait.lang_item_name())?; | ||
770 | match target { | ||
771 | crate::lang_item::LangItemTarget::Trait(t) => Some(*t), | ||
772 | _ => None, | ||
773 | } | ||
774 | } | ||
775 | |||
664 | fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { | 776 | fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { |
665 | T::from_intern_id(InternId::from(chalk_id.index)) | 777 | T::from_intern_id(InternId::from(chalk_id.index)) |
666 | } | 778 | } |