diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 99dd4ab1bf5fd..5d0df837825e5 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -102,6 +102,7 @@ pub struct CtxtInterners<'tcx> { // Specifically use a speedy hash algorithm for these hash sets, since // they're accessed quite often. type_: InternedSet<'tcx, TyS<'tcx>>, + type_list: InternedSet<'tcx, List>>, substs: InternedSet<'tcx, InternalSubsts<'tcx>>, canonical_var_infos: InternedSet<'tcx, List>>, region: InternedSet<'tcx, RegionKind>, @@ -123,6 +124,7 @@ impl<'tcx> CtxtInterners<'tcx> { CtxtInterners { arena, type_: Default::default(), + type_list: Default::default(), substs: Default::default(), region: Default::default(), poly_existential_predicates: Default::default(), @@ -1670,25 +1672,6 @@ macro_rules! nop_lift { }; } -// Can't use the macros as we have reuse the `substs` here. -// -// See `intern_type_list` for more info. -impl<'a, 'tcx> Lift<'tcx> for &'a List> { - type Lifted = &'tcx List>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - if self.is_empty() { - return Some(List::empty()); - } - if tcx.interners.substs.contains_pointer_to(&InternedInSet(self.as_substs())) { - // SAFETY: `self` is interned and therefore valid - // for the entire lifetime of the `TyCtxt`. - Some(unsafe { mem::transmute::<&'a List>, &'tcx List>>(self) }) - } else { - None - } - } -} - macro_rules! nop_list_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> { @@ -1713,6 +1696,7 @@ nop_lift! {const_; Const<'a> => Const<'tcx>} nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>} nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} +nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>} nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>} nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>} @@ -2203,6 +2187,7 @@ macro_rules! slice_interners { } slice_interners!( + type_list: _intern_type_list(Ty<'tcx>), substs: _intern_substs(GenericArg<'tcx>), canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo<'tcx>), poly_existential_predicates: @@ -2620,19 +2605,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx List> { - if ts.is_empty() { - List::empty() - } else { - // Actually intern type lists as lists of `GenericArg`s. - // - // Transmuting from `Ty<'tcx>` to `GenericArg<'tcx>` is sound - // as explained in ty_slice_as_generic_arg`. With this, - // we guarantee that even when transmuting between `List>` - // and `List>`, the uniqueness requirement for - // lists is upheld. - let substs = self._intern_substs(ty::subst::ty_slice_as_generic_args(ts)); - substs.try_as_type_list().unwrap() - } + if ts.is_empty() { List::empty() } else { self._intern_type_list(ts) } } pub fn intern_substs(self, ts: &[GenericArg<'tcx>]) -> &'tcx List> { diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 54a345daec8a5..00ce15bea3f28 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -61,36 +61,6 @@ impl<'a, 'tcx> HashStable> for ty::subst::GenericArg<'t } } -impl<'a, 'tcx> HashStable> for ty::subst::GenericArgKind<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - match self { - // WARNING: We dedup cache the `HashStable` results for `List` - // while ignoring types and freely transmute - // between `List>` and `List>`. - // See `fn intern_type_list` for more details. - // - // We therefore hash types without adding a hash for their discriminant. - // - // In order to make it very unlikely for the sequence of bytes being hashed for - // a `GenericArgKind::Type` to be the same as the sequence of bytes being - // hashed for one of the other variants, we hash a `0xFF` byte before hashing - // their discriminant (since the discriminant of `TyKind` is unlikely to ever start - // with 0xFF). - ty::subst::GenericArgKind::Type(ty) => ty.hash_stable(hcx, hasher), - ty::subst::GenericArgKind::Const(ct) => { - 0xFFu8.hash_stable(hcx, hasher); - mem::discriminant(self).hash_stable(hcx, hasher); - ct.hash_stable(hcx, hasher); - } - ty::subst::GenericArgKind::Lifetime(lt) => { - 0xFFu8.hash_stable(hcx, hasher); - mem::discriminant(self).hash_stable(hcx, hasher); - lt.hash_stable(hcx, hasher); - } - } - } -} - impl<'a> HashStable> for ty::RegionKind { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 364ba07a44167..b28fd11f20ad3 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -20,7 +20,6 @@ use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; use std::ops::ControlFlow; -use std::slice; /// An entity in the Rust type system, which can be one of /// several kinds (types, lifetimes, and consts). @@ -41,38 +40,13 @@ const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; const CONST_TAG: usize = 0b10; -#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)] pub enum GenericArgKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), Const(ty::Const<'tcx>), } -/// This function goes from `&'a [Ty<'tcx>]` to `&'a [GenericArg<'tcx>]` -/// -/// This is sound as, for types, `GenericArg` is just -/// `NonZeroUsize::new_unchecked(ty as *const _ as usize)` as -/// long as we use `0` for the `TYPE_TAG`. -pub fn ty_slice_as_generic_args<'a, 'tcx>(ts: &'a [Ty<'tcx>]) -> &'a [GenericArg<'tcx>] { - assert_eq!(TYPE_TAG, 0); - // SAFETY: the whole slice is valid and immutable. - // `Ty` and `GenericArg` is explained above. - unsafe { slice::from_raw_parts(ts.as_ptr().cast(), ts.len()) } -} - -impl<'tcx> List> { - /// Allows to freely switch betwen `List>` and `List>`. - /// - /// As lists are interned, `List>` and `List>` have - /// be interned together, see `intern_type_list` for more details. - #[inline] - pub fn as_substs(&'tcx self) -> SubstsRef<'tcx> { - assert_eq!(TYPE_TAG, 0); - // SAFETY: `List` is `#[repr(C)]`. `Ty` and `GenericArg` is explained above. - unsafe { &*(self as *const List> as *const List>) } - } -} - impl<'tcx> GenericArgKind<'tcx> { #[inline] fn pack(self) -> GenericArg<'tcx> { @@ -234,17 +208,6 @@ pub type InternalSubsts<'tcx> = List>; pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>; impl<'a, 'tcx> InternalSubsts<'tcx> { - /// Checks whether all elements of this list are types, if so, transmute. - pub fn try_as_type_list(&'tcx self) -> Option<&'tcx List>> { - if self.iter().all(|arg| matches!(arg.unpack(), GenericArgKind::Type(_))) { - assert_eq!(TYPE_TAG, 0); - // SAFETY: All elements are types, see `List>::as_substs`. - Some(unsafe { &*(self as *const List> as *const List>) }) - } else { - None - } - } - /// Interpret these substitutions as the substitutions of a closure type. /// Closure substitutions have a particular structure controlled by the /// compiler that encodes information like the signature and closure kind; diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 9f57e1a977a93..fbdd93617df2a 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -178,7 +178,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::FnDef(_, substs) => { stack.extend(substs.iter().rev()); } - ty::Tuple(ts) => stack.extend(ts.as_substs().iter().rev()), + ty::Tuple(ts) => stack.extend(ts.iter().map(|ty| ty.into()).rev()), ty::GeneratorWitness(ts) => { stack.extend(ts.skip_binder().iter().rev().map(|ty| ty.into())); } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e3c865ce9e632..64ba6d60ca663 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -329,9 +329,13 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { ), ty::GeneratorWitness(_) => unimplemented!(), ty::Never => chalk_ir::TyKind::Never, - ty::Tuple(types) => { - chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner)) - } + ty::Tuple(types) => chalk_ir::TyKind::Tuple( + types.len(), + chalk_ir::Substitution::from_iter( + interner, + types.iter().map(|ty| ty::subst::GenericArg::from(ty).lower_into(interner)), + ), + ), ty::Projection(proj) => chalk_ir::TyKind::Alias(proj.lower_into(interner)), ty::Opaque(def_id, substs) => { chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { @@ -403,9 +407,9 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty> { TyKind::Generator(..) => unimplemented!(), TyKind::GeneratorWitness(..) => unimplemented!(), TyKind::Never => ty::Never, - TyKind::Tuple(_len, substitution) => { - ty::Tuple(substitution.lower_into(interner).try_as_type_list().unwrap()) - } + TyKind::Tuple(_len, substitution) => ty::Tuple(interner.tcx.mk_type_list( + substitution.iter(interner).map(|subst| subst.lower_into(interner).expect_ty()), + )), TyKind::Slice(ty) => ty::Slice(ty.lower_into(interner)), TyKind::Raw(mutbl, ty) => ty::RawPtr(ty::TypeAndMut { ty: ty.lower_into(interner),