diff options
author | Florian Diebold <[email protected]> | 2019-12-03 11:16:39 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-12-03 11:30:50 +0000 |
commit | 176207f1e87bb1f2c70529cdbc66ae8c96584b03 (patch) | |
tree | dca2b8617d47a9fb498c153ae291c5eedffe7dd1 /crates | |
parent | 3376c08052a563a5d2db487c458972378edebf44 (diff) |
Extract built-in trait implementations to separate module
This untangles the builtin logic from the Chalk translation.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 161 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 184 |
3 files changed, 219 insertions, 127 deletions
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 76189a60b..d49f8fb4b 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -15,6 +15,7 @@ use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, | |||
15 | use self::chalk::{from_chalk, ToChalk}; | 15 | use self::chalk::{from_chalk, ToChalk}; |
16 | 16 | ||
17 | pub(crate) mod chalk; | 17 | pub(crate) mod chalk; |
18 | mod builtin; | ||
18 | 19 | ||
19 | #[derive(Debug, Clone)] | 20 | #[derive(Debug, Clone)] |
20 | pub struct TraitSolver { | 21 | pub struct TraitSolver { |
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`. | ||
3 | use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; | ||
4 | use hir_expand::name; | ||
5 | use ra_db::CrateId; | ||
6 | |||
7 | use super::{AssocTyValue, Impl}; | ||
8 | use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; | ||
9 | |||
10 | pub(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 | |||
17 | pub(super) struct BuiltinImplAssocTyValueData { | ||
18 | pub impl_: Impl, | ||
19 | pub assoc_ty_id: TypeAliasId, | ||
20 | pub num_vars: usize, | ||
21 | pub value: Ty, | ||
22 | } | ||
23 | |||
24 | pub(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 | |||
44 | pub(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 | |||
55 | pub(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 | |||
68 | fn 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 | |||
118 | fn 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 | |||
151 | fn 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 | }; |
10 | use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; | 10 | use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; |
11 | use ra_db::CrateId; | ||
12 | 11 | ||
13 | use hir_def::{ | 12 | use 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 | }; |
15 | use ra_db::{ | ||
16 | salsa::{InternId, InternKey}, | ||
17 | CrateId, | ||
16 | }; | 18 | }; |
17 | use hir_expand::name; | ||
18 | |||
19 | use ra_db::salsa::{InternId, InternKey}; | ||
20 | 19 | ||
21 | use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; | 20 | use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; |
22 | use crate::{ | 21 | use 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 | ||
397 | impl 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 | |||
421 | impl 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 | |||
398 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | 442 | fn 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 | ||
703 | fn 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 | |||
760 | pub(crate) fn associated_ty_value_query( | 739 | pub(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 | ||
805 | fn 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 | |||
840 | fn 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 | |||
852 | fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { | 782 | fn 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 | } |