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 {
}
}
+#[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 ==
///
/// `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<'tcx, T>(T, u32, std::marker::PhantomData<&'tcx ()>);
+pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>);
impl<'tcx, T> Binder<'tcx, T>
where
/// different binding level.
pub fn dummy(value: T) -> Binder<'tcx, T> {
debug_assert!(!value.has_escaping_bound_vars());
- Binder(value, 0, std::marker::PhantomData)
+ Binder(value, ty::List::empty())
}
/// Wraps `value` in a binder, binding higher-ranked vars (if any).
- pub fn bind(value: T) -> Binder<'tcx, T> {
- use crate::ty::fold::CountBoundVars;
- use rustc_data_structures::fx::FxHashSet;
- let mut counter = CountBoundVars {
- outer_index: ty::INNERMOST,
- bound_tys: FxHashSet::default(),
- bound_regions: FxHashSet::default(),
- bound_consts: FxHashSet::default(),
- };
- value.visit_with(&mut counter);
- let bound_tys = counter.bound_tys.len();
- let bound_regions = if !counter.bound_regions.is_empty() {
- let mut env = false;
- let mut anons = FxHashSet::default();
- let mut named = FxHashSet::default();
- for br in counter.bound_regions {
- match br.kind {
- ty::BrAnon(idx) => {
- anons.insert(idx);
- }
- ty::BrNamed(def_id, _) => {
- named.insert(def_id);
- }
- ty::BrEnv => env = true,
- }
- }
- (if env { 1 } else { 0 }) + anons.len() + named.len()
- } else {
- 0
- };
- let bound_consts = counter.bound_consts.len();
+ 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))
+ }
- let bound_vars = bound_tys + bound_regions + bound_consts;
- Binder(value, bound_vars as u32, std::marker::PhantomData)
+ 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)
}
}
self.0
}
- pub fn bound_vars(&self) -> u32 {
+ pub fn bound_vars(&self) -> &'tcx List<BoundVariableKind> {
self.1
}
pub fn as_ref(&self) -> Binder<'tcx, &T> {
- Binder(&self.0, self.1, std::marker::PhantomData)
+ Binder(&self.0, self.1)
}
- pub fn map_bound_ref<F, U>(&self, f: F) -> Binder<'tcx, U>
+ 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<'tcx, U>
+ pub fn map_bound<F, U: TypeFoldable<'tcx>>(self, f: F) -> Binder<'tcx, U>
where
F: FnOnce(T) -> U,
{
- Binder(f(self.0), self.1, std::marker::PhantomData)
+ 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<'tcx, U> {
- Binder(value, self.1, std::marker::PhantomData)
+ 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
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<'tcx, U>, f: F) -> Binder<'tcx, R>
- where
- F: FnOnce(T, U) -> R,
- {
- Binder(f(self.0, u.0), self.1, std::marker::PhantomData)
- }
-
/// Splits the contents into two things that share the same binder
/// level as the original, returning two distinct binders.
///
F: FnOnce(T) -> (U, V),
{
let (u, v) = f(self.0);
- (Binder(u, self.1, std::marker::PhantomData), Binder(v, self.1, std::marker::PhantomData))
+ (Binder(u, self.1), Binder(v, self.1))
}
}
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, std::marker::PhantomData))
+ self.0.map(|v| Binder(v, bound_vars))
}
}
impl<'tcx> PolyFnSig<'tcx> {
#[inline]
pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> {
- self.map_bound_ref(|fn_sig| fn_sig.inputs())
+ self.map_bound_ref_unchecked(|fn_sig| fn_sig.inputs())
}
#[inline]
pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> {