1use core::intrinsics;
4use std::marker::PhantomData;
5use std::num::NonZero;
6use std::ptr::NonNull;
7
8use rustc_data_structures::intern::Interned;
9use rustc_errors::{DiagArgValue, IntoDiagArg};
10use rustc_hir::def_id::DefId;
11use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
12use rustc_serialize::{Decodable, Encodable};
13use rustc_type_ir::WithCachedTypeInfo;
14use smallvec::SmallVec;
15
16use crate::ty::codec::{TyDecoder, TyEncoder};
17use crate::ty::{
18 self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, InlineConstArgs,
19 Lift, List, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, VisitorResult,
20 walk_visitable_list,
21};
22
23pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind<TyCtxt<'tcx>>;
24pub type TermKind<'tcx> = rustc_type_ir::TermKind<TyCtxt<'tcx>>;
25
26#[derive(Copy, Clone, PartialEq, Eq, Hash)]
35pub struct GenericArg<'tcx> {
36 ptr: NonNull<()>,
37 marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>,
38}
39
40impl<'tcx> rustc_type_ir::inherent::GenericArg<TyCtxt<'tcx>> for GenericArg<'tcx> {}
41
42impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
43 fn rebase_onto(
44 self,
45 tcx: TyCtxt<'tcx>,
46 source_ancestor: DefId,
47 target_args: GenericArgsRef<'tcx>,
48 ) -> GenericArgsRef<'tcx> {
49 self.rebase_onto(tcx, source_ancestor, target_args)
50 }
51
52 fn type_at(self, i: usize) -> Ty<'tcx> {
53 self.type_at(i)
54 }
55
56 fn region_at(self, i: usize) -> ty::Region<'tcx> {
57 self.region_at(i)
58 }
59
60 fn const_at(self, i: usize) -> ty::Const<'tcx> {
61 self.const_at(i)
62 }
63
64 fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
65 GenericArgs::identity_for_item(tcx, def_id)
66 }
67
68 fn extend_with_error(
69 tcx: TyCtxt<'tcx>,
70 def_id: DefId,
71 original_args: &[ty::GenericArg<'tcx>],
72 ) -> ty::GenericArgsRef<'tcx> {
73 ty::GenericArgs::extend_with_error(tcx, def_id, original_args)
74 }
75
76 fn split_closure_args(self) -> ty::ClosureArgsParts<TyCtxt<'tcx>> {
77 match self[..] {
78 [ref parent_args @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
79 ty::ClosureArgsParts {
80 parent_args,
81 closure_kind_ty: closure_kind_ty.expect_ty(),
82 closure_sig_as_fn_ptr_ty: closure_sig_as_fn_ptr_ty.expect_ty(),
83 tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
84 }
85 }
86 _ => bug!("closure args missing synthetics"),
87 }
88 }
89
90 fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts<TyCtxt<'tcx>> {
91 match self[..] {
92 [
93 ref parent_args @ ..,
94 closure_kind_ty,
95 signature_parts_ty,
96 tupled_upvars_ty,
97 coroutine_captures_by_ref_ty,
98 coroutine_witness_ty,
99 ] => ty::CoroutineClosureArgsParts {
100 parent_args,
101 closure_kind_ty: closure_kind_ty.expect_ty(),
102 signature_parts_ty: signature_parts_ty.expect_ty(),
103 tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
104 coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(),
105 coroutine_witness_ty: coroutine_witness_ty.expect_ty(),
106 },
107 _ => bug!("closure args missing synthetics"),
108 }
109 }
110
111 fn split_coroutine_args(self) -> ty::CoroutineArgsParts<TyCtxt<'tcx>> {
112 match self[..] {
113 [
114 ref parent_args @ ..,
115 kind_ty,
116 resume_ty,
117 yield_ty,
118 return_ty,
119 witness,
120 tupled_upvars_ty,
121 ] => ty::CoroutineArgsParts {
122 parent_args,
123 kind_ty: kind_ty.expect_ty(),
124 resume_ty: resume_ty.expect_ty(),
125 yield_ty: yield_ty.expect_ty(),
126 return_ty: return_ty.expect_ty(),
127 witness: witness.expect_ty(),
128 tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
129 },
130 _ => bug!("coroutine args missing synthetics"),
131 }
132 }
133}
134
135impl<'tcx> rustc_type_ir::inherent::IntoKind for GenericArg<'tcx> {
136 type Kind = GenericArgKind<'tcx>;
137
138 fn kind(self) -> Self::Kind {
139 self.unpack()
140 }
141}
142
143unsafe impl<'tcx> rustc_data_structures::sync::DynSend for GenericArg<'tcx> where
144 &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSend
145{
146}
147unsafe impl<'tcx> rustc_data_structures::sync::DynSync for GenericArg<'tcx> where
148 &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSync
149{
150}
151unsafe impl<'tcx> Send for GenericArg<'tcx> where
152 &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): Send
153{
154}
155unsafe impl<'tcx> Sync for GenericArg<'tcx> where
156 &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): Sync
157{
158}
159
160impl<'tcx> IntoDiagArg for GenericArg<'tcx> {
161 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
162 self.to_string().into_diag_arg(&mut None)
163 }
164}
165
166const TAG_MASK: usize = 0b11;
167const TYPE_TAG: usize = 0b00;
168const REGION_TAG: usize = 0b01;
169const CONST_TAG: usize = 0b10;
170
171#[extension(trait GenericArgPackExt<'tcx>)]
172impl<'tcx> GenericArgKind<'tcx> {
173 #[inline]
174 fn pack(self) -> GenericArg<'tcx> {
175 let (tag, ptr) = match self {
176 GenericArgKind::Lifetime(lt) => {
177 assert_eq!(align_of_val(&*lt.0.0) & TAG_MASK, 0);
179 (REGION_TAG, NonNull::from(lt.0.0).cast())
180 }
181 GenericArgKind::Type(ty) => {
182 assert_eq!(align_of_val(&*ty.0.0) & TAG_MASK, 0);
184 (TYPE_TAG, NonNull::from(ty.0.0).cast())
185 }
186 GenericArgKind::Const(ct) => {
187 assert_eq!(align_of_val(&*ct.0.0) & TAG_MASK, 0);
189 (CONST_TAG, NonNull::from(ct.0.0).cast())
190 }
191 };
192
193 GenericArg { ptr: ptr.map_addr(|addr| addr | tag), marker: PhantomData }
194 }
195}
196
197impl<'tcx> From<ty::Region<'tcx>> for GenericArg<'tcx> {
198 #[inline]
199 fn from(r: ty::Region<'tcx>) -> GenericArg<'tcx> {
200 GenericArgKind::Lifetime(r).pack()
201 }
202}
203
204impl<'tcx> From<Ty<'tcx>> for GenericArg<'tcx> {
205 #[inline]
206 fn from(ty: Ty<'tcx>) -> GenericArg<'tcx> {
207 GenericArgKind::Type(ty).pack()
208 }
209}
210
211impl<'tcx> From<ty::Const<'tcx>> for GenericArg<'tcx> {
212 #[inline]
213 fn from(c: ty::Const<'tcx>) -> GenericArg<'tcx> {
214 GenericArgKind::Const(c).pack()
215 }
216}
217
218impl<'tcx> From<ty::Term<'tcx>> for GenericArg<'tcx> {
219 fn from(value: ty::Term<'tcx>) -> Self {
220 match value.unpack() {
221 ty::TermKind::Ty(t) => t.into(),
222 ty::TermKind::Const(c) => c.into(),
223 }
224 }
225}
226
227impl<'tcx> GenericArg<'tcx> {
228 #[inline]
229 pub fn unpack(self) -> GenericArgKind<'tcx> {
230 let ptr =
231 unsafe { self.ptr.map_addr(|addr| NonZero::new_unchecked(addr.get() & !TAG_MASK)) };
232 unsafe {
236 match self.ptr.addr().get() & TAG_MASK {
237 REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked(
238 ptr.cast::<ty::RegionKind<'tcx>>().as_ref(),
239 ))),
240 TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
241 ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(),
242 ))),
243 CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
244 ptr.cast::<WithCachedTypeInfo<ty::ConstKind<'tcx>>>().as_ref(),
245 ))),
246 _ => intrinsics::unreachable(),
247 }
248 }
249 }
250
251 #[inline]
252 pub fn as_type(self) -> Option<Ty<'tcx>> {
253 match self.unpack() {
254 GenericArgKind::Type(ty) => Some(ty),
255 _ => None,
256 }
257 }
258
259 #[inline]
260 pub fn as_region(self) -> Option<ty::Region<'tcx>> {
261 match self.unpack() {
262 GenericArgKind::Lifetime(re) => Some(re),
263 _ => None,
264 }
265 }
266
267 #[inline]
268 pub fn as_const(self) -> Option<ty::Const<'tcx>> {
269 match self.unpack() {
270 GenericArgKind::Const(ct) => Some(ct),
271 _ => None,
272 }
273 }
274
275 pub fn expect_region(self) -> ty::Region<'tcx> {
277 self.as_region().unwrap_or_else(|| bug!("expected a region, but found another kind"))
278 }
279
280 pub fn expect_ty(self) -> Ty<'tcx> {
284 self.as_type().unwrap_or_else(|| bug!("expected a type, but found another kind"))
285 }
286
287 pub fn expect_const(self) -> ty::Const<'tcx> {
289 self.as_const().unwrap_or_else(|| bug!("expected a const, but found another kind"))
290 }
291
292 pub fn is_non_region_infer(self) -> bool {
293 match self.unpack() {
294 GenericArgKind::Lifetime(_) => false,
295 GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(),
297 GenericArgKind::Const(ct) => ct.is_ct_infer(),
298 }
299 }
300}
301
302impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for GenericArg<'a> {
303 type Lifted = GenericArg<'tcx>;
304
305 fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
306 match self.unpack() {
307 GenericArgKind::Lifetime(lt) => tcx.lift(lt).map(|lt| lt.into()),
308 GenericArgKind::Type(ty) => tcx.lift(ty).map(|ty| ty.into()),
309 GenericArgKind::Const(ct) => tcx.lift(ct).map(|ct| ct.into()),
310 }
311 }
312}
313
314impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArg<'tcx> {
315 fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
316 self,
317 folder: &mut F,
318 ) -> Result<Self, F::Error> {
319 match self.unpack() {
320 GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into),
321 GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into),
322 GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
323 }
324 }
325}
326
327impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for GenericArg<'tcx> {
328 fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
329 match self.unpack() {
330 GenericArgKind::Lifetime(lt) => lt.visit_with(visitor),
331 GenericArgKind::Type(ty) => ty.visit_with(visitor),
332 GenericArgKind::Const(ct) => ct.visit_with(visitor),
333 }
334 }
335}
336
337impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for GenericArg<'tcx> {
338 fn encode(&self, e: &mut E) {
339 self.unpack().encode(e)
340 }
341}
342
343impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for GenericArg<'tcx> {
344 fn decode(d: &mut D) -> GenericArg<'tcx> {
345 GenericArgKind::decode(d).pack()
346 }
347}
348
349pub type GenericArgs<'tcx> = List<GenericArg<'tcx>>;
351
352pub type GenericArgsRef<'tcx> = &'tcx GenericArgs<'tcx>;
353
354impl<'tcx> GenericArgs<'tcx> {
355 pub fn into_type_list(&self, tcx: TyCtxt<'tcx>) -> &'tcx List<Ty<'tcx>> {
361 tcx.mk_type_list_from_iter(self.iter().map(|arg| match arg.unpack() {
362 GenericArgKind::Type(ty) => ty,
363 _ => bug!("`into_type_list` called on generic arg with non-types"),
364 }))
365 }
366
367 pub fn as_closure(&'tcx self) -> ClosureArgs<TyCtxt<'tcx>> {
372 ClosureArgs { args: self }
373 }
374
375 pub fn as_coroutine_closure(&'tcx self) -> CoroutineClosureArgs<TyCtxt<'tcx>> {
380 CoroutineClosureArgs { args: self }
381 }
382
383 pub fn as_coroutine(&'tcx self) -> CoroutineArgs<TyCtxt<'tcx>> {
388 CoroutineArgs { args: self }
389 }
390
391 pub fn as_inline_const(&'tcx self) -> InlineConstArgs<'tcx> {
396 InlineConstArgs { args: self }
397 }
398
399 pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: impl Into<DefId>) -> GenericArgsRef<'tcx> {
401 Self::for_item(tcx, def_id.into(), |param, _| tcx.mk_param_from_def(param))
402 }
403
404 pub fn for_item<F>(tcx: TyCtxt<'tcx>, def_id: DefId, mut mk_kind: F) -> GenericArgsRef<'tcx>
410 where
411 F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>,
412 {
413 let defs = tcx.generics_of(def_id);
414 let count = defs.count();
415 let mut args = SmallVec::with_capacity(count);
416 Self::fill_item(&mut args, tcx, defs, &mut mk_kind);
417 tcx.mk_args(&args)
418 }
419
420 pub fn extend_to<F>(
421 &self,
422 tcx: TyCtxt<'tcx>,
423 def_id: DefId,
424 mut mk_kind: F,
425 ) -> GenericArgsRef<'tcx>
426 where
427 F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>,
428 {
429 Self::for_item(tcx, def_id, |param, args| {
430 self.get(param.index as usize).cloned().unwrap_or_else(|| mk_kind(param, args))
431 })
432 }
433
434 pub fn fill_item<F>(
435 args: &mut SmallVec<[GenericArg<'tcx>; 8]>,
436 tcx: TyCtxt<'tcx>,
437 defs: &ty::Generics,
438 mk_kind: &mut F,
439 ) where
440 F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>,
441 {
442 if let Some(def_id) = defs.parent {
443 let parent_defs = tcx.generics_of(def_id);
444 Self::fill_item(args, tcx, parent_defs, mk_kind);
445 }
446 Self::fill_single(args, defs, mk_kind)
447 }
448
449 pub fn fill_single<F>(
450 args: &mut SmallVec<[GenericArg<'tcx>; 8]>,
451 defs: &ty::Generics,
452 mk_kind: &mut F,
453 ) where
454 F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>,
455 {
456 args.reserve(defs.own_params.len());
457 for param in &defs.own_params {
458 let kind = mk_kind(param, args);
459 assert_eq!(param.index as usize, args.len(), "{args:#?}, {defs:#?}");
460 args.push(kind);
461 }
462 }
463
464 pub fn extend_with_error(
467 tcx: TyCtxt<'tcx>,
468 def_id: DefId,
469 original_args: &[GenericArg<'tcx>],
470 ) -> GenericArgsRef<'tcx> {
471 ty::GenericArgs::for_item(tcx, def_id, |def, _| {
472 if let Some(arg) = original_args.get(def.index as usize) {
473 *arg
474 } else {
475 def.to_error(tcx)
476 }
477 })
478 }
479
480 #[inline]
481 pub fn types(&self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> {
482 self.iter().filter_map(|k| k.as_type())
483 }
484
485 #[inline]
486 pub fn regions(&self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> {
487 self.iter().filter_map(|k| k.as_region())
488 }
489
490 #[inline]
491 pub fn consts(&self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> {
492 self.iter().filter_map(|k| k.as_const())
493 }
494
495 #[inline]
497 pub fn non_erasable_generics(&self) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> {
498 self.iter().filter_map(|k| match k.unpack() {
499 ty::GenericArgKind::Lifetime(_) => None,
500 generic => Some(generic),
501 })
502 }
503
504 #[inline]
505 #[track_caller]
506 pub fn type_at(&self, i: usize) -> Ty<'tcx> {
507 self[i].as_type().unwrap_or_else(|| bug!("expected type for param #{} in {:?}", i, self))
508 }
509
510 #[inline]
511 #[track_caller]
512 pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
513 self[i]
514 .as_region()
515 .unwrap_or_else(|| bug!("expected region for param #{} in {:?}", i, self))
516 }
517
518 #[inline]
519 #[track_caller]
520 pub fn const_at(&self, i: usize) -> ty::Const<'tcx> {
521 self[i].as_const().unwrap_or_else(|| bug!("expected const for param #{} in {:?}", i, self))
522 }
523
524 #[inline]
525 #[track_caller]
526 pub fn type_for_def(&self, def: &ty::GenericParamDef) -> GenericArg<'tcx> {
527 self.type_at(def.index as usize).into()
528 }
529
530 pub fn rebase_onto(
549 &self,
550 tcx: TyCtxt<'tcx>,
551 source_ancestor: DefId,
552 target_args: GenericArgsRef<'tcx>,
553 ) -> GenericArgsRef<'tcx> {
554 let defs = tcx.generics_of(source_ancestor);
555 tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.count())))
556 }
557
558 pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> GenericArgsRef<'tcx> {
559 tcx.mk_args_from_iter(self.iter().take(generics.count()))
560 }
561
562 pub fn print_as_list(&self) -> String {
563 let v = self.iter().map(|arg| arg.to_string()).collect::<Vec<_>>();
564 format!("[{}]", v.join(", "))
565 }
566}
567
568impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArgsRef<'tcx> {
569 fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
570 self,
571 folder: &mut F,
572 ) -> Result<Self, F::Error> {
573 match self.len() {
580 1 => {
581 let param0 = self[0].try_fold_with(folder)?;
582 if param0 == self[0] { Ok(self) } else { Ok(folder.cx().mk_args(&[param0])) }
583 }
584 2 => {
585 let param0 = self[0].try_fold_with(folder)?;
586 let param1 = self[1].try_fold_with(folder)?;
587 if param0 == self[0] && param1 == self[1] {
588 Ok(self)
589 } else {
590 Ok(folder.cx().mk_args(&[param0, param1]))
591 }
592 }
593 0 => Ok(self),
594 _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_args(v)),
595 }
596 }
597}
598
599impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
600 fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
601 self,
602 folder: &mut F,
603 ) -> Result<Self, F::Error> {
604 match self.len() {
620 2 => {
621 let param0 = self[0].try_fold_with(folder)?;
622 let param1 = self[1].try_fold_with(folder)?;
623 if param0 == self[0] && param1 == self[1] {
624 Ok(self)
625 } else {
626 Ok(folder.cx().mk_type_list(&[param0, param1]))
627 }
628 }
629 _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)),
630 }
631 }
632}
633
634impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for &'tcx ty::List<T> {
635 #[inline]
636 fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
637 walk_visitable_list!(visitor, self.iter());
638 V::Result::output()
639 }
640}
641
642#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
645#[derive(HashStable, TypeFoldable, TypeVisitable)]
646pub struct UserArgs<'tcx> {
647 pub args: GenericArgsRef<'tcx>,
649
650 pub user_self_ty: Option<UserSelfTy<'tcx>>,
653}
654
655#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
672#[derive(HashStable, TypeFoldable, TypeVisitable)]
673pub struct UserSelfTy<'tcx> {
674 pub impl_def_id: DefId,
675 pub self_ty: Ty<'tcx>,
676}