1use std::iter;
4
5use chalk_ir::{
6 AdtId, DebruijnIndex, Scalar,
7 cast::{Cast, CastTo, Caster},
8 fold::TypeFoldable,
9 interner::HasInterner,
10};
11use hir_def::{
12 DefWithBodyId, GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType,
13};
14use smallvec::SmallVec;
15
16use crate::{
17 Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy,
18 Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind, consteval::unknown_const_as_generic,
19 db::HirDatabase, error_lifetime, generics::generics, infer::unify::InferenceTable, primitive,
20 to_assoc_type_id, to_chalk_trait_id,
21};
22
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub enum ParamKind {
25 Type,
26 Lifetime,
27 Const(Ty),
28}
29
30pub struct TyBuilder<D> {
32 data: D,
35 vec: SmallVec<[GenericArg; 2]>,
36 param_kinds: SmallVec<[ParamKind; 2]>,
37 parent_subst: Substitution,
38}
39
40impl<A> TyBuilder<A> {
41 fn with_data<B>(self, data: B) -> TyBuilder<B> {
42 TyBuilder {
43 data,
44 vec: self.vec,
45 param_kinds: self.param_kinds,
46 parent_subst: self.parent_subst,
47 }
48 }
49}
50
51impl<D> TyBuilder<D> {
52 fn new(
53 data: D,
54 param_kinds: SmallVec<[ParamKind; 2]>,
55 parent_subst: Option<Substitution>,
56 ) -> Self {
57 let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
58 Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
59 }
60
61 fn new_empty(data: D) -> Self {
62 TyBuilder::new(data, SmallVec::new(), None)
63 }
64
65 fn build_internal(self) -> (D, Substitution) {
66 assert_eq!(
67 self.vec.len(),
68 self.param_kinds.len(),
69 "{} args received, {} expected ({:?})",
70 self.vec.len(),
71 self.param_kinds.len(),
72 &self.param_kinds
73 );
74 for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
75 self.assert_match_kind(a, e);
76 }
77 let subst = Substitution::from_iter(
78 Interner,
79 self.parent_subst.iter(Interner).cloned().chain(self.vec),
80 );
81 (self.data, subst)
82 }
83
84 pub fn build_into_subst(self) -> Substitution {
85 self.build_internal().1
86 }
87
88 pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
89 assert!(self.remaining() > 0);
90 let arg = arg.cast(Interner);
91 let expected_kind = &self.param_kinds[self.vec.len()];
92
93 let arg_kind = match arg.data(Interner) {
94 GenericArgData::Ty(_) => ParamKind::Type,
95 GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
96 GenericArgData::Const(c) => {
97 let c = c.data(Interner);
98 ParamKind::Const(c.ty.clone())
99 }
100 };
101 assert_eq!(*expected_kind, arg_kind);
102
103 self.vec.push(arg);
104
105 self
106 }
107
108 pub fn remaining(&self) -> usize {
109 self.param_kinds.len() - self.vec.len()
110 }
111
112 pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
113 let mut this = self;
115 let other = &this.param_kinds[this.vec.len()..];
116 let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
117 ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
118 ParamKind::Const(ty) => {
119 BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
120 }
121 ParamKind::Lifetime => {
122 BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
123 }
124 });
125 this.vec.extend(filler.take(this.remaining()).casted(Interner));
126 assert_eq!(this.remaining(), 0);
127 this
128 }
129
130 pub fn fill_with_unknown(self) -> Self {
131 let mut this = self;
133 let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
134 ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
135 ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
136 ParamKind::Lifetime => error_lifetime().cast(Interner),
137 });
138 this.vec.extend(filler.casted(Interner));
139 assert_eq!(this.remaining(), 0);
140 this
141 }
142
143 #[tracing::instrument(skip_all)]
144 pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
145 self.fill(|x| match x {
146 ParamKind::Type => table.new_type_var().cast(Interner),
147 ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
148 ParamKind::Lifetime => table.new_lifetime_var().cast(Interner),
149 })
150 }
151
152 pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
153 self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
154 assert_eq!(self.remaining(), 0);
155 self
156 }
157
158 fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
159 match (a.data(Interner), e) {
160 (GenericArgData::Ty(_), ParamKind::Type)
161 | (GenericArgData::Const(_), ParamKind::Const(_))
162 | (GenericArgData::Lifetime(_), ParamKind::Lifetime) => (),
163 _ => panic!("Mismatched kinds: {a:?}, {:?}, {:?}", self.vec, self.param_kinds),
164 }
165 }
166}
167
168impl TyBuilder<()> {
169 pub fn unit() -> Ty {
170 TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
171 }
172
173 pub fn discr_ty() -> Ty {
175 TyKind::Scalar(chalk_ir::Scalar::Int(chalk_ir::IntTy::I128)).intern(Interner)
176 }
177
178 pub fn bool() -> Ty {
179 TyKind::Scalar(chalk_ir::Scalar::Bool).intern(Interner)
180 }
181
182 pub fn usize() -> Ty {
183 TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner)
184 }
185
186 pub fn fn_ptr(sig: CallableSig) -> Ty {
187 TyKind::Function(sig.to_fn_ptr()).intern(Interner)
188 }
189
190 pub fn builtin(builtin: BuiltinType) -> Ty {
191 match builtin {
192 BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner),
193 BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner),
194 BuiltinType::Str => TyKind::Str.intern(Interner),
195 BuiltinType::Int(t) => {
196 TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(Interner)
197 }
198 BuiltinType::Uint(t) => {
199 TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(Interner)
200 }
201 BuiltinType::Float(t) => {
202 TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(Interner)
203 }
204 }
205 }
206
207 pub fn slice(argument: Ty) -> Ty {
208 TyKind::Slice(argument).intern(Interner)
209 }
210
211 pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
212 let params = generics(db, def.into());
213 params.placeholder_subst(db)
214 }
215
216 pub fn unknown_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
217 let params = generics(db, def.into());
218 Substitution::from_iter(
219 Interner,
220 params.iter_id().map(|id| match id {
221 GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
222 GenericParamId::ConstParamId(id) => {
223 unknown_const_as_generic(db.const_param_ty(id)).cast(Interner)
224 }
225 GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
226 }),
227 )
228 }
229
230 #[tracing::instrument(skip_all)]
231 pub fn subst_for_def(
232 db: &dyn HirDatabase,
233 def: impl Into<GenericDefId>,
234 parent_subst: Option<Substitution>,
235 ) -> TyBuilder<()> {
236 let generics = generics(db, def.into());
237 assert!(generics.parent_generics().is_some() == parent_subst.is_some());
238 let params = generics
239 .iter_self()
240 .map(|(id, _data)| match id {
241 GenericParamId::TypeParamId(_) => ParamKind::Type,
242 GenericParamId::ConstParamId(id) => ParamKind::Const(db.const_param_ty(id)),
243 GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
244 })
245 .collect();
246 TyBuilder::new((), params, parent_subst)
247 }
248
249 pub fn subst_for_coroutine(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
262 let parent_subst =
263 parent.as_generic_def_id(db).map(|p| generics(db, p).placeholder_subst(db));
264 let params = std::iter::repeat_n(ParamKind::Type, 3).collect();
266 TyBuilder::new((), params, parent_subst)
267 }
268
269 pub fn subst_for_closure(
270 db: &dyn HirDatabase,
271 parent: DefWithBodyId,
272 sig_ty: Ty,
273 ) -> Substitution {
274 let sig_ty = sig_ty.cast(Interner);
275 let self_subst = iter::once(&sig_ty);
276 let Some(parent) = parent.as_generic_def_id(db) else {
277 return Substitution::from_iter(Interner, self_subst);
278 };
279 Substitution::from_iter(
280 Interner,
281 generics(db, parent)
282 .placeholder_subst(db)
283 .iter(Interner)
284 .chain(self_subst)
285 .cloned()
286 .collect::<Vec<_>>(),
287 )
288 }
289
290 pub fn build(self) -> Substitution {
291 let ((), subst) = self.build_internal();
292 subst
293 }
294}
295
296impl TyBuilder<hir_def::AdtId> {
297 pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
298 TyBuilder::subst_for_def(db, def, None).with_data(def)
299 }
300
301 pub fn fill_with_defaults(
302 mut self,
303 db: &dyn HirDatabase,
304 mut fallback: impl FnMut() -> Ty,
305 ) -> Self {
306 let defaults = db.generic_defaults(self.data.into());
308
309 if let Some(defaults) = defaults.get(self.vec.len()..) {
310 for default_ty in defaults {
311 if let Some(x) = default_ty.skip_binders().ty(Interner)
313 && x.is_unknown()
314 {
315 self.vec.push(fallback().cast(Interner));
316 continue;
317 }
318 self.vec.push(default_ty.clone().substitute(Interner, &*self.vec).cast(Interner));
320 }
321 }
322
323 let filler = self.param_kinds[self.vec.len()..].iter().map(|x| match x {
325 ParamKind::Type => fallback().cast(Interner),
326 ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
327 ParamKind::Lifetime => error_lifetime().cast(Interner),
328 });
329 self.vec.extend(filler.casted(Interner));
330
331 self
332 }
333
334 pub fn build(self) -> Ty {
335 let (adt, subst) = self.build_internal();
336 TyKind::Adt(AdtId(adt), subst).intern(Interner)
337 }
338}
339
340pub struct Tuple(usize);
341impl TyBuilder<Tuple> {
342 pub fn tuple(size: usize) -> TyBuilder<Tuple> {
343 TyBuilder::new(Tuple(size), std::iter::repeat_n(ParamKind::Type, size).collect(), None)
344 }
345
346 pub fn build(self) -> Ty {
347 let (Tuple(size), subst) = self.build_internal();
348 TyKind::Tuple(size, subst).intern(Interner)
349 }
350
351 pub fn tuple_with<I>(elements: I) -> Ty
352 where
353 I: IntoIterator<Item = Ty>,
354 <I as IntoIterator>::IntoIter: ExactSizeIterator,
355 {
356 let elements = elements.into_iter();
357 let len = elements.len();
358 let mut b =
359 TyBuilder::new(Tuple(len), std::iter::repeat_n(ParamKind::Type, len).collect(), None);
360 for e in elements {
361 b = b.push(e);
362 }
363 b.build()
364 }
365}
366
367impl TyBuilder<TraitId> {
368 pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
369 TyBuilder::subst_for_def(db, def, None).with_data(def)
370 }
371
372 pub fn build(self) -> TraitRef {
373 let (trait_id, substitution) = self.build_internal();
374 TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }
375 }
376}
377
378impl TyBuilder<TypeAliasId> {
379 pub fn assoc_type_projection(
380 db: &dyn HirDatabase,
381 def: TypeAliasId,
382 parent_subst: Option<Substitution>,
383 ) -> TyBuilder<TypeAliasId> {
384 TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
385 }
386
387 pub fn build(self) -> ProjectionTy {
388 let (type_alias, substitution) = self.build_internal();
389 ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution }
390 }
391}
392
393impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
394 pub fn build(self) -> T {
395 let (b, subst) = self.build_internal();
396 b.substitute(Interner, &subst)
397 }
398}
399
400impl TyBuilder<Binders<Ty>> {
401 pub fn def_ty(
402 db: &dyn HirDatabase,
403 def: TyDefId,
404 parent_subst: Option<Substitution>,
405 ) -> TyBuilder<Binders<Ty>> {
406 let poly_ty = db.ty(def);
407 let id: GenericDefId = match def {
408 TyDefId::BuiltinType(_) => {
409 assert!(parent_subst.is_none());
410 return TyBuilder::new_empty(poly_ty);
411 }
412 TyDefId::AdtId(id) => id.into(),
413 TyDefId::TypeAliasId(id) => id.into(),
414 };
415 TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
416 }
417
418 pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
419 TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
420 }
421}