use self::TyKind::*;
use crate::infer::canonical::Canonical;
+use crate::ty::fold::BoundVarsCollector;
+use crate::ty::fold::ValidateBoundVars;
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
use crate::ty::InferTy::{self, *};
use crate::ty::{
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)]
#[derive(HashStable)]
pub struct BoundRegion {
+ pub var: BoundVar,
pub kind: BoundRegionKind,
}
-impl BoundRegion {
- /// When canonicalizing, we replace unbound inference variables and free
- /// regions with anonymous late bound regions. This method asserts that
- /// we have an anonymous late bound region, which hence may refer to
- /// a canonical variable.
- pub fn assert_bound_var(&self) -> BoundVar {
- match self.kind {
- BoundRegionKind::BrAnon(var) => BoundVar::from_u32(var),
- _ => bug!("bound region is not anonymous"),
- }
- }
-}
-
impl BoundRegionKind {
pub fn is_named(&self) -> bool {
match *self {
FnPtr(PolyFnSig<'tcx>),
/// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
- Dynamic(&'tcx List<Binder<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
+ Dynamic(&'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
/// The anonymous type of a closure. Used to represent the type of
/// `|a| a`.
/// A type representing the types stored inside a generator.
/// This should only appear in GeneratorInteriors.
- GeneratorWitness(Binder<&'tcx List<Ty<'tcx>>>),
+ GeneratorWitness(Binder<'tcx, &'tcx List<Ty<'tcx>>>),
/// The never type `!`.
Never,
// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(TyKind<'_>, 24);
+static_assert_size!(TyKind<'_>, 32);
/// A closure can be modeled as a struct that looks like:
///
}
}
-impl<'tcx> Binder<ExistentialPredicate<'tcx>> {
+impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> {
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
use crate::ty::ToPredicate;
match self.skip_binder() {
}
}
-impl<'tcx> List<ty::Binder<ExistentialPredicate<'tcx>>> {
+impl<'tcx> List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> {
/// Returns the "principal `DefId`" of this set of existential predicates.
///
/// A Rust trait object type consists (in addition to a lifetime bound)
/// is `{Send, Sync}`, while there is no principal. These trait objects
/// have a "trivial" vtable consisting of just the size, alignment,
/// and destructor.
- pub fn principal(&self) -> Option<ty::Binder<ExistentialTraitRef<'tcx>>> {
+ pub fn principal(&self) -> Option<ty::Binder<'tcx, ExistentialTraitRef<'tcx>>> {
self[0]
.map_bound(|this| match this {
ExistentialPredicate::Trait(tr) => Some(tr),
#[inline]
pub fn projection_bounds<'a>(
&'a self,
- ) -> impl Iterator<Item = ty::Binder<ExistentialProjection<'tcx>>> + 'a {
+ ) -> impl Iterator<Item = ty::Binder<'tcx, ExistentialProjection<'tcx>>> + 'a {
self.iter().filter_map(|predicate| {
predicate
.map_bound(|pred| match pred {
}
}
-pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
+pub type PolyTraitRef<'tcx> = Binder<'tcx, TraitRef<'tcx>>;
impl<'tcx> PolyTraitRef<'tcx> {
- pub fn self_ty(&self) -> Binder<Ty<'tcx>> {
+ pub fn self_ty(&self) -> Binder<'tcx, Ty<'tcx>> {
self.map_bound_ref(|tr| tr.self_ty())
}
}
}
-pub type PolyExistentialTraitRef<'tcx> = Binder<ExistentialTraitRef<'tcx>>;
+pub type PolyExistentialTraitRef<'tcx> = Binder<'tcx, ExistentialTraitRef<'tcx>>;
impl<'tcx> PolyExistentialTraitRef<'tcx> {
pub fn def_id(&self) -> DefId {
}
}
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable)]
+pub enum BoundVariableKind {
+ Ty(BoundTyKind),
+ Region(BoundRegionKind),
+ Const,
+}
+
/// Binder is a binder for higher-ranked lifetimes or types. It is part of the
/// compiler's representation for things like `for<'a> Fn(&'a isize)`
/// (which would be represented by the type `PolyTraitRef ==
-/// Binder<TraitRef>`). Note that when we instantiate,
+/// Binder<'tcx, TraitRef>`). Note that when we instantiate,
/// erase, or otherwise "discharge" these bound vars, we change the
-/// type from `Binder<T>` to just `T` (see
+/// type from `Binder<'tcx, T>` to just `T` (see
/// e.g., `liberate_late_bound_regions`).
///
/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-pub struct Binder<T>(T);
+pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>);
-impl<T> Binder<T> {
+impl<'tcx, T> Binder<'tcx, T>
+where
+ T: TypeFoldable<'tcx>,
+{
/// Wraps `value` in a binder, asserting that `value` does not
/// contain any bound vars that would be bound by the
/// binder. This is commonly used to 'inject' a value T into a
/// different binding level.
- pub fn dummy<'tcx>(value: T) -> Binder<T>
- where
- T: TypeFoldable<'tcx>,
- {
+ pub fn dummy(value: T) -> Binder<'tcx, T> {
debug_assert!(!value.has_escaping_bound_vars());
- Binder(value)
+ Binder(value, ty::List::empty())
}
/// Wraps `value` in a binder, binding higher-ranked vars (if any).
- pub fn bind(value: T) -> Binder<T> {
- Binder(value)
+ pub fn bind(value: T, tcx: TyCtxt<'tcx>) -> Binder<'tcx, T> {
+ let mut collector = BoundVarsCollector::new();
+ value.visit_with(&mut collector);
+ Binder(value, collector.into_vars(tcx))
}
- /// Wraps `value` in a binder without actually binding any currently
- /// unbound variables.
- ///
- /// Note that this will shift all debrujin indices of escaping bound variables
- /// by 1 to avoid accidential captures.
- pub fn wrap_nonbinding(tcx: TyCtxt<'tcx>, value: T) -> Binder<T>
- where
- T: TypeFoldable<'tcx>,
- {
- if value.has_escaping_bound_vars() {
- Binder::bind(super::fold::shift_vars(tcx, value, 1))
- } else {
- Binder::dummy(value)
+ pub fn bind_with_vars(value: T, vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> {
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(vars);
+ value.visit_with(&mut validator);
}
+ Binder(value, vars)
}
+}
+impl<'tcx, T> Binder<'tcx, T> {
/// Skips the binder and returns the "bound" value. This is a
/// risky thing to do because it's easy to get confused about
/// De Bruijn indices and the like. It is usually better to
self.0
}
- pub fn as_ref(&self) -> Binder<&T> {
- Binder(&self.0)
+ pub fn bound_vars(&self) -> &'tcx List<BoundVariableKind> {
+ self.1
}
- pub fn map_bound_ref<F, U>(&self, f: F) -> Binder<U>
+ pub fn as_ref(&self) -> Binder<'tcx, &T> {
+ Binder(&self.0, self.1)
+ }
+
+ pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U>
+ where
+ F: FnOnce(&T) -> U,
+ {
+ let value = f(&self.0);
+ Binder(value, self.1)
+ }
+
+ pub fn map_bound_ref<F, U: TypeFoldable<'tcx>>(&self, f: F) -> Binder<'tcx, U>
where
F: FnOnce(&T) -> U,
{
self.as_ref().map_bound(f)
}
- pub fn map_bound<F, U>(self, f: F) -> Binder<U>
+ pub fn map_bound<F, U: TypeFoldable<'tcx>>(self, f: F) -> Binder<'tcx, U>
where
F: FnOnce(T) -> U,
{
- Binder(f(self.0))
+ let value = f(self.0);
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(self.1);
+ value.visit_with(&mut validator);
+ }
+ Binder(value, self.1)
}
/// Wraps a `value` in a binder, using the same bound variables as the
/// don't actually track bound vars. However, semantically, it is different
/// because bound vars aren't allowed to change here, whereas they are
/// in `bind`. This may be (debug) asserted in the future.
- pub fn rebind<U>(&self, value: U) -> Binder<U> {
- Binder(value)
+ pub fn rebind<U>(&self, value: U) -> Binder<'tcx, U>
+ where
+ U: TypeFoldable<'tcx>,
+ {
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(self.bound_vars());
+ value.visit_with(&mut validator);
+ }
+ Binder(value, self.1)
}
/// Unwraps and returns the value within, but only if it contains
/// binders, but that would require adjusting the debruijn
/// indices, and given the shallow binding structure we often use,
/// would not be that useful.)
- pub fn no_bound_vars<'tcx>(self) -> Option<T>
+ pub fn no_bound_vars(self) -> Option<T>
where
T: TypeFoldable<'tcx>,
{
if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
}
- /// Given two things that have the same binder level,
- /// and an operation that wraps on their contents, executes the operation
- /// and then wraps its result.
- ///
- /// `f` should consider bound regions at depth 1 to be free, and
- /// anything it produces with bound regions at depth 1 will be
- /// bound in the resulting return value.
- pub fn fuse<U, F, R>(self, u: Binder<U>, f: F) -> Binder<R>
- where
- F: FnOnce(T, U) -> R,
- {
- Binder(f(self.0, u.0))
- }
-
/// Splits the contents into two things that share the same binder
/// level as the original, returning two distinct binders.
///
/// `f` should consider bound regions at depth 1 to be free, and
/// anything it produces with bound regions at depth 1 will be
/// bound in the resulting return values.
- pub fn split<U, V, F>(self, f: F) -> (Binder<U>, Binder<V>)
+ pub fn split<U, V, F>(self, f: F) -> (Binder<'tcx, U>, Binder<'tcx, V>)
where
F: FnOnce(T) -> (U, V),
{
let (u, v) = f(self.0);
- (Binder(u), Binder(v))
+ (Binder(u, self.1), Binder(v, self.1))
}
}
-impl<T> Binder<Option<T>> {
- pub fn transpose(self) -> Option<Binder<T>> {
- self.0.map(Binder)
+impl<'tcx, T> Binder<'tcx, Option<T>> {
+ pub fn transpose(self) -> Option<Binder<'tcx, T>> {
+ let bound_vars = self.1;
+ self.0.map(|v| Binder(v, bound_vars))
}
}
pub return_ty: Ty<'tcx>,
}
-pub type PolyGenSig<'tcx> = Binder<GenSig<'tcx>>;
-
-impl<'tcx> PolyGenSig<'tcx> {
- pub fn resume_ty(&self) -> ty::Binder<Ty<'tcx>> {
- self.map_bound_ref(|sig| sig.resume_ty)
- }
- pub fn yield_ty(&self) -> ty::Binder<Ty<'tcx>> {
- self.map_bound_ref(|sig| sig.yield_ty)
- }
- pub fn return_ty(&self) -> ty::Binder<Ty<'tcx>> {
- self.map_bound_ref(|sig| sig.return_ty)
- }
-}
+pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>;
/// Signature of a function type, which we have arbitrarily
/// decided to use to refer to the input/output types.
}
}
-pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
+pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>;
impl<'tcx> PolyFnSig<'tcx> {
#[inline]
- pub fn inputs(&self) -> Binder<&'tcx [Ty<'tcx>]> {
- self.map_bound_ref(|fn_sig| fn_sig.inputs())
+ pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> {
+ self.map_bound_ref_unchecked(|fn_sig| fn_sig.inputs())
}
#[inline]
- pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
+ pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> {
self.map_bound_ref(|fn_sig| fn_sig.inputs()[index])
}
- pub fn inputs_and_output(&self) -> ty::Binder<&'tcx List<Ty<'tcx>>> {
+ pub fn inputs_and_output(&self) -> ty::Binder<'tcx, &'tcx List<Ty<'tcx>>> {
self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output)
}
#[inline]
- pub fn output(&self) -> ty::Binder<Ty<'tcx>> {
+ pub fn output(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
self.map_bound_ref(|fn_sig| fn_sig.output())
}
pub fn c_variadic(&self) -> bool {
}
}
-pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<FnSig<'tcx>>>;
+pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable)]
ParamTy { index, name }
}
- pub fn for_self() -> ParamTy {
- ParamTy::new(0, kw::SelfUpper)
- }
-
pub fn for_def(def: &ty::GenericParamDef) -> ParamTy {
ParamTy::new(def.index, def.name)
}
pub name: Symbol,
}
-impl<'tcx> ParamConst {
+impl ParamConst {
pub fn new(index: u32, name: Symbol) -> ParamConst {
ParamConst { index, name }
}
pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
ParamConst::new(def.index, def.name)
}
-
- pub fn to_const(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
- tcx.mk_const_param(self.index, self.name, ty)
- }
}
pub type Region<'tcx> = &'tcx RegionKind;
pub ty: Ty<'tcx>,
}
-pub type PolyExistentialProjection<'tcx> = Binder<ExistentialProjection<'tcx>>;
+pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>;
impl<'tcx> ExistentialProjection<'tcx> {
/// Extracts the underlying existential trait reference from this projection.
}
}
- /// Adjusts any De Bruijn indices so as to make `to_binder` the
- /// innermost binder. That is, if we have something bound at `to_binder`,
- /// it will now be bound at INNERMOST. This is an appropriate thing to do
- /// when moving a region out from inside binders:
- ///
- /// ```
- /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _)
- /// // Binder: D3 D2 D1 ^^
- /// ```
- ///
- /// Here, the region `'a` would have the De Bruijn index D3,
- /// because it is the bound 3 binders out. However, if we wanted
- /// to refer to that region `'a` in the second argument (the `_`),
- /// those two binders would not be in scope. In that case, we
- /// might invoke `shift_out_to_binder(D3)`. This would adjust the
- /// De Bruijn index of `'a` to D1 (the innermost binder).
- ///
- /// If we invoke `shift_out_to_binder` and the region is in fact
- /// bound by one of the binders we are shifting out of, that is an
- /// error (and should fail an assertion failure).
- pub fn shifted_out_to_binder(&self, to_binder: ty::DebruijnIndex) -> RegionKind {
- match *self {
- ty::ReLateBound(debruijn, r) => {
- ty::ReLateBound(debruijn.shifted_out_to_binder(to_binder), r)
- }
- r => r,
- }
- }
-
pub fn type_flags(&self) -> TypeFlags {
let mut flags = TypeFlags::empty();