diff options
Diffstat (limited to 'compiler/rustc_middle/src/ty/subst.rs')
-rw-r--r-- | compiler/rustc_middle/src/ty/subst.rs | 63 |
1 files changed, 58 insertions, 5 deletions
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index a1b084a5e..a07582fc8 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -7,6 +7,7 @@ use crate::ty::visit::{TypeVisitable, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; use rustc_data_structures::intern::Interned; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; @@ -36,6 +37,12 @@ pub struct GenericArg<'tcx> { marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>, } +impl<'tcx> IntoDiagnosticArg for GenericArg<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + const TAG_MASK: usize = 0b11; const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; @@ -90,7 +97,7 @@ impl<'tcx> GenericArgKind<'tcx> { GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); - (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize) + (CONST_TAG, ct.0.0 as *const ty::ConstData<'tcx> as usize) } }; @@ -166,7 +173,7 @@ impl<'tcx> GenericArg<'tcx> { &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>), ))), CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), + &*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>), ))), _ => intrinsics::unreachable(), } @@ -202,7 +209,7 @@ impl<'tcx> GenericArg<'tcx> { pub fn is_non_region_infer(self) -> bool { match self.unpack() { GenericArgKind::Lifetime(_) => false, - GenericArgKind::Type(ty) => ty.is_ty_infer(), + GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(), GenericArgKind::Const(ct) => ct.is_ct_infer(), } } @@ -252,7 +259,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for GenericArg<'tcx> { } } -/// A substitution mapping generic parameters to new values. +/// List of generic arguments that are gonna be used to substitute generic parameters. pub type InternalSubsts<'tcx> = List<GenericArg<'tcx>>; pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>; @@ -348,7 +355,7 @@ impl<'tcx> InternalSubsts<'tcx> { substs.reserve(defs.params.len()); for param in &defs.params { let kind = mk_kind(param, substs); - assert_eq!(param.index as usize, substs.len()); + assert_eq!(param.index as usize, substs.len(), "{substs:#?}, {defs:#?}"); substs.push(kind); } } @@ -400,6 +407,7 @@ 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 @@ -409,6 +417,7 @@ impl<'tcx> InternalSubsts<'tcx> { } #[inline] + #[track_caller] pub fn region_at(&self, i: usize) -> ty::Region<'tcx> { if let GenericArgKind::Lifetime(lt) = self[i].unpack() { lt @@ -418,6 +427,7 @@ impl<'tcx> InternalSubsts<'tcx> { } #[inline] + #[track_caller] pub fn const_at(&self, i: usize) -> ty::Const<'tcx> { if let GenericArgKind::Const(ct) = self[i].unpack() { ct @@ -427,6 +437,7 @@ impl<'tcx> InternalSubsts<'tcx> { } #[inline] + #[track_caller] pub fn type_for_def(&self, def: &ty::GenericParamDef) -> GenericArg<'tcx> { self.type_at(def.index as usize).into() } @@ -534,6 +545,9 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List<T> { /// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)` /// needs `T` substituted immediately. This type primarily exists to avoid forgetting to call /// `subst`. +/// +/// If you don't have anything to `subst`, you may be looking for +/// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable)] pub struct EarlyBinder<T>(pub T); @@ -573,6 +587,18 @@ impl<T> EarlyBinder<T> { pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> { EarlyBinder(value) } + + /// Skips the binder and returns the "bound" value. + /// This can be used to extract data that does not depend on generic parameters + /// (e.g., getting the `DefId` of the inner value or getting the number of + /// arguments of an `FnSig`). Otherwise, consider using + /// [`subst_identity`](EarlyBinder::subst_identity). + /// + /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is + /// the analogous operation on [`super::Binder`]. + pub fn skip_binder(self) -> T { + self.0 + } } impl<T> EarlyBinder<Option<T>> { @@ -631,6 +657,13 @@ where } } +impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIter<'_, 'tcx, I> +where + I::IntoIter: ExactSizeIterator, + I::Item: TypeFoldable<'tcx>, +{ +} + impl<'tcx, 's, I: IntoIterator> EarlyBinder<I> where I::Item: Deref, @@ -678,6 +711,14 @@ where } } +impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIterCopied<'_, 'tcx, I> +where + I::IntoIter: ExactSizeIterator, + I::Item: Deref, + <I::Item as Deref>::Target: Copy + TypeFoldable<'tcx>, +{ +} + pub struct EarlyBinderIter<T> { t: T, } @@ -705,6 +746,18 @@ impl<'tcx, T: TypeFoldable<'tcx>> ty::EarlyBinder<T> { let mut folder = SubstFolder { tcx, substs, binders_passed: 0 }; self.0.fold_with(&mut folder) } + + /// Makes the identity substitution `T0 => T0, ..., TN => TN`. + /// Conceptually, this converts universally bound variables into placeholders + /// when inside of a given item. + /// + /// For example, consider `for<T> fn foo<T>(){ .. }`: + /// - Outside of `foo`, `T` is bound (represented by the presence of `EarlyBinder`). + /// - Inside of the body of `foo`, we treat `T` as a placeholder by calling + /// `subst_identity` to discharge the `EarlyBinder`. + pub fn subst_identity(self) -> T { + self.0 + } } /////////////////////////////////////////////////////////////////////////// |