aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/builder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/builder.rs')
-rw-r--r--crates/hir_ty/src/builder.rs211
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
3use std::iter;
4
5use chalk_ir::{
6 cast::{Cast, CastTo, Caster},
7 interner::HasInterner,
8 AdtId, BoundVar, DebruijnIndex, Safety, Scalar,
9};
10use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId};
11use smallvec::SmallVec;
12
13use 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
19pub struct TyBuilder<D> {
20 data: D,
21 vec: SmallVec<[GenericArg; 2]>,
22 param_count: usize,
23}
24
25impl<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
71impl 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
115impl 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
146pub struct Tuple(usize);
147impl 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
158impl 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
171impl 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
187impl<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
199impl 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}