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(std::iter::zip(a.iter(), b.iter()).map(|(a, b)| {
627            relation.relate_with_variance(Variance::Invariant, VarianceDiagInfo::default(), a, b)
628        }))
629    }
630}
631
632impl<'db> rustc_type_ir::inherent::GenericArgs<DbInterner<'db>> for GenericArgs<'db> {
633    fn as_closure(self) -> ClosureArgs<DbInterner<'db>> {
634        ClosureArgs { args: self }
635    }
636    fn as_coroutine(self) -> CoroutineArgs<DbInterner<'db>> {
637        CoroutineArgs { args: self }
638    }
639    fn as_coroutine_closure(self) -> CoroutineClosureArgs<DbInterner<'db>> {
640        CoroutineClosureArgs { args: self }
641    }
642    fn rebase_onto(
643        self,
644        interner: DbInterner<'db>,
645        source_def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
646        target: <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs,
647    ) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
648        let defs = interner.generics_of(source_def_id);
649        interner.mk_args_from_iter(target.iter().chain(self.iter().skip(defs.count())))
650    }
651
652    fn identity_for_item(
653        interner: DbInterner<'db>,
654        def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
655    ) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
656        Self::for_item(interner, def_id, |index, kind, _, _| mk_param(interner, index, kind))
657    }
658
659    fn extend_with_error(
660        interner: DbInterner<'db>,
661        def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId,
662        original_args: &[<DbInterner<'db> as rustc_type_ir::Interner>::GenericArg],
663    ) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs {
664        Self::for_item(interner, def_id, |index, kind, _, _| {
665            if let Some(arg) = original_args.get(index as usize) {
666                *arg
667            } else {
668                error_for_param_kind(kind, interner)
669            }
670        })
671    }
672    fn type_at(self, i: usize) -> <DbInterner<'db> as rustc_type_ir::Interner>::Ty {
673        self.get(i)
674            .and_then(|g| g.as_type())
675            .unwrap_or_else(|| Ty::new_error(DbInterner::conjure(), ErrorGuaranteed))
676    }
677
678    fn region_at(self, i: usize) -> <DbInterner<'db> as rustc_type_ir::Interner>::Region {
679        self.get(i)
680            .and_then(|g| g.as_region())
681            .unwrap_or_else(|| Region::error(DbInterner::conjure()))
682    }
683
684    fn const_at(self, i: usize) -> <DbInterner<'db> as rustc_type_ir::Interner>::Const {
685        self.get(i)
686            .and_then(|g| g.as_const())
687            .unwrap_or_else(|| Const::error(DbInterner::conjure()))
688    }
689
690    fn split_closure_args(self) -> rustc_type_ir::ClosureArgsParts<DbInterner<'db>> {
691        // FIXME: should use `ClosureSubst` when possible
692        match self.as_slice() {
693            [parent_args @ .., closure_kind_ty, sig_ty, tupled_upvars_ty] => {
694                rustc_type_ir::ClosureArgsParts {
695                    parent_args,
696                    closure_sig_as_fn_ptr_ty: sig_ty.expect_ty(),
697                    closure_kind_ty: closure_kind_ty.expect_ty(),
698                    tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
699                }
700            }
701            _ => {
702                unreachable!("unexpected closure sig");
703            }
704        }
705    }
706
707    fn split_coroutine_closure_args(
708        self,
709    ) -> rustc_type_ir::CoroutineClosureArgsParts<DbInterner<'db>> {
710        match self.as_slice() {
711            [
712                parent_args @ ..,
713                closure_kind_ty,
714                signature_parts_ty,
715                tupled_upvars_ty,
716                coroutine_captures_by_ref_ty,
717            ] => rustc_type_ir::CoroutineClosureArgsParts {
718                parent_args,
719                closure_kind_ty: closure_kind_ty.expect_ty(),
720                signature_parts_ty: signature_parts_ty.expect_ty(),
721                tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
722                coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(),
723            },
724            _ => panic!("GenericArgs were likely not for a CoroutineClosure."),
725        }
726    }
727
728    fn split_coroutine_args(self) -> rustc_type_ir::CoroutineArgsParts<DbInterner<'db>> {
729        match self.as_slice() {
730            [parent_args @ .., kind_ty, resume_ty, yield_ty, return_ty, tupled_upvars_ty] => {
731                rustc_type_ir::CoroutineArgsParts {
732                    parent_args,
733                    kind_ty: kind_ty.expect_ty(),
734                    resume_ty: resume_ty.expect_ty(),
735                    yield_ty: yield_ty.expect_ty(),
736                    return_ty: return_ty.expect_ty(),
737                    tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
738                }
739            }
740            _ => panic!("GenericArgs were likely not for a Coroutine."),
741        }
742    }
743}
744
745pub fn mk_param<'db>(interner: DbInterner<'db>, index: u32, id: GenericParamId) -> GenericArg<'db> {
746    match id {
747        GenericParamId::LifetimeParamId(id) => {
748            Region::new_early_param(interner, EarlyParamRegion { index, id }).into()
749        }
750        GenericParamId::TypeParamId(id) => Ty::new_param(interner, id, index).into(),
751        GenericParamId::ConstParamId(id) => {
752            Const::new_param(interner, ParamConst { index, id }).into()
753        }
754    }
755}
756
757pub fn error_for_param_kind<'db>(id: GenericParamId, interner: DbInterner<'db>) -> GenericArg<'db> {
758    match id {
759        GenericParamId::LifetimeParamId(_) => Region::error(interner).into(),
760        GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
761        GenericParamId::ConstParamId(_) => Const::error(interner).into(),
762    }
763}
764
765impl<'db> IntoKind for Term<'db> {
766    type Kind = TermKind<'db>;
767
768    #[inline]
769    fn kind(self) -> Self::Kind {
770        self.ptr.term_kind()
771    }
772}
773
774impl<'db> From<Ty<'db>> for Term<'db> {
775    #[inline]
776    fn from(value: Ty<'db>) -> Self {
777        Term { ptr: GenericArgImpl::new_ty(value) }
778    }
779}
780
781impl<'db> From<Const<'db>> for Term<'db> {
782    #[inline]
783    fn from(value: Const<'db>) -> Self {
784        Term { ptr: GenericArgImpl::new_const(value) }
785    }
786}
787
788impl<'db> Relate<DbInterner<'db>> for Term<'db> {
789    fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
790        relation: &mut R,
791        a: Self,
792        b: Self,
793    ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
794        match (a.kind(), b.kind()) {
795            (TermKind::Ty(a_ty), TermKind::Ty(b_ty)) => Ok(relation.relate(a_ty, b_ty)?.into()),
796            (TermKind::Const(a_ct), TermKind::Const(b_ct)) => {
797                Ok(relation.relate(a_ct, b_ct)?.into())
798            }
799            (TermKind::Ty(unpacked), x) => {
800                unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
801            }
802            (TermKind::Const(unpacked), x) => {
803                unreachable!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
804            }
805        }
806    }
807}
808
809impl<'db> rustc_type_ir::inherent::Term<DbInterner<'db>> for Term<'db> {}
810
811#[derive(Clone, Eq, PartialEq, Debug)]
812pub enum TermVid {
813    Ty(TyVid),
814    Const(ConstVid),
815}
816
817impl From<TyVid> for TermVid {
818    fn from(value: TyVid) -> Self {
819        TermVid::Ty(value)
820    }
821}
822
823impl From<ConstVid> for TermVid {
824    fn from(value: ConstVid) -> Self {
825        TermVid::Const(value)
826    }
827}
828
829impl<'db> DbInterner<'db> {
830    pub(super) fn mk_args(self, args: &[GenericArg<'db>]) -> GenericArgs<'db> {
831        GenericArgs::new_from_slice(args)
832    }
833
834    pub(super) fn mk_args_from_iter<I, T>(self, iter: I) -> T::Output
835    where
836        I: Iterator<Item = T>,
837        T: rustc_type_ir::CollectAndApply<GenericArg<'db>, GenericArgs<'db>>,
838    {
839        T::collect_and_apply(iter, |xs| self.mk_args(xs))
840    }
841}