]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_middle/src/ty/sty.rs
Fmt and test revert
[rust.git] / compiler / rustc_middle / src / ty / sty.rs
index c6d72e78df83501f7ad1d5c9529f9194b9387ae8..e352d0bc756976d039daa460450ac0e10a6aa19c 100644 (file)
@@ -5,6 +5,8 @@
 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::{
@@ -62,22 +64,10 @@ pub enum BoundRegionKind {
 #[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 {
@@ -947,6 +937,14 @@ pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTrai
     }
 }
 
+#[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 ==
@@ -957,7 +955,7 @@ pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTrai
 ///
 /// `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
@@ -969,44 +967,22 @@ impl<'tcx, T> Binder<'tcx, T>
     /// 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)
     }
 }
 
@@ -1031,26 +1007,39 @@ pub fn skip_binder(self) -> T {
         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
@@ -1062,8 +1051,15 @@ pub fn map_bound<F, U>(self, f: F) -> Binder<'tcx, U>
     /// 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
@@ -1083,20 +1079,6 @@ pub fn no_bound_vars(self) -> Option<T>
         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.
     ///
@@ -1108,14 +1090,14 @@ pub fn split<U, V, F>(self, f: F) -> (Binder<'tcx, U>, Binder<'tcx, V>)
         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))
     }
 }
 
@@ -1221,7 +1203,7 @@ fn fake() -> FnSig<'tcx> {
 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>> {