diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9f6a6a58bb7b3..3557a5f8727de 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1,5 +1,4 @@ //! Type context book-keeping. - #![allow(rustc::usage_of_ty_tykind)] mod impl_interner; @@ -45,7 +44,6 @@ use rustc_session::{IncrCompSession, Session}; use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, bug, kw, sym}; use rustc_structures::{CrateType, Limit}; -use rustc_type_ir::TyKind::*; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::{ CollectAndApply, PlaceholderType, WithCachedTypeInfo, elaborate, search_graph, @@ -74,10 +72,10 @@ use crate::traits::solve::{ use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, CanonicalizerState, Clause, ClausePolarity, Clauses, - Const, ConstKind, FnSigKind, GenericArg, GenericArgsUnsized, GenericParamDefKind, List, - ListWithCachedTypeInfo, ParamConst, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, - Predicate, PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, - TyVid, ValTree, ValTreeKind, Visibility, + Const, ConstKind, FnSigKind, GenericArg, GenericArgs, GenericArgsUnsized, GenericParamDefKind, + List, ListWithCachedTypeInfo, ParamConst, Pattern, PatternKind, PolyExistentialPredicate, + PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, + TyKind, TyVid, ValTree, ValTreeKind, Visibility, }; impl<'tcx> rustc_type_ir::inherent::DefId> for DefId { @@ -141,9 +139,7 @@ pub struct CtxtInterners<'tcx> { /// The arena that types, regions, etc. are allocated from. arena: &'tcx WorkerLocal>, - // Specifically use a speedy hash algorithm for these hash sets, since - // they're accessed quite often. - type_: InternedSet<'tcx, WithCachedTypeInfo>>, + pub(super) types: TyKindInterners<'tcx>, const_lists: InternedSet<'tcx, List>>, args: InternedSet<'tcx, GenericArgsUnsized<'tcx>>, type_lists: InternedSet<'tcx, List>>, @@ -171,6 +167,226 @@ pub struct CtxtInterners<'tcx> { canonical_inputs: InternedSet<'tcx, CanonicalInputData>>, } +/// The type tables share an arena but intern each `TyKind` variant separately. +pub(super) struct TyKindInterners<'tcx> { + arena: &'tcx WorkerLocal>, + + // Specifically use a speedy hash algorithm for these hash sets, since + // they're accessed quite often. + bool_: InternedSet<'tcx, WithCachedTypeInfo>>, + char_: InternedSet<'tcx, WithCachedTypeInfo>>, + int: InternedSet<'tcx, WithCachedTypeInfo>>, + uint: InternedSet<'tcx, WithCachedTypeInfo>>, + float: InternedSet<'tcx, WithCachedTypeInfo>>, + adt: InternedSet<'tcx, WithCachedTypeInfo>>, + foreign: InternedSet<'tcx, WithCachedTypeInfo>>, + str_: InternedSet<'tcx, WithCachedTypeInfo>>, + array: InternedSet<'tcx, WithCachedTypeInfo>>, + pat_ty: InternedSet<'tcx, WithCachedTypeInfo>>, + slice: InternedSet<'tcx, WithCachedTypeInfo>>, + raw_ptr: InternedSet<'tcx, WithCachedTypeInfo>>, + ref_: InternedSet<'tcx, WithCachedTypeInfo>>, + fn_def: InternedSet<'tcx, WithCachedTypeInfo>>, + fn_ptr: InternedSet<'tcx, WithCachedTypeInfo>>, + unsafe_binder: InternedSet<'tcx, WithCachedTypeInfo>>, + dynamic: InternedSet<'tcx, WithCachedTypeInfo>>, + closure: InternedSet<'tcx, WithCachedTypeInfo>>, + coroutine_closure: InternedSet<'tcx, WithCachedTypeInfo>>, + coroutine: InternedSet<'tcx, WithCachedTypeInfo>>, + coroutine_witness: InternedSet<'tcx, WithCachedTypeInfo>>, + never: InternedSet<'tcx, WithCachedTypeInfo>>, + tuple: InternedSet<'tcx, WithCachedTypeInfo>>, + alias: InternedSet<'tcx, WithCachedTypeInfo>>, + param: InternedSet<'tcx, WithCachedTypeInfo>>, + bound: InternedSet<'tcx, WithCachedTypeInfo>>, + placeholder: InternedSet<'tcx, WithCachedTypeInfo>>, + infer: InternedSet<'tcx, WithCachedTypeInfo>>, + error: InternedSet<'tcx, WithCachedTypeInfo>>, +} + +// Keep allocation and cached type information identical across the variant-specific +// interners. Compute flags only on an interner miss, directly from the payload. +macro_rules! type_interning_methods { + ($($name:ident($($arg:ident: $ty:ty),*) => $table:ident: + $variant:ident $(($($value:expr),*))?;)*) => { + $( + #[inline(never)] + pub(super) fn $name(&self, $($arg: $ty),*) -> Ty<'tcx> { + Ty(Interned::new_unchecked( + self.$table.intern(ty::$variant $(($($value),*))?, |kind| { + let flags = ty::FlagComputation::>::for_kind_generic::<{ + rustc_type_ir::TyKindMarker::$variant + }>(&kind); + InternedInSet(self.arena.alloc(WithCachedTypeInfo { + internee: kind, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + })) + }).0, + )) + } + )* + }; +} + +impl<'tcx> TyKindInterners<'tcx> { + fn new(arena: &'tcx WorkerLocal>) -> Self { + Self { + arena, + // Grow each type interner on demand rather than reserving the old combined + // type interner's capacity for every variant. + bool_: InternedSet::default(), + char_: InternedSet::default(), + int: InternedSet::default(), + uint: InternedSet::default(), + float: InternedSet::default(), + adt: InternedSet::default(), + foreign: InternedSet::default(), + str_: InternedSet::default(), + array: InternedSet::default(), + pat_ty: InternedSet::default(), + slice: InternedSet::default(), + raw_ptr: InternedSet::default(), + ref_: InternedSet::default(), + fn_def: InternedSet::default(), + fn_ptr: InternedSet::default(), + unsafe_binder: InternedSet::default(), + dynamic: InternedSet::default(), + closure: InternedSet::default(), + coroutine_closure: InternedSet::default(), + coroutine: InternedSet::default(), + coroutine_witness: InternedSet::default(), + never: InternedSet::default(), + tuple: InternedSet::default(), + alias: InternedSet::default(), + param: InternedSet::default(), + bound: InternedSet::default(), + placeholder: InternedSet::default(), + infer: InternedSet::default(), + error: InternedSet::default(), + } + } + + /// Selects the unique interner for a type's variant, including when checking + /// whether a type from another lifetime belongs to this context. + fn interner(&self, kind: &TyKind<'_>) -> &InternedSet<'tcx, WithCachedTypeInfo>> { + match kind { + ty::Bool => &self.bool_, + ty::Char => &self.char_, + ty::Int(..) => &self.int, + ty::Uint(..) => &self.uint, + ty::Float(..) => &self.float, + ty::Adt(..) => &self.adt, + ty::Foreign(..) => &self.foreign, + ty::Str => &self.str_, + ty::Array(..) => &self.array, + ty::Pat(..) => &self.pat_ty, + ty::Slice(..) => &self.slice, + ty::RawPtr(..) => &self.raw_ptr, + ty::Ref(..) => &self.ref_, + ty::FnDef(..) => &self.fn_def, + ty::FnPtr(..) => &self.fn_ptr, + ty::UnsafeBinder(..) => &self.unsafe_binder, + ty::Dynamic(..) => &self.dynamic, + ty::Closure(..) => &self.closure, + ty::CoroutineClosure(..) => &self.coroutine_closure, + ty::Coroutine(..) => &self.coroutine, + ty::CoroutineWitness(..) => &self.coroutine_witness, + ty::Never => &self.never, + ty::Tuple(..) => &self.tuple, + ty::Alias(..) => &self.alias, + ty::Param(..) => &self.param, + ty::Bound(..) => &self.bound, + ty::Placeholder(..) => &self.placeholder, + ty::Infer(..) => &self.infer, + ty::Error(..) => &self.error, + } + } + + fn iter(&self) -> impl Iterator>>> { + [ + &self.bool_, + &self.char_, + &self.int, + &self.uint, + &self.float, + &self.adt, + &self.foreign, + &self.str_, + &self.array, + &self.pat_ty, + &self.slice, + &self.raw_ptr, + &self.ref_, + &self.fn_def, + &self.fn_ptr, + &self.unsafe_binder, + &self.dynamic, + &self.closure, + &self.coroutine_closure, + &self.coroutine, + &self.coroutine_witness, + &self.never, + &self.tuple, + &self.alias, + &self.param, + &self.bound, + &self.placeholder, + &self.infer, + &self.error, + ] + .into_iter() + } + + type_interning_methods! { + intern_bool() => bool_: Bool; + intern_char() => char_: Char; + intern_int(int: ty::IntTy) => int: Int(int); + intern_uint(uint: ty::UintTy) => uint: Uint(uint); + intern_float(float: ty::FloatTy) => float: Float(float); + intern_adt(def: AdtDef<'tcx>, args: GenericArgs<'tcx>) => adt: + Adt(def, args); + intern_foreign(def_id: DefId) => foreign: Foreign(def_id); + intern_str() => str_: Str; + intern_array(element: Ty<'tcx>, len: Const<'tcx>) => array: + Array(element, len); + intern_pat(base: Ty<'tcx>, pat: Pattern<'tcx>) => pat_ty: + Pat(base, pat); + intern_slice(element: Ty<'tcx>) => slice: Slice(element); + intern_raw_ptr(pointee: Ty<'tcx>, mutability: hir::Mutability) => raw_ptr: + RawPtr(pointee, mutability); + intern_ref(region: Region<'tcx>, pointee: Ty<'tcx>, mutability: hir::Mutability) => ref_: + Ref(region, pointee, mutability); + intern_fn_def(def_id: DefId, args: Binder<'tcx, GenericArgs<'tcx>>) => fn_def: + FnDef(def_id, args); + intern_fn_ptr(sig_tys: Binder<'tcx, ty::FnSigTys>>, header: ty::FnHeader>) => fn_ptr: + FnPtr(sig_tys, header); + intern_unsafe_binder(bound_ty: ty::UnsafeBinderInner>) => unsafe_binder: + UnsafeBinder(bound_ty); + intern_dynamic(predicates: &'tcx List>, region: Region<'tcx>) => dynamic: + Dynamic(predicates, region); + intern_closure(def_id: DefId, args: GenericArgs<'tcx>) => closure: + Closure(def_id, args); + intern_coroutine_closure(def_id: DefId, args: GenericArgs<'tcx>) => coroutine_closure: + CoroutineClosure(def_id, args); + intern_coroutine(def_id: DefId, args: GenericArgs<'tcx>) => coroutine: + Coroutine(def_id, args); + intern_coroutine_witness(def_id: DefId, args: GenericArgs<'tcx>) => coroutine_witness: + CoroutineWitness(def_id, args); + intern_never() => never: Never; + intern_tuple(types: &'tcx List>) => tuple: Tuple(types); + intern_alias(is_rigid: ty::IsRigid, alias: ty::AliasTy<'tcx>) => alias: + Alias(is_rigid, alias); + intern_param(param: ty::ParamTy) => param: Param(param); + intern_bound(index: ty::BoundVarIndexKind, bound_ty: ty::BoundTy<'tcx>) => bound: + Bound(index, bound_ty); + intern_placeholder(placeholder: ty::PlaceholderType<'tcx>) => placeholder: + Placeholder(placeholder); + intern_infer(infer: ty::InferTy) => infer: Infer(infer); + intern_error(error: rustc_errors::ErrorGuaranteed) => error: Error(error); + } +} + impl<'tcx> CtxtInterners<'tcx> { fn new(arena: &'tcx WorkerLocal>) -> CtxtInterners<'tcx> { // Default interner size - this value has been chosen empirically, and may need to be @@ -178,11 +394,11 @@ impl<'tcx> CtxtInterners<'tcx> { const N: usize = 2048; CtxtInterners { arena, + types: TyKindInterners::new(arena), // The factors have been chosen by @FractalFir based on observed interner sizes, and // local perf runs. To get the interner sizes, insert `eprintln` printing the size of // the interner in functions like `intern_ty`. Bigger benchmarks tend to give more // accurate ratios, so use something like `x perf eprintln --includes cargo`. - type_: InternedSet::with_capacity(N * 16), const_lists: InternedSet::with_capacity(N * 4), args: InternedSet::with_capacity(N * 4), type_lists: InternedSet::with_capacity(N * 4), @@ -211,24 +427,6 @@ impl<'tcx> CtxtInterners<'tcx> { } } - /// Interns a type. (Use `mk_*` functions instead, where possible.) - #[allow(rustc::usage_of_ty_tykind)] - #[inline(never)] - fn intern_ty(&self, kind: TyKind<'tcx>) -> Ty<'tcx> { - Ty(Interned::new_unchecked( - self.type_ - .intern(kind, |kind| { - let flags = ty::FlagComputation::>::for_kind(&kind); - InternedInSet(self.arena.alloc(WithCachedTypeInfo { - internee: kind, - flags: flags.flags, - outer_exclusive_binder: flags.outer_exclusive_binder, - })) - }) - .0, - )) - } - /// Interns a const. (Use `mk_*` functions instead, where possible.) #[allow(rustc::usage_of_ty_tykind)] #[inline(never)] @@ -419,29 +617,28 @@ pub struct CommonConsts<'tcx> { } impl<'tcx> CommonTypes<'tcx> { - fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { - let mk = |ty| interners.intern_ty(ty); - + fn new(interners: &TyKindInterners<'tcx>) -> CommonTypes<'tcx> { let infer_ty_vars = (0..NUM_PREINTERNED_INFER_TY_VARS) - .map(|n| mk(Infer(ty::TyVar(TyVid::from(n))))) + .map(|n| interners.intern_infer(ty::TyVar(TyVid::from(n)))) + .collect(); + let infer_fresh_tys: Vec<_> = (0..NUM_PREINTERNED_INFER_FRESH_TYS) + .map(|n| interners.intern_infer(ty::FreshTy(n))) .collect(); - let infer_fresh_tys: Vec<_> = - (0..NUM_PREINTERNED_INFER_FRESH_TYS).map(|n| mk(Infer(ty::FreshTy(n)))).collect(); let infer_fresh_int_tys: Vec<_> = (0..NUM_PREINTERNED_INFER_FRESH_INT_TYS) - .map(|n| mk(Infer(ty::FreshIntTy(n)))) + .map(|n| interners.intern_infer(ty::FreshIntTy(n))) .collect(); let infer_fresh_float_tys: Vec<_> = (0..NUM_PREINTERNED_INFER_FRESH_FLOAT_TYS) - .map(|n| mk(Infer(ty::FreshFloatTy(n)))) + .map(|n| interners.intern_infer(ty::FreshFloatTy(n))) .collect(); let bound_bound_anons = (0..NUM_PREINTERNED_BOUND_BOUND_ANONS_I) .map(|i| { (0..NUM_PREINTERNED_BOUND_BOUND_ANONS_V) .map(|v| { - mk(ty::Bound( + interners.intern_bound( ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)), ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon }, - )) + ) }) .collect() }) @@ -449,45 +646,45 @@ impl<'tcx> CommonTypes<'tcx> { let bound_canonical_anons = (0..NUM_PREINTERNED_BOUND_CANONICAL_ANONS) .map(|v| { - mk(ty::Bound( + interners.intern_bound( ty::BoundVarIndexKind::Canonical, ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon }, - )) + ) }) .collect(); let placeholder_root_anons = (0..NUM_PREINTERNED_PLACEHOLDER_ROOT_ANONS) .map(|v| { - mk(ty::Placeholder(PlaceholderType::new_anon( + interners.intern_placeholder(PlaceholderType::new_anon( ty::UniverseIndex::ROOT, ty::BoundVar::from(v), - ))) + )) }) .collect(); CommonTypes { - unit: mk(Tuple(List::empty())), - bool: mk(Bool), - char: mk(Char), - never: mk(Never), - isize: mk(Int(ty::IntTy::Isize)), - i8: mk(Int(ty::IntTy::I8)), - i16: mk(Int(ty::IntTy::I16)), - i32: mk(Int(ty::IntTy::I32)), - i64: mk(Int(ty::IntTy::I64)), - i128: mk(Int(ty::IntTy::I128)), - usize: mk(Uint(ty::UintTy::Usize)), - u8: mk(Uint(ty::UintTy::U8)), - u16: mk(Uint(ty::UintTy::U16)), - u32: mk(Uint(ty::UintTy::U32)), - u64: mk(Uint(ty::UintTy::U64)), - u128: mk(Uint(ty::UintTy::U128)), - f16: mk(Float(ty::FloatTy::F16)), - f32: mk(Float(ty::FloatTy::F32)), - f64: mk(Float(ty::FloatTy::F64)), - f128: mk(Float(ty::FloatTy::F128)), - str_: mk(Str), - self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })), + unit: interners.intern_tuple(List::empty()), + bool: interners.intern_bool(), + char: interners.intern_char(), + never: interners.intern_never(), + isize: interners.intern_int(ty::IntTy::Isize), + i8: interners.intern_int(ty::IntTy::I8), + i16: interners.intern_int(ty::IntTy::I16), + i32: interners.intern_int(ty::IntTy::I32), + i64: interners.intern_int(ty::IntTy::I64), + i128: interners.intern_int(ty::IntTy::I128), + usize: interners.intern_uint(ty::UintTy::Usize), + u8: interners.intern_uint(ty::UintTy::U8), + u16: interners.intern_uint(ty::UintTy::U16), + u32: interners.intern_uint(ty::UintTy::U32), + u64: interners.intern_uint(ty::UintTy::U64), + u128: interners.intern_uint(ty::UintTy::U128), + f16: interners.intern_float(ty::FloatTy::F16), + f32: interners.intern_float(ty::FloatTy::F32), + f64: interners.intern_float(ty::FloatTy::F64), + f128: interners.intern_float(ty::FloatTy::F128), + str_: interners.intern_str(), + self_param: interners.intern_param(ty::ParamTy { index: 0, name: kw::SelfUpper }), trait_object_dummy_self: infer_fresh_tys[0], @@ -767,7 +964,7 @@ pub struct GlobalCtxt<'tcx> { pub arena: &'tcx WorkerLocal>, pub hir_arena: &'tcx WorkerLocal>, - interners: CtxtInterners<'tcx>, + pub(super) interners: CtxtInterners<'tcx>, pub sess: &'tcx Session, crate_types: Vec, @@ -988,7 +1185,7 @@ impl<'tcx> TyCtxt<'tcx> { sess.dcx().emit_fatal(err); }); let interners = CtxtInterners::new(arena); - let common_types = CommonTypes::new(&interners); + let common_types = CommonTypes::new(&interners.types); let common_lifetimes = CommonLifetimes::new(&interners); let common_consts = CommonConsts::new(&interners, &common_types); @@ -1767,7 +1964,23 @@ macro_rules! nop_list_lift { }; } -nop_lift! { type_; Ty<'a> => Ty<'tcx> } +impl<'a, 'tcx> Lift> for Ty<'a> { + type Lifted = Ty<'tcx>; + + #[track_caller] + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { + assert!( + tcx.interners + .types + .interner(self.kind()) + .contains_pointer_to(&InternedInSet(&*self.0.0)) + ); + // SAFETY: we just checked that `self` is interned and therefore is valid for the + // entire lifetime of the `TyCtxt`. + unsafe { mem::transmute(self) } + } +} + nop_lift! { pat; Pattern<'a> => Pattern<'tcx> } nop_lift! { const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx> } nop_lift! { predicate; Predicate<'a> => Predicate<'tcx> } @@ -1838,7 +2051,7 @@ macro_rules! sty_debug_print { }; $(let mut $variant = total;)* - for shard in tcx.interners.type_.lock_shards() { + for shard in tcx.interners.types.iter().flat_map(|interner| interner.lock_shards()) { // It seems that ordering doesn't affect anything here. #[allow(rustc::potential_query_instability)] let types = shard.iter(); @@ -2404,7 +2617,47 @@ impl<'tcx> TyCtxt<'tcx> { #[allow(rustc::usage_of_ty_tykind)] #[inline] pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> { - self.interners.intern_ty(st) + match st { + ty::Bool => self.interners.types.intern_bool(), + ty::Char => self.interners.types.intern_char(), + ty::Int(int) => self.interners.types.intern_int(int), + ty::Uint(uint) => self.interners.types.intern_uint(uint), + ty::Float(float) => self.interners.types.intern_float(float), + ty::Adt(def, args) => self.interners.types.intern_adt(def, args), + ty::Foreign(def_id) => self.interners.types.intern_foreign(def_id), + ty::Str => self.interners.types.intern_str(), + ty::Array(element, len) => self.interners.types.intern_array(element, len), + ty::Pat(base, pat) => self.interners.types.intern_pat(base, pat), + ty::Slice(element) => self.interners.types.intern_slice(element), + ty::RawPtr(pointee, mutability) => { + self.interners.types.intern_raw_ptr(pointee, mutability) + } + ty::Ref(region, pointee, mutability) => { + self.interners.types.intern_ref(region, pointee, mutability) + } + ty::FnDef(def_id, args) => self.interners.types.intern_fn_def(def_id, args), + ty::FnPtr(sig_tys, header) => self.interners.types.intern_fn_ptr(sig_tys, header), + ty::UnsafeBinder(bound_ty) => self.interners.types.intern_unsafe_binder(bound_ty), + ty::Dynamic(predicates, region) => { + self.interners.types.intern_dynamic(predicates, region) + } + ty::Closure(def_id, args) => self.interners.types.intern_closure(def_id, args), + ty::CoroutineClosure(def_id, args) => { + self.interners.types.intern_coroutine_closure(def_id, args) + } + ty::Coroutine(def_id, args) => self.interners.types.intern_coroutine(def_id, args), + ty::CoroutineWitness(def_id, args) => { + self.interners.types.intern_coroutine_witness(def_id, args) + } + ty::Never => self.interners.types.intern_never(), + ty::Tuple(types) => self.interners.types.intern_tuple(types), + ty::Alias(is_rigid, alias) => self.interners.types.intern_alias(is_rigid, alias), + ty::Param(param) => self.interners.types.intern_param(param), + ty::Bound(index, bound_ty) => self.interners.types.intern_bound(index, bound_ty), + ty::Placeholder(placeholder) => self.interners.types.intern_placeholder(placeholder), + ty::Infer(infer) => self.interners.types.intern_infer(infer), + ty::Error(error) => self.interners.types.intern_error(error), + } } pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index b7719ec0598de..422900deaf379 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -361,16 +361,9 @@ impl ParamConst { /// Constructors for `Ty` impl<'tcx> Ty<'tcx> { - /// Avoid using this in favour of more specific `new_*` methods, where possible. - /// The more specific methods will often optimize their creation. - #[inline] - fn new(tcx: TyCtxt<'tcx>, st: TyKind<'tcx>) -> Ty<'tcx> { - tcx.mk_ty_from_kind(st) - } - #[inline] pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Ty<'tcx> { - Ty::new(tcx, TyKind::Infer(infer)) + tcx.interners.types.intern_infer(infer) } #[inline] @@ -380,7 +373,7 @@ impl<'tcx> Ty<'tcx> { .infer_ty_vars .get(v.as_usize()) .copied() - .unwrap_or_else(|| Ty::new(tcx, Infer(TyVar(v)))) + .unwrap_or_else(|| tcx.interners.types.intern_infer(TyVar(v))) } #[inline] @@ -425,7 +418,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_param(tcx: TyCtxt<'tcx>, index: u32, name: Symbol) -> Ty<'tcx> { - Ty::new(tcx, Param(ParamTy { index, name })) + tcx.interners.types.intern_param(ParamTy { index, name }) } #[inline] @@ -441,7 +434,7 @@ impl<'tcx> Ty<'tcx> { { ty } else { - Ty::new(tcx, Bound(ty::BoundVarIndexKind::Bound(index), bound_ty)) + tcx.interners.types.intern_bound(ty::BoundVarIndexKind::Bound(index), bound_ty) } } @@ -451,12 +444,9 @@ impl<'tcx> Ty<'tcx> { if let Some(ty) = tcx.types.bound_canonical_anons.get(var.as_usize()).copied() { ty } else { - Ty::new( - tcx, - Bound( - ty::BoundVarIndexKind::Canonical, - ty::BoundTy { var, kind: ty::BoundTyKind::Anon }, - ), + tcx.interners.types.intern_bound( + ty::BoundVarIndexKind::Canonical, + ty::BoundTy { var, kind: ty::BoundTyKind::Anon }, ) } } @@ -470,7 +460,7 @@ impl<'tcx> Ty<'tcx> { { ty } else { - Ty::new(tcx, Placeholder(placeholder)) + tcx.interners.types.intern_placeholder(placeholder) } } @@ -480,12 +470,12 @@ impl<'tcx> Ty<'tcx> { is_rigid: ty::IsRigid, alias_ty: ty::AliasTy<'tcx>, ) -> Ty<'tcx> { - Ty::new(tcx, Alias(is_rigid, alias_ty)) + tcx.interners.types.intern_alias(is_rigid, alias_ty) } #[inline] pub fn new_pat(tcx: TyCtxt<'tcx>, base: Ty<'tcx>, pat: ty::Pattern<'tcx>) -> Ty<'tcx> { - Ty::new(tcx, Pat(base, pat)) + tcx.interners.types.intern_pat(base, pat) } #[inline] @@ -530,7 +520,7 @@ impl<'tcx> Ty<'tcx> { /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed` pub fn new_error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Ty<'tcx> { - Ty::new(tcx, Error(guar)) + tcx.interners.types.intern_error(guar) } /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` to ensure it gets used. @@ -548,7 +538,7 @@ impl<'tcx> Ty<'tcx> { msg: impl Into>, ) -> Ty<'tcx> { let reported = tcx.dcx().span_delayed_bug(span, msg); - Ty::new(tcx, Error(reported)) + tcx.interners.types.intern_error(reported) } #[inline] @@ -595,7 +585,7 @@ impl<'tcx> Ty<'tcx> { ty: Ty<'tcx>, mutbl: ty::Mutability, ) -> Ty<'tcx> { - Ty::new(tcx, Ref(r, ty, mutbl)) + tcx.interners.types.intern_ref(r, ty, mutbl) } #[inline] @@ -620,7 +610,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mutbl: ty::Mutability) -> Ty<'tcx> { - Ty::new(tcx, ty::RawPtr(ty, mutbl)) + tcx.interners.types.intern_raw_ptr(ty, mutbl) } #[inline] @@ -671,17 +661,17 @@ impl<'tcx> Ty<'tcx> { } } } - Ty::new(tcx, Adt(def, args)) + tcx.interners.types.intern_adt(def, args) } #[inline] pub fn new_foreign(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { - Ty::new(tcx, Foreign(def_id)) + tcx.interners.types.intern_foreign(def_id) } #[inline] pub fn new_array(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - Ty::new(tcx, Array(ty, ty::Const::from_target_usize(tcx, n))) + tcx.interners.types.intern_array(ty, ty::Const::from_target_usize(tcx, n)) } #[inline] @@ -690,17 +680,21 @@ impl<'tcx> Ty<'tcx> { ty: Ty<'tcx>, ct: ty::Const<'tcx>, ) -> Ty<'tcx> { - Ty::new(tcx, Array(ty, ct)) + tcx.interners.types.intern_array(ty, ct) } #[inline] pub fn new_slice(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - Ty::new(tcx, Slice(ty)) + tcx.interners.types.intern_slice(ty) } #[inline] pub fn new_tup(tcx: TyCtxt<'tcx>, ts: &[Ty<'tcx>]) -> Ty<'tcx> { - if ts.is_empty() { tcx.types.unit } else { Ty::new(tcx, Tuple(tcx.mk_type_list(ts))) } + if ts.is_empty() { + tcx.types.unit + } else { + tcx.interners.types.intern_tuple(tcx.mk_type_list(ts)) + } } pub fn new_tup_from_iter(tcx: TyCtxt<'tcx>, iter: I) -> T::Output @@ -723,18 +717,18 @@ impl<'tcx> Ty<'tcx> { DefKind::AssocFn | DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) ); let args = args.map_bound(|args| tcx.check_and_mk_args(def_id, args)); - Ty::new(tcx, FnDef(def_id, args)) + tcx.interners.types.intern_fn_def(def_id, args) } #[inline] pub fn new_fn_ptr(tcx: TyCtxt<'tcx>, fty: PolyFnSig<'tcx>) -> Ty<'tcx> { let (sig_tys, hdr) = fty.split(); - Ty::new(tcx, FnPtr(sig_tys, hdr)) + tcx.interners.types.intern_fn_ptr(sig_tys, hdr) } #[inline] pub fn new_unsafe_binder(tcx: TyCtxt<'tcx>, b: Binder<'tcx, Ty<'tcx>>) -> Ty<'tcx> { - Ty::new(tcx, UnsafeBinder(b.into())) + tcx.interners.types.intern_unsafe_binder(b.into()) } #[inline] @@ -770,7 +764,7 @@ impl<'tcx> Ty<'tcx> { but it has {projection_count}" ); } - Ty::new(tcx, Dynamic(obj, reg)) + tcx.interners.types.intern_dynamic(obj, reg) } #[inline] @@ -808,7 +802,7 @@ impl<'tcx> Ty<'tcx> { closure_args: GenericArgs<'tcx>, ) -> Ty<'tcx> { tcx.debug_assert_args_compatible(def_id, closure_args); - Ty::new(tcx, Closure(def_id, closure_args)) + tcx.interners.types.intern_closure(def_id, closure_args) } #[inline] @@ -818,7 +812,7 @@ impl<'tcx> Ty<'tcx> { closure_args: GenericArgs<'tcx>, ) -> Ty<'tcx> { tcx.debug_assert_args_compatible(def_id, closure_args); - Ty::new(tcx, CoroutineClosure(def_id, closure_args)) + tcx.interners.types.intern_coroutine_closure(def_id, closure_args) } #[inline] @@ -828,7 +822,7 @@ impl<'tcx> Ty<'tcx> { coroutine_args: GenericArgs<'tcx>, ) -> Ty<'tcx> { tcx.debug_assert_args_compatible(def_id, coroutine_args); - Ty::new(tcx, Coroutine(def_id, coroutine_args)) + tcx.interners.types.intern_coroutine(def_id, coroutine_args) } #[inline] @@ -840,7 +834,7 @@ impl<'tcx> Ty<'tcx> { if cfg!(debug_assertions) { tcx.debug_assert_args_compatible(tcx.typeck_root_def_id(def_id), args); } - Ty::new(tcx, CoroutineWitness(def_id, args)) + tcx.interners.types.intern_coroutine_witness(def_id, args) } pub fn new_coroutine_witness_for_coroutine( diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 4af4f1479ec82..26d81a5920c98 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -172,7 +172,7 @@ pub struct FlagComputation { } impl FlagComputation { - fn new() -> FlagComputation { + const fn new() -> FlagComputation { FlagComputation { flags: TypeFlags::empty(), outer_exclusive_binder: ty::INNERMOST, @@ -182,9 +182,131 @@ impl FlagComputation { #[allow(rustc::usage_of_ty_tykind)] pub fn for_kind(kind: &ty::TyKind) -> FlagComputation { - let mut result = FlagComputation::new(); - result.add_kind(kind); - result + match *kind { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Float(_) + | ty::Uint(_) + | ty::Never + | ty::Str + | ty::Foreign(..) => Self::new(), + ty::Error(_) => Self::for_flags(TypeFlags::HAS_NON_REGION_ERROR), + ty::Param(_) => Self::for_flags(TypeFlags::HAS_TY_PARAM), + ty::Placeholder(..) => Self::for_flags(TypeFlags::HAS_TY_PLACEHOLDER), + ty::Closure(_, args) + | ty::CoroutineClosure(_, args) + | ty::CoroutineWitness(_, args) + | ty::Adt(_, args) => Self::for_args(args), + ty::Coroutine(_, args) => Self::for_coroutine(args), + ty::Bound(index, _) => Self::for_bound(index), + ty::Infer(infer) => Self::for_infer(infer), + ty::Alias(is_rigid, alias) => Self::for_alias(is_rigid, alias), + ty::Dynamic(obj, region) => Self::for_dynamic(obj, region), + ty::Array(ty, len) => Self::for_array(ty, len), + ty::Pat(ty, pat) => Self::for_pat(ty, pat), + ty::Slice(ty) | ty::RawPtr(ty, _) => Self::for_ty(ty), + ty::Ref(region, ty, _) => Self::for_ref(region, ty), + ty::Tuple(types) => Self::for_tys(types), + ty::FnDef(_, args) => Self::for_fn_def(args), + ty::FnPtr(sig_tys, _) => Self::for_fn_ptr(sig_tys), + ty::UnsafeBinder(bound_ty) => Self::for_unsafe_binder(bound_ty), + } + } + + #[cfg(feature = "nightly")] + #[allow(rustc::usage_of_ty_tykind)] + pub fn for_kind_generic(kind: &ty::TyKind) -> FlagComputation { + macro_rules! with_kind { + ($pat:pat => $body:expr) => { + match *kind { + $pat => $body, + _ => unreachable!("TyKindMarker does not match TyKind"), + } + }; + } + + match K { + ty::TyKindMarker::Bool + | ty::TyKindMarker::Char + | ty::TyKindMarker::Int + | ty::TyKindMarker::Float + | ty::TyKindMarker::Uint + | ty::TyKindMarker::Never + | ty::TyKindMarker::Str + | ty::TyKindMarker::Foreign => Self::new(), + ty::TyKindMarker::Error => Self::for_flags(TypeFlags::HAS_NON_REGION_ERROR), + ty::TyKindMarker::Param => Self::for_flags(TypeFlags::HAS_TY_PARAM), + ty::TyKindMarker::Placeholder => Self::for_flags(TypeFlags::HAS_TY_PLACEHOLDER), + + ty::TyKindMarker::Closure + | ty::TyKindMarker::CoroutineClosure + | ty::TyKindMarker::CoroutineWitness => { + with_kind!(ty::Closure(_, args) + | ty::CoroutineClosure(_, args) + | ty::CoroutineWitness(_, args) => Self::for_args(args)) + } + + ty::TyKindMarker::Adt => { + with_kind!(ty::Adt(_, args) => Self::for_args(args)) + } + + ty::TyKindMarker::Coroutine => { + with_kind!(ty::Coroutine(_, args) => Self::for_coroutine(args)) + } + + ty::TyKindMarker::Bound => { + with_kind!(ty::Bound(index, _) => Self::for_bound(index)) + } + + ty::TyKindMarker::Infer => { + with_kind!(ty::Infer(infer) => Self::for_infer(infer)) + } + + ty::TyKindMarker::Alias => { + with_kind!(ty::Alias(is_rigid, alias) => Self::for_alias(is_rigid, alias)) + } + + ty::TyKindMarker::Dynamic => { + with_kind!(ty::Dynamic(obj, region) => Self::for_dynamic(obj, region)) + } + + ty::TyKindMarker::Array => { + with_kind!(ty::Array(ty, len) => Self::for_array(ty, len)) + } + + ty::TyKindMarker::Pat => { + with_kind!(ty::Pat(ty, pat) => Self::for_pat(ty, pat)) + } + + ty::TyKindMarker::Slice => { + with_kind!(ty::Slice(ty) => Self::for_ty(ty)) + } + + ty::TyKindMarker::RawPtr => { + with_kind!(ty::RawPtr(ty, _) => Self::for_ty(ty)) + } + + ty::TyKindMarker::Ref => { + with_kind!(ty::Ref(region, ty, _) => Self::for_ref(region, ty)) + } + + ty::TyKindMarker::Tuple => { + with_kind!(ty::Tuple(types) => Self::for_tys(types)) + } + + ty::TyKindMarker::FnDef => { + with_kind!(ty::FnDef(_, args) => Self::for_fn_def(args)) + } + + ty::TyKindMarker::FnPtr => { + with_kind!(ty::FnPtr(sig_tys, _) => Self::for_fn_ptr(sig_tys)) + } + + ty::TyKindMarker::UnsafeBinder => { + with_kind!(ty::UnsafeBinder(bound_ty) => Self::for_unsafe_binder(bound_ty)) + } + } } pub fn for_predicate(binder: ty::Binder>) -> FlagComputation { @@ -250,129 +372,118 @@ impl FlagComputation { } // otherwise, this binder captures nothing } - #[allow(rustc::usage_of_ty_tykind)] - fn add_kind(&mut self, kind: &ty::TyKind) { - match *kind { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Float(_) - | ty::Uint(_) - | ty::Never - | ty::Str - | ty::Foreign(..) => {} - - ty::Error(_) => self.add_flags(TypeFlags::HAS_NON_REGION_ERROR), - - ty::Param(_) => { - self.add_flags(TypeFlags::HAS_TY_PARAM); - } - - ty::Closure(_, args) - | ty::CoroutineClosure(_, args) - | ty::CoroutineWitness(_, args) => { - self.add_args(args.as_slice()); - } - - ty::Coroutine(_, args) => { - self.add_flags(TypeFlags::HAS_TY_CORO); - self.add_args(args.as_slice()); - } - - ty::Bound(ty::BoundVarIndexKind::Canonical, _) => { - self.add_flags(TypeFlags::HAS_TY_BOUND); - self.add_flags(TypeFlags::HAS_CANONICAL_BOUND); - } + /// Flags for a type with no nested types, constants, regions, or binders. + pub fn for_flags(flags: TypeFlags) -> Self { + Self { flags, ..Self::new() } + } - ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) => { - self.add_bound_var(debruijn); - self.add_flags(TypeFlags::HAS_TY_BOUND); - } + pub fn for_args(args: I::GenericArgs) -> Self { + let mut result = Self::new(); + result.add_args(args.as_slice()); + result + } - ty::Placeholder(..) => { - self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); - } + pub fn for_coroutine(args: I::GenericArgs) -> Self { + let mut result = Self::for_args(args); + result.add_flags(TypeFlags::HAS_TY_CORO); + result + } - ty::Infer(infer) => match infer { - ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { - self.add_flags(TypeFlags::HAS_TY_FRESH) - } + pub fn for_bound(index: ty::BoundVarIndexKind) -> Self { + let mut result = Self::for_flags(TypeFlags::HAS_TY_BOUND); + match index { + ty::BoundVarIndexKind::Canonical => result.add_flags(TypeFlags::HAS_CANONICAL_BOUND), + ty::BoundVarIndexKind::Bound(debruijn) => result.add_bound_var(debruijn), + } + result + } - ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => { - self.add_flags(TypeFlags::HAS_TY_INFER) - } - }, + pub fn for_infer(infer: ty::InferTy) -> Self { + Self::for_flags(match infer { + ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => TypeFlags::HAS_TY_FRESH, + ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => TypeFlags::HAS_TY_INFER, + }) + } - ty::Adt(_, args) => { - self.add_args(args.as_slice()); - } + pub fn for_alias(is_rigid: ty::IsRigid, alias: ty::AliasTy) -> Self { + let mut result = Self::new(); + result.add_is_rigid(is_rigid); + result.add_flags(match alias.kind { + ty::Projection { .. } => TypeFlags::HAS_TY_PROJECTION, + ty::Free { .. } => TypeFlags::HAS_TY_FREE_ALIAS, + ty::Opaque { .. } => TypeFlags::HAS_TY_OPAQUE, + ty::Inherent { .. } => TypeFlags::HAS_TY_INHERENT, + }); + result.add_alias_ty(alias); + result + } - ty::Alias(is_rigid, alias) => { - self.add_is_rigid(is_rigid); - self.add_flags(match alias.kind { - ty::Projection { .. } => TypeFlags::HAS_TY_PROJECTION, - ty::Free { .. } => TypeFlags::HAS_TY_FREE_ALIAS, - ty::Opaque { .. } => TypeFlags::HAS_TY_OPAQUE, - ty::Inherent { .. } => TypeFlags::HAS_TY_INHERENT, - }); - self.add_alias_ty(alias); - } - - ty::Dynamic(obj, r) => { - for predicate in obj.iter() { - self.bound_computation(predicate, |computation, predicate| match predicate { - ty::ExistentialPredicate::Trait(tr) => { - computation.add_args(tr.args.as_slice()) - } - ty::ExistentialPredicate::Projection(p) => { - computation.add_existential_projection(&p); - } - ty::ExistentialPredicate::AutoTrait(_) => {} - }); + pub fn for_dynamic(obj: I::BoundExistentialPredicates, region: Region) -> Self { + let mut result = Self::new(); + for predicate in obj.iter() { + result.bound_computation(predicate, |computation, predicate| match predicate { + ty::ExistentialPredicate::Trait(tr) => computation.add_args(tr.args.as_slice()), + ty::ExistentialPredicate::Projection(p) => { + computation.add_existential_projection(&p) } + ty::ExistentialPredicate::AutoTrait(_) => {} + }); + } + result.add_region(region); + result + } - self.add_region(r); - } - - ty::Array(tt, len) => { - self.add_ty(tt); - self.add_const(len); - } - - ty::Pat(ty, pat) => { - self.add_ty(ty); - self.add_ty_pat(pat); - } + pub fn for_array(ty: I::Ty, len: Const) -> Self { + let mut result = Self::for_ty(ty); + result.add_const(len); + result + } - ty::Slice(tt) => self.add_ty(tt), + pub fn for_pat(ty: I::Ty, pat: I::Pat) -> Self { + let mut result = Self::for_ty(ty); + result.add_ty_pat(pat); + result + } - ty::RawPtr(ty, _) => { - self.add_ty(ty); - } + pub fn for_ty(ty: I::Ty) -> Self { + let mut result = Self::new(); + result.add_ty(ty); + result + } - ty::Ref(r, ty, _) => { - self.add_region(r); - self.add_ty(ty); - } + pub fn for_ref(region: Region, ty: I::Ty) -> Self { + let mut result = Self::new(); + result.add_region(region); + result.add_ty(ty); + result + } - ty::Tuple(types) => { - self.add_tys(types); - } + pub fn for_tys(types: I::Tys) -> Self { + let mut result = Self::new(); + result.add_tys(types); + result + } - ty::FnDef(_, args) => { - self.add_binder_args(args); - } + pub fn for_fn_def(args: ty::Binder) -> Self { + let mut result = Self::new(); + result.add_binder_args(args); + result + } - ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| { - computation.add_tys(sig_tys.inputs_and_output); - }), + pub fn for_fn_ptr(sig_tys: ty::Binder>) -> Self { + let mut result = Self::new(); + result.bound_computation(sig_tys, |computation, sig_tys| { + computation.add_tys(sig_tys.inputs_and_output); + }); + result + } - ty::UnsafeBinder(bound_ty) => { - self.bound_computation(bound_ty.into(), |computation, ty| { - computation.add_ty(ty); - }) - } - } + pub fn for_unsafe_binder(bound_ty: ty::UnsafeBinderInner) -> Self { + let mut result = Self::new(); + result.bound_computation(bound_ty.into(), |computation, ty| { + computation.add_ty(ty); + }); + result } fn add_ty_pat(&mut self, pat: ::Pat) { diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index a1c5bcacc4b5f..a445dbafd51fe 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -26,13 +26,23 @@ #![allow(rustc::usage_of_type_ir_inherent)] #![allow(rustc::usage_of_type_ir_traits)] #![cfg_attr(feature = "nightly", allow(internal_features))] -#![cfg_attr(feature = "nightly", feature(associated_type_defaults, rustc_attrs, negative_impls))] // NOTE: the outer `cfg_attr` is only there so that r-a doesn't see the nightly-only `bootstrap` // in the inner `cfg_attr`. When the latter is removed, the former can be removed as well. #![cfg_attr( feature = "nightly", cfg_attr(not(bootstrap), deny(rustc::missing_generic_type_visitable_derive)) )] +#![cfg_attr( + feature = "nightly", + feature( + associated_type_defaults, + const_cmp, + const_param_ty_unchecked, + derive_const, + negative_impls, + rustc_attrs, + ) +)] // tidy-alphabetical-end extern crate self as rustc_type_ir; diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 70efba8361b24..194a9f624010a 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -10,6 +10,8 @@ use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHashe #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash, StableHash_NoContext}; use rustc_type_ir::data_structures::{NoError, UnifyKey, UnifyValue}; +#[cfg(feature = "nightly")] +use rustc_type_ir_macros::GenMarker; use rustc_type_ir_macros::{ GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic, }; @@ -152,7 +154,7 @@ impl IsRigid { #[derive(GenericTypeVisitable)] #[cfg_attr( feature = "nightly", - derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) + derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext, GenMarker) )] pub enum TyKind { /// The primitive boolean type. Written as `bool`. diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 8a437c4995724..5cdba513d9028 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -7,6 +7,7 @@ use syn::visit_mut::VisitMut; use syn::{Attribute, parse_quote}; use synstructure::decl_derive; +decl_derive!([GenMarker, attributes(gen_marker)] => gen_marker); decl_derive!( [TypeVisitable_Generic, attributes(type_visitable)] => type_visitable_derive ); @@ -481,3 +482,50 @@ fn parse_generic_type_visitable_bound( if input.is_empty() { Ok(proof) } else { Err(input.error("unexpected token")) } }) } + +/// Generate a marker enum for an enum... For example; +/// +/// ```ignore (purely an example) +/// enum MyEnum { +/// Foo, +/// Bar(u32), +/// Baz(SomeStruct), +/// Exotic(I::ExternDefinedStruct) +/// } +/// ``` +/// +/// Where you want to discriminate on MyEnum but you want the variants as `u32`'s +/// so you can create static dispatch based off `MyEnum` but perhaps the properties +/// in `MyEnum` cannot use `ConstParamTy`. +/// +/// We get; +/// +/// ```ignore (purely an example building upon the above example to show what would be generated) +/// #[repr(u32)] +/// #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +/// enum MyEnumMarker { +/// Foo, +/// Bar, +/// Baz, +/// Exotic +/// } +/// ``` +fn gen_marker(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + let input = s.ast(); + let syn::Data::Enum(enum_data) = &input.data else { panic!("can only derive enums") }; + + let variants = enum_data.variants.iter().map(|variant| &variant.ident); + + let vis = &input.vis; + let marker_name = quote::format_ident!("{}Marker", input.ident); + + quote::quote! { + #[repr(u32)] + #[derive(Clone, Copy, Debug, Hash)] + #[derive_const(PartialEq, Eq)] + #vis enum #marker_name { + #(#variants),* + } + } + .into() +}