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};
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;
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)
}
};
&*((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(),
}
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(),
}
}
}
}
-/// 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>;
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);
}
}
}
#[inline]
+ #[track_caller]
pub fn type_at(&self, i: usize) -> Ty<'tcx> {
if let GenericArgKind::Type(ty) = self[i].unpack() {
ty
}
#[inline]
+ #[track_caller]
pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
if let GenericArgKind::Lifetime(lt) = self[i].unpack() {
lt
}
#[inline]
+ #[track_caller]
pub fn const_at(&self, i: usize) -> ty::Const<'tcx> {
if let GenericArgKind::Const(ct) = self[i].unpack() {
ct
}
#[inline]
+ #[track_caller]
pub fn type_for_def(&self, def: &ty::GenericParamDef) -> GenericArg<'tcx> {
self.type_at(def.index as usize).into()
}
/// 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);
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>> {
}
}
+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,
}
}
+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,
}
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
+ }
}
///////////////////////////////////////////////////////////////////////////