diff options
-rw-r--r-- | crates/hir_ty/src/builder.rs | 211 | ||||
-rw-r--r-- | crates/hir_ty/src/lib.rs | 214 |
2 files changed, 221 insertions, 204 deletions
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs new file mode 100644 index 000000000..ba158a749 --- /dev/null +++ b/crates/hir_ty/src/builder.rs | |||
@@ -0,0 +1,211 @@ | |||
1 | //! `TyBuilder`, a helper for building instances of `Ty` and related types. | ||
2 | |||
3 | use std::iter; | ||
4 | |||
5 | use chalk_ir::{ | ||
6 | cast::{Cast, CastTo, Caster}, | ||
7 | interner::HasInterner, | ||
8 | AdtId, BoundVar, DebruijnIndex, Safety, Scalar, | ||
9 | }; | ||
10 | use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId}; | ||
11 | use smallvec::SmallVec; | ||
12 | |||
13 | use crate::{ | ||
14 | db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, | ||
15 | CallableSig, FnPointer, FnSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, | ||
16 | TyDefId, TyKind, TypeWalk, ValueTyDefId, | ||
17 | }; | ||
18 | |||
19 | pub struct TyBuilder<D> { | ||
20 | data: D, | ||
21 | vec: SmallVec<[GenericArg; 2]>, | ||
22 | param_count: usize, | ||
23 | } | ||
24 | |||
25 | impl<D> TyBuilder<D> { | ||
26 | fn new(data: D, param_count: usize) -> TyBuilder<D> { | ||
27 | TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) } | ||
28 | } | ||
29 | |||
30 | fn build_internal(self) -> (D, Substitution) { | ||
31 | assert_eq!(self.vec.len(), self.param_count); | ||
32 | // FIXME: would be good to have a way to construct a chalk_ir::Substitution from the interned form | ||
33 | let subst = Substitution(self.vec); | ||
34 | (self.data, subst) | ||
35 | } | ||
36 | |||
37 | pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self { | ||
38 | self.vec.push(arg.cast(&Interner)); | ||
39 | self | ||
40 | } | ||
41 | |||
42 | pub fn remaining(&self) -> usize { | ||
43 | self.param_count - self.vec.len() | ||
44 | } | ||
45 | |||
46 | pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self { | ||
47 | self.fill( | ||
48 | (starting_from..) | ||
49 | .map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)), | ||
50 | ) | ||
51 | } | ||
52 | |||
53 | pub fn fill_with_unknown(self) -> Self { | ||
54 | self.fill(iter::repeat(TyKind::Unknown.intern(&Interner))) | ||
55 | } | ||
56 | |||
57 | pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self { | ||
58 | self.vec.extend(filler.take(self.remaining()).casted(&Interner)); | ||
59 | assert_eq!(self.remaining(), 0); | ||
60 | self | ||
61 | } | ||
62 | |||
63 | pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self { | ||
64 | assert!(self.vec.is_empty()); | ||
65 | assert!(parent_substs.len(&Interner) <= self.param_count); | ||
66 | self.vec.extend(parent_substs.iter(&Interner).cloned()); | ||
67 | self | ||
68 | } | ||
69 | } | ||
70 | |||
71 | impl TyBuilder<()> { | ||
72 | pub fn unit() -> Ty { | ||
73 | TyKind::Tuple(0, Substitution::empty(&Interner)).intern(&Interner) | ||
74 | } | ||
75 | |||
76 | pub fn fn_ptr(sig: CallableSig) -> Ty { | ||
77 | TyKind::Function(FnPointer { | ||
78 | num_args: sig.params().len(), | ||
79 | sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs }, | ||
80 | substs: Substitution::from_iter(&Interner, sig.params_and_return.iter().cloned()), | ||
81 | }) | ||
82 | .intern(&Interner) | ||
83 | } | ||
84 | |||
85 | pub fn builtin(builtin: BuiltinType) -> Ty { | ||
86 | match builtin { | ||
87 | BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(&Interner), | ||
88 | BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(&Interner), | ||
89 | BuiltinType::Str => TyKind::Str.intern(&Interner), | ||
90 | BuiltinType::Int(t) => { | ||
91 | TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(&Interner) | ||
92 | } | ||
93 | BuiltinType::Uint(t) => { | ||
94 | TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(&Interner) | ||
95 | } | ||
96 | BuiltinType::Float(t) => { | ||
97 | TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(&Interner) | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> { | ||
103 | let def = def.into(); | ||
104 | let params = generics(db.upcast(), def); | ||
105 | let param_count = params.len(); | ||
106 | TyBuilder::new((), param_count) | ||
107 | } | ||
108 | |||
109 | pub fn build(self) -> Substitution { | ||
110 | let ((), subst) = self.build_internal(); | ||
111 | subst | ||
112 | } | ||
113 | } | ||
114 | |||
115 | impl TyBuilder<hir_def::AdtId> { | ||
116 | pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> { | ||
117 | let generics = generics(db.upcast(), adt.into()); | ||
118 | let param_count = generics.len(); | ||
119 | TyBuilder::new(adt, param_count) | ||
120 | } | ||
121 | |||
122 | pub fn fill_with_defaults( | ||
123 | mut self, | ||
124 | db: &dyn HirDatabase, | ||
125 | mut fallback: impl FnMut() -> Ty, | ||
126 | ) -> Self { | ||
127 | let defaults = db.generic_defaults(self.data.into()); | ||
128 | for default_ty in defaults.iter().skip(self.vec.len()) { | ||
129 | if default_ty.skip_binders().is_unknown() { | ||
130 | self.vec.push(fallback().cast(&Interner)); | ||
131 | } else { | ||
132 | // each default can depend on the previous parameters | ||
133 | let subst_so_far = Substitution(self.vec.clone()); | ||
134 | self.vec.push(default_ty.clone().subst(&subst_so_far).cast(&Interner)); | ||
135 | } | ||
136 | } | ||
137 | self | ||
138 | } | ||
139 | |||
140 | pub fn build(self) -> Ty { | ||
141 | let (adt, subst) = self.build_internal(); | ||
142 | TyKind::Adt(AdtId(adt), subst).intern(&Interner) | ||
143 | } | ||
144 | } | ||
145 | |||
146 | pub struct Tuple(usize); | ||
147 | impl TyBuilder<Tuple> { | ||
148 | pub fn tuple(size: usize) -> TyBuilder<Tuple> { | ||
149 | TyBuilder::new(Tuple(size), size) | ||
150 | } | ||
151 | |||
152 | pub fn build(self) -> Ty { | ||
153 | let (Tuple(size), subst) = self.build_internal(); | ||
154 | TyKind::Tuple(size, subst).intern(&Interner) | ||
155 | } | ||
156 | } | ||
157 | |||
158 | impl TyBuilder<TraitId> { | ||
159 | pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder<TraitId> { | ||
160 | let generics = generics(db.upcast(), trait_id.into()); | ||
161 | let param_count = generics.len(); | ||
162 | TyBuilder::new(trait_id, param_count) | ||
163 | } | ||
164 | |||
165 | pub fn build(self) -> TraitRef { | ||
166 | let (trait_id, substitution) = self.build_internal(); | ||
167 | TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | impl TyBuilder<TypeAliasId> { | ||
172 | pub fn assoc_type_projection( | ||
173 | db: &dyn HirDatabase, | ||
174 | type_alias: TypeAliasId, | ||
175 | ) -> TyBuilder<TypeAliasId> { | ||
176 | let generics = generics(db.upcast(), type_alias.into()); | ||
177 | let param_count = generics.len(); | ||
178 | TyBuilder::new(type_alias, param_count) | ||
179 | } | ||
180 | |||
181 | pub fn build(self) -> ProjectionTy { | ||
182 | let (type_alias, substitution) = self.build_internal(); | ||
183 | ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution } | ||
184 | } | ||
185 | } | ||
186 | |||
187 | impl<T: TypeWalk + HasInterner<Interner = Interner>> TyBuilder<Binders<T>> { | ||
188 | fn subst_binders(b: Binders<T>) -> Self { | ||
189 | let param_count = b.num_binders; | ||
190 | TyBuilder::new(b, param_count) | ||
191 | } | ||
192 | |||
193 | pub fn build(self) -> T { | ||
194 | let (b, subst) = self.build_internal(); | ||
195 | b.subst(&subst) | ||
196 | } | ||
197 | } | ||
198 | |||
199 | impl TyBuilder<Binders<Ty>> { | ||
200 | pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> { | ||
201 | TyBuilder::subst_binders(db.ty(def.into())) | ||
202 | } | ||
203 | |||
204 | pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> { | ||
205 | TyBuilder::subst_binders(db.impl_self_ty(def)) | ||
206 | } | ||
207 | |||
208 | pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> { | ||
209 | TyBuilder::subst_binders(db.value_ty(def)) | ||
210 | } | ||
211 | } | ||
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index f99b70f2b..ebdcc4804 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -14,6 +14,8 @@ mod lower; | |||
14 | pub(crate) mod infer; | 14 | pub(crate) mod infer; |
15 | pub(crate) mod utils; | 15 | pub(crate) mod utils; |
16 | mod chalk_cast; | 16 | mod chalk_cast; |
17 | mod chalk_ext; | ||
18 | mod builder; | ||
17 | 19 | ||
18 | pub mod display; | 20 | pub mod display; |
19 | pub mod db; | 21 | pub mod db; |
@@ -23,21 +25,18 @@ pub mod diagnostics; | |||
23 | mod tests; | 25 | mod tests; |
24 | #[cfg(test)] | 26 | #[cfg(test)] |
25 | mod test_db; | 27 | mod test_db; |
26 | mod chalk_ext; | ||
27 | 28 | ||
28 | use std::{iter, mem, sync::Arc}; | 29 | use std::{mem, sync::Arc}; |
30 | |||
31 | use chalk_ir::cast::{CastTo, Caster}; | ||
32 | use itertools::Itertools; | ||
33 | use smallvec::SmallVec; | ||
29 | 34 | ||
30 | use base_db::salsa; | 35 | use base_db::salsa; |
31 | use chalk_ir::{ | ||
32 | cast::{CastTo, Caster}, | ||
33 | interner::HasInterner, | ||
34 | }; | ||
35 | use hir_def::{ | 36 | use hir_def::{ |
36 | builtin_type::BuiltinType, expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, | 37 | expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, |
37 | GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, | 38 | LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, |
38 | }; | 39 | }; |
39 | use itertools::Itertools; | ||
40 | use smallvec::SmallVec; | ||
41 | 40 | ||
42 | use crate::{ | 41 | use crate::{ |
43 | db::HirDatabase, | 42 | db::HirDatabase, |
@@ -46,6 +45,7 @@ use crate::{ | |||
46 | }; | 45 | }; |
47 | 46 | ||
48 | pub use autoderef::autoderef; | 47 | pub use autoderef::autoderef; |
48 | pub use builder::TyBuilder; | ||
49 | pub use chalk_ext::TyExt; | 49 | pub use chalk_ext::TyExt; |
50 | pub use infer::{could_unify, InferenceResult, InferenceVar}; | 50 | pub use infer::{could_unify, InferenceResult, InferenceVar}; |
51 | pub use lower::{ | 51 | pub use lower::{ |
@@ -744,200 +744,6 @@ impl TypeWalk for CallableSig { | |||
744 | } | 744 | } |
745 | } | 745 | } |
746 | 746 | ||
747 | pub struct TyBuilder<D> { | ||
748 | data: D, | ||
749 | vec: SmallVec<[GenericArg; 2]>, | ||
750 | param_count: usize, | ||
751 | } | ||
752 | |||
753 | impl<D> TyBuilder<D> { | ||
754 | fn new(data: D, param_count: usize) -> TyBuilder<D> { | ||
755 | TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) } | ||
756 | } | ||
757 | |||
758 | fn build_internal(self) -> (D, Substitution) { | ||
759 | assert_eq!(self.vec.len(), self.param_count); | ||
760 | // FIXME: would be good to have a way to construct a chalk_ir::Substitution from the interned form | ||
761 | let subst = Substitution(self.vec); | ||
762 | (self.data, subst) | ||
763 | } | ||
764 | |||
765 | pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self { | ||
766 | self.vec.push(arg.cast(&Interner)); | ||
767 | self | ||
768 | } | ||
769 | |||
770 | fn remaining(&self) -> usize { | ||
771 | self.param_count - self.vec.len() | ||
772 | } | ||
773 | |||
774 | pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self { | ||
775 | self.fill( | ||
776 | (starting_from..) | ||
777 | .map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)), | ||
778 | ) | ||
779 | } | ||
780 | |||
781 | pub fn fill_with_unknown(self) -> Self { | ||
782 | self.fill(iter::repeat(TyKind::Unknown.intern(&Interner))) | ||
783 | } | ||
784 | |||
785 | pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self { | ||
786 | self.vec.extend(filler.take(self.remaining()).casted(&Interner)); | ||
787 | assert_eq!(self.remaining(), 0); | ||
788 | self | ||
789 | } | ||
790 | |||
791 | pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self { | ||
792 | assert!(self.vec.is_empty()); | ||
793 | assert!(parent_substs.len(&Interner) <= self.param_count); | ||
794 | self.vec.extend(parent_substs.iter(&Interner).cloned()); | ||
795 | self | ||
796 | } | ||
797 | } | ||
798 | |||
799 | impl TyBuilder<()> { | ||
800 | pub fn unit() -> Ty { | ||
801 | TyKind::Tuple(0, Substitution::empty(&Interner)).intern(&Interner) | ||
802 | } | ||
803 | |||
804 | pub fn fn_ptr(sig: CallableSig) -> Ty { | ||
805 | TyKind::Function(FnPointer { | ||
806 | num_args: sig.params().len(), | ||
807 | sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs }, | ||
808 | substs: Substitution::from_iter(&Interner, sig.params_and_return.iter().cloned()), | ||
809 | }) | ||
810 | .intern(&Interner) | ||
811 | } | ||
812 | |||
813 | pub fn builtin(builtin: BuiltinType) -> Ty { | ||
814 | match builtin { | ||
815 | BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(&Interner), | ||
816 | BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(&Interner), | ||
817 | BuiltinType::Str => TyKind::Str.intern(&Interner), | ||
818 | BuiltinType::Int(t) => { | ||
819 | TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(&Interner) | ||
820 | } | ||
821 | BuiltinType::Uint(t) => { | ||
822 | TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(&Interner) | ||
823 | } | ||
824 | BuiltinType::Float(t) => { | ||
825 | TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(&Interner) | ||
826 | } | ||
827 | } | ||
828 | } | ||
829 | |||
830 | pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> { | ||
831 | let def = def.into(); | ||
832 | let params = generics(db.upcast(), def); | ||
833 | let param_count = params.len(); | ||
834 | TyBuilder::new((), param_count) | ||
835 | } | ||
836 | |||
837 | pub fn build(self) -> Substitution { | ||
838 | let ((), subst) = self.build_internal(); | ||
839 | subst | ||
840 | } | ||
841 | } | ||
842 | |||
843 | impl TyBuilder<hir_def::AdtId> { | ||
844 | pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> { | ||
845 | let generics = generics(db.upcast(), adt.into()); | ||
846 | let param_count = generics.len(); | ||
847 | TyBuilder::new(adt, param_count) | ||
848 | } | ||
849 | |||
850 | pub fn fill_with_defaults( | ||
851 | mut self, | ||
852 | db: &dyn HirDatabase, | ||
853 | mut fallback: impl FnMut() -> Ty, | ||
854 | ) -> Self { | ||
855 | let defaults = db.generic_defaults(self.data.into()); | ||
856 | for default_ty in defaults.iter().skip(self.vec.len()) { | ||
857 | if default_ty.skip_binders().is_unknown() { | ||
858 | self.vec.push(fallback().cast(&Interner)); | ||
859 | } else { | ||
860 | // each default can depend on the previous parameters | ||
861 | let subst_so_far = Substitution(self.vec.clone()); | ||
862 | self.vec.push(default_ty.clone().subst(&subst_so_far).cast(&Interner)); | ||
863 | } | ||
864 | } | ||
865 | self | ||
866 | } | ||
867 | |||
868 | pub fn build(self) -> Ty { | ||
869 | let (adt, subst) = self.build_internal(); | ||
870 | TyKind::Adt(AdtId(adt), subst).intern(&Interner) | ||
871 | } | ||
872 | } | ||
873 | |||
874 | struct Tuple(usize); | ||
875 | impl TyBuilder<Tuple> { | ||
876 | pub fn tuple(size: usize) -> TyBuilder<Tuple> { | ||
877 | TyBuilder::new(Tuple(size), size) | ||
878 | } | ||
879 | |||
880 | pub fn build(self) -> Ty { | ||
881 | let (Tuple(size), subst) = self.build_internal(); | ||
882 | TyKind::Tuple(size, subst).intern(&Interner) | ||
883 | } | ||
884 | } | ||
885 | |||
886 | impl TyBuilder<TraitId> { | ||
887 | pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder<TraitId> { | ||
888 | let generics = generics(db.upcast(), trait_id.into()); | ||
889 | let param_count = generics.len(); | ||
890 | TyBuilder::new(trait_id, param_count) | ||
891 | } | ||
892 | |||
893 | pub fn build(self) -> TraitRef { | ||
894 | let (trait_id, substitution) = self.build_internal(); | ||
895 | TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution } | ||
896 | } | ||
897 | } | ||
898 | |||
899 | impl TyBuilder<TypeAliasId> { | ||
900 | pub fn assoc_type_projection( | ||
901 | db: &dyn HirDatabase, | ||
902 | type_alias: TypeAliasId, | ||
903 | ) -> TyBuilder<TypeAliasId> { | ||
904 | let generics = generics(db.upcast(), type_alias.into()); | ||
905 | let param_count = generics.len(); | ||
906 | TyBuilder::new(type_alias, param_count) | ||
907 | } | ||
908 | |||
909 | pub fn build(self) -> ProjectionTy { | ||
910 | let (type_alias, substitution) = self.build_internal(); | ||
911 | ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution } | ||
912 | } | ||
913 | } | ||
914 | |||
915 | impl<T: TypeWalk + HasInterner<Interner = Interner>> TyBuilder<Binders<T>> { | ||
916 | fn subst_binders(b: Binders<T>) -> Self { | ||
917 | let param_count = b.num_binders; | ||
918 | TyBuilder::new(b, param_count) | ||
919 | } | ||
920 | |||
921 | pub fn build(self) -> T { | ||
922 | let (b, subst) = self.build_internal(); | ||
923 | b.subst(&subst) | ||
924 | } | ||
925 | } | ||
926 | |||
927 | impl TyBuilder<Binders<Ty>> { | ||
928 | pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> { | ||
929 | TyBuilder::subst_binders(db.ty(def.into())) | ||
930 | } | ||
931 | |||
932 | pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> { | ||
933 | TyBuilder::subst_binders(db.impl_self_ty(def)) | ||
934 | } | ||
935 | |||
936 | pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> { | ||
937 | TyBuilder::subst_binders(db.value_ty(def)) | ||
938 | } | ||
939 | } | ||
940 | |||
941 | impl Ty { | 747 | impl Ty { |
942 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { | 748 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { |
943 | match self.kind(&Interner) { | 749 | match self.kind(&Interner) { |