diff options
Diffstat (limited to 'compiler/rustc_middle/src/ty/subst.rs')
-rw-r--r-- | compiler/rustc_middle/src/ty/subst.rs | 139 |
1 files changed, 67 insertions, 72 deletions
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index f05b87343..43f95635a 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -21,7 +21,6 @@ use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; use std::ops::{ControlFlow, Deref}; -use std::slice; /// An entity in the Rust type system, which can be one of /// several kinds (types, lifetimes, and consts). @@ -48,38 +47,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<Ty<'tcx>> { - /// Allows to freely switch between `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>`. - /// - /// As lists are interned, `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>` have - /// be interned together, see `mk_type_list` for more details. - #[inline] - pub fn as_substs(&'tcx self) -> SubstsRef<'tcx> { - assert_eq!(TYPE_TAG, 0); - // SAFETY: `List<T>` is `#[repr(C)]`. `Ty` and `GenericArg` is explained above. - unsafe { &*(self as *const List<Ty<'tcx>> as *const List<GenericArg<'tcx>>) } - } -} - impl<'tcx> GenericArgKind<'tcx> { #[inline] fn pack(self) -> GenericArg<'tcx> { @@ -180,30 +154,45 @@ impl<'tcx> GenericArg<'tcx> { } } - /// Unpack the `GenericArg` as a region when it is known certainly to be a region. - pub fn expect_region(self) -> ty::Region<'tcx> { + #[inline] + pub fn as_type(self) -> Option<Ty<'tcx>> { match self.unpack() { - GenericArgKind::Lifetime(lt) => lt, - _ => bug!("expected a region, but found another kind"), + GenericArgKind::Type(ty) => Some(ty), + _ => None, } } + #[inline] + pub fn as_region(self) -> Option<ty::Region<'tcx>> { + match self.unpack() { + GenericArgKind::Lifetime(re) => Some(re), + _ => None, + } + } + + #[inline] + pub fn as_const(self) -> Option<ty::Const<'tcx>> { + match self.unpack() { + GenericArgKind::Const(ct) => Some(ct), + _ => None, + } + } + + /// Unpack the `GenericArg` as a region when it is known certainly to be a region. + pub fn expect_region(self) -> ty::Region<'tcx> { + self.as_region().unwrap_or_else(|| bug!("expected a region, but found another kind")) + } + /// Unpack the `GenericArg` as a type when it is known certainly to be a type. /// This is true in cases where `Substs` is used in places where the kinds are known /// to be limited (e.g. in tuples, where the only parameters are type parameters). pub fn expect_ty(self) -> Ty<'tcx> { - match self.unpack() { - GenericArgKind::Type(ty) => ty, - _ => bug!("expected a type, but found another kind"), - } + self.as_type().unwrap_or_else(|| bug!("expected a type, but found another kind")) } /// Unpack the `GenericArg` as a const when it is known certainly to be a const. pub fn expect_const(self) -> ty::Const<'tcx> { - match self.unpack() { - GenericArgKind::Const(c) => c, - _ => bug!("expected a const, but found another kind"), - } + self.as_const().unwrap_or_else(|| bug!("expected a const, but found another kind")) } pub fn is_non_region_infer(self) -> bool { @@ -268,13 +257,16 @@ pub type InternalSubsts<'tcx> = List<GenericArg<'tcx>>; pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>; impl<'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<Ty<'tcx>>> { - self.iter().all(|arg| matches!(arg.unpack(), GenericArgKind::Type(_))).then(|| { - assert_eq!(TYPE_TAG, 0); - // SAFETY: All elements are types, see `List<Ty<'tcx>>::as_substs`. - unsafe { &*(self as *const List<GenericArg<'tcx>> as *const List<Ty<'tcx>>) } - }) + /// Converts substs to a type list. + /// + /// # Panics + /// + /// If any of the generic arguments are not types. + pub fn into_type_list(&self, tcx: TyCtxt<'tcx>) -> &'tcx List<Ty<'tcx>> { + tcx.mk_type_list_from_iter(self.iter().map(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => ty, + _ => bug!("`into_type_list` called on substs with non-types"), + })) } /// Interpret these substitutions as the substitutions of a closure type. @@ -379,22 +371,17 @@ impl<'tcx> InternalSubsts<'tcx> { #[inline] pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx { - self.iter() - .filter_map(|k| if let GenericArgKind::Type(ty) = k.unpack() { Some(ty) } else { None }) + self.iter().filter_map(|k| k.as_type()) } #[inline] pub fn regions(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'tcx { - self.iter().filter_map(|k| { - if let GenericArgKind::Lifetime(lt) = k.unpack() { Some(lt) } else { None } - }) + self.iter().filter_map(|k| k.as_region()) } #[inline] pub fn consts(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'tcx { - self.iter().filter_map(|k| { - if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None } - }) + self.iter().filter_map(|k| k.as_const()) } #[inline] @@ -410,31 +397,21 @@ impl<'tcx> InternalSubsts<'tcx> { #[inline] #[track_caller] pub fn type_at(&self, i: usize) -> Ty<'tcx> { - if let GenericArgKind::Type(ty) = self[i].unpack() { - ty - } else { - bug!("expected type for param #{} in {:?}", i, self); - } + self[i].as_type().unwrap_or_else(|| bug!("expected type for param #{} in {:?}", i, self)) } #[inline] #[track_caller] pub fn region_at(&self, i: usize) -> ty::Region<'tcx> { - if let GenericArgKind::Lifetime(lt) = self[i].unpack() { - lt - } else { - bug!("expected region for param #{} in {:?}", i, self); - } + self[i] + .as_region() + .unwrap_or_else(|| bug!("expected region for param #{} in {:?}", i, self)) } #[inline] #[track_caller] pub fn const_at(&self, i: usize) -> ty::Const<'tcx> { - if let GenericArgKind::Const(ct) = self[i].unpack() { - ct - } else { - bug!("expected const for param #{} in {:?}", i, self); - } + self[i].as_const().unwrap_or_else(|| bug!("expected const for param #{} in {:?}", i, self)) } #[inline] @@ -635,6 +612,12 @@ where ) -> SubstIter<'s, 'tcx, I> { SubstIter { it: self.0.into_iter(), tcx, substs } } + + /// Similar to [`subst_identity`](EarlyBinder::subst_identity), + /// but on an iterator of `TypeFoldable` values. + pub fn subst_identity_iter(self) -> I::IntoIter { + self.0.into_iter() + } } pub struct SubstIter<'s, 'tcx, I: IntoIterator> { @@ -687,6 +670,12 @@ where ) -> SubstIterCopied<'s, 'tcx, I> { SubstIterCopied { it: self.0.into_iter(), tcx, substs } } + + /// Similar to [`subst_identity`](EarlyBinder::subst_identity), + /// but on an iterator of values that deref to a `TypeFoldable`. + pub fn subst_identity_iter_copied(self) -> impl Iterator<Item = <I::Item as Deref>::Target> { + self.0.into_iter().map(|v| *v) + } } pub struct SubstIterCopied<'a, 'tcx, I: IntoIterator> { @@ -772,7 +761,7 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> { /// Returns the inner value, but only if it contains no bound vars. pub fn no_bound_vars(self) -> Option<T> { - if !self.0.needs_subst() { Some(self.0) } else { None } + if !self.0.has_param() { Some(self.0) } else { None } } } @@ -840,12 +829,18 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for SubstFolder<'a, 'tcx> { None => region_param_out_of_range(data, self.substs), } } - _ => r, + ty::ReLateBound(..) + | ty::ReFree(_) + | ty::ReStatic + | ty::RePlaceholder(_) + | ty::ReErased + | ty::ReError(_) => r, + ty::ReVar(_) => bug!("unexpected region: {r:?}"), } } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_subst() { + if !t.has_param() { return t; } |