diff options
author | Florian Diebold <[email protected]> | 2021-04-04 11:55:47 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2021-04-04 12:16:39 +0100 |
commit | 715c178f0b52117c4c689c39a0921012bfbb2386 (patch) | |
tree | 63d578f6ed6d84bf98a2c368ea80b1e159746ab4 /crates/hir_ty/src/builder.rs | |
parent | 584d1c9e5bc39402e2855d0ffa9394ae5a066060 (diff) |
Move TyBuilder to its own module
Diffstat (limited to 'crates/hir_ty/src/builder.rs')
-rw-r--r-- | crates/hir_ty/src/builder.rs | 211 |
1 files changed, 211 insertions, 0 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 | } | ||