]> git.lizzy.rs Git - rust.git/blob - crates/hir-ty/src/builder.rs
Auto merge of #13223 - lowr:fix/hir-proj-normalization, r=flodiebold
[rust.git] / crates / hir-ty / src / builder.rs
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     fold::TypeFoldable,
8     interner::HasInterner,
9     AdtId, BoundVar, DebruijnIndex, Scalar,
10 };
11 use hir_def::{
12     builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
13     TypeAliasId,
14 };
15 use smallvec::SmallVec;
16
17 use crate::{
18     consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
19     to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
20     ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
21     TyDefId, TyExt, TyKind, ValueTyDefId,
22 };
23
24 #[derive(Debug, Clone, PartialEq, Eq)]
25 pub enum ParamKind {
26     Type,
27     Const(Ty),
28 }
29
30 /// This is a builder for `Ty` or anything that needs a `Substitution`.
31 pub struct TyBuilder<D> {
32     /// The `data` field is used to keep track of what we're building (e.g. an
33     /// ADT, a `TraitRef`, ...).
34     data: D,
35     vec: SmallVec<[GenericArg; 2]>,
36     param_kinds: SmallVec<[ParamKind; 2]>,
37 }
38
39 impl<A> TyBuilder<A> {
40     fn with_data<B>(self, data: B) -> TyBuilder<B> {
41         TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
42     }
43 }
44
45 impl<D> TyBuilder<D> {
46     fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
47         TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
48     }
49
50     fn build_internal(self) -> (D, Substitution) {
51         assert_eq!(self.vec.len(), self.param_kinds.len());
52         for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
53             self.assert_match_kind(a, e);
54         }
55         let subst = Substitution::from_iter(Interner, self.vec);
56         (self.data, subst)
57     }
58
59     pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
60         let arg = arg.cast(Interner);
61         let expected_kind = &self.param_kinds[self.vec.len()];
62         let arg_kind = match arg.data(Interner) {
63             chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
64             chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
65             chalk_ir::GenericArgData::Const(c) => {
66                 let c = c.data(Interner);
67                 ParamKind::Const(c.ty.clone())
68             }
69         };
70         assert_eq!(*expected_kind, arg_kind);
71         self.vec.push(arg);
72         self
73     }
74
75     pub fn remaining(&self) -> usize {
76         self.param_kinds.len() - self.vec.len()
77     }
78
79     pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
80         // self.fill is inlined to make borrow checker happy
81         let mut this = self;
82         let other = this.param_kinds.iter().skip(this.vec.len());
83         let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
84             ParamKind::Type => {
85                 GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
86                     .intern(Interner)
87             }
88             ParamKind::Const(ty) => GenericArgData::Const(
89                 ConstData {
90                     value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
91                     ty: ty.clone(),
92                 }
93                 .intern(Interner),
94             )
95             .intern(Interner),
96         });
97         this.vec.extend(filler.take(this.remaining()).casted(Interner));
98         assert_eq!(this.remaining(), 0);
99         this
100     }
101
102     pub fn fill_with_unknown(self) -> Self {
103         // self.fill is inlined to make borrow checker happy
104         let mut this = self;
105         let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
106             ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
107             ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
108         });
109         this.vec.extend(filler.casted(Interner));
110         assert_eq!(this.remaining(), 0);
111         this
112     }
113
114     pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
115         self.fill(|x| match x {
116             ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
117             ParamKind::Const(ty) => {
118                 GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
119             }
120         })
121     }
122
123     pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
124         self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
125         assert_eq!(self.remaining(), 0);
126         self
127     }
128
129     pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
130         assert!(self.vec.is_empty());
131         assert!(parent_substs.len(Interner) <= self.param_kinds.len());
132         self.extend(parent_substs.iter(Interner).cloned());
133         self
134     }
135
136     fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
137         for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
138             self.assert_match_kind(&x.0, &x.1);
139         }
140         self.vec.extend(it);
141     }
142
143     fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
144         match (a.data(Interner), e) {
145             (chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
146             | (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (),
147             _ => panic!("Mismatched kinds: {:?}, {:?}, {:?}", a, self.vec, self.param_kinds),
148         }
149     }
150 }
151
152 impl TyBuilder<()> {
153     pub fn unit() -> Ty {
154         TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
155     }
156
157     pub fn usize() -> Ty {
158         TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner)
159     }
160
161     pub fn fn_ptr(sig: CallableSig) -> Ty {
162         TyKind::Function(sig.to_fn_ptr()).intern(Interner)
163     }
164
165     pub fn builtin(builtin: BuiltinType) -> Ty {
166         match builtin {
167             BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner),
168             BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner),
169             BuiltinType::Str => TyKind::Str.intern(Interner),
170             BuiltinType::Int(t) => {
171                 TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(Interner)
172             }
173             BuiltinType::Uint(t) => {
174                 TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(Interner)
175             }
176             BuiltinType::Float(t) => {
177                 TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(Interner)
178             }
179         }
180     }
181
182     pub fn slice(argument: Ty) -> Ty {
183         TyKind::Slice(argument).intern(Interner)
184     }
185
186     pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
187         let params = generics(db.upcast(), def.into());
188         params.placeholder_subst(db)
189     }
190
191     pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
192         let def = def.into();
193         let params = generics(db.upcast(), def);
194         TyBuilder::new(
195             (),
196             params
197                 .iter()
198                 .map(|(id, data)| match data {
199                     TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
200                     TypeOrConstParamData::ConstParamData(_) => {
201                         ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
202                     }
203                 })
204                 .collect(),
205         )
206     }
207
208     pub fn build(self) -> Substitution {
209         let ((), subst) = self.build_internal();
210         subst
211     }
212 }
213
214 impl TyBuilder<hir_def::AdtId> {
215     pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
216         TyBuilder::subst_for_def(db, def).with_data(def)
217     }
218
219     pub fn fill_with_defaults(
220         mut self,
221         db: &dyn HirDatabase,
222         mut fallback: impl FnMut() -> Ty,
223     ) -> Self {
224         let defaults = db.generic_defaults(self.data.into());
225         for default_ty in defaults.iter().skip(self.vec.len()) {
226             if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
227                 if x.is_unknown() {
228                     self.vec.push(fallback().cast(Interner));
229                     continue;
230                 }
231             };
232             // each default can depend on the previous parameters
233             let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
234             self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
235         }
236         self
237     }
238
239     pub fn build(self) -> Ty {
240         let (adt, subst) = self.build_internal();
241         TyKind::Adt(AdtId(adt), subst).intern(Interner)
242     }
243 }
244
245 pub struct Tuple(usize);
246 impl TyBuilder<Tuple> {
247     pub fn tuple(size: usize) -> TyBuilder<Tuple> {
248         TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
249     }
250
251     pub fn build(self) -> Ty {
252         let (Tuple(size), subst) = self.build_internal();
253         TyKind::Tuple(size, subst).intern(Interner)
254     }
255 }
256
257 impl TyBuilder<TraitId> {
258     pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
259         TyBuilder::subst_for_def(db, def).with_data(def)
260     }
261
262     pub fn build(self) -> TraitRef {
263         let (trait_id, substitution) = self.build_internal();
264         TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }
265     }
266 }
267
268 impl TyBuilder<TypeAliasId> {
269     pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
270         TyBuilder::subst_for_def(db, def).with_data(def)
271     }
272
273     pub fn build(self) -> ProjectionTy {
274         let (type_alias, substitution) = self.build_internal();
275         ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution }
276     }
277 }
278
279 impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
280     fn subst_binders(b: Binders<T>) -> Self {
281         let param_kinds = b
282             .binders
283             .iter(Interner)
284             .map(|x| match x {
285                 chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
286                 chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
287                 chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
288             })
289             .collect();
290         TyBuilder::new(b, param_kinds)
291     }
292
293     pub fn build(self) -> T {
294         let (b, subst) = self.build_internal();
295         b.substitute(Interner, &subst)
296     }
297 }
298
299 impl TyBuilder<Binders<Ty>> {
300     pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
301         TyBuilder::subst_binders(db.ty(def))
302     }
303
304     pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
305         TyBuilder::subst_binders(db.impl_self_ty(def))
306     }
307
308     pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
309         TyBuilder::subst_binders(db.value_ty(def))
310     }
311 }