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/builtin.rs161
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs184
2 files changed, 218 insertions, 127 deletions
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
new file mode 100644
index 000000000..598fd81e3
--- /dev/null
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -0,0 +1,161 @@
1//! This module provides the built-in trait implementations, e.g. to make
2//! closures implement `Fn`.
3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
4use hir_expand::name;
5use ra_db::CrateId;
6
7use super::{AssocTyValue, Impl};
8use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor};
9
10pub(super) struct BuiltinImplData {
11 pub num_vars: usize,
12 pub trait_ref: TraitRef,
13 pub where_clauses: Vec<super::GenericPredicate>,
14 pub assoc_ty_values: Vec<AssocTyValue>,
15}
16
17pub(super) struct BuiltinImplAssocTyValueData {
18 pub impl_: Impl,
19 pub assoc_ty_id: TypeAliasId,
20 pub num_vars: usize,
21 pub value: Ty,
22}
23
24pub(super) fn get_builtin_impls(
25 db: &impl HirDatabase,
26 krate: CrateId,
27 ty: &Ty,
28 trait_: TraitId,
29 mut callback: impl FnMut(Impl),
30) {
31 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty {
32 for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
33 {
34 if let Some(actual_trait) = get_fn_trait(db, krate, fn_trait) {
35 if trait_ == actual_trait {
36 let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait };
37 callback(Impl::ClosureFnTraitImpl(impl_));
38 }
39 }
40 }
41 }
42}
43
44pub(super) fn impl_datum(
45 db: &impl HirDatabase,
46 krate: CrateId,
47 impl_: Impl,
48) -> Option<BuiltinImplData> {
49 match impl_ {
50 Impl::ImplBlock(_) => unreachable!(),
51 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
52 }
53}
54
55pub(super) fn associated_ty_value(
56 db: &impl HirDatabase,
57 krate: CrateId,
58 data: AssocTyValue,
59) -> BuiltinImplAssocTyValueData {
60 match data {
61 AssocTyValue::TypeAlias(_) => unreachable!(),
62 AssocTyValue::ClosureFnTraitImplOutput(data) => {
63 closure_fn_trait_output_assoc_ty_value(db, krate, data)
64 }
65 }
66}
67
68fn closure_fn_trait_impl_datum(
69 db: &impl HirDatabase,
70 krate: CrateId,
71 data: super::ClosureFnTraitImplData,
72) -> Option<BuiltinImplData> {
73 // for some closure |X, Y| -> Z:
74 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
75
76 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
77
78 // validate FnOnce trait, since we need it in the assoc ty value definition
79 // and don't want to return a valid value only to find out later that FnOnce
80 // is broken
81 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
82 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?;
83
84 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
85 Expr::Lambda { args, .. } => args.len() as u16,
86 _ => {
87 log::warn!("closure for closure type {:?} not found", data);
88 0
89 }
90 };
91
92 let arg_ty = Ty::apply(
93 TypeCtor::Tuple { cardinality: num_args },
94 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
95 );
96 let sig_ty = Ty::apply(
97 TypeCtor::FnPtr { num_args },
98 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
99 );
100
101 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
102
103 let trait_ref = TraitRef {
104 trait_: trait_.into(),
105 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
106 };
107
108 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone());
109
110 Some(BuiltinImplData {
111 num_vars: num_args as usize + 1,
112 trait_ref,
113 where_clauses: Vec::new(),
114 assoc_ty_values: vec![output_ty_id],
115 })
116}
117
118fn closure_fn_trait_output_assoc_ty_value(
119 db: &impl HirDatabase,
120 krate: CrateId,
121 data: super::ClosureFnTraitImplData,
122) -> BuiltinImplAssocTyValueData {
123 let impl_ = Impl::ClosureFnTraitImpl(data.clone());
124
125 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
126 Expr::Lambda { args, .. } => args.len() as u16,
127 _ => {
128 log::warn!("closure for closure type {:?} not found", data);
129 0
130 }
131 };
132
133 let output_ty = Ty::Bound(num_args.into());
134
135 let fn_once_trait =
136 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
137
138 let output_ty_id = db
139 .trait_data(fn_once_trait)
140 .associated_type_by_name(&name::OUTPUT_TYPE)
141 .expect("assoc ty value should not exist");
142
143 BuiltinImplAssocTyValueData {
144 impl_,
145 assoc_ty_id: output_ty_id,
146 num_vars: num_args as usize + 1,
147 value: output_ty,
148 }
149}
150
151fn get_fn_trait(
152 db: &impl HirDatabase,
153 krate: CrateId,
154 fn_trait: super::FnTrait,
155) -> Option<TraitId> {
156 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
157 match target {
158 LangItemTarget::TraitId(t) => Some(t),
159 _ => None,
160 }
161}
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 104346ada..e3f02fa15 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -8,17 +8,16 @@ use chalk_ir::{
8 TypeName, UniverseIndex, 8 TypeName, UniverseIndex,
9}; 9};
10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
11use ra_db::CrateId;
12 11
13use hir_def::{ 12use hir_def::{
14 expr::Expr, lang_item::LangItemTarget, AssocItemId, AstItemDef, ContainerId, GenericDefId, 13 AssocItemId, AstItemDef, ContainerId, GenericDefId, ImplId, Lookup, TraitId, TypeAliasId,
15 ImplId, Lookup, TraitId, TypeAliasId, 14};
15use ra_db::{
16 salsa::{InternId, InternKey},
17 CrateId,
16}; 18};
17use hir_expand::name;
18
19use ra_db::salsa::{InternId, InternKey};
20 19
21use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 20use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
22use crate::{ 21use crate::{
23 db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ProjectionTy, Substs, 22 db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ProjectionTy, Substs,
24 TraitRef, Ty, TypeCtor, TypeWalk, 23 TraitRef, Ty, TypeCtor, TypeWalk,
@@ -395,6 +394,51 @@ where
395 } 394 }
396} 395}
397 396
397impl ToChalk for builtin::BuiltinImplData {
398 type Chalk = chalk_rust_ir::ImplDatum<ChalkIr>;
399
400 fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::ImplDatum<ChalkIr> {
401 let impl_type = chalk_rust_ir::ImplType::External;
402 let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect();
403
404 let impl_datum_bound =
405 chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses };
406 let associated_ty_value_ids =
407 self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect();
408 chalk_rust_ir::ImplDatum {
409 binders: make_binders(impl_datum_bound, self.num_vars),
410 impl_type,
411 polarity: chalk_rust_ir::Polarity::Positive,
412 associated_ty_value_ids,
413 }
414 }
415
416 fn from_chalk(_db: &impl HirDatabase, _data: chalk_rust_ir::ImplDatum<ChalkIr>) -> Self {
417 unimplemented!()
418 }
419}
420
421impl ToChalk for builtin::BuiltinImplAssocTyValueData {
422 type Chalk = chalk_rust_ir::AssociatedTyValue<ChalkIr>;
423
424 fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::AssociatedTyValue<ChalkIr> {
425 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: self.value.to_chalk(db) };
426
427 chalk_rust_ir::AssociatedTyValue {
428 associated_ty_id: self.assoc_ty_id.to_chalk(db),
429 impl_id: self.impl_.to_chalk(db),
430 value: make_binders(value_bound, self.num_vars),
431 }
432 }
433
434 fn from_chalk(
435 _db: &impl HirDatabase,
436 _data: chalk_rust_ir::AssociatedTyValue<ChalkIr>,
437 ) -> builtin::BuiltinImplAssocTyValueData {
438 unimplemented!()
439 }
440}
441
398fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 442fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
399 chalk_ir::Binders { 443 chalk_ir::Binders {
400 value, 444 value,
@@ -456,18 +500,10 @@ where
456 .collect(); 500 .collect();
457 501
458 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); 502 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 { 503
460 for &fn_trait in 504 builtin::get_builtin_impls(self.db, self.krate, &ty, trait_, |i| {
461 [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() 505 result.push(i.to_chalk(self.db))
462 { 506 });
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 507
472 debug!("impls_for_trait returned {} impls", result.len()); 508 debug!("impls_for_trait returned {} impls", result.len());
473 result 509 result
@@ -619,7 +655,7 @@ pub(crate) fn impl_datum_query(
619 let impl_: Impl = from_chalk(db, impl_id); 655 let impl_: Impl = from_chalk(db, impl_id);
620 match impl_ { 656 match impl_ {
621 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), 657 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), 658 _ => builtin::impl_datum(db, krate, impl_).map(|d| Arc::new(d.to_chalk(db))),
623 } 659 }
624 .unwrap_or_else(invalid_impl_datum) 660 .unwrap_or_else(invalid_impl_datum)
625} 661}
@@ -700,63 +736,6 @@ fn invalid_impl_datum() -> Arc<ImplDatum<ChalkIr>> {
700 Arc::new(impl_datum) 736 Arc::new(impl_datum)
701} 737}
702 738
703fn closure_fn_trait_impl_datum(
704 db: &impl HirDatabase,
705 krate: CrateId,
706 data: super::ClosureFnTraitImplData,
707) -> Option<Arc<ImplDatum<ChalkIr>>> {
708 // for some closure |X, Y| -> Z:
709 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
710
711 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
712
713 // validate FnOnce trait, since we need it in the assoc ty value definition
714 // and don't want to return a valid value only to find out later that FnOnce
715 // is broken
716 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
717 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?;
718
719 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
720 Expr::Lambda { args, .. } => args.len() as u16,
721 _ => {
722 log::warn!("closure for closure type {:?} not found", data);
723 0
724 }
725 };
726
727 let arg_ty = Ty::apply(
728 TypeCtor::Tuple { cardinality: num_args },
729 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
730 );
731 let sig_ty = Ty::apply(
732 TypeCtor::FnPtr { num_args },
733 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
734 );
735
736 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
737
738 let trait_ref = TraitRef {
739 trait_: trait_.into(),
740 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
741 };
742
743 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db);
744
745 let impl_type = chalk_rust_ir::ImplType::External;
746
747 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
748 trait_ref: trait_ref.to_chalk(db),
749 where_clauses: Vec::new(),
750 };
751 let impl_datum = ImplDatum {
752 binders: make_binders(impl_datum_bound, num_args as usize + 1),
753 impl_type,
754 polarity: chalk_rust_ir::Polarity::Positive,
755 associated_ty_value_ids: vec![output_ty_id],
756 };
757 Some(Arc::new(impl_datum))
758}
759
760pub(crate) fn associated_ty_value_query( 739pub(crate) fn associated_ty_value_query(
761 db: &impl HirDatabase, 740 db: &impl HirDatabase,
762 krate: CrateId, 741 krate: CrateId,
@@ -767,9 +746,7 @@ pub(crate) fn associated_ty_value_query(
767 AssocTyValue::TypeAlias(type_alias) => { 746 AssocTyValue::TypeAlias(type_alias) => {
768 type_alias_associated_ty_value(db, krate, type_alias) 747 type_alias_associated_ty_value(db, krate, type_alias)
769 } 748 }
770 AssocTyValue::ClosureFnTraitImplOutput(data) => { 749 _ => Arc::new(builtin::associated_ty_value(db, krate, data).to_chalk(db)),
771 closure_fn_trait_output_assoc_ty_value(db, krate, data)
772 }
773 } 750 }
774} 751}
775 752
@@ -802,53 +779,6 @@ fn type_alias_associated_ty_value(
802 Arc::new(value) 779 Arc::new(value)
803} 780}
804 781
805fn closure_fn_trait_output_assoc_ty_value(
806 db: &impl HirDatabase,
807 krate: CrateId,
808 data: super::ClosureFnTraitImplData,
809) -> Arc<AssociatedTyValue<ChalkIr>> {
810 let impl_id = Impl::ClosureFnTraitImpl(data.clone()).to_chalk(db);
811
812 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
813 Expr::Lambda { args, .. } => args.len() as u16,
814 _ => {
815 log::warn!("closure for closure type {:?} not found", data);
816 0
817 }
818 };
819
820 let output_ty = Ty::Bound(num_args.into());
821
822 let fn_once_trait =
823 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
824
825 let output_ty_id = db
826 .trait_data(fn_once_trait)
827 .associated_type_by_name(&name::OUTPUT_TYPE)
828 .expect("assoc ty value should not exist");
829
830 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) };
831
832 let value = chalk_rust_ir::AssociatedTyValue {
833 associated_ty_id: output_ty_id.to_chalk(db),
834 impl_id,
835 value: make_binders(value_bound, num_args as usize + 1),
836 };
837 Arc::new(value)
838}
839
840fn get_fn_trait(
841 db: &impl HirDatabase,
842 krate: CrateId,
843 fn_trait: super::FnTrait,
844) -> Option<TraitId> {
845 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
846 match target {
847 LangItemTarget::TraitId(t) => Some(t),
848 _ => None,
849 }
850}
851
852fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { 782fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
853 T::from_intern_id(InternId::from(chalk_id.index)) 783 T::from_intern_id(InternId::from(chalk_id.index))
854} 784}