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