Skip to main content

hir_ty/next_solver/
generic_arg.rs

1//! Things related to generic args in the next-trait-solver (`GenericArg`, `GenericArgs`, `Term`).
2//!
3//! Implementations of `GenericArg` and `Term` are pointer-tagged instead of an enum (rustc does
4//! the same). This is done to save memory (which also helps speed) - one `GenericArg` is a machine
5//! word instead of two, while matching on it is basically as cheap. The implementation for both
6//! `GenericArg` and `Term` is shared in [`GenericArgImpl`]. This both simplifies the implementation,
7//! as well as enables a noop conversion from `Term` to `GenericArg`.
8
9use std::{hint::unreachable_unchecked, marker::PhantomData, ptr::NonNull};
10
11use arrayvec::ArrayVec;
12use hir_def::{GenericDefId, GenericParamId, hir::generics::LifetimeParamData};
13use intern::InternedRef;
14use rustc_type_ir::{
15    ClosureArgs, ConstVid, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder,
16    GenericTypeVisitable, Interner, TyVid, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
17    Variance,
18    inherent::{GenericArg as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _},
19    relate::{Relate, VarianceDiagInfo},
20    walk::TypeWalker,
21};
22
23use crate::next_solver::{
24    ConstInterned, RegionInterned, TyInterned, impl_foldable_for_interned_slice,
25    impl_foldable_for_stored_type, interned_slice,
26};
27
28use super::{
29    Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty,
30    generics::Generics,
31};
32
33pub type GenericArgKind<'db> = rustc_type_ir::GenericArgKind<DbInterner<'db>>;
34pub type TermKind<'db> = rustc_type_ir::TermKind<DbInterner<'db>>;
35
36#[derive(Clone, Copy, PartialEq, Eq, Hash)]
37struct GenericArgImpl<'db> {
38    /// # Invariant
39    ///
40    /// Contains an [`InternedRef`] of a [`Ty`], [`Const`] or [`Region`], bit-tagged as per the consts below.
41    ptr: NonNull<()>,
42    _marker: PhantomData<(Ty<'db>, Const<'db>, Region<'db>)>,
43}
44
45// SAFETY: We essentially own the `Ty`, `Const` or `Region`, and they are `Send + Sync`.
46unsafe impl Send for GenericArgImpl<'_> {}
47unsafe impl Sync for GenericArgImpl<'_> {}
48
49impl<'db> GenericArgImpl<'db> {
50    const KIND_MASK: usize = 0b11;
51    const PTR_MASK: usize = !Self::KIND_MASK;
52    const TY_TAG: usize = 0b00;
53    const CONST_TAG: usize = 0b01;
54    const REGION_TAG: usize = 0b10;
55
56    #[inline]
57    fn new_ty(ty: Ty<'db>) -> Self {
58        Self {
59            // SAFETY: We create it from an `InternedRef`, and it's never null.
60            ptr: unsafe {
61                NonNull::new_unchecked(
62                    ty.interned
63                        .as_raw()
64                        .cast::<()>()
65                        .cast_mut()
66                        .map_addr(|addr| addr | Self::TY_TAG),
67                )
68            },
69            _marker: PhantomData,
70        }
71    }
72
73    #[inline]
74    fn new_const(ty: Const<'db>) -> Self {
75        Self {
76            // SAFETY: We create it from an `InternedRef`, and it's never null.
77            ptr: unsafe {
78                NonNull::new_unchecked(
79                    ty.interned
80                        .as_raw()
81                        .cast::<()>()
82                        .cast_mut()
83                        .map_addr(|addr| addr | Self::CONST_TAG),
84                )
85            },
86            _marker: PhantomData,
87        }
88    }
89
90    #[inline]
91    fn new_region(ty: Region<'db>) -> Self {
92        Self {
93            // SAFETY: We create it from an `InternedRef`, and it's never null.
94            ptr: unsafe {
95                NonNull::new_unchecked(
96                    ty.interned
97                        .as_raw()
98                        .cast::<()>()
99                        .cast_mut()
100                        .map_addr(|addr| addr | Self::REGION_TAG),
101                )
102            },
103            _marker: PhantomData,
104        }
105    }
106
107    #[inline]
108    fn kind(self) -> GenericArgKind<'db> {
109        let ptr = self.ptr.as_ptr().map_addr(|addr| addr & Self::PTR_MASK);
110        // SAFETY: We can only be created from a `Ty`, a `Const` or a `Region`, and the tag will match.
111        unsafe {
112            match self.ptr.addr().get() & Self::KIND_MASK {
113                Self::TY_TAG => GenericArgKind::Type(Ty {
114                    interned: InternedRef::from_raw(ptr.cast::<TyInterned>()),
115                }),
116                Self::CONST_TAG => GenericArgKind::Const(Const {
117                    interned: InternedRef::from_raw(ptr.cast::<ConstInterned>()),
118                }),
119                Self::REGION_TAG => GenericArgKind::Lifetime(Region {
120                    interned: InternedRef::from_raw(ptr.cast::<RegionInterned>()),
121                }),
122                _ => unreachable_unchecked(),
123            }
124        }
125    }
126
127    #[inline]
128    fn term_kind(self) -> TermKind<'db> {
129        let ptr = self.ptr.as_ptr().map_addr(|addr| addr & Self::PTR_MASK);
130        // SAFETY: We can only be created from a `Ty`, a `Const` or a `Region`, and the tag will match.
131        // It is the caller's responsibility (encapsulated within this module) to only call this with
132        // `Term`, which cannot be constructed from a `Region`.
133        unsafe {
134            match self.ptr.addr().get() & Self::KIND_MASK {
135                Self::TY_TAG => {
136                    TermKind::Ty(Ty { interned: InternedRef::from_raw(ptr.cast::<TyInterned>()) })
137                }
138                Self::CONST_TAG => TermKind::Const(Const {
139                    interned: InternedRef::from_raw(ptr.cast::<ConstInterned>()),
140                }),
141                _ => unreachable_unchecked(),
142            }
143        }
144    }
145}
146
147#[derive(PartialEq, Eq, Hash)]
148pub struct StoredGenericArg {
149    ptr: GenericArgImpl<'static>,
150}
151
152impl Clone for StoredGenericArg {
153    #[inline]
154    fn clone(&self) -> Self {
155        match self.ptr.kind() {
156            GenericArgKind::Lifetime(it) => std::mem::forget(it.interned.to_owned()),
157            GenericArgKind::Type(it) => std::mem::forget(it.interned.to_owned()),
158            GenericArgKind::Const(it) => std::mem::forget(it.interned.to_owned()),
159        }
160        Self { ptr: self.ptr }
161    }
162}
163
164impl Drop for StoredGenericArg {
165    #[inline]
166    fn drop(&mut self) {
167        unsafe {
168            match self.ptr.kind() {
169                GenericArgKind::Lifetime(it) => it.interned.decrement_refcount(),
170                GenericArgKind::Type(it) => it.interned.decrement_refcount(),
171                GenericArgKind::Const(it) => it.interned.decrement_refcount(),
172            }
173        }
174    }
175}
176
177impl StoredGenericArg {
178    #[inline]
179    fn new(value: GenericArg<'_>) -> Self {
180        let result = Self { ptr: GenericArgImpl { ptr: value.ptr.ptr, _marker: PhantomData } };
181        // Increase refcount.
182        std::mem::forget(result.clone());
183        result
184    }
185
186    #[inline]
187    pub fn as_ref<'db>(&self) -> GenericArg<'db> {
188        GenericArg { ptr: self.ptr }
189    }
190}
191
192impl std::fmt::Debug for StoredGenericArg {
193    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194        self.as_ref().fmt(f)
195    }
196}
197
198impl_foldable_for_stored_type!(StoredGenericArg);
199
200#[derive(Copy, Clone, PartialEq, Eq, Hash)]
201pub struct GenericArg<'db> {
202    ptr: GenericArgImpl<'db>,
203}
204
205impl<'db> std::fmt::Debug for GenericArg<'db> {
206    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
207        match self.kind() {
208            GenericArgKind::Type(t) => std::fmt::Debug::fmt(&t, f),
209            GenericArgKind::Lifetime(r) => std::fmt::Debug::fmt(&r, f),
210            GenericArgKind::Const(c) => std::fmt::Debug::fmt(&c, f),
211        }
212    }
213}
214
215impl<'db> GenericArg<'db> {
216    #[inline]
217    pub fn store(self) -> StoredGenericArg {
218        StoredGenericArg::new(self)
219    }
220
221    #[inline]
222    pub fn kind(self) -> GenericArgKind<'db> {
223        self.ptr.kind()
224    }
225
226    pub fn ty(self) -> Option<Ty<'db>> {
227        match self.kind() {
228            GenericArgKind::Type(ty) => Some(ty),
229            _ => None,
230        }
231    }
232
233    pub fn expect_ty(self) -> Ty<'db> {
234        match self.kind() {
235            GenericArgKind::Type(ty) => ty,
236            _ => panic!("Expected ty, got {self:?}"),
237        }
238    }
239
240    pub fn konst(self) -> Option<Const<'db>> {
241        match self.kind() {
242            GenericArgKind::Const(konst) => Some(konst),
243            _ => None,
244        }
245    }
246
247    pub fn region(self) -> Option<Region<'db>> {
248        match self.kind() {
249            GenericArgKind::Lifetime(r) => Some(r),
250            _ => None,
251        }
252    }
253
254    #[inline]
255    pub(crate) fn expect_region(self) -> Region<'db> {
256        match self.kind() {
257            GenericArgKind::Lifetime(region) => region,
258            _ => panic!("expected a region, got {self:?}"),
259        }
260    }
261
262    pub fn error_from_id(interner: DbInterner<'db>, id: GenericParamId) -> GenericArg<'db> {
263        match id {
264            GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
265            GenericParamId::ConstParamId(_) => Const::error(interner).into(),
266            GenericParamId::LifetimeParamId(_) => Region::error(interner).into(),
267        }
268    }
269
270    #[inline]
271    pub fn walk(self) -> TypeWalker<DbInterner<'db>> {
272        TypeWalker::new(self)
273    }
274}
275
276impl<'db> From<Term<'db>> for GenericArg<'db> {
277    #[inline]
278    fn from(value: Term<'db>) -> Self {
279        GenericArg { ptr: value.ptr }
280    }
281}
282
283#[derive(Copy, Clone, PartialEq, Eq, Hash)]
284pub struct Term<'db> {
285    ptr: GenericArgImpl<'db>,
286}
287
288impl<'db> std::fmt::Debug for Term<'db> {
289    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290        match self.kind() {
291            TermKind::Ty(t) => std::fmt::Debug::fmt(&t, f),
292            TermKind::Const(c) => std::fmt::Debug::fmt(&c, f),
293        }
294    }
295}
296
297impl<'db> Term<'db> {
298    #[inline]
299    pub fn kind(self) -> TermKind<'db> {
300        self.ptr.term_kind()
301    }
302
303    pub fn expect_type(&self) -> Ty<'db> {
304        self.as_type().expect("expected a type, but found a const")
305    }
306
307    pub fn is_trivially_wf(&self, tcx: DbInterner<'db>) -> bool {
308        match self.kind() {
309            TermKind::Ty(ty) => ty.is_trivially_wf(tcx),
310            TermKind::Const(ct) => ct.is_trivially_wf(),
311        }
312    }
313}
314
315impl<'db> From<Ty<'db>> for GenericArg<'db> {
316    #[inline]
317    fn from(value: Ty<'db>) -> Self {
318        GenericArg { ptr: GenericArgImpl::new_ty(value) }
319    }
320}
321
322impl<'db> From<Region<'db>> for GenericArg<'db> {
323    #[inline]
324    fn from(value: Region<'db>) -> Self {
325        GenericArg { ptr: GenericArgImpl::new_region(value) }
326    }
327}
328
329impl<'db> From<Const<'db>> for GenericArg<'db> {
330    #[inline]
331    fn from(value: Const<'db>) -> Self {
332        GenericArg { ptr: GenericArgImpl::new_const(value) }
333    }
334}
335
336impl<'db> IntoKind for GenericArg<'db> {
337    type Kind = GenericArgKind<'db>;
338
339    #[inline]
340    fn kind(self) -> Self::Kind {
341        self.ptr.kind()
342    }
343}
344
345impl<'db, V> GenericTypeVisitable<V> for GenericArg<'db>
346where
347    GenericArgKind<'db>: GenericTypeVisitable<V>,
348{
349    fn generic_visit_with(&self, visitor: &mut V) {
350        self.kind().generic_visit_with(visitor);
351    }
352}
353
354impl<'db, V> GenericTypeVisitable<V> for Term<'db>
355where
356    TermKind<'db>: GenericTypeVisitable<V>,
357{
358    fn generic_visit_with(&self, visitor: &mut V) {
359        self.kind().generic_visit_with(visitor);
360    }
361}
362
363impl<'db> TypeVisitable<DbInterner<'db>> for GenericArg<'db> {
364    fn visit_with<V: TypeVisitor<DbInterner<'db>>>(&self, visitor: &mut V) -> V::Result {
365        match self.kind() {
366            GenericArgKind::Lifetime(it) => it.visit_with(visitor),
367            GenericArgKind::Type(it) => it.visit_with(visitor),
368            GenericArgKind::Const(it) => it.visit_with(visitor),
369        }
370    }
371}
372
373impl<'db> TypeVisitable<DbInterner<'db>> for Term<'db> {
374    fn visit_with<V: TypeVisitor<DbInterner<'db>>>(&self, visitor: &mut V) -> V::Result {
375        match self.kind() {
376            TermKind::Ty(it) => it.visit_with(visitor),
377            TermKind::Const(it) => it.visit_with(visitor),
378        }
379    }
380}
381
382impl<'db> TypeFoldable<DbInterner<'db>> for GenericArg<'db> {
383    fn try_fold_with<F: FallibleTypeFolder<DbInterner<'db>>>(
384        self,
385        folder: &mut F,
386    ) -> Result<Self, F::Error> {
387        Ok(match self.kind() {
388            GenericArgKind::Lifetime(it) => it.try_fold_with(folder)?.into(),
389            GenericArgKind::Type(it) => it.try_fold_with(folder)?.into(),
390            GenericArgKind::Const(it) => it.try_fold_with(folder)?.into(),
391        })
392    }
393
394    fn fold_with<F: TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
395        match self.kind() {
396            GenericArgKind::Lifetime(it) => it.fold_with(folder).into(),
397            GenericArgKind::Type(it) => it.fold_with(folder).into(),
398            GenericArgKind::Const(it) => it.fold_with(folder).into(),
399        }
400    }
401}
402
403impl<'db> TypeFoldable<DbInterner<'db>> for Term<'db> {
404    fn try_fold_with<F: FallibleTypeFolder<DbInterner<'db>>>(
405        self,
406        folder: &mut F,
407    ) -> Result<Self, F::Error> {
408        Ok(match self.kind() {
409            TermKind::Ty(it) => it.try_fold_with(folder)?.into(),
410            TermKind::Const(it) => it.try_fold_with(folder)?.into(),
411        })
412    }
413
414    fn fold_with<F: TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
415        match self.kind() {
416            TermKind::Ty(it) => it.fold_with(folder).into(),
417            TermKind::Const(it) => it.fold_with(folder).into(),
418        }
419    }
420}
421
422impl<'db> Relate<DbInterner<'db>> for GenericArg<'db> {
423    fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
424        relation: &mut R,
425        a: Self,
426        b: Self,
427    ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
428        match (a.kind(), b.kind()) {
429            (GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => {
430                Ok(relation.relate(a_lt, b_lt)?.into())
431            }
432            (GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => {
433                Ok(relation.relate(a_ty, b_ty)?.into())
434            }
435            (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => {
436                Ok(relation.relate(a_ct, b_ct)?.into())
437            }
438            (GenericArgKind::Lifetime(unpacked), x) => {
439                unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
440            }
441            (GenericArgKind::Type(unpacked), x) => {
442                unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
443            }
444            (GenericArgKind::Const(unpacked), x) => {
445                unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
446            }
447        }
448    }
449}
450
451interned_slice!(
452    GenericArgsStorage,
453    GenericArgs,
454    StoredGenericArgs,
455    generic_args,
456    GenericArg<'db>,
457    GenericArg<'static>,
458);
459impl_foldable_for_interned_slice!(GenericArgs);
460impl_foldable_for_stored_type!(StoredGenericArgs);
461
462impl<'db> rustc_type_ir::inherent::GenericArg<DbInterner<'db>> for GenericArg<'db> {}
463
464trait GenericArgsBuilder<'db>: AsRef<[GenericArg<'db>]> {
465    fn push(&mut self, arg: GenericArg<'db>);
466}
467
468impl<'db, const N: usize> GenericArgsBuilder<'db> for ArrayVec<GenericArg<'db>, N> {
469    fn push(&mut self, arg: GenericArg<'db>) {
470        self.push(arg);
471    }
472}
473
474impl<'db> GenericArgsBuilder<'db> for Vec<GenericArg<'db>> {
475    fn push(&mut self, arg: GenericArg<'db>) {
476        self.push(arg);
477    }
478}
479
480impl<'db> GenericArgs<'db> {
481    #[inline(always)]
482    fn fill_builder<F>(
483        args: &mut impl GenericArgsBuilder<'db>,
484        defs: &Generics<'db>,
485        mut mk_kind: F,
486    ) where
487        F: FnMut(
488            u32,
489            GenericParamId,
490            Option<&LifetimeParamData>,
491            &[GenericArg<'db>],
492        ) -> GenericArg<'db>,
493    {
494        defs.iter().enumerate().for_each(|(idx, (param, lt_data))| {
495            let new_arg = mk_kind(idx as u32, param, lt_data, args.as_ref());
496            args.push(new_arg);
497        });
498    }
499
500    #[cold]
501    fn fill_vec_builder<F>(defs: &Generics<'db>, count: usize, mk_kind: F) -> GenericArgs<'db>
502    where
503        F: FnMut(
504            u32,
505            GenericParamId,
506            Option<&LifetimeParamData>,
507            &[GenericArg<'db>],
508        ) -> GenericArg<'db>,
509    {
510        let mut args = Vec::with_capacity(count);
511        Self::fill_builder(&mut args, defs, mk_kind);
512        GenericArgs::new_from_slice(&args)
513    }
514
515    /// Creates an `GenericArgs` for generic parameter definitions,
516    /// by calling closures to obtain each kind.
517    /// The closures get to observe the `GenericArgs` as they're
518    /// being built, which can be used to correctly
519    /// replace defaults of generic parameters.
520    pub fn for_item<F>(
521        interner: DbInterner<'db>,
522        def_id: SolverDefId<'db>,
523        mk_kind: F,
524    ) -> GenericArgs<'db>
525    where
526        F: FnMut(
527            u32,
528            GenericParamId,
529            Option<&LifetimeParamData>,
530            &[GenericArg<'db>],
531        ) -> GenericArg<'db>,
532    {
533        let defs = interner.generics_of(def_id);
534        let count = defs.count();
535
536        if count == 0 {
537            GenericArgs::default()
538        } else if count <= 10 {
539            let mut args = ArrayVec::<_, 10>::new();
540            Self::fill_builder(&mut args, &defs, mk_kind);
541            GenericArgs::new_from_slice(&args)
542        } else {
543            Self::fill_vec_builder(&defs, count, mk_kind)
544        }
545    }
546
547    /// Creates an all-error `GenericArgs`.
548    pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId<'db>) -> GenericArgs<'db> {
549        GenericArgs::for_item(interner, def_id, |_, id, _, _| {
550            GenericArg::error_from_id(interner, id)
551        })
552    }
553
554    /// Like `for_item`, but prefers the default of a parameter if it has any.
555    pub fn for_item_with_defaults<F>(
556        interner: DbInterner<'db>,
557        def_id: GenericDefId,
558        mut fallback: F,
559    ) -> GenericArgs<'db>
560    where
561        F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
562    {
563        let defaults = interner.db.generic_defaults(def_id);
564        Self::for_item(interner, def_id.into(), |idx, id, _, prev| {
565            match defaults.get(idx as usize) {
566                Some(default) => default.instantiate(interner, prev).skip_norm_wip(),
567                None => fallback(idx, id, prev),
568            }
569        })
570    }
571
572    /// Like `for_item()`, but calls first uses the args from `first`.
573    pub fn fill_rest<F>(
574        interner: DbInterner<'db>,
575        def_id: SolverDefId<'db>,
576        first: impl IntoIterator<Item = GenericArg<'db>>,
577        mut fallback: F,
578    ) -> GenericArgs<'db>
579    where
580        F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
581    {
582        let mut iter = first.into_iter();
583        Self::for_item(interner, def_id, |idx, id, _, prev| {
584            iter.next().unwrap_or_else(|| fallback(idx, id, prev))
585        })
586    }
587
588    /// Appends default param values to `first` if needed. Params without default will call `fallback()`.
589    pub fn fill_with_defaults<F>(
590        interner: DbInterner<'db>,
591        def_id: GenericDefId,
592        first: impl IntoIterator<Item = GenericArg<'db>>,
593        mut fallback: F,
594    ) -> GenericArgs<'db>
595    where
596        F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>,
597    {
598        let defaults = interner.db.generic_defaults(def_id);
599        Self::fill_rest(interner, def_id.into(), first, |idx, id, prev| {
600            defaults
601                .get(idx as usize)
602                .map(|default| default.instantiate(interner, prev).skip_norm_wip())
603                .unwrap_or_else(|| fallback(idx, id, prev))
604        })
605    }
606
607    pub fn types(self) -> impl Iterator<Item = Ty<'db>> {
608        self.iter().filter_map(|it| it.as_type())
609    }
610
611    pub fn consts(self) -> impl Iterator<Item = Const<'db>> {
612        self.iter().filter_map(|it| it.as_const())
613    }
614
615    pub fn regions(self) -> impl Iterator<Item = Region<'db>> {
616        self.iter().filter_map(|it| it.as_region())
617    }
618}
619
620impl<'db> rustc_type_ir::relate::Relate<DbInterner<'db>> for GenericArgs<'db> {
621    fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
622        relation: &mut R,
623        a: Self,
624        b: Self,
625    ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
626        GenericArgs::new_from_iter(
627            relation.cx(),
628            std::iter::zip(a.iter(), b.iter()).map(|(a, b)| {
629                relation.relate_with_variance(
630                    Variance::Invariant,
631                    VarianceDiagInfo::default(),
632                    a,
633                    b,
634                )
635            }),
636        )
637    }
638}
639
640impl<'db> rustc_type_ir::inherent::GenericArgs<DbInterner<'db>> for GenericArgs<'db> {
641    fn as_closure(self) -> ClosureArgs<DbInterner<'db>> {
642        ClosureArgs { args: self }
643    }
644    fn as_coroutine(self) -> CoroutineArgs<DbInterner<'db>> {
645        CoroutineArgs { args: self }
646    }
647    fn as_coroutine_closure(self) -> CoroutineClosureArgs<DbInterner<'db>> {
648        CoroutineClosureArgs { args: self }
649    }
650    fn rebase_onto(
651        self,
652        interner: DbInterner<'db>,
653        source_def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
654        target: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
655    ) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
656        let defs = interner.generics_of(source_def_id);
657        interner.mk_args_from_iter(target.iter().chain(self.iter().skip(defs.count())))
658    }
659
660    fn identity_for_item(
661        interner: DbInterner<'db>,
662        def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
663    ) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
664        Self::for_item(interner, def_id, |index, kind, _, _| mk_param(interner, index, kind))
665    }
666
667    fn extend_with_error(
668        interner: DbInterner<'db>,
669        def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
670        original_args: &[<DbInterner<'db> as rustc_type_ir::Interner>::GenericArg],
671    ) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
672        Self::for_item(interner, def_id, |index, kind, _, _| {
673            if let Some(arg) = original_args.get(index as usize) {
674                *arg
675            } else {
676                error_for_param_kind(kind, interner)
677            }
678        })
679    }
680    fn type_at(self, i: usize) -> <DbInterner<'db> as rustc_type_ir::Interner>::Ty {
681        self.get(i)
682            .and_then(|g| g.as_type())
683            .unwrap_or_else(|| Ty::new_error(DbInterner::conjure(), ErrorGuaranteed))
684    }
685
686    fn region_at(self, i: usize) -> <DbInterner<'db> as rustc_type_ir::Interner>::Region {
687        self.get(i)
688            .and_then(|g| g.as_region())
689            .unwrap_or_else(|| Region::error(DbInterner::conjure()))
690    }
691
692    fn const_at(self, i: usize) -> <DbInterner<'db> as rustc_type_ir::Interner>::Const {
693        self.get(i)
694            .and_then(|g| g.as_const())
695            .unwrap_or_else(|| Const::error(DbInterner::conjure()))
696    }
697
698    fn split_closure_args(self) -> rustc_type_ir::ClosureArgsParts<DbInterner<'db>> {
699        // FIXME: should use `ClosureSubst` when possible
700        match self.as_slice() {
701            [parent_args @ .., closure_kind_ty, sig_ty, tupled_upvars_ty] => {
702                rustc_type_ir::ClosureArgsParts {
703                    parent_args,
704                    closure_sig_as_fn_ptr_ty: sig_ty.expect_ty(),
705                    closure_kind_ty: closure_kind_ty.expect_ty(),
706                    tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
707                }
708            }
709            _ => {
710                unreachable!("unexpected closure sig");
711            }
712        }
713    }
714
715    fn split_coroutine_closure_args(
716        self,
717    ) -> rustc_type_ir::CoroutineClosureArgsParts<DbInterner<'db>> {
718        match self.as_slice() {
719            [
720                parent_args @ ..,
721                closure_kind_ty,
722                signature_parts_ty,
723                tupled_upvars_ty,
724                coroutine_captures_by_ref_ty,
725            ] => rustc_type_ir::CoroutineClosureArgsParts {
726                parent_args,
727                closure_kind_ty: closure_kind_ty.expect_ty(),
728                signature_parts_ty: signature_parts_ty.expect_ty(),
729                tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
730                coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(),
731            },
732            _ => panic!("GenericArgs were likely not for a CoroutineClosure."),
733        }
734    }
735
736    fn split_coroutine_args(self) -> rustc_type_ir::CoroutineArgsParts<DbInterner<'db>> {
737        match self.as_slice() {
738            [parent_args @ .., kind_ty, resume_ty, yield_ty, return_ty, tupled_upvars_ty] => {
739                rustc_type_ir::CoroutineArgsParts {
740                    parent_args,
741                    kind_ty: kind_ty.expect_ty(),
742                    resume_ty: resume_ty.expect_ty(),
743                    yield_ty: yield_ty.expect_ty(),
744                    return_ty: return_ty.expect_ty(),
745                    tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
746                }
747            }
748            _ => panic!("GenericArgs were likely not for a Coroutine."),
749        }
750    }
751}
752
753pub fn mk_param<'db>(interner: DbInterner<'db>, index: u32, id: GenericParamId) -> GenericArg<'db> {
754    match id {
755        GenericParamId::LifetimeParamId(id) => {
756            Region::new_early_param(interner, EarlyParamRegion { index, id }).into()
757        }
758        GenericParamId::TypeParamId(id) => Ty::new_param(interner, id, index).into(),
759        GenericParamId::ConstParamId(id) => {
760            Const::new_param(interner, ParamConst { index, id }).into()
761        }
762    }
763}
764
765pub fn error_for_param_kind<'db>(id: GenericParamId, interner: DbInterner<'db>) -> GenericArg<'db> {
766    match id {
767        GenericParamId::LifetimeParamId(_) => Region::error(interner).into(),
768        GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
769        GenericParamId::ConstParamId(_) => Const::error(interner).into(),
770    }
771}
772
773impl<'db> IntoKind for Term<'db> {
774    type Kind = TermKind<'db>;
775
776    #[inline]
777    fn kind(self) -> Self::Kind {
778        self.ptr.term_kind()
779    }
780}
781
782impl<'db> From<Ty<'db>> for Term<'db> {
783    #[inline]
784    fn from(value: Ty<'db>) -> Self {
785        Term { ptr: GenericArgImpl::new_ty(value) }
786    }
787}
788
789impl<'db> From<Const<'db>> for Term<'db> {
790    #[inline]
791    fn from(value: Const<'db>) -> Self {
792        Term { ptr: GenericArgImpl::new_const(value) }
793    }
794}
795
796impl<'db> Relate<DbInterner<'db>> for Term<'db> {
797    fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
798        relation: &mut R,
799        a: Self,
800        b: Self,
801    ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
802        match (a.kind(), b.kind()) {
803            (TermKind::Ty(a_ty), TermKind::Ty(b_ty)) => Ok(relation.relate(a_ty, b_ty)?.into()),
804            (TermKind::Const(a_ct), TermKind::Const(b_ct)) => {
805                Ok(relation.relate(a_ct, b_ct)?.into())
806            }
807            (TermKind::Ty(unpacked), x) => {
808                unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
809            }
810            (TermKind::Const(unpacked), x) => {
811                unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
812            }
813        }
814    }
815}
816
817impl<'db> rustc_type_ir::inherent::Term<DbInterner<'db>> for Term<'db> {}
818
819#[derive(Clone, Eq, PartialEq, Debug)]
820pub enum TermVid {
821    Ty(TyVid),
822    Const(ConstVid),
823}
824
825impl From<TyVid> for TermVid {
826    fn from(value: TyVid) -> Self {
827        TermVid::Ty(value)
828    }
829}
830
831impl From<ConstVid> for TermVid {
832    fn from(value: ConstVid) -> Self {
833        TermVid::Const(value)
834    }
835}
836
837impl<'db> DbInterner<'db> {
838    pub(super) fn mk_args(self, args: &[GenericArg<'db>]) -> GenericArgs<'db> {
839        GenericArgs::new_from_slice(args)
840    }
841
842    pub(super) fn mk_args_from_iter<I, T>(self, iter: I) -> T::Output
843    where
844        I: Iterator<Item = T>,
845        T: rustc_type_ir::CollectAndApply<GenericArg<'db>, GenericArgs<'db>>,
846    {
847        T::collect_and_apply(iter, |xs| self.mk_args(xs))
848    }
849}