hir_ty/
builder.rs

1//! `TyBuilder`, a helper for building instances of `Ty` and related types.
2
3use 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
30/// This is a builder for `Ty` or anything that needs a `Substitution`.
31pub 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    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        // self.fill is inlined to make borrow checker happy
114        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        // self.fill is inlined to make borrow checker happy
132        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    // FIXME: rustc's ty is dependent on the adt type, maybe we need to do that as well
174    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    /// Creates a `TyBuilder` to build `Substitution` for a coroutine defined in `parent`.
250    ///
251    /// A coroutine's substitution consists of:
252    /// - resume type of coroutine
253    /// - yield type of coroutine ([`Coroutine::Yield`](std::ops::Coroutine::Yield))
254    /// - return type of coroutine ([`Coroutine::Return`](std::ops::Coroutine::Return))
255    /// - generic parameters in scope on `parent`
256    ///
257    /// in this order.
258    ///
259    /// This method prepopulates the builder with placeholder substitution of `parent`, so you
260    /// should only push exactly 3 `GenericArg`s before building.
261    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        // These represent resume type, yield type, and return type of coroutine.
265        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        // Note that we're building ADT, so we never have parent generic parameters.
307        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                // NOTE(skip_binders): we only check if the arg type is error type.
312                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                // Each default can only depend on the previous parameters.
319                self.vec.push(default_ty.clone().substitute(Interner, &*self.vec).cast(Interner));
320            }
321        }
322
323        // The defaults may be missing if no param has default, so fill that.
324        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}