From 803bd761278e6e06baabfd5aa1aa15e75c4a16a4 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sat, 15 Jul 2017 06:41:19 -0400
Subject: [PATCH 01/22] introduce `Universe` struct

---
 src/librustc/ty/mod.rs | 62 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 3ab2cd274b90e..26fcd5c311056 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1306,6 +1306,68 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
     }
 }
 
+/// "Universes" are used during type- and trait-checking in the
+/// presence of `for<..>` binders to control what sets of names are
+/// visible. Universes are arranged into a tree: the root universe
+/// contains names that are always visible. But when you enter into
+/// some subuniverse, then it may add names that are only visible
+/// within that subtree (but it can still name the names of its
+/// ancestor universes).
+///
+/// To make this more concrete, consider this program:
+///
+/// ```
+/// struct Foo { }
+/// fn bar<T>(x: T) {
+///   let y: for<'a> fn(&'a u8, Foo) = ...;
+/// }
+/// ```
+///
+/// The struct name `Foo` is in the root universe U0. But the type
+/// parameter `T`, introduced on `bar`, is in a subuniverse U1 --
+/// i.e., within `bar`, we can name both `T` and `Foo`, but outside of
+/// `bar`, we cannot name `T`. Then, within the type of `y`, the
+/// region `'a` is in a subuniverse U2 of U1, because we can name it
+/// inside the fn type but not outside.
+///
+/// Universes are related to **skolemization** -- which is a way of
+/// doing type- and trait-checking around these "forall" binders (also
+/// called **universal quantification**). The idea is that when, in
+/// the body of `bar`, we refer to `T` as a type, we aren't referring
+/// to any type in particular, but rather a kind of "fresh" type that
+/// is distinct from all other types we have actually declared. This
+/// is called a **skolemized** type, and we use universes to talk
+/// about this. In other words, a type name in universe 0 always
+/// corresponds to some "ground" type that the user declared, but a
+/// type name in a non-zero universe is a skolemized type -- an
+/// idealized representative of "types in general" that we use for
+/// checking generic functions.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct UniverseIndex(u32);
+
+impl UniverseIndex {
+    /// The root universe, where things that the user defined are
+    /// visible.
+    pub fn root() -> UniverseIndex {
+        UniverseIndex(0)
+    }
+
+    /// A "subuniverse" corresponds to being inside a `forall` quantifier.
+    /// So, for example, suppose we have this type in universe `U`:
+    ///
+    /// ```
+    /// for<'a> fn(&'a u32)
+    /// ```
+    ///
+    /// Once we "enter" into this `for<'a>` quantifier, we are in a
+    /// subuniverse of `U` -- in this new universe, we can name the
+    /// region `'a`, but that region was not nameable from `U` because
+    /// it was not in scope there.
+    pub fn subuniverse(self) -> UniverseIndex {
+        UniverseIndex(self.0 + 1)
+    }
+}
+
 /// When type checking, we use the `ParamEnv` to track
 /// details about the set of where-clauses that are in scope at this
 /// particular point.

From e7efce23618adcc9c960e1518d00883da8a8c444 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sat, 15 Jul 2017 06:47:30 -0400
Subject: [PATCH 02/22] add some comments to `Obligation`

---
 src/librustc/traits/mod.rs | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index c1ffc10c3c0f0..027ad4174bd15 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -77,10 +77,21 @@ pub enum IntercrateMode {
 /// scope. The eventual result is usually a `Selection` (defined below).
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Obligation<'tcx, T> {
+    /// Why do we have to prove this thing?
     pub cause: ObligationCause<'tcx>,
+
+    /// In which environment should we prove this thing?
     pub param_env: ty::ParamEnv<'tcx>,
-    pub recursion_depth: usize,
+
+    /// What are we trying to prove?
     pub predicate: T,
+
+    /// If we started proving this as a result of trying to prove
+    /// something else, track the total depth to ensure termination.
+    /// If this goes over a certain threshold, we abort compilation --
+    /// in such cases, we can not say whether or not the predicate
+    /// holds for certain. Stupid halting problem. Such a drag.
+    pub recursion_depth: usize,
 }
 
 pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;

From d4df52cacbee5d95e912a43188192a5054d36b4f Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sat, 15 Jul 2017 07:23:28 -0400
Subject: [PATCH 03/22] introduce `UniverseIndex` into `ParamEnv`

Always using root environment for now.
---
 src/librustc/ich/impls_ty.rs                | 10 ++++++++
 src/librustc/traits/mod.rs                  |  7 ++++--
 src/librustc/ty/mod.rs                      | 25 ++++++++++++++++----
 src/librustc/ty/structural_impls.rs         | 26 +++++++++++++++++++--
 src/librustc/ty/util.rs                     |  7 +++---
 src/librustc_typeck/check/compare_method.rs |  3 ++-
 6 files changed, 66 insertions(+), 12 deletions(-)

diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 71a57dbf32fb1..7b2cfa0a3ffec 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -870,6 +870,7 @@ for ty::steal::Steal<T>
 
 impl_stable_hash_for!(struct ty::ParamEnv<'tcx> {
     caller_bounds,
+    universe,
     reveal
 });
 
@@ -1039,3 +1040,12 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContex
         nested.hash_stable(hcx, hasher);
     }
 }
+
+impl<'gcx> HashStable<StableHashingContext<'gcx>>
+for ty::UniverseIndex {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        self.depth().hash_stable(hcx, hasher);
+    }
+}
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 027ad4174bd15..76d3c7f150670 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -546,7 +546,8 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            predicates);
 
     let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
-                                           unnormalized_env.reveal);
+                                           unnormalized_env.reveal,
+                                           unnormalized_env.universe);
 
     tcx.infer_ctxt().enter(|infcx| {
         // FIXME. We should really... do something with these region
@@ -620,7 +621,9 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         debug!("normalize_param_env_or_error: resolved predicates={:?}",
                predicates);
 
-        ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal)
+        ty::ParamEnv::new(tcx.intern_predicates(&predicates),
+                          unnormalized_env.reveal,
+                          unnormalized_env.universe)
     })
 }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 26fcd5c311056..856c53d19c98c 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1348,9 +1348,7 @@ pub struct UniverseIndex(u32);
 impl UniverseIndex {
     /// The root universe, where things that the user defined are
     /// visible.
-    pub fn root() -> UniverseIndex {
-        UniverseIndex(0)
-    }
+    pub const ROOT: UniverseIndex = UniverseIndex(0);
 
     /// A "subuniverse" corresponds to being inside a `forall` quantifier.
     /// So, for example, suppose we have this type in universe `U`:
@@ -1366,6 +1364,13 @@ impl UniverseIndex {
     pub fn subuniverse(self) -> UniverseIndex {
         UniverseIndex(self.0 + 1)
     }
+
+    /// Gets the "depth" of this universe in the universe tree. This
+    /// is not really useful except for e.g. the `HashStable`
+    /// implementation
+    pub fn depth(&self) -> u32 {
+        self.0
+    }
 }
 
 /// When type checking, we use the `ParamEnv` to track
@@ -1382,6 +1387,17 @@ pub struct ParamEnv<'tcx> {
     /// want `Reveal::All` -- note that this is always paired with an
     /// empty environment. To get that, use `ParamEnv::reveal()`.
     pub reveal: traits::Reveal,
+
+    /// What is the innermost universe we have created? Starts out as
+    /// `UniverseIndex::root()` but grows from there as we enter
+    /// universal quantifiers.
+    ///
+    /// NB: At present, we exclude the universal quantifiers on the
+    /// item we are type-checking, and just consider those names as
+    /// part of the root universe. So this would only get incremented
+    /// when we enter into a higher-ranked (`for<..>`) type or trait
+    /// bound.
+    pub universe: UniverseIndex,
 }
 
 impl<'tcx> ParamEnv<'tcx> {
@@ -2657,7 +2673,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // sure that this will succeed without errors anyway.
 
     let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
-                                             traits::Reveal::UserFacing);
+                                             traits::Reveal::UserFacing,
+                                             ty::UniverseIndex::ROOT);
 
     let body_id = tcx.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
         tcx.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id)
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 0dc1338fff860..3a1ad8db9c20a 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -405,6 +405,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
         tcx.lift(&self.caller_bounds).map(|caller_bounds| {
             ty::ParamEnv {
                 reveal: self.reveal,
+                universe: self.universe,
                 caller_bounds,
             }
         })
@@ -733,8 +734,29 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
     }
 }
 
-BraceStructTypeFoldableImpl! {
-    impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> { reveal, caller_bounds }
+impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        ty::ParamEnv {
+            reveal: self.reveal,
+            caller_bounds: self.caller_bounds.fold_with(folder),
+            universe: self.universe.fold_with(folder),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        let &ty::ParamEnv { reveal: _, ref universe, ref caller_bounds } = self;
+        universe.super_visit_with(visitor) || caller_bounds.super_visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::UniverseIndex {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
+        *self
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
+        false
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 110808919e905..44771444c8aa8 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -153,14 +153,15 @@ impl<'tcx> ty::ParamEnv<'tcx> {
     /// Construct a trait environment suitable for contexts where
     /// there are no where clauses in scope.
     pub fn empty(reveal: Reveal) -> Self {
-        Self::new(ty::Slice::empty(), reveal)
+        Self::new(ty::Slice::empty(), reveal, ty::UniverseIndex::ROOT)
     }
 
     /// Construct a trait environment with the given set of predicates.
     pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>,
-               reveal: Reveal)
+               reveal: Reveal,
+               universe: ty::UniverseIndex)
                -> Self {
-        ty::ParamEnv { caller_bounds, reveal }
+        ty::ParamEnv { caller_bounds, reveal, universe }
     }
 
     /// Returns a new parameter environment with the same clauses, but
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 4c10f28eb8e5d..d0419382bc312 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -218,7 +218,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // the new hybrid bounds we computed.
     let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id);
     let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates),
-                                      Reveal::UserFacing);
+                                      Reveal::UserFacing,
+                                      ty::UniverseIndex::ROOT);
     let param_env = traits::normalize_param_env_or_error(tcx,
                                                          impl_m.def_id,
                                                          param_env,

From d516b263c6bda687bc5ca52e6940cd5f5bd40149 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sat, 15 Jul 2017 14:47:49 -0400
Subject: [PATCH 04/22] use `{}` for `Known` variant just for more parity

---
 src/librustc/infer/type_variable.rs | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 6aa094d2cd6d7..d89625ac871a7 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -79,7 +79,9 @@ struct TypeVariableData<'tcx> {
 }
 
 enum TypeVariableValue<'tcx> {
-    Known(Ty<'tcx>),
+    Known {
+        value: Ty<'tcx>
+    },
     Bounded {
         default: Option<Default<'tcx>>
     }
@@ -120,7 +122,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
 
     pub fn default(&self, vid: ty::TyVid) -> Option<Default<'tcx>> {
         match &self.values.get(vid.index as usize).value {
-            &Known(_) => None,
+            &Known { .. } => None,
             &Bounded { ref default, .. } => default.clone()
         }
     }
@@ -161,14 +163,14 @@ impl<'tcx> TypeVariableTable<'tcx> {
 
         let old_value = {
             let vid_data = &mut self.values[vid.index as usize];
-            mem::replace(&mut vid_data.value, TypeVariableValue::Known(ty))
+            mem::replace(&mut vid_data.value, TypeVariableValue::Known { value: ty })
         };
 
         match old_value {
             TypeVariableValue::Bounded { default } => {
                 self.values.record(Instantiate { vid: vid, default: default });
             }
-            TypeVariableValue::Known(old_ty) => {
+            TypeVariableValue::Known { value: old_ty } => {
                 bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
                      vid, ty, old_ty)
             }
@@ -236,7 +238,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
         debug_assert!(self.root_var(vid) == vid);
         match self.values.get(vid.index as usize).value {
             Bounded { .. } => None,
-            Known(t) => Some(t)
+            Known { value } => Some(value)
         }
     }
 
@@ -337,7 +339,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
                         // created since the snapshot started or not.
                         let escaping_type = match self.values.get(vid.index as usize).value {
                             Bounded { .. } => bug!(),
-                            Known(ty) => ty,
+                            Known { value } => value,
                         };
                         escaping_types.push(escaping_type);
                     }

From 7112d6584c355fa13df5cb672befb0f7c383cafb Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sat, 15 Jul 2017 14:52:32 -0400
Subject: [PATCH 05/22] make `Default` Copy and Clone

---
 src/librustc/infer/type_variable.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index d89625ac871a7..36afb8b536725 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -89,7 +89,7 @@ enum TypeVariableValue<'tcx> {
 
 // We will use this to store the required information to recapitulate what happened when
 // an error occurs.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct Default<'tcx> {
     pub ty: Ty<'tcx>,
     /// The span where the default was incurred
@@ -123,7 +123,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
     pub fn default(&self, vid: ty::TyVid) -> Option<Default<'tcx>> {
         match &self.values.get(vid.index as usize).value {
             &Known { .. } => None,
-            &Bounded { ref default, .. } => default.clone()
+            &Bounded { default, .. } => default,
         }
     }
 
@@ -185,7 +185,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
         self.eq_relations.new_key(());
         self.sub_relations.new_key(());
         let index = self.values.push(TypeVariableData {
-            value: Bounded { default: default },
+            value: Bounded { default },
             origin,
             diverging,
         });

From 047a8d016111c5a12beba2202c61df5b897eea45 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sat, 15 Jul 2017 18:24:51 -0400
Subject: [PATCH 06/22] kill custom type inference defaults (these don't really
 work anyway)

---
 src/librustc/infer/mod.rs                   | 23 +++++----------------
 src/librustc_typeck/astconv.rs              |  3 +--
 src/librustc_typeck/check/method/confirm.rs |  4 ++--
 src/librustc_typeck/check/method/mod.rs     |  4 ++--
 src/librustc_typeck/check/method/probe.rs   |  4 ++--
 src/librustc_typeck/check/mod.rs            |  9 ++++----
 6 files changed, 16 insertions(+), 31 deletions(-)

diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 7a386c144b738..349a2af5aa9ab 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -22,7 +22,7 @@ use middle::free_region::RegionRelations;
 use middle::region;
 use middle::lang_items;
 use mir::tcx::PlaceTy;
-use ty::subst::{Kind, Subst, Substs};
+use ty::subst::Substs;
 use ty::{TyVid, IntVid, FloatVid};
 use ty::{self, Ty, TyCtxt};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
@@ -1093,26 +1093,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// as the substitutions for the default, `(T, U)`.
     pub fn type_var_for_def(&self,
                             span: Span,
-                            def: &ty::TypeParameterDef,
-                            substs: &[Kind<'tcx>])
+                            def: &ty::TypeParameterDef)
                             -> Ty<'tcx> {
-        let default = if def.has_default {
-            let default = self.tcx.type_of(def.def_id);
-            Some(type_variable::Default {
-                ty: default.subst_spanned(self.tcx, substs, Some(span)),
-                origin_span: span,
-                def_id: def.def_id
-            })
-        } else {
-            None
-        };
-
-
         let ty_var_id = self.type_variables
                             .borrow_mut()
                             .new_var(false,
                                      TypeVariableOrigin::TypeParameterDefinition(span, def.name),
-                                     default);
+                                     None);
 
         self.tcx.mk_var(ty_var_id)
     }
@@ -1125,8 +1112,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                  -> &'tcx Substs<'tcx> {
         Substs::for_item(self.tcx, def_id, |def, _| {
             self.region_var_for_def(span, def)
-        }, |def, substs| {
-            self.type_var_for_def(span, def, substs)
+        }, |def, _| {
+            self.type_var_for_def(span, def)
         })
     }
 
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 650e530519887..bc1b70ffc8e1c 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -51,7 +51,6 @@ pub trait AstConv<'gcx, 'tcx> {
     /// Same as ty_infer, but with a known type parameter definition.
     fn ty_infer_for_def(&self,
                         _def: &ty::TypeParameterDef,
-                        _substs: &[Kind<'tcx>],
                         span: Span) -> Ty<'tcx> {
         self.ty_infer(span)
     }
@@ -261,7 +260,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             } else if infer_types {
                 // No type parameters were provided, we can infer all.
                 let ty_var = if !default_needs_object_self(def) {
-                    self.ty_infer_for_def(def, substs, span)
+                    self.ty_infer_for_def(def, span)
                 } else {
                     self.ty_infer(span)
                 };
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 20d5899149645..a3233c8d86599 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -325,7 +325,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             } else {
                 self.region_var_for_def(self.span, def)
             }
-        }, |def, cur_substs| {
+        }, |def, _cur_substs| {
             let i = def.index as usize;
             if i < parent_substs.len() {
                 parent_substs.type_at(i)
@@ -336,7 +336,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             {
                 self.to_ty(ast_ty)
             } else {
-                self.type_var_for_def(self.span, def, cur_substs)
+                self.type_var_for_def(self.span, def)
             }
         })
     }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 58d72e37d51cf..4a122fbc4c195 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -249,13 +249,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let substs = Substs::for_item(self.tcx,
                                       trait_def_id,
                                       |def, _| self.region_var_for_def(span, def),
-                                      |def, substs| {
+                                      |def, _substs| {
             if def.index == 0 {
                 self_ty
             } else if let Some(ref input_types) = opt_input_types {
                 input_types[def.index as usize - 1]
             } else {
-                self.type_var_for_def(span, def, substs)
+                self.type_var_for_def(span, def)
             }
         });
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 9f3e44f56dae2..0a20af23e2e9d 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -1304,12 +1304,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                     // `impl_self_ty()` for an explanation.
                     self.tcx.types.re_erased
                 }
-            }, |def, cur_substs| {
+            }, |def, _cur_substs| {
                 let i = def.index as usize;
                 if i < substs.len() {
                     substs.type_at(i)
                 } else {
-                    self.type_var_for_def(self.span, def, cur_substs)
+                    self.type_var_for_def(self.span, def)
                 }
             });
             xform_fn_sig.subst(self.tcx, substs)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 91fa3c5da6991..4fa48d96d36c4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -93,7 +93,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
 use rustc::infer::anon_types::AnonTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
-use rustc::ty::subst::{Kind, Subst, Substs};
+use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
 use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
 use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
@@ -1692,9 +1692,8 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
 
     fn ty_infer_for_def(&self,
                         ty_param_def: &ty::TypeParameterDef,
-                        substs: &[Kind<'tcx>],
                         span: Span) -> Ty<'tcx> {
-        self.type_var_for_def(span, ty_param_def, substs)
+        self.type_var_for_def(span, ty_param_def)
     }
 
     fn projected_ty_from_poly_trait_ref(&self,
@@ -4793,7 +4792,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // Handle Self first, so we can adjust the index to match the AST.
                 if has_self && i == 0 {
                     return opt_self_ty.unwrap_or_else(|| {
-                        self.type_var_for_def(span, def, substs)
+                        self.type_var_for_def(span, def)
                     });
                 }
                 i -= has_self as usize;
@@ -4826,7 +4825,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // This can also be reached in some error cases:
                 // We prefer to use inference variables instead of
                 // TyError to let type inference recover somewhat.
-                self.type_var_for_def(span, def, substs)
+                self.type_var_for_def(span, def)
             }
         });
 

From b680b12e949097602dd6d39009fee8c95d86a261 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sun, 16 Jul 2017 04:55:48 -0400
Subject: [PATCH 07/22] kill supporting code from type-variable defaults

This was all unused anyway.
---
 src/librustc/infer/combine.rs       |  2 +-
 src/librustc/infer/mod.rs           | 43 ++-----------------------
 src/librustc/infer/type_variable.rs | 50 ++++++++---------------------
 src/librustc/ty/error.rs            | 45 +-------------------------
 src/librustc/ty/structural_impls.rs | 29 +----------------
 5 files changed, 18 insertions(+), 151 deletions(-)

diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index f7bc092a3d7ae..bd175c510fba3 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -424,7 +424,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                             }
 
                             let origin = variables.origin(vid);
-                            let new_var_id = variables.new_var(false, origin, None);
+                            let new_var_id = variables.new_var(false, origin);
                             let u = self.tcx().mk_var(new_var_id);
                             debug!("generalize: replacing original vid={:?} with new={:?}",
                                    vid, u);
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 349a2af5aa9ab..4292845792560 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -695,22 +695,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// Returns a type variable's default fallback if any exists. A default
-    /// must be attached to the variable when created, if it is created
-    /// without a default, this will return None.
-    ///
-    /// This code does not apply to integral or floating point variables,
-    /// only to use declared defaults.
-    ///
-    /// See `new_ty_var_with_default` to create a type variable with a default.
-    /// See `type_variable::Default` for details about what a default entails.
-    pub fn default(&self, ty: Ty<'tcx>) -> Option<type_variable::Default<'tcx>> {
-        match ty.sty {
-            ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid),
-            _ => None
-        }
-    }
-
     pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
         let mut variables = Vec::new();
 
@@ -1029,7 +1013,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
         self.type_variables
             .borrow_mut()
-            .new_var(diverging, origin, None)
+            .new_var(diverging, origin)
     }
 
     pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
@@ -1098,8 +1082,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         let ty_var_id = self.type_variables
                             .borrow_mut()
                             .new_var(false,
-                                     TypeVariableOrigin::TypeParameterDefinition(span, def.name),
-                                     None);
+                                     TypeVariableOrigin::TypeParameterDefinition(span, def.name));
 
         self.tcx.mk_var(ty_var_id)
     }
@@ -1389,28 +1372,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.report_and_explain_type_error(trace, &err)
     }
 
-    pub fn report_conflicting_default_types(&self,
-                                            span: Span,
-                                            body_id: ast::NodeId,
-                                            expected: type_variable::Default<'tcx>,
-                                            actual: type_variable::Default<'tcx>) {
-        let trace = TypeTrace {
-            cause: ObligationCause::misc(span, body_id),
-            values: Types(ExpectedFound {
-                expected: expected.ty,
-                found: actual.ty
-            })
-        };
-
-        self.report_and_explain_type_error(
-            trace,
-            &TypeError::TyParamDefaultMismatch(ExpectedFound {
-                expected,
-                found: actual
-            }))
-            .emit();
-    }
-
     pub fn replace_late_bound_regions_with_fresh_var<T>(
         &self,
         span: Span,
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 36afb8b536725..e07cc92ec2158 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use self::TypeVariableValue::*;
-use hir::def_id::{DefId};
 use syntax::ast;
 use syntax_pos::Span;
 use ty::{self, Ty};
@@ -82,20 +81,7 @@ enum TypeVariableValue<'tcx> {
     Known {
         value: Ty<'tcx>
     },
-    Bounded {
-        default: Option<Default<'tcx>>
-    }
-}
-
-// We will use this to store the required information to recapitulate what happened when
-// an error occurs.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub struct Default<'tcx> {
-    pub ty: Ty<'tcx>,
-    /// The span where the default was incurred
-    pub origin_span: Span,
-    /// The definition that the default originates from
-    pub def_id: DefId
+    Unknown,
 }
 
 pub struct Snapshot {
@@ -104,9 +90,8 @@ pub struct Snapshot {
     sub_snapshot: ut::Snapshot<ty::TyVid>,
 }
 
-struct Instantiate<'tcx> {
+struct Instantiate {
     vid: ty::TyVid,
-    default: Option<Default<'tcx>>,
 }
 
 struct Delegate<'tcx>(PhantomData<&'tcx ()>);
@@ -120,13 +105,6 @@ impl<'tcx> TypeVariableTable<'tcx> {
         }
     }
 
-    pub fn default(&self, vid: ty::TyVid) -> Option<Default<'tcx>> {
-        match &self.values.get(vid.index as usize).value {
-            &Known { .. } => None,
-            &Bounded { default, .. } => default,
-        }
-    }
-
     pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
         self.values.get(vid.index as usize).diverging
     }
@@ -167,8 +145,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
         };
 
         match old_value {
-            TypeVariableValue::Bounded { default } => {
-                self.values.record(Instantiate { vid: vid, default: default });
+            TypeVariableValue::Unknown => {
+                self.values.record(Instantiate { vid: vid });
             }
             TypeVariableValue::Known { value: old_ty } => {
                 bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
@@ -179,13 +157,13 @@ impl<'tcx> TypeVariableTable<'tcx> {
 
     pub fn new_var(&mut self,
                    diverging: bool,
-                   origin: TypeVariableOrigin,
-                   default: Option<Default<'tcx>>,) -> ty::TyVid {
+                   origin: TypeVariableOrigin)
+                   -> ty::TyVid {
         debug!("new_var(diverging={:?}, origin={:?})", diverging, origin);
         self.eq_relations.new_key(());
         self.sub_relations.new_key(());
         let index = self.values.push(TypeVariableData {
-            value: Bounded { default },
+            value: Unknown,
             origin,
             diverging,
         });
@@ -237,7 +215,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
     pub fn probe_root(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
         debug_assert!(self.root_var(vid) == vid);
         match self.values.get(vid.index as usize).value {
-            Bounded { .. } => None,
+            Unknown => None,
             Known { value } => Some(value)
         }
     }
@@ -338,7 +316,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
                         // quick check to see if this variable was
                         // created since the snapshot started or not.
                         let escaping_type = match self.values.get(vid.index as usize).value {
-                            Bounded { .. } => bug!(),
+                            Unknown => bug!(),
                             Known { value } => value,
                         };
                         escaping_types.push(escaping_type);
@@ -369,12 +347,10 @@ impl<'tcx> TypeVariableTable<'tcx> {
 
 impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
     type Value = TypeVariableData<'tcx>;
-    type Undo = Instantiate<'tcx>;
+    type Undo = Instantiate;
 
-    fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate<'tcx>) {
-        let Instantiate { vid, default } = action;
-        values[vid.index as usize].value = Bounded {
-            default,
-        };
+    fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate) {
+        let Instantiate { vid } = action;
+        values[vid.index as usize].value = Unknown;
     }
 }
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 583612f9590f1..be89aeebdea75 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -9,9 +9,8 @@
 // except according to those terms.
 
 use hir::def_id::DefId;
-use infer::type_variable;
 use middle::const_val::ConstVal;
-use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};
+use ty::{self, BoundRegion, Region, Ty, TyCtxt};
 
 use std::fmt;
 use syntax::abi;
@@ -56,7 +55,6 @@ pub enum TypeError<'tcx> {
     CyclicTy(Ty<'tcx>),
     ProjectionMismatched(ExpectedFound<DefId>),
     ProjectionBoundsLength(ExpectedFound<usize>),
-    TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
     ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
 
     OldStyleLUB(Box<TypeError<'tcx>>),
@@ -167,11 +165,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                        values.expected,
                        values.found)
             },
-            TyParamDefaultMismatch(ref values) => {
-                write!(f, "conflicting type parameter defaults `{}` and `{}`",
-                       values.expected.ty,
-                       values.found.ty)
-            }
             ExistentialMismatch(ref values) => {
                 report_maybe_different(f, format!("trait `{}`", values.expected),
                                        format!("trait `{}`", values.found))
@@ -265,42 +258,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     db.help("consider boxing your closure and/or using it as a trait object");
                 }
             },
-            TyParamDefaultMismatch(values) => {
-                let expected = values.expected;
-                let found = values.found;
-                db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`",
-                                          expected.ty,
-                                          found.ty));
-
-                match self.hir.span_if_local(expected.def_id) {
-                    Some(span) => {
-                        db.span_note(span, "a default was defined here...");
-                    }
-                    None => {
-                        let item_def_id = self.parent(expected.def_id).unwrap();
-                        db.note(&format!("a default is defined on `{}`",
-                                         self.item_path_str(item_def_id)));
-                    }
-                }
-
-                db.span_note(
-                    expected.origin_span,
-                    "...that was applied to an unconstrained type variable here");
-
-                match self.hir.span_if_local(found.def_id) {
-                    Some(span) => {
-                        db.span_note(span, "a second default was defined here...");
-                    }
-                    None => {
-                        let item_def_id = self.parent(found.def_id).unwrap();
-                        db.note(&format!("a second default is defined on `{}`",
-                                         self.item_path_str(item_def_id)));
-                    }
-                }
-
-                db.span_note(found.origin_span,
-                             "...that also applies to the same type variable here");
-            }
             OldStyleLUB(err) => {
                 db.note("this was previously accepted by the compiler but has been phased out");
                 db.note("for more information, see https://github.com/rust-lang/rust/issues/45852");
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 3a1ad8db9c20a..6147b52844fe4 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -13,7 +13,6 @@
 //! hand, though we've recently added some macros (e.g.,
 //! `BraceStructLiftImpl!`) to help with the tedium.
 
-use infer::type_variable;
 use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr};
 use ty::{self, Lift, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@@ -548,13 +547,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> {
     }
 }
 
-BraceStructLiftImpl! {
-    impl<'a, 'tcx> Lift<'tcx> for type_variable::Default<'a> {
-        type Lifted = type_variable::Default<'tcx>;
-        ty, origin_span, def_id
-    }
-}
-
 impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
     type Lifted = ty::error::TypeError<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@@ -586,11 +578,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
 
             Sorts(ref x) => return tcx.lift(x).map(Sorts),
-            TyParamDefaultMismatch(ref x) => {
-                return tcx.lift(x).map(TyParamDefaultMismatch)
-            }
-            ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
             OldStyleLUB(ref x) => return tcx.lift(x).map(OldStyleLUB),
+            ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
         })
     }
 }
@@ -1199,20 +1188,6 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFoun
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for type_variable::Default<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        type_variable::Default {
-            ty: self.ty.fold_with(folder),
-            origin_span: self.origin_span,
-            def_id: self.def_id
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.ty.visit_with(visitor)
-    }
-}
-
 impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         self.iter().map(|x| x.fold_with(folder)).collect()
@@ -1252,7 +1227,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
             ProjectionMismatched(x) => ProjectionMismatched(x),
             ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
             Sorts(x) => Sorts(x.fold_with(folder)),
-            TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)),
             ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)),
             OldStyleLUB(ref x) => OldStyleLUB(x.fold_with(folder)),
         }
@@ -1273,7 +1247,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
             },
             Sorts(x) => x.visit_with(visitor),
             OldStyleLUB(ref x) => x.visit_with(visitor),
-            TyParamDefaultMismatch(ref x) => x.visit_with(visitor),
             ExistentialMismatch(x) => x.visit_with(visitor),
             CyclicTy(t) => t.visit_with(visitor),
             Mismatch |

From c7953bb6d67dead45033434161be2ed8cdd6cd31 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sun, 16 Jul 2017 07:07:51 -0400
Subject: [PATCH 08/22] obtain `UnificationTable` and `snapshot_vec` from `ena`
 instead

The ena version has an improved interface. I suspect
`librustc_data_structures` should start migrating out to crates.io in
general.
---
 src/librustc/infer/combine.rs           |  8 +--
 src/librustc/infer/freshen.rs           |  4 +-
 src/librustc/infer/mod.rs               | 65 +++++++++++++------------
 src/librustc/infer/type_variable.rs     | 15 ++++--
 src/librustc/infer/unify_key.rs         | 44 ++++++++---------
 src/librustc/ty/mod.rs                  |  5 +-
 src/librustc/util/ppaux.rs              |  6 +++
 src/librustc_data_structures/Cargo.toml |  1 +
 src/librustc_data_structures/lib.rs     |  5 +-
 9 files changed, 88 insertions(+), 65 deletions(-)

diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index bd175c510fba3..8997e7d99dac1 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -132,7 +132,7 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
     {
         self.int_unification_table
             .borrow_mut()
-            .unify_var_value(vid, val)
+            .unify_var_value(vid, Some(val))
             .map_err(|e| int_unification_error(vid_is_expected, e))?;
         match val {
             IntType(v) => Ok(self.tcx.mk_mach_int(v)),
@@ -148,7 +148,7 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
     {
         self.float_unification_table
             .borrow_mut()
-            .unify_var_value(vid, val)
+            .unify_var_value(vid, Some(ty::FloatVarValue(val)))
             .map_err(|e| float_unification_error(vid_is_expected, e))?;
         Ok(self.tcx.mk_mach_float(val))
     }
@@ -518,9 +518,9 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int
 }
 
 fn float_unification_error<'tcx>(a_is_expected: bool,
-                                 v: (ast::FloatTy, ast::FloatTy))
+                                 v: (ty::FloatVarValue, ty::FloatVarValue))
                                  -> TypeError<'tcx>
 {
-    let (a, b) = v;
+    let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
     TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
 }
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index 8b61fcff2335e..25300eed548ba 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -143,7 +143,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
             ty::TyInfer(ty::IntVar(v)) => {
                 self.freshen(
                     self.infcx.int_unification_table.borrow_mut()
-                                                    .probe(v)
+                                                    .probe_value(v)
                                                     .map(|v| v.to_type(tcx)),
                     ty::IntVar(v),
                     ty::FreshIntTy)
@@ -152,7 +152,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
             ty::TyInfer(ty::FloatVar(v)) => {
                 self.freshen(
                     self.infcx.float_unification_table.borrow_mut()
-                                                      .probe(v)
+                                                      .probe_value(v)
                                                       .map(|v| v.to_type(tcx)),
                     ty::FloatVar(v),
                     ty::FreshFloatTy)
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 4292845792560..72a4dfbb7e0ec 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -29,7 +29,7 @@ use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use ty::relate::RelateResult;
 use traits::{self, ObligationCause, PredicateObligations, Reveal};
-use rustc_data_structures::unify::{self, UnificationTable};
+use rustc_data_structures::unify as ut;
 use std::cell::{Cell, RefCell, Ref, RefMut};
 use std::collections::BTreeMap;
 use std::fmt;
@@ -99,10 +99,10 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub type_variables: RefCell<type_variable::TypeVariableTable<'tcx>>,
 
     // Map from integral variable to the kind of integer it represents
-    int_unification_table: RefCell<UnificationTable<ty::IntVid>>,
+    int_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::IntVid>>>,
 
     // Map from floating variable to the kind of float it represents
-    float_unification_table: RefCell<UnificationTable<ty::FloatVid>>,
+    float_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::FloatVid>>>,
 
     // Tracks the set of region variables and the constraints between
     // them.  This is initially `Some(_)` but when
@@ -441,8 +441,8 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
             in_progress_tables,
             projection_cache: RefCell::new(traits::ProjectionCache::new()),
             type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
-            int_unification_table: RefCell::new(UnificationTable::new()),
-            float_unification_table: RefCell::new(UnificationTable::new()),
+            int_unification_table: RefCell::new(ut::UnificationTable::new()),
+            float_unification_table: RefCell::new(ut::UnificationTable::new()),
             region_constraints: RefCell::new(Some(RegionConstraintCollector::new())),
             lexical_region_resolutions: RefCell::new(None),
             selection_cache: traits::SelectionCache::new(),
@@ -476,8 +476,8 @@ impl<'tcx, T> InferOk<'tcx, T> {
 pub struct CombinedSnapshot<'a, 'tcx:'a> {
     projection_cache_snapshot: traits::ProjectionCacheSnapshot,
     type_snapshot: type_variable::Snapshot,
-    int_snapshot: unify::Snapshot<ty::IntVid>,
-    float_snapshot: unify::Snapshot<ty::FloatVid>,
+    int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
+    float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>,
     region_constraints_snapshot: RegionSnapshot,
     region_obligations_snapshot: usize,
     was_in_snapshot: bool,
@@ -678,14 +678,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         use ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
         match ty.sty {
             ty::TyInfer(ty::IntVar(vid)) => {
-                if self.int_unification_table.borrow_mut().has_value(vid) {
+                if self.int_unification_table.borrow_mut().probe_value(vid).is_some() {
                     Neither
                 } else {
                     UnconstrainedInt
                 }
             },
             ty::TyInfer(ty::FloatVar(vid)) => {
-                if self.float_unification_table.borrow_mut().has_value(vid) {
+                if self.float_unification_table.borrow_mut().probe_value(vid).is_some() {
                     Neither
                 } else {
                     UnconstrainedFloat
@@ -698,27 +698,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
         let mut variables = Vec::new();
 
-        let unbound_ty_vars = self.type_variables
-                                  .borrow_mut()
-                                  .unsolved_variables()
-                                  .into_iter()
-                                  .map(|t| self.tcx.mk_var(t));
-
-        let unbound_int_vars = self.int_unification_table
-                                   .borrow_mut()
-                                   .unsolved_variables()
-                                   .into_iter()
-                                   .map(|v| self.tcx.mk_int_var(v));
+        {
+            let mut type_variables = self.type_variables.borrow_mut();
+            variables.extend(
+                type_variables
+                    .unsolved_variables()
+                    .into_iter()
+                    .map(|t| self.tcx.mk_var(t)));
+        }
 
-        let unbound_float_vars = self.float_unification_table
-                                     .borrow_mut()
-                                     .unsolved_variables()
-                                     .into_iter()
-                                     .map(|v| self.tcx.mk_float_var(v));
+        {
+            let mut int_unification_table = self.int_unification_table.borrow_mut();
+            variables.extend(
+                (0..int_unification_table.len())
+                    .map(|i| ty::IntVid { index: i as u32 })
+                    .filter(|&vid| int_unification_table.probe_value(vid).is_none())
+                    .map(|v| self.tcx.mk_int_var(v)));
+        }
 
-        variables.extend(unbound_ty_vars);
-        variables.extend(unbound_int_vars);
-        variables.extend(unbound_float_vars);
+        {
+            let mut float_unification_table = self.float_unification_table.borrow_mut();
+            variables.extend(
+                (0..float_unification_table.len())
+                    .map(|i| ty::FloatVid { index: i as u32 })
+                    .filter(|&vid| float_unification_table.probe_value(vid).is_none())
+                    .map(|v| self.tcx.mk_float_var(v)));
+        }
 
         return variables;
     }
@@ -1262,7 +1267,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             ty::TyInfer(ty::IntVar(v)) => {
                 self.int_unification_table
                     .borrow_mut()
-                    .probe(v)
+                    .probe_value(v)
                     .map(|v| v.to_type(self.tcx))
                     .unwrap_or(typ)
             }
@@ -1270,7 +1275,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             ty::TyInfer(ty::FloatVar(v)) => {
                 self.float_unification_table
                     .borrow_mut()
-                    .probe(v)
+                    .probe_value(v)
                     .map(|v| v.to_type(self.tcx))
                     .unwrap_or(typ)
             }
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index e07cc92ec2158..423b18823b148 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -26,7 +26,7 @@ pub struct TypeVariableTable<'tcx> {
 
     /// Two variables are unified in `eq_relations` when we have a
     /// constraint `?X == ?Y`.
-    eq_relations: ut::UnificationTable<ty::TyVid>,
+    eq_relations: ut::UnificationTable<ut::InPlace<ty::TyVid>>,
 
     /// Two variables are unified in `eq_relations` when we have a
     /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second
@@ -45,7 +45,7 @@ pub struct TypeVariableTable<'tcx> {
     /// This is reasonable because, in Rust, subtypes have the same
     /// "skeleton" and hence there is no possible type such that
     /// (e.g.)  `Box<?3> <: ?3` for any `?3`.
-    sub_relations: ut::UnificationTable<ty::TyVid>,
+    sub_relations: ut::UnificationTable<ut::InPlace<ty::TyVid>>,
 }
 
 /// Reasons to create a type inference variable
@@ -86,8 +86,8 @@ enum TypeVariableValue<'tcx> {
 
 pub struct Snapshot {
     snapshot: sv::Snapshot,
-    eq_snapshot: ut::Snapshot<ty::TyVid>,
-    sub_snapshot: ut::Snapshot<ty::TyVid>,
+    eq_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>,
+    sub_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>,
 }
 
 struct Instantiate {
@@ -354,3 +354,10 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
         values[vid.index as usize].value = Unknown;
     }
 }
+
+impl ut::UnifyKey for ty::TyVid {
+    type Value = ();
+    fn index(&self) -> u32 { self.index }
+    fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } }
+    fn tag() -> &'static str { "TyVid" }
+}
diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs
index 99b11794cc5b5..a1145572b79d9 100644
--- a/src/librustc/infer/unify_key.rs
+++ b/src/librustc/infer/unify_key.rs
@@ -8,9 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use syntax::ast;
-use ty::{self, IntVarValue, Ty, TyCtxt};
-use rustc_data_structures::unify::{Combine, UnifyKey};
+use ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt};
+use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue};
 
 pub trait ToType {
     fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
@@ -20,7 +19,10 @@ impl UnifyKey for ty::IntVid {
     type Value = Option<IntVarValue>;
     fn index(&self) -> u32 { self.index }
     fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } }
-    fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" }
+    fn tag() -> &'static str { "IntVid" }
+}
+
+impl EqUnifyValue for IntVarValue {
 }
 
 #[derive(PartialEq, Copy, Clone, Debug)]
@@ -31,15 +33,17 @@ pub struct RegionVidKey {
     pub min_vid: ty::RegionVid
 }
 
-impl Combine for RegionVidKey {
-    fn combine(&self, other: &RegionVidKey) -> RegionVidKey {
-        let min_vid = if self.min_vid.index() < other.min_vid.index() {
-            self.min_vid
+impl UnifyValue for RegionVidKey {
+    type Error = NoError;
+
+    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
+        let min_vid = if value1.min_vid.index() < value2.min_vid.index() {
+            value1.min_vid
         } else {
-            other.min_vid
+            value2.min_vid
         };
 
-        RegionVidKey { min_vid: min_vid }
+        Ok(RegionVidKey { min_vid: min_vid })
     }
 }
 
@@ -47,7 +51,7 @@ impl UnifyKey for ty::RegionVid {
     type Value = RegionVidKey;
     fn index(&self) -> u32 { self.0 }
     fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid(i) }
-    fn tag(_: Option<ty::RegionVid>) -> &'static str { "RegionVid" }
+    fn tag() -> &'static str { "RegionVid" }
 }
 
 impl ToType for IntVarValue {
@@ -62,21 +66,17 @@ impl ToType for IntVarValue {
 // Floating point type keys
 
 impl UnifyKey for ty::FloatVid {
-    type Value = Option<ast::FloatTy>;
+    type Value = Option<FloatVarValue>;
     fn index(&self) -> u32 { self.index }
     fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } }
-    fn tag(_: Option<ty::FloatVid>) -> &'static str { "FloatVid" }
+    fn tag() -> &'static str { "FloatVid" }
 }
 
-impl ToType for ast::FloatTy {
-    fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
-        tcx.mk_mach_float(*self)
-    }
+impl EqUnifyValue for FloatVarValue {
 }
 
-impl UnifyKey for ty::TyVid {
-    type Value = ();
-    fn index(&self) -> u32 { self.index }
-    fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } }
-    fn tag(_: Option<ty::TyVid>) -> &'static str { "TyVid" }
+impl ToType for FloatVarValue {
+    fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
+        tcx.mk_mach_float(self.0)
+    }
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 856c53d19c98c..4315d1f2c8ca3 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -685,12 +685,15 @@ pub struct ClosureUpvar<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Eq)]
 pub enum IntVarValue {
     IntType(ast::IntTy),
     UintType(ast::UintTy),
 }
 
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct FloatVarValue(pub ast::FloatTy);
+
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 pub struct TypeParameterDef {
     pub name: Name,
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 37d1c568515b5..d390d1c15e2aa 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -916,6 +916,12 @@ impl fmt::Debug for ty::IntVarValue {
     }
 }
 
+impl fmt::Debug for ty::FloatVarValue {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
 // The generic impl doesn't work yet because projections are not
 // normalized under HRTB.
 /*impl<T> fmt::Display for ty::Binder<T>
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index 23e42f6a672c6..40d557ee5e04a 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -9,6 +9,7 @@ path = "lib.rs"
 crate-type = ["dylib"]
 
 [dependencies]
+ena = "0.8.0"
 log = "0.4"
 serialize = { path = "../libserialize" }
 cfg-if = "0.1.2"
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 33d760d0a1482..265c64858300b 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -39,6 +39,7 @@
 #![cfg_attr(test, feature(test))]
 
 extern crate core;
+extern crate ena;
 #[macro_use]
 extern crate log;
 extern crate serialize as rustc_serialize; // used by deriving
@@ -63,10 +64,10 @@ pub mod indexed_vec;
 pub mod obligation_forest;
 pub mod sip128;
 pub mod snapshot_map;
-pub mod snapshot_vec;
+pub use ena::snapshot_vec;
 pub mod stable_hasher;
 pub mod transitive_relation;
-pub mod unify;
+pub use ena::unify;
 pub mod fx;
 pub mod tuple_slice;
 pub mod control_flow_graph;

From 57a593fcbb6af3db567c27b70b3a03c5a244705f Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sun, 16 Jul 2017 08:32:21 -0400
Subject: [PATCH 09/22] store type values in the unification table directly

---
 src/librustc/infer/combine.rs           |   4 +-
 src/librustc/infer/higher_ranked/mod.rs |  17 +-
 src/librustc/infer/mod.rs               |  14 +-
 src/librustc/infer/type_variable.rs     | 223 ++++++++++++++++--------
 src/librustc/traits/select.rs           |  16 +-
 5 files changed, 176 insertions(+), 98 deletions(-)

diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 8997e7d99dac1..959fefbe6b6e4 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -402,7 +402,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                     // `vid` are related via subtyping.
                     return Err(TypeError::CyclicTy(self.root_ty));
                 } else {
-                    match variables.probe_root(vid) {
+                    match variables.probe(vid) {
                         Some(u) => {
                             drop(variables);
                             self.relate(&u, &u)
@@ -423,7 +423,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                                 ty::Covariant | ty::Contravariant => (),
                             }
 
-                            let origin = variables.origin(vid);
+                            let origin = *variables.var_origin(vid);
                             let new_var_id = variables.new_var(false, origin);
                             let u = self.tcx().mk_var(new_var_id);
                             debug!("generalize: replacing original vid={:?} with new={:?}",
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index 57e237fb9137f..a317e0699b4bb 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -244,7 +244,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
         fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                              span: Span,
-                                             snapshot: &CombinedSnapshot,
+                                             snapshot: &CombinedSnapshot<'a, 'tcx>,
                                              debruijn: ty::DebruijnIndex,
                                              new_vars: &[ty::RegionVid],
                                              a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
@@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
         fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                              span: Span,
-                                             snapshot: &CombinedSnapshot,
+                                             snapshot: &CombinedSnapshot<'a, 'tcx>,
                                              debruijn: ty::DebruijnIndex,
                                              new_vars: &[ty::RegionVid],
                                              a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
@@ -479,7 +479,7 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     fn tainted_regions(&self,
-                       snapshot: &CombinedSnapshot,
+                       snapshot: &CombinedSnapshot<'a, 'tcx>,
                        r: ty::Region<'tcx>,
                        directions: TaintDirections)
                        -> FxHashSet<ty::Region<'tcx>> {
@@ -491,7 +491,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn region_vars_confined_to_snapshot(&self,
-                                        snapshot: &CombinedSnapshot)
+                                        snapshot: &CombinedSnapshot<'a, 'tcx>)
                                         -> Vec<ty::RegionVid>
     {
         /*!
@@ -583,7 +583,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// See `README.md` for more details.
     pub fn skolemize_late_bound_regions<T>(&self,
                                            binder: &ty::Binder<T>,
-                                           snapshot: &CombinedSnapshot)
+                                           snapshot: &CombinedSnapshot<'a, 'tcx>)
                                            -> (T, SkolemizationMap<'tcx>)
         where T : TypeFoldable<'tcx>
     {
@@ -609,7 +609,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                       overly_polymorphic: bool,
                       _span: Span,
                       skol_map: &SkolemizationMap<'tcx>,
-                      snapshot: &CombinedSnapshot)
+                      snapshot: &CombinedSnapshot<'a, 'tcx>)
                       -> RelateResult<'tcx, ()>
     {
         debug!("leak_check: skol_map={:?}",
@@ -684,7 +684,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// predicate is `for<'a> &'a int : Clone`.
     pub fn plug_leaks<T>(&self,
                          skol_map: SkolemizationMap<'tcx>,
-                         snapshot: &CombinedSnapshot,
+                         snapshot: &CombinedSnapshot<'a, 'tcx>,
                          value: T) -> T
         where T : TypeFoldable<'tcx>
     {
@@ -770,8 +770,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// Note: popping also occurs implicitly as part of `leak_check`.
     pub fn pop_skolemized(&self,
                           skol_map: SkolemizationMap<'tcx>,
-                          snapshot: &CombinedSnapshot)
-    {
+                          snapshot: &CombinedSnapshot<'a, 'tcx>) {
         debug!("pop_skolemized({:?})", skol_map);
         let skol_regions: FxHashSet<_> = skol_map.values().cloned().collect();
         self.borrow_region_constraints()
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 72a4dfbb7e0ec..fa224b575a312 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -475,7 +475,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
 #[must_use = "once you start a snapshot, you should always consume it"]
 pub struct CombinedSnapshot<'a, 'tcx:'a> {
     projection_cache_snapshot: traits::ProjectionCacheSnapshot,
-    type_snapshot: type_variable::Snapshot,
+    type_snapshot: type_variable::Snapshot<'tcx>,
     int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
     float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>,
     region_constraints_snapshot: RegionSnapshot,
@@ -765,7 +765,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         result
     }
 
-    fn start_snapshot<'b>(&'b self) -> CombinedSnapshot<'b, 'tcx> {
+    fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
         debug!("start_snapshot()");
 
         let in_snapshot = self.in_snapshot.get();
@@ -787,7 +787,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot) {
+    fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
         debug!("rollback_to(cause={})", cause);
         let CombinedSnapshot { projection_cache_snapshot,
                                type_snapshot,
@@ -819,7 +819,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             .rollback_to(region_constraints_snapshot);
     }
 
-    fn commit_from(&self, snapshot: CombinedSnapshot) {
+    fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
         debug!("commit_from()");
         let CombinedSnapshot { projection_cache_snapshot,
                                type_snapshot,
@@ -861,7 +861,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`
     pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
-        F: FnOnce(&CombinedSnapshot) -> Result<T, E>
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>
     {
         debug!("commit_if_ok()");
         let snapshot = self.start_snapshot();
@@ -876,7 +876,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     // Execute `f` in a snapshot, and commit the bindings it creates
     pub fn in_snapshot<T, F>(&self, f: F) -> T where
-        F: FnOnce(&CombinedSnapshot) -> T
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> T
     {
         debug!("in_snapshot()");
         let snapshot = self.start_snapshot();
@@ -887,7 +887,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     /// Execute `f` then unroll any bindings it creates
     pub fn probe<R, F>(&self, f: F) -> R where
-        F: FnOnce(&CombinedSnapshot) -> R,
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
     {
         debug!("probe()");
         let snapshot = self.start_snapshot();
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 423b18823b148..261cd396fced7 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -8,25 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use self::TypeVariableValue::*;
 use syntax::ast;
 use syntax_pos::Span;
 use ty::{self, Ty};
 
 use std::cmp::min;
 use std::marker::PhantomData;
-use std::mem;
 use std::u32;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::snapshot_vec as sv;
 use rustc_data_structures::unify as ut;
 
 pub struct TypeVariableTable<'tcx> {
-    values: sv::SnapshotVec<Delegate<'tcx>>,
+    values: sv::SnapshotVec<Delegate>,
 
     /// Two variables are unified in `eq_relations` when we have a
-    /// constraint `?X == ?Y`.
-    eq_relations: ut::UnificationTable<ut::InPlace<ty::TyVid>>,
+    /// constraint `?X == ?Y`. This table also stores, for each key,
+    /// the known value.
+    eq_relations: ut::UnificationTable<ut::InPlace<TyVidEqKey<'tcx>>>,
 
     /// Two variables are unified in `eq_relations` when we have a
     /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second
@@ -71,22 +70,20 @@ pub enum TypeVariableOrigin {
 
 pub type TypeVariableMap = FxHashMap<ty::TyVid, TypeVariableOrigin>;
 
-struct TypeVariableData<'tcx> {
-    value: TypeVariableValue<'tcx>,
+struct TypeVariableData {
     origin: TypeVariableOrigin,
     diverging: bool
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum TypeVariableValue<'tcx> {
-    Known {
-        value: Ty<'tcx>
-    },
+    Known { value: Ty<'tcx> },
     Unknown,
 }
 
-pub struct Snapshot {
+pub struct Snapshot<'tcx> {
     snapshot: sv::Snapshot,
-    eq_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>,
+    eq_snapshot: ut::Snapshot<ut::InPlace<TyVidEqKey<'tcx>>>,
     sub_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>,
 }
 
@@ -94,7 +91,7 @@ struct Instantiate {
     vid: ty::TyVid,
 }
 
-struct Delegate<'tcx>(PhantomData<&'tcx ()>);
+struct Delegate;
 
 impl<'tcx> TypeVariableTable<'tcx> {
     pub fn new() -> TypeVariableTable<'tcx> {
@@ -105,10 +102,18 @@ impl<'tcx> TypeVariableTable<'tcx> {
         }
     }
 
+    /// Returns the diverges flag given when `vid` was created.
+    ///
+    /// Note that this function does not return care whether
+    /// `vid` has been unified with something else or not.
     pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
         self.values.get(vid.index as usize).diverging
     }
 
+    /// Returns the origin that was given when `vid` was created.
+    ///
+    /// Note that this function does not return care whether
+    /// `vid` has been unified with something else or not.
     pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin {
         &self.values.get(vid.index as usize).origin
     }
@@ -137,41 +142,49 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// Precondition: `vid` must not have been previously instantiated.
     pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
         let vid = self.root_var(vid);
-        debug_assert!(self.probe_root(vid).is_none());
-
-        let old_value = {
-            let vid_data = &mut self.values[vid.index as usize];
-            mem::replace(&mut vid_data.value, TypeVariableValue::Known { value: ty })
-        };
-
-        match old_value {
-            TypeVariableValue::Unknown => {
-                self.values.record(Instantiate { vid: vid });
-            }
-            TypeVariableValue::Known { value: old_ty } => {
-                bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
-                     vid, ty, old_ty)
-            }
-        }
+        debug_assert!(self.probe(vid).is_none());
+        debug_assert!(self.eq_relations.probe_value(vid) == TypeVariableValue::Unknown,
+                      "instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
+                      vid, ty, self.eq_relations.probe_value(vid));
+        self.eq_relations.union_value(vid, TypeVariableValue::Known { value: ty });
+
+        // Hack: we only need this so that `types_escaping_snapshot`
+        // can see what has been unified; see the Delegate impl for
+        // more details.
+        self.values.record(Instantiate { vid: vid });
     }
 
+    /// Creates a new type variable.
+    ///
+    /// - `diverging`: indicates if this is a "diverging" type
+    ///   variable, e.g.  one created as the type of a `return`
+    ///   expression. The code in this module doesn't care if a
+    ///   variable is diverging, but the main Rust type-checker will
+    ///   sometimes "unify" such variables with the `!` or `()` types.
+    /// - `origin`: indicates *why* the type variable was created.
+    ///   The code in this module doesn't care, but it can be useful
+    ///   for improving error messages.
     pub fn new_var(&mut self,
                    diverging: bool,
                    origin: TypeVariableOrigin)
                    -> ty::TyVid {
-        debug!("new_var(diverging={:?}, origin={:?})", diverging, origin);
-        self.eq_relations.new_key(());
-        self.sub_relations.new_key(());
+        let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown);
+
+        let sub_key = self.sub_relations.new_key(());
+        assert_eq!(eq_key.vid, sub_key);
+
         let index = self.values.push(TypeVariableData {
-            value: Unknown,
             origin,
             diverging,
         });
-        let v = ty::TyVid { index: index as u32 };
-        debug!("new_var: diverging={:?} index={:?}", diverging, v);
-        v
+        assert_eq!(eq_key.vid.index, index as u32);
+
+        debug!("new_var(index={:?}, diverging={:?}, origin={:?}", eq_key.vid, diverging, origin);
+
+        eq_key.vid
     }
 
+    /// Returns the number of type variables created thus far.
     pub fn num_vars(&self) -> usize {
         self.values.len()
     }
@@ -182,7 +195,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// algorithm), so `root_var(a) == root_var(b)` implies that `a ==
     /// b` (transitively).
     pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
-        self.eq_relations.find(vid)
+        self.eq_relations.find(vid).vid
     }
 
     /// Returns the "root" variable of `vid` in the `sub_relations`
@@ -202,24 +215,19 @@ impl<'tcx> TypeVariableTable<'tcx> {
         self.sub_root_var(a) == self.sub_root_var(b)
     }
 
+    /// Retrieves the type to which `vid` has been instantiated, if
+    /// any.
     pub fn probe(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
         let vid = self.root_var(vid);
-        self.probe_root(vid)
-    }
-
-    pub fn origin(&self, vid: ty::TyVid) -> TypeVariableOrigin {
-        self.values.get(vid.index as usize).origin.clone()
-    }
-
-    /// Retrieves the type of `vid` given that it is currently a root in the unification table
-    pub fn probe_root(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
-        debug_assert!(self.root_var(vid) == vid);
-        match self.values.get(vid.index as usize).value {
-            Unknown => None,
-            Known { value } => Some(value)
+        match self.eq_relations.probe_value(vid) {
+            TypeVariableValue::Unknown => None,
+            TypeVariableValue::Known { value } => Some(value)
         }
     }
 
+    /// If `t` is a type-inference variable, and it has been
+    /// instantiated, then return the with which it was
+    /// instantiated. Otherwise, returns `t`.
     pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         match t.sty {
             ty::TyInfer(ty::TyVar(v)) => {
@@ -232,7 +240,11 @@ impl<'tcx> TypeVariableTable<'tcx> {
         }
     }
 
-    pub fn snapshot(&mut self) -> Snapshot {
+    /// Creates a snapshot of the type variable state.  This snapshot
+    /// must later be committed (`commit()`) or rolled back
+    /// (`rollback_to()`).  Nested snapshots are permitted, but must
+    /// be processed in a stack-like fashion.
+    pub fn snapshot(&mut self) -> Snapshot<'tcx> {
         Snapshot {
             snapshot: self.values.start_snapshot(),
             eq_snapshot: self.eq_relations.snapshot(),
@@ -240,7 +252,10 @@ impl<'tcx> TypeVariableTable<'tcx> {
         }
     }
 
-    pub fn rollback_to(&mut self, s: Snapshot) {
+    /// Undoes all changes since the snapshot was created. Any
+    /// snapshots created since that point must already have been
+    /// committed or rolled back.
+    pub fn rollback_to(&mut self, s: Snapshot<'tcx>) {
         debug!("rollback_to{:?}", {
             for action in self.values.actions_since_snapshot(&s.snapshot) {
                 match *action {
@@ -258,7 +273,11 @@ impl<'tcx> TypeVariableTable<'tcx> {
         self.sub_relations.rollback_to(sub_snapshot);
     }
 
-    pub fn commit(&mut self, s: Snapshot) {
+    /// Commits all changes since the snapshot was created, making
+    /// them permanent (unless this snapshot was created within
+    /// another snapshot). Any snapshots created since that point
+    /// must already have been committed or rolled back.
+    pub fn commit(&mut self, s: Snapshot<'tcx>) {
         let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
         self.values.commit(snapshot);
         self.eq_relations.commit(eq_snapshot);
@@ -269,7 +288,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// ty-variables created during the snapshot, and the values
     /// `{V2}` are the root variables that they were unified with,
     /// along with their origin.
-    pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap {
+    pub fn types_created_since_snapshot(&mut self, s: &Snapshot<'tcx>) -> TypeVariableMap {
         let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
 
         actions_since_snapshot
@@ -285,16 +304,13 @@ impl<'tcx> TypeVariableTable<'tcx> {
             .collect()
     }
 
-    pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec<Ty<'tcx>> {
-        /*!
-         * Find the set of type variables that existed *before* `s`
-         * but which have only been unified since `s` started, and
-         * return the types with which they were unified. So if we had
-         * a type variable `V0`, then we started the snapshot, then we
-         * created a type variable `V1`, unifed `V0` with `T0`, and
-         * unified `V1` with `T1`, this function would return `{T0}`.
-         */
-
+    /// Find the set of type variables that existed *before* `s`
+    /// but which have only been unified since `s` started, and
+    /// return the types with which they were unified. So if we had
+    /// a type variable `V0`, then we started the snapshot, then we
+    /// created a type variable `V1`, unifed `V0` with `T0`, and
+    /// unified `V1` with `T1`, this function would return `{T0}`.
+    pub fn types_escaping_snapshot(&mut self, s: &Snapshot<'tcx>) -> Vec<Ty<'tcx>> {
         let mut new_elem_threshold = u32::MAX;
         let mut escaping_types = Vec::new();
         let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
@@ -315,9 +331,9 @@ impl<'tcx> TypeVariableTable<'tcx> {
                     if vid.index < new_elem_threshold {
                         // quick check to see if this variable was
                         // created since the snapshot started or not.
-                        let escaping_type = match self.values.get(vid.index as usize).value {
-                            Unknown => bug!(),
-                            Known { value } => value,
+                        let escaping_type = match self.eq_relations.probe_value(vid) {
+                            TypeVariableValue::Unknown => bug!(),
+                            TypeVariableValue::Known { value } => value,
                         };
                         escaping_types.push(escaping_type);
                     }
@@ -331,6 +347,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
         escaping_types
     }
 
+    /// Returns indices of all variables that are not yet
+    /// instantiated.
     pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> {
         (0..self.values.len())
             .filter_map(|i| {
@@ -345,19 +363,80 @@ impl<'tcx> TypeVariableTable<'tcx> {
     }
 }
 
-impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
-    type Value = TypeVariableData<'tcx>;
+impl sv::SnapshotVecDelegate for Delegate {
+    type Value = TypeVariableData;
     type Undo = Instantiate;
 
-    fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate) {
-        let Instantiate { vid } = action;
-        values[vid.index as usize].value = Unknown;
+    fn reverse(_values: &mut Vec<TypeVariableData>, _action: Instantiate) {
+        // We don't actually have to *do* anything to reverse an
+        // instanation; the value for a variable is stored in the
+        // `eq_relations` and hence its rollback code will handle
+        // it. In fact, we could *almost* just remove the
+        // `SnapshotVec` entirely, except that we would have to
+        // reproduce *some* of its logic, since we want to know which
+        // type variables have been instantiated since the snapshot
+        // was started, so we can implement `types_escaping_snapshot`.
+        //
+        // (If we extended the `UnificationTable` to let us see which
+        // values have been unified and so forth, that might also
+        // suffice.)
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/// These structs (a newtyped TyVid) are used as the unification key
+/// for the `eq_relations`; they carry a `TypeVariableValue` along
+/// with them.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+struct TyVidEqKey<'tcx> {
+    vid: ty::TyVid,
+
+    // in the table, we map each ty-vid to one of these:
+    phantom: PhantomData<TypeVariableValue<'tcx>>,
+}
+
+impl<'tcx> From<ty::TyVid> for TyVidEqKey<'tcx> {
+    fn from(vid: ty::TyVid) -> Self {
+        TyVidEqKey { vid, phantom: PhantomData }
+    }
+}
+
+impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> {
+    type Value = TypeVariableValue<'tcx>;
+    fn index(&self) -> u32 { self.vid.index }
+    fn from_index(i: u32) -> Self { TyVidEqKey::from(ty::TyVid { index: i }) }
+    fn tag() -> &'static str { "TyVidEqKey" }
+}
+
+impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
+    type Error = ut::NoError;
+
+    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, ut::NoError> {
+        match (value1, value2) {
+            // We never equate two type variables, both of which
+            // have known types.  Instead, we recursively equate
+            // those types.
+            (&TypeVariableValue::Known { .. }, &TypeVariableValue::Known { .. }) => {
+                bug!("equating two type variables, both of which have known types")
+            }
+
+            // If one side is known, prefer that one.
+            (&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => Ok(*value1),
+            (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => Ok(*value2),
+
+            // If both sides are *unknown*, it hardly matters, does it?
+            (&TypeVariableValue::Unknown, &TypeVariableValue::Unknown) => Ok(*value1),
+        }
     }
 }
 
+/// Raw `TyVid` are used as the unification key for `sub_relations`;
+/// they carry no values.
 impl ut::UnifyKey for ty::TyVid {
     type Value = ();
     fn index(&self) -> u32 { self.index }
     fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } }
     fn tag() -> &'static str { "TyVid" }
 }
+
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index f21ec295c5f7b..e5f05f30fd8a8 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -496,7 +496,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
     /// context's self.
     fn in_snapshot<R, F>(&mut self, f: F) -> R
-        where F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> R
+        where F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R
     {
         // The irrefutable nature of the operation means we don't need to snapshot the
         // inferred_obligations vector.
@@ -506,7 +506,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     /// Wraps a probe s.t. obligations collected during it are ignored and old obligations are
     /// retained.
     fn probe<R, F>(&mut self, f: F) -> R
-        where F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> R
+        where F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R
     {
         let inferred_obligations_snapshot = self.inferred_obligations.start_snapshot();
         let result = self.infcx.probe(|snapshot| f(self, snapshot));
@@ -1478,7 +1478,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &infer::CombinedSnapshot)
+        snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
         -> bool
     {
         let poly_trait_predicate =
@@ -1549,7 +1549,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                         trait_bound: ty::PolyTraitRef<'tcx>,
                         skol_trait_ref: ty::TraitRef<'tcx>,
                         skol_map: &infer::SkolemizationMap<'tcx>,
-                        snapshot: &infer::CombinedSnapshot)
+                        snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
                         -> bool
     {
         assert!(!skol_trait_ref.has_escaping_regions());
@@ -2587,7 +2587,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                    recursion_depth: usize,
                    param_env: ty::ParamEnv<'tcx>,
                    skol_map: infer::SkolemizationMap<'tcx>,
-                   snapshot: &infer::CombinedSnapshot)
+                   snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
                    -> VtableImplData<'tcx, PredicateObligation<'tcx>>
     {
         debug!("vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, skol_map={:?})",
@@ -3076,7 +3076,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn rematch_impl(&mut self,
                     impl_def_id: DefId,
                     obligation: &TraitObligation<'tcx>,
-                    snapshot: &infer::CombinedSnapshot)
+                    snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
                     -> (Normalized<'tcx, &'tcx Substs<'tcx>>,
                         infer::SkolemizationMap<'tcx>)
     {
@@ -3093,7 +3093,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn match_impl(&mut self,
                   impl_def_id: DefId,
                   obligation: &TraitObligation<'tcx>,
-                  snapshot: &infer::CombinedSnapshot)
+                  snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
                   -> Result<(Normalized<'tcx, &'tcx Substs<'tcx>>,
                              infer::SkolemizationMap<'tcx>), ()>
     {
@@ -3288,7 +3288,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                                  def_id: DefId, // of impl or trait
                                  substs: &Substs<'tcx>, // for impl or trait
                                  skol_map: infer::SkolemizationMap<'tcx>,
-                                 snapshot: &infer::CombinedSnapshot)
+                                 snapshot: &infer::CombinedSnapshot<'cx, 'tcx>)
                                  -> Vec<PredicateObligation<'tcx>>
     {
         debug!("impl_or_trait_obligations(def_id={:?})", def_id);

From ccd92c2a4e5ed634bbbd6d3a5bd491c47b80f642 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sun, 16 Jul 2017 08:49:21 -0400
Subject: [PATCH 10/22] correct subtle bug in the type variable code

---
 src/librustc/infer/type_variable.rs | 171 ++++++++++------------------
 1 file changed, 63 insertions(+), 108 deletions(-)

diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 261cd396fced7..9e98c16c819b9 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -12,15 +12,18 @@ use syntax::ast;
 use syntax_pos::Span;
 use ty::{self, Ty};
 
-use std::cmp::min;
 use std::marker::PhantomData;
 use std::u32;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::snapshot_vec as sv;
 use rustc_data_structures::unify as ut;
 
 pub struct TypeVariableTable<'tcx> {
-    values: sv::SnapshotVec<Delegate>,
+    /// Extra data for each type variable, such as the origin. This is
+    /// not stored in the unification table since, when we inquire
+    /// after the origin of a variable X, we want the origin of **that
+    /// variable X**, not the origin of some other variable Y with
+    /// which X has been unified.
+    var_data: Vec<TypeVariableData>,
 
     /// Two variables are unified in `eq_relations` when we have a
     /// constraint `?X == ?Y`. This table also stores, for each key,
@@ -82,21 +85,20 @@ enum TypeVariableValue<'tcx> {
 }
 
 pub struct Snapshot<'tcx> {
-    snapshot: sv::Snapshot,
+    /// number of variables at the time of the snapshot
+    num_vars: usize,
+
+    /// snapshot from the `eq_relations` table
     eq_snapshot: ut::Snapshot<ut::InPlace<TyVidEqKey<'tcx>>>,
-    sub_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>,
-}
 
-struct Instantiate {
-    vid: ty::TyVid,
+    /// snapshot from the `sub_relations` table
+    sub_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>,
 }
 
-struct Delegate;
-
 impl<'tcx> TypeVariableTable<'tcx> {
     pub fn new() -> TypeVariableTable<'tcx> {
         TypeVariableTable {
-            values: sv::SnapshotVec::new(),
+            var_data: Vec::new(),
             eq_relations: ut::UnificationTable::new(),
             sub_relations: ut::UnificationTable::new(),
         }
@@ -107,7 +109,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// Note that this function does not return care whether
     /// `vid` has been unified with something else or not.
     pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
-        self.values.get(vid.index as usize).diverging
+        self.var_data[vid.index as usize].diverging
     }
 
     /// Returns the origin that was given when `vid` was created.
@@ -115,7 +117,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// Note that this function does not return care whether
     /// `vid` has been unified with something else or not.
     pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin {
-        &self.values.get(vid.index as usize).origin
+        &self.var_data[vid.index as usize].origin
     }
 
     /// Records that `a == b`, depending on `dir`.
@@ -147,11 +149,6 @@ impl<'tcx> TypeVariableTable<'tcx> {
                       "instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
                       vid, ty, self.eq_relations.probe_value(vid));
         self.eq_relations.union_value(vid, TypeVariableValue::Known { value: ty });
-
-        // Hack: we only need this so that `types_escaping_snapshot`
-        // can see what has been unified; see the Delegate impl for
-        // more details.
-        self.values.record(Instantiate { vid: vid });
     }
 
     /// Creates a new type variable.
@@ -173,11 +170,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
         let sub_key = self.sub_relations.new_key(());
         assert_eq!(eq_key.vid, sub_key);
 
-        let index = self.values.push(TypeVariableData {
-            origin,
-            diverging,
-        });
-        assert_eq!(eq_key.vid.index, index as u32);
+        assert_eq!(self.var_data.len(), sub_key.index as usize);
+        self.var_data.push(TypeVariableData { origin, diverging });
 
         debug!("new_var(index={:?}, diverging={:?}, origin={:?}", eq_key.vid, diverging, origin);
 
@@ -186,7 +180,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
 
     /// Returns the number of type variables created thus far.
     pub fn num_vars(&self) -> usize {
-        self.values.len()
+        self.var_data.len()
     }
 
     /// Returns the "root" variable of `vid` in the `eq_relations`
@@ -246,7 +240,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// be processed in a stack-like fashion.
     pub fn snapshot(&mut self) -> Snapshot<'tcx> {
         Snapshot {
-            snapshot: self.values.start_snapshot(),
+            num_vars: self.var_data.len(),
             eq_snapshot: self.eq_relations.snapshot(),
             sub_snapshot: self.sub_relations.snapshot(),
         }
@@ -256,21 +250,12 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// snapshots created since that point must already have been
     /// committed or rolled back.
     pub fn rollback_to(&mut self, s: Snapshot<'tcx>) {
-        debug!("rollback_to{:?}", {
-            for action in self.values.actions_since_snapshot(&s.snapshot) {
-                match *action {
-                    sv::UndoLog::NewElem(index) => {
-                        debug!("inference variable _#{}t popped", index)
-                    }
-                    _ => { }
-                }
-            }
-        });
-
-        let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
-        self.values.rollback_to(snapshot);
+        let Snapshot { num_vars, eq_snapshot, sub_snapshot } = s;
+        debug!("type_variables::rollback_to(num_vars = {})", num_vars);
+        assert!(self.var_data.len() >= num_vars);
         self.eq_relations.rollback_to(eq_snapshot);
         self.sub_relations.rollback_to(sub_snapshot);
+        self.var_data.truncate(num_vars);
     }
 
     /// Commits all changes since the snapshot was created, making
@@ -278,8 +263,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// another snapshot). Any snapshots created since that point
     /// must already have been committed or rolled back.
     pub fn commit(&mut self, s: Snapshot<'tcx>) {
-        let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
-        self.values.commit(snapshot);
+        let Snapshot { num_vars, eq_snapshot, sub_snapshot } = s;
+        debug!("type_variables::commit(num_vars = {})", num_vars);
         self.eq_relations.commit(eq_snapshot);
         self.sub_relations.commit(sub_snapshot);
     }
@@ -288,19 +273,12 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// ty-variables created during the snapshot, and the values
     /// `{V2}` are the root variables that they were unified with,
     /// along with their origin.
-    pub fn types_created_since_snapshot(&mut self, s: &Snapshot<'tcx>) -> TypeVariableMap {
-        let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
-
-        actions_since_snapshot
+    pub fn types_created_since_snapshot(&mut self, snapshot: &Snapshot<'tcx>) -> TypeVariableMap {
+        self.var_data
             .iter()
-            .filter_map(|action| match action {
-                &sv::UndoLog::NewElem(index) => Some(ty::TyVid { index: index as u32 }),
-                _ => None,
-            })
-            .map(|vid| {
-                let origin = self.values.get(vid.index as usize).origin.clone();
-                (vid, origin)
-            })
+            .enumerate()
+            .skip(snapshot.num_vars) // skip those that existed when snapshot was taken
+            .map(|(index, data)| (ty::TyVid { index: index as u32 }, data.origin))
             .collect()
     }
 
@@ -310,47 +288,45 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// a type variable `V0`, then we started the snapshot, then we
     /// created a type variable `V1`, unifed `V0` with `T0`, and
     /// unified `V1` with `T1`, this function would return `{T0}`.
-    pub fn types_escaping_snapshot(&mut self, s: &Snapshot<'tcx>) -> Vec<Ty<'tcx>> {
-        let mut new_elem_threshold = u32::MAX;
-        let mut escaping_types = Vec::new();
-        let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
-        debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len());
-        for action in actions_since_snapshot {
-            match *action {
-                sv::UndoLog::NewElem(index) => {
-                    // if any new variables were created during the
-                    // snapshot, remember the lower index (which will
-                    // always be the first one we see). Note that this
-                    // action must precede those variables being
-                    // specified.
-                    new_elem_threshold = min(new_elem_threshold, index as u32);
-                    debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
-                }
-
-                sv::UndoLog::Other(Instantiate { vid, .. }) => {
-                    if vid.index < new_elem_threshold {
-                        // quick check to see if this variable was
-                        // created since the snapshot started or not.
-                        let escaping_type = match self.eq_relations.probe_value(vid) {
-                            TypeVariableValue::Unknown => bug!(),
-                            TypeVariableValue::Known { value } => value,
-                        };
-                        escaping_types.push(escaping_type);
-                    }
-                    debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold);
-                }
-
-                _ => { }
-            }
-        }
-
+    pub fn types_escaping_snapshot(&mut self, snapshot: &Snapshot<'tcx>) -> Vec<Ty<'tcx>> {
+        // We want to select only those instantiations that have
+        // occurred since the snapshot *and* which affect some
+        // variable that existed prior to the snapshot. This code just
+        // affects all instantiatons that ever occurred which affect
+        // variables prior to the snapshot.
+        //
+        // It's hard to do better than this, though, without changing
+        // the unification table to prefer "lower" vids -- the problem
+        // is that we may have a variable X (from before the snapshot)
+        // and Y (from after the snapshot) which get unified, with Y
+        // chosen as the new root. Now we are "instantiating" Y with a
+        // value, but it escapes into X, but we wouldn't readily see
+        // that. (In fact, earlier revisions of this code had this
+        // bug; it was introduced when we added the `eq_relations`
+        // table, but it's hard to create rust code that triggers it.)
+        //
+        // We could tell the table to prefer lower vids, and then we would
+        // see the case above, but we would get less-well-balanced trees.
+        //
+        // Since I hope to kill the leak-check in this branch, and
+        // that's the code which uses this logic anyway, I'm going to
+        // use the less efficient algorithm for now.
+        let mut escaping_types = Vec::with_capacity(snapshot.num_vars);
+        escaping_types.extend(
+            (0..snapshot.num_vars) // for all variables that pre-exist the snapshot...
+                .map(|i| ty::TyVid { index: i as u32 })
+                .filter_map(|vid| match self.eq_relations.probe_value(vid) {
+                    TypeVariableValue::Unknown => None,
+                    TypeVariableValue::Known { value } => Some(value),
+                })); // ...collect what types they've been instantiated with.
+        debug!("types_escaping_snapshot = {:?}", escaping_types);
         escaping_types
     }
 
     /// Returns indices of all variables that are not yet
     /// instantiated.
     pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> {
-        (0..self.values.len())
+        (0..self.var_data.len())
             .filter_map(|i| {
                 let vid = ty::TyVid { index: i as u32 };
                 if self.probe(vid).is_some() {
@@ -362,27 +338,6 @@ impl<'tcx> TypeVariableTable<'tcx> {
             .collect()
     }
 }
-
-impl sv::SnapshotVecDelegate for Delegate {
-    type Value = TypeVariableData;
-    type Undo = Instantiate;
-
-    fn reverse(_values: &mut Vec<TypeVariableData>, _action: Instantiate) {
-        // We don't actually have to *do* anything to reverse an
-        // instanation; the value for a variable is stored in the
-        // `eq_relations` and hence its rollback code will handle
-        // it. In fact, we could *almost* just remove the
-        // `SnapshotVec` entirely, except that we would have to
-        // reproduce *some* of its logic, since we want to know which
-        // type variables have been instantiated since the snapshot
-        // was started, so we can implement `types_escaping_snapshot`.
-        //
-        // (If we extended the `UnificationTable` to let us see which
-        // values have been unified and so forth, that might also
-        // suffice.)
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 
 /// These structs (a newtyped TyVid) are used as the unification key

From 69fe43c97e46ed920ead85a2c9c44630bf20570f Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sun, 16 Jul 2017 10:18:55 -0400
Subject: [PATCH 11/22] have `probe()` return `TypeVariableValue`

---
 src/librustc/infer/combine.rs       | 10 ++---
 src/librustc/infer/freshen.rs       |  2 +-
 src/librustc/infer/fudge.rs         |  4 +-
 src/librustc/infer/mod.rs           |  7 ++--
 src/librustc/infer/type_variable.rs | 58 ++++++++++++++++-------------
 5 files changed, 46 insertions(+), 35 deletions(-)

diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 959fefbe6b6e4..44a848d3cc6e3 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -34,10 +34,10 @@
 
 use super::equate::Equate;
 use super::glb::Glb;
+use super::{InferCtxt, MiscVariable, TypeTrace};
 use super::lub::Lub;
 use super::sub::Sub;
-use super::InferCtxt;
-use super::{MiscVariable, TypeTrace};
+use super::type_variable::TypeVariableValue;
 
 use hir::def_id::DefId;
 use ty::{IntType, UintType};
@@ -194,7 +194,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
         use self::RelationDir::*;
 
         // Get the actual variable that b_vid has been inferred to
-        debug_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_none());
+        debug_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_unknown());
 
         debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid);
 
@@ -403,11 +403,11 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                     return Err(TypeError::CyclicTy(self.root_ty));
                 } else {
                     match variables.probe(vid) {
-                        Some(u) => {
+                        TypeVariableValue::Known { value: u } => {
                             drop(variables);
                             self.relate(&u, &u)
                         }
-                        None => {
+                        TypeVariableValue::Unknown { .. } => {
                             match self.ambient_variance {
                                 // Invariant: no need to make a fresh type variable.
                                 ty::Invariant => return Ok(t),
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index 25300eed548ba..ee0921f4b07ae 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -133,7 +133,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
 
         match t.sty {
             ty::TyInfer(ty::TyVar(v)) => {
-                let opt_ty = self.infcx.type_variables.borrow_mut().probe(v);
+                let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known();
                 self.freshen(
                     opt_ty,
                     ty::TyVar(v),
diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs
index 756a6947ee3f8..961dd70a46852 100644
--- a/src/librustc/infer/fudge.rs
+++ b/src/librustc/infer/fudge.rs
@@ -131,7 +131,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> {
                         // variables to their binding anyhow, we know
                         // that it is unbound, so we can just return
                         // it.
-                        debug_assert!(self.infcx.type_variables.borrow_mut().probe(vid).is_none());
+                        debug_assert!(self.infcx.type_variables.borrow_mut()
+                                      .probe(vid)
+                                      .is_unknown());
                         ty
                     }
 
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index fa224b575a312..9b856f94c5615 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1259,9 +1259,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 // so this recursion should always be of very limited
                 // depth.
                 self.type_variables.borrow_mut()
-                    .probe(v)
-                    .map(|t| self.shallow_resolve(t))
-                    .unwrap_or(typ)
+                                   .probe(v)
+                                   .known()
+                                   .map(|t| self.shallow_resolve(t))
+                                   .unwrap_or(typ)
             }
 
             ty::TyInfer(ty::IntVar(v)) => {
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 9e98c16c819b9..9b9e9fa0015fa 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -78,12 +78,28 @@ struct TypeVariableData {
     diverging: bool
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum TypeVariableValue<'tcx> {
+#[derive(Copy, Clone, Debug)]
+pub enum TypeVariableValue<'tcx> {
     Known { value: Ty<'tcx> },
     Unknown,
 }
 
+impl<'tcx> TypeVariableValue<'tcx> {
+    pub fn known(&self) -> Option<Ty<'tcx>> {
+        match *self {
+            TypeVariableValue::Unknown { .. } => None,
+            TypeVariableValue::Known { value } => Some(value),
+        }
+    }
+
+    pub fn is_unknown(&self) -> bool {
+        match *self {
+            TypeVariableValue::Unknown { .. } => true,
+            TypeVariableValue::Known { .. } => false,
+        }
+    }
+}
+
 pub struct Snapshot<'tcx> {
     /// number of variables at the time of the snapshot
     num_vars: usize,
@@ -124,8 +140,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
     ///
     /// Precondition: neither `a` nor `b` are known.
     pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
-        debug_assert!(self.probe(a).is_none());
-        debug_assert!(self.probe(b).is_none());
+        debug_assert!(self.probe(a).is_unknown());
+        debug_assert!(self.probe(b).is_unknown());
         self.eq_relations.union(a, b);
         self.sub_relations.union(a, b);
     }
@@ -134,8 +150,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
     ///
     /// Precondition: neither `a` nor `b` are known.
     pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) {
-        debug_assert!(self.probe(a).is_none());
-        debug_assert!(self.probe(b).is_none());
+        debug_assert!(self.probe(a).is_unknown());
+        debug_assert!(self.probe(b).is_unknown());
         self.sub_relations.union(a, b);
     }
 
@@ -144,8 +160,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
     /// Precondition: `vid` must not have been previously instantiated.
     pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
         let vid = self.root_var(vid);
-        debug_assert!(self.probe(vid).is_none());
-        debug_assert!(self.eq_relations.probe_value(vid) == TypeVariableValue::Unknown,
+        debug_assert!(self.probe(vid).is_unknown());
+        debug_assert!(self.eq_relations.probe_value(vid).is_unknown(),
                       "instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
                       vid, ty, self.eq_relations.probe_value(vid));
         self.eq_relations.union_value(vid, TypeVariableValue::Known { value: ty });
@@ -211,12 +227,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
 
     /// Retrieves the type to which `vid` has been instantiated, if
     /// any.
-    pub fn probe(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
-        let vid = self.root_var(vid);
-        match self.eq_relations.probe_value(vid) {
-            TypeVariableValue::Unknown => None,
-            TypeVariableValue::Known { value } => Some(value)
-        }
+    pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
+        self.eq_relations.probe_value(vid)
     }
 
     /// If `t` is a type-inference variable, and it has been
@@ -226,8 +238,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
         match t.sty {
             ty::TyInfer(ty::TyVar(v)) => {
                 match self.probe(v) {
-                    None => t,
-                    Some(u) => u
+                    TypeVariableValue::Unknown { .. } => t,
+                    TypeVariableValue::Known { value } => value,
                 }
             }
             _ => t,
@@ -313,12 +325,9 @@ impl<'tcx> TypeVariableTable<'tcx> {
         // use the less efficient algorithm for now.
         let mut escaping_types = Vec::with_capacity(snapshot.num_vars);
         escaping_types.extend(
-            (0..snapshot.num_vars) // for all variables that pre-exist the snapshot...
+            (0..snapshot.num_vars) // for all variables that pre-exist the snapshot, collect..
                 .map(|i| ty::TyVid { index: i as u32 })
-                .filter_map(|vid| match self.eq_relations.probe_value(vid) {
-                    TypeVariableValue::Unknown => None,
-                    TypeVariableValue::Known { value } => Some(value),
-                })); // ...collect what types they've been instantiated with.
+                .filter_map(|vid| self.probe(vid).known())); // ..types they are instantiated with.
         debug!("types_escaping_snapshot = {:?}", escaping_types);
         escaping_types
     }
@@ -329,10 +338,9 @@ impl<'tcx> TypeVariableTable<'tcx> {
         (0..self.var_data.len())
             .filter_map(|i| {
                 let vid = ty::TyVid { index: i as u32 };
-                if self.probe(vid).is_some() {
-                    None
-                } else {
-                    Some(vid)
+                match self.probe(vid) {
+                    TypeVariableValue::Unknown { .. } => Some(vid),
+                    TypeVariableValue::Known { .. } => None,
                 }
             })
             .collect()

From 44d992984acd4f736743b103467e19e907d8d4c5 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sun, 16 Jul 2017 13:32:34 -0400
Subject: [PATCH 12/22] remove unnecessary clause propagating divergence

This should not be needed: the new variable will be related to the old
ones, so if they are constrained, so is the new variable; if they are
not, and hence default to diverging, so will the new variable.
---
 src/librustc/infer/lattice.rs | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs
index d5c1163cfc1b1..28aba51ab3724 100644
--- a/src/librustc/infer/lattice.rs
+++ b/src/librustc/infer/lattice.rs
@@ -70,14 +70,6 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
     let a = infcx.type_variables.borrow_mut().replace_if_possible(a);
     let b = infcx.type_variables.borrow_mut().replace_if_possible(b);
     match (&a.sty, &b.sty) {
-        (&ty::TyInfer(TyVar(..)), &ty::TyInfer(TyVar(..)))
-            if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => {
-            let v = infcx.next_diverging_ty_var(
-                TypeVariableOrigin::LatticeVariable(this.cause().span));
-            this.relate_bound(v, a, b)?;
-            Ok(v)
-        }
-
         // If one side is known to be a variable and one is not,
         // create a variable (`v`) to represent the LUB. Make sure to
         // relate `v` to the non-type-variable first (by passing it

From 13efaf0481275dba18f1d18f4b59b664b2d2031a Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Mon, 17 Jul 2017 16:16:14 -0400
Subject: [PATCH 13/22] add universes to type inference variables

---
 src/librustc/infer/anon_types/mod.rs        |  3 +-
 src/librustc/infer/combine.rs               |  4 +--
 src/librustc/infer/fudge.rs                 |  6 +++-
 src/librustc/infer/lattice.rs               | 12 ++++---
 src/librustc/infer/mod.rs                   | 23 ++++++++-----
 src/librustc/infer/type_variable.rs         | 30 ++++++++++++++---
 src/librustc/traits/coherence.rs            |  4 ++-
 src/librustc/traits/error_reporting.rs      | 17 +++++++---
 src/librustc/traits/project.rs              |  2 ++
 src/librustc/traits/select.rs               |  3 +-
 src/librustc/traits/specialize/mod.rs       |  2 +-
 src/librustc_typeck/check/_match.rs         | 11 ++++--
 src/librustc_typeck/check/closure.rs        |  3 +-
 src/librustc_typeck/check/coercion.rs       |  3 +-
 src/librustc_typeck/check/dropck.rs         |  2 +-
 src/librustc_typeck/check/method/confirm.rs |  4 +--
 src/librustc_typeck/check/method/mod.rs     |  2 +-
 src/librustc_typeck/check/method/probe.rs   |  7 ++--
 src/librustc_typeck/check/method/suggest.rs |  3 +-
 src/librustc_typeck/check/mod.rs            | 37 +++++++++++++--------
 src/librustc_typeck/check/op.rs             |  9 +++--
 21 files changed, 132 insertions(+), 55 deletions(-)

diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs
index a749d0dddd7ee..eb26f0c1188bf 100644
--- a/src/librustc/infer/anon_types/mod.rs
+++ b/src/librustc/infer/anon_types/mod.rs
@@ -600,7 +600,8 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
             return anon_defn.concrete_ty;
         }
         let span = tcx.def_span(def_id);
-        let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
+        let ty_var = infcx.next_ty_var(ty::UniverseIndex::ROOT,
+                                       TypeVariableOrigin::TypeInference(span));
 
         let predicates_of = tcx.predicates_of(def_id);
         let bounds = predicates_of.instantiate(tcx, substs);
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 44a848d3cc6e3..469cb4591124e 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -407,7 +407,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                             drop(variables);
                             self.relate(&u, &u)
                         }
-                        TypeVariableValue::Unknown { .. } => {
+                        TypeVariableValue::Unknown { universe } => {
                             match self.ambient_variance {
                                 // Invariant: no need to make a fresh type variable.
                                 ty::Invariant => return Ok(t),
@@ -424,7 +424,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                             }
 
                             let origin = *variables.var_origin(vid);
-                            let new_var_id = variables.new_var(false, origin);
+                            let new_var_id = variables.new_var(universe, false, origin);
                             let u = self.tcx().mk_var(new_var_id);
                             debug!("generalize: replacing original vid={:?} with new={:?}",
                                    vid, u);
diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs
index 961dd70a46852..48eb253415cdf 100644
--- a/src/librustc/infer/fudge.rs
+++ b/src/librustc/infer/fudge.rs
@@ -141,7 +141,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> {
                         // This variable was created during the
                         // fudging. Recreate it with a fresh variable
                         // here.
-                        self.infcx.next_ty_var(origin)
+                        //
+                        // The ROOT universe is fine because we only
+                        // ever invoke this routine at the
+                        // "item-level" of inference.
+                        self.infcx.next_ty_var(ty::UniverseIndex::ROOT, origin)
                     }
                 }
             }
diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs
index 28aba51ab3724..c4722f9a7f96c 100644
--- a/src/librustc/infer/lattice.rs
+++ b/src/librustc/infer/lattice.rs
@@ -88,13 +88,17 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
         // is (e.g.) `Box<i32>`. A more obvious solution might be to
         // iterate on the subtype obligations that are returned, but I
         // think this suffices. -nmatsakis
-        (&ty::TyInfer(TyVar(..)), _) => {
-            let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span));
+        (&ty::TyInfer(TyVar(a_vid)), _) => {
+            let universe = infcx.type_variables.borrow_mut().probe(a_vid).universe().unwrap();
+            let v = infcx.next_ty_var(universe,
+                                      TypeVariableOrigin::LatticeVariable(this.cause().span));
             this.relate_bound(v, b, a)?;
             Ok(v)
         }
-        (_, &ty::TyInfer(TyVar(..))) => {
-            let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span));
+        (_, &ty::TyInfer(TyVar(b_vid))) => {
+            let universe = infcx.type_variables.borrow_mut().probe(b_vid).universe().unwrap();
+            let v = infcx.next_ty_var(universe,
+                                      TypeVariableOrigin::LatticeVariable(this.cause().span));
             this.relate_bound(v, a, b)?;
             Ok(v)
         }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 9b856f94c5615..58026007320d0 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1015,18 +1015,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
-    pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
+    pub fn next_ty_var_id(&self,
+                          universe: ty::UniverseIndex,
+                          diverging: bool,
+                          origin: TypeVariableOrigin)
+                          -> TyVid {
         self.type_variables
             .borrow_mut()
-            .new_var(diverging, origin)
+            .new_var(universe, diverging, origin)
     }
 
-    pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_var(self.next_ty_var_id(false, origin))
+    pub fn next_ty_var(&self, universe: ty::UniverseIndex, origin: TypeVariableOrigin) -> Ty<'tcx> {
+        self.tcx.mk_var(self.next_ty_var_id(universe, false, origin))
     }
 
-    pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_var(self.next_ty_var_id(true, origin))
+    pub fn next_diverging_ty_var(&self, universe: ty::UniverseIndex, origin: TypeVariableOrigin) -> Ty<'tcx> {
+        self.tcx.mk_var(self.next_ty_var_id(universe, true, origin))
     }
 
     pub fn next_int_var_id(&self) -> IntVid {
@@ -1081,12 +1085,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// use an inference variable for `C` with `[T, U]`
     /// as the substitutions for the default, `(T, U)`.
     pub fn type_var_for_def(&self,
+                            universe: ty::UniverseIndex,
                             span: Span,
                             def: &ty::TypeParameterDef)
                             -> Ty<'tcx> {
         let ty_var_id = self.type_variables
                             .borrow_mut()
-                            .new_var(false,
+                            .new_var(universe,
+                                     false,
                                      TypeVariableOrigin::TypeParameterDefinition(span, def.name));
 
         self.tcx.mk_var(ty_var_id)
@@ -1095,13 +1101,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// Given a set of generics defined on a type or impl, returns a substitution mapping each
     /// type/region parameter to a fresh inference variable.
     pub fn fresh_substs_for_item(&self,
+                                 universe: ty::UniverseIndex,
                                  span: Span,
                                  def_id: DefId)
                                  -> &'tcx Substs<'tcx> {
         Substs::for_item(self.tcx, def_id, |def, _| {
             self.region_var_for_def(span, def)
         }, |def, _| {
-            self.type_var_for_def(span, def)
+            self.type_var_for_def(universe, span, def)
         })
     }
 
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 9b9e9fa0015fa..5daac988f80b7 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -12,6 +12,7 @@ use syntax::ast;
 use syntax_pos::Span;
 use ty::{self, Ty};
 
+use std::cmp;
 use std::marker::PhantomData;
 use std::u32;
 use rustc_data_structures::fx::FxHashMap;
@@ -81,10 +82,18 @@ struct TypeVariableData {
 #[derive(Copy, Clone, Debug)]
 pub enum TypeVariableValue<'tcx> {
     Known { value: Ty<'tcx> },
-    Unknown,
+    Unknown { universe: ty::UniverseIndex },
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum ProbeTyValue<'tcx> {
+    Ty(Ty<'tcx>),
+    Vid(ty::TyVid),
 }
 
 impl<'tcx> TypeVariableValue<'tcx> {
+    /// If this value is known, returns the type it is known to be.
+    /// Otherwise, `None`.
     pub fn known(&self) -> Option<Ty<'tcx>> {
         match *self {
             TypeVariableValue::Unknown { .. } => None,
@@ -92,6 +101,14 @@ impl<'tcx> TypeVariableValue<'tcx> {
         }
     }
 
+    /// If this value is unknown, returns the universe, otherwise `None`.
+    pub fn universe(&self) -> Option<ty::UniverseIndex> {
+        match *self {
+            TypeVariableValue::Unknown { universe } => Some(universe),
+            TypeVariableValue::Known { .. } => None,
+        }
+    }
+
     pub fn is_unknown(&self) -> bool {
         match *self {
             TypeVariableValue::Unknown { .. } => true,
@@ -178,10 +195,11 @@ impl<'tcx> TypeVariableTable<'tcx> {
     ///   The code in this module doesn't care, but it can be useful
     ///   for improving error messages.
     pub fn new_var(&mut self,
+                   universe: ty::UniverseIndex,
                    diverging: bool,
                    origin: TypeVariableOrigin)
                    -> ty::TyVid {
-        let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown);
+        let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown { universe });
 
         let sub_key = self.sub_relations.new_key(());
         assert_eq!(eq_key.vid, sub_key);
@@ -388,8 +406,12 @@ impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
             (&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => Ok(*value1),
             (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => Ok(*value2),
 
-            // If both sides are *unknown*, it hardly matters, does it?
-            (&TypeVariableValue::Unknown, &TypeVariableValue::Unknown) => Ok(*value1),
+            // If both sides are unknown, we need to pick the most restrictive universe.
+            (&TypeVariableValue::Unknown { universe: universe1 },
+             &TypeVariableValue::Unknown { universe: universe2 }) => {
+                let universe = cmp::min(universe1, universe2);
+                Ok(TypeVariableValue::Unknown { universe })
+            }
         }
     }
 }
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index a9f1c8750f4be..183b1a5470e5a 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -92,7 +92,9 @@ fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, '
                                        -> ty::ImplHeader<'tcx>
 {
     let tcx = selcx.tcx();
-    let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id);
+    let impl_substs = selcx.infcx().fresh_substs_for_item(param_env.universe,
+                                                          DUMMY_SP,
+                                                          impl_def_id);
 
     let header = ty::ImplHeader {
         impl_def_id,
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 118d4ddd4457b..dba23c22647f8 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -292,7 +292,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         self.tcx.for_each_relevant_impl(
             trait_ref.def_id, trait_self_ty, |def_id| {
-                let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
+                let impl_substs = self.fresh_substs_for_item(param_env.universe,
+                                                             obligation.cause.span,
+                                                             def_id);
                 let impl_trait_ref = tcx
                     .impl_trait_ref(def_id)
                     .unwrap()
@@ -1194,6 +1196,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                            -> bool {
         struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
             infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+            param_env: ty::ParamEnv<'tcx>,
             var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>
         }
 
@@ -1203,9 +1206,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 if let ty::TyParam(ty::ParamTy {name, ..}) = ty.sty {
                     let infcx = self.infcx;
-                    self.var_map.entry(ty).or_insert_with(||
-                        infcx.next_ty_var(
-                            TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, name)))
+                    let param_env = self.param_env;
+                    self.var_map
+                        .entry(ty)
+                        .or_insert_with(|| {
+                            let origin = TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP,
+                                                                                     name);
+                            infcx.next_ty_var(param_env.universe, origin)
+                        })
                 } else {
                     ty.super_fold_with(self)
                 }
@@ -1217,6 +1225,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
             let cleaned_pred = pred.fold_with(&mut ParamToVarFolder {
                 infcx: self,
+                param_env,
                 var_map: FxHashMap()
             });
 
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 1cf92d5a78669..3fe72344e8fea 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -469,6 +469,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             let tcx = selcx.infcx().tcx;
             let def_id = projection_ty.item_def_id;
             let ty_var = selcx.infcx().next_ty_var(
+                param_env.universe,
                 TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
             let projection = ty::Binder(ty::ProjectionPredicate {
                 projection_ty,
@@ -789,6 +790,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc
     let tcx = selcx.infcx().tcx;
     let def_id = projection_ty.item_def_id;
     let new_value = selcx.infcx().next_ty_var(
+        param_env.universe,
         TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
     Normalized {
         value: new_value,
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index e5f05f30fd8a8..9e24a4e6afacf 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -3111,7 +3111,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             snapshot);
         let skol_obligation_trait_ref = skol_obligation.trait_ref;
 
-        let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span,
+        let impl_substs = self.infcx.fresh_substs_for_item(obligation.param_env.universe,
+                                                           obligation.cause.span,
                                                            impl_def_id);
 
         let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 72d9dd9012ca9..5dfeb1bb42928 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -221,7 +221,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                        target_impl: DefId)
                                        -> Result<&'tcx Substs<'tcx>, ()> {
     let selcx = &mut SelectionContext::new(&infcx);
-    let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
+    let target_substs = infcx.fresh_substs_for_item(param_env.universe, DUMMY_SP, target_impl);
     let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx,
                                                                        param_env,
                                                                        target_impl,
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 427641aaf0951..da66a2e52e81f 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -329,6 +329,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(
                     // FIXME: MiscVariable for now, obtaining the span and name information
                     //       from all tuple elements isn't trivial.
+                    ty::UniverseIndex::ROOT,
                     TypeVariableOrigin::TypeInference(pat.span)));
                 let element_tys = tcx.mk_type_list(element_tys_iter);
                 let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys, false));
@@ -339,7 +340,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 pat_ty
             }
             PatKind::Box(ref inner) => {
-                let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span));
+                let inner_ty = self.next_ty_var(ty::UniverseIndex::ROOT,
+                                                TypeVariableOrigin::TypeInference(inner.span));
                 let uniq_ty = tcx.mk_box(inner_ty);
 
                 if self.check_dereferencable(pat.span, expected, &inner) {
@@ -372,6 +374,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                         _ => {
                             let inner_ty = self.next_ty_var(
+                                ty::UniverseIndex::ROOT,
                                 TypeVariableOrigin::TypeInference(inner.span));
                             let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
                             let region = self.next_region_var(infer::PatternRegion(pat.span));
@@ -630,7 +633,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
             // ...but otherwise we want to use any supertype of the
             // discriminant. This is sort of a workaround, see note (*) in
             // `check_pat` for some details.
-            discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span));
+            discrim_ty = self.next_ty_var(ty::UniverseIndex::ROOT,
+                                          TypeVariableOrigin::TypeInference(discrim.span));
             self.check_expr_has_type_or_error(discrim, discrim_ty);
         };
 
@@ -691,7 +695,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
                 // arm for inconsistent arms or to the whole match when a `()` type
                 // is required).
                 Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety,
-                _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)),
+                _ => self.next_ty_var(ty::UniverseIndex::ROOT,
+                                      TypeVariableOrigin::MiscVariable(expr.span)),
             };
             CoerceMany::with_coercion_sites(coerce_first, arms)
         };
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 794d466ee7cdb..5e0c47f18bf5a 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -110,7 +110,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             |_, _| span_bug!(expr.span, "closure has region param"),
             |_, _| {
                 self.infcx
-                    .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span))
+                    .next_ty_var(ty::UniverseIndex::ROOT,
+                                 TypeVariableOrigin::ClosureSynthetic(expr.span))
             },
         );
         let substs = ty::ClosureSubsts { substs };
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 47e4b0272bed4..e2d6817697e8f 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -177,6 +177,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
                 // micro-optimization: no need for this if `b` is
                 // already resolved in some way.
                 let diverging_ty = self.next_diverging_ty_var(
+                    ty::UniverseIndex::ROOT,
                     TypeVariableOrigin::AdjustmentType(self.cause.span));
                 self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
             } else {
@@ -510,7 +511,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
         // We only have the latter, so we use an inference variable
         // for the former and let type inference do the rest.
         let origin = TypeVariableOrigin::MiscVariable(self.cause.span);
-        let coerce_target = self.next_ty_var(origin);
+        let coerce_target = self.next_ty_var(ty::UniverseIndex::ROOT, origin);
         let mut coercion = self.unify_and(coerce_target, target, |target| {
             let unsize = Adjustment {
                 kind: Adjust::Unsize,
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 039669a62e104..165cfe6604e8b 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -90,7 +90,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
 
         let drop_impl_span = tcx.def_span(drop_impl_did);
         let fresh_impl_substs =
-            infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
+            infcx.fresh_substs_for_item(ty::UniverseIndex::ROOT, drop_impl_span, drop_impl_did);
         let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
 
         let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index a3233c8d86599..b777ac30920cd 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -259,7 +259,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                 // the process we will unify the transformed-self-type
                 // of the method with the actual type in order to
                 // unify some of these variables.
-                self.fresh_substs_for_item(self.span, trait_def_id)
+                self.fresh_substs_for_item(ty::UniverseIndex::ROOT, self.span, trait_def_id)
             }
 
             probe::WhereClausePick(ref poly_trait_ref) => {
@@ -336,7 +336,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             {
                 self.to_ty(ast_ty)
             } else {
-                self.type_var_for_def(self.span, def)
+                self.type_var_for_def(ty::UniverseIndex::ROOT, self.span, def)
             }
         })
     }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 4a122fbc4c195..af86570309dfd 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -255,7 +255,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             } else if let Some(ref input_types) = opt_input_types {
                 input_types[def.index as usize - 1]
             } else {
-                self.type_var_for_def(span, def)
+                self.type_var_for_def(ty::UniverseIndex::ROOT, span, def)
             }
         });
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 0a20af23e2e9d..c95ead285594b 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -730,7 +730,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             Def::Method(def_id) => {
                 let fty = self.tcx.fn_sig(def_id);
                 self.probe(|_| {
-                    let substs = self.fresh_substs_for_item(self.span, method.def_id);
+                    let substs = self.fresh_substs_for_item(ty::UniverseIndex::ROOT,
+                                                            self.span,
+                                                            method.def_id);
                     let fty = fty.subst(self.tcx, substs);
                     let (fty, _) = self.replace_late_bound_regions_with_fresh_var(
                         self.span, infer::FnCall, &fty);
@@ -1309,7 +1311,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                 if i < substs.len() {
                     substs.type_at(i)
                 } else {
-                    self.type_var_for_def(self.span, def)
+                    self.type_var_for_def(ty::UniverseIndex::ROOT, self.span, def)
                 }
             });
             xform_fn_sig.subst(self.tcx, substs)
@@ -1326,6 +1328,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                          def_id,
                          |_, _| self.tcx.types.re_erased,
                          |_, _| self.next_ty_var(
+                             ty::UniverseIndex::ROOT,
                              TypeVariableOrigin::SubstitutionPlaceholder(
                                  self.tcx.def_span(def_id))))
     }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 4556b5a42b3d6..5c20490f82303 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -54,7 +54,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.autoderef(span, ty).any(|(ty, _)| {
                     self.probe(|_| {
                         let fn_once_substs = tcx.mk_substs_trait(ty,
-                            &[self.next_ty_var(TypeVariableOrigin::MiscVariable(span))]);
+                            &[self.next_ty_var(ty::UniverseIndex::ROOT,
+                                               TypeVariableOrigin::MiscVariable(span))]);
                         let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
                         let poly_trait_ref = trait_ref.to_poly_trait_ref();
                         let obligation =
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 4fa48d96d36c4..a7001acc495a3 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -362,7 +362,8 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
     /// hard constraint exists, creates a fresh type variable.
     fn coercion_target_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> {
         self.only_has_type(fcx)
-            .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span)))
+            .unwrap_or_else(|| fcx.next_ty_var(ty::UniverseIndex::ROOT,
+                                               TypeVariableOrigin::MiscVariable(span)))
     }
 }
 
@@ -921,7 +922,8 @@ impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> {
         match ty_opt {
             None => {
                 // infer the variable's type
-                let var_ty = self.fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
+                let var_ty = self.fcx.next_ty_var(ty::UniverseIndex::ROOT,
+                                                  TypeVariableOrigin::TypeInference(span));
                 self.fcx.locals.borrow_mut().insert(nid, var_ty);
                 var_ty
             }
@@ -1025,7 +1027,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     let span = body.value.span;
 
     if body.is_generator && can_be_generator.is_some() {
-        let yield_ty = fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
+        let yield_ty = fcx.next_ty_var(fcx.next_ty_var(ty::UniverseIndex::ROOT,
+                                                       TypeVariableOrigin::TypeInference(span)));
         fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
         fcx.yield_ty = Some(yield_ty);
     }
@@ -1058,7 +1061,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     // This ensures that all nested generators appear before the entry of this generator.
     // resolve_generator_interiors relies on this property.
     let gen_ty = if can_be_generator.is_some() && body.is_generator {
-        let witness = fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span));
+        let witness = fcx.next_ty_var(ty::UniverseIndex::ROOT,
+                                      TypeVariableOrigin::MiscVariable(span));
         let interior = ty::GeneratorInterior {
             witness,
             movable: can_be_generator.unwrap() == hir::GeneratorMovability::Movable,
@@ -1096,6 +1100,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     let mut actual_return_ty = coercion.complete(&fcx);
     if actual_return_ty.is_never() {
         actual_return_ty = fcx.next_diverging_ty_var(
+            ty::UniverseIndex::ROOT,
             TypeVariableOrigin::DivergingFn(span));
     }
     fcx.demand_suptype(span, ret_ty, actual_return_ty);
@@ -1687,13 +1692,14 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn ty_infer(&self, span: Span) -> Ty<'tcx> {
-        self.next_ty_var(TypeVariableOrigin::TypeInference(span))
+        self.next_ty_var(ty::UniverseIndex::ROOT,
+                         TypeVariableOrigin::TypeInference(span))
     }
 
     fn ty_infer_for_def(&self,
                         ty_param_def: &ty::TypeParameterDef,
                         span: Span) -> Ty<'tcx> {
-        self.type_var_for_def(span, ty_param_def)
+        self.type_var_for_def(ty::UniverseIndex::ROOT, span, ty_param_def)
     }
 
     fn projected_ty_from_poly_trait_ref(&self,
@@ -2315,7 +2321,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // If some lookup succeeds, write callee into table and extract index/element
             // type from the method signature.
             // If some lookup succeeded, install method in table
-            let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span));
+            let input_ty = self.next_ty_var(ty::UniverseIndex::ROOT,
+                                            TypeVariableOrigin::AutoDeref(base_expr.span));
             let method = self.try_overloaded_place_op(
                 expr.span, self_ty, &[input_ty], needs, PlaceOp::Index);
 
@@ -2754,6 +2761,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             assert!(!self.tables.borrow().adjustments().contains_key(expr.hir_id),
                     "expression with never type wound up being adjusted");
             let adj_ty = self.next_diverging_ty_var(
+                ty::UniverseIndex::ROOT,
                 TypeVariableOrigin::AdjustmentType(expr.span));
             self.apply_adjustments(expr, vec![Adjustment {
                 kind: Adjust::NeverToAny,
@@ -2831,7 +2839,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let ity = self.tcx.type_of(did);
         debug!("impl_self_ty: ity={:?}", ity);
 
-        let substs = self.fresh_substs_for_item(span, did);
+        let substs = self.fresh_substs_for_item(ty::UniverseIndex::ROOT, span, did);
         let substd_ty = self.instantiate_type_scheme(span, &substs, &ity);
 
         TypeAndSubsts { substs: substs, ty: substd_ty }
@@ -3971,7 +3979,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
               let element_ty = if !args.is_empty() {
                   let coerce_to = uty.unwrap_or_else(
-                      || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)));
+                      || self.next_ty_var(ty::UniverseIndex::ROOT,
+                                          TypeVariableOrigin::TypeInference(expr.span)));
                   let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
                   assert_eq!(self.diverges.get(), Diverges::Maybe);
                   for e in args {
@@ -3981,7 +3990,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   }
                   coerce.complete(self)
               } else {
-                  self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))
+                  self.next_ty_var(ty::UniverseIndex::ROOT,
+                                   TypeVariableOrigin::TypeInference(expr.span))
               };
               tcx.mk_array(element_ty, args.len() as u64)
           }
@@ -4011,7 +4021,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     (uty, uty)
                 }
                 None => {
-                    let t: Ty = self.next_ty_var(TypeVariableOrigin::MiscVariable(element.span));
+                    let t: Ty = self.next_ty_var(ty::UniverseIndex::ROOT,
+                                                 TypeVariableOrigin::MiscVariable(element.span));
                     let element_ty = self.check_expr_has_type_or_error(&element, t);
                     (element_ty, t)
                 }
@@ -4792,7 +4803,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // Handle Self first, so we can adjust the index to match the AST.
                 if has_self && i == 0 {
                     return opt_self_ty.unwrap_or_else(|| {
-                        self.type_var_for_def(span, def)
+                        self.type_var_for_def(ty::UniverseIndex::ROOT, span, def)
                     });
                 }
                 i -= has_self as usize;
@@ -4825,7 +4836,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // This can also be reached in some error cases:
                 // We prefer to use inference variables instead of
                 // TyError to let type inference recover somewhat.
-                self.type_var_for_def(span, def)
+                self.type_var_for_def(ty::UniverseIndex::ROOT, span, def)
             }
         });
 
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index a28625be2c739..12791107ebb41 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -174,8 +174,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // trait matching creating lifetime constraints that are too strict.
         // E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
         // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
-        let lhs_ty = self.check_expr_coercable_to_type_with_needs(lhs_expr,
-            self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span)),
+        let lhs_ty = self.check_expr_coercable_to_type_with_needs(
+            lhs_expr,
+            self.next_ty_var(ty::UniverseIndex::ROOT,
+                             TypeVariableOrigin::MiscVariable(lhs_expr.span)),
             lhs_needs);
         let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
 
@@ -185,7 +187,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // using this variable as the expected type, which sometimes lets
         // us do better coercions than we would be able to do otherwise,
         // particularly for things like `String + &String`.
-        let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span));
+        let rhs_ty_var = self.next_ty_var(ty::UniverseIndex::ROOT,
+                         TypeVariableOrigin::MiscVariable(rhs_expr.span));
 
         let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign));
 

From 35e78b5cddc04c6bd13da2a1290d27cfb8ae8db8 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Mon, 31 Jul 2017 07:40:24 +0300
Subject: [PATCH 14/22] change skolemizations to use universe index

---
 src/librustc/ty/mod.rs     | 18 +++++++++++++++---
 src/librustc/ty/sty.rs     |  7 +------
 src/librustc/util/ppaux.rs |  2 +-
 3 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 4315d1f2c8ca3..88422a3ef8235 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -69,7 +69,7 @@ pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
 pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const};
 pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
 pub use self::sty::RegionKind;
-pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
+pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid};
 pub use self::sty::BoundRegion::*;
 pub use self::sty::InferTy::*;
 pub use self::sty::RegionKind::*;
@@ -1345,7 +1345,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
 /// type name in a non-zero universe is a skolemized type -- an
 /// idealized representative of "types in general" that we use for
 /// checking generic functions.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
 pub struct UniverseIndex(u32);
 
 impl UniverseIndex {
@@ -1365,7 +1365,19 @@ impl UniverseIndex {
     /// region `'a`, but that region was not nameable from `U` because
     /// it was not in scope there.
     pub fn subuniverse(self) -> UniverseIndex {
-        UniverseIndex(self.0 + 1)
+        UniverseIndex(self.0.checked_add(1).unwrap())
+    }
+
+    pub fn from(v: u32) -> UniverseIndex {
+        UniverseIndex(v)
+    }
+
+    pub fn as_u32(&self) -> u32 {
+        self.0
+    }
+
+    pub fn as_usize(&self) -> usize {
+        self.0 as usize
     }
 
     /// Gets the "depth" of this universe in the universe tree. This
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index a18e8f578364d..7bcc816b5f03d 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1028,7 +1028,7 @@ pub enum RegionKind {
 
     /// A skolemized region - basically the higher-ranked version of ReFree.
     /// Should not exist after typeck.
-    ReSkolemized(SkolemizedRegionVid, BoundRegion),
+    ReSkolemized(ty::UniverseIndex, BoundRegion),
 
     /// Empty lifetime is for data that is never accessed.
     /// Bottom in the region lattice. We treat ReEmpty somewhat
@@ -1079,11 +1079,6 @@ newtype_index!(RegionVid
         DEBUG_FORMAT = custom,
     });
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)]
-pub struct SkolemizedRegionVid {
-    pub index: u32,
-}
-
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum InferTy {
     TyVar(TyVid),
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index d390d1c15e2aa..40c8e8aa4a29a 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -786,7 +786,7 @@ define_print! {
                 }
 
                 ty::ReSkolemized(id, ref bound_region) => {
-                    write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
+                    write!(f, "ReSkolemized({:?}, {:?})", id, bound_region)
                 }
 
                 ty::ReEmpty => write!(f, "ReEmpty"),

From a985634fc08893d9e1255e287ad4bacc2cefa2ce Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Tue, 31 Oct 2017 11:40:24 -0400
Subject: [PATCH 15/22] fix tidy error

---
 src/librustc/infer/mod.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 58026007320d0..402cb6a8fef43 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1029,7 +1029,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.tcx.mk_var(self.next_ty_var_id(universe, false, origin))
     }
 
-    pub fn next_diverging_ty_var(&self, universe: ty::UniverseIndex, origin: TypeVariableOrigin) -> Ty<'tcx> {
+    pub fn next_diverging_ty_var(&self,
+                                 universe: ty::UniverseIndex,
+                                 origin: TypeVariableOrigin)
+                                 -> Ty<'tcx> {
         self.tcx.mk_var(self.next_ty_var_id(universe, true, origin))
     }
 

From 17df455c2eda9717e2d7ff2f43809b553852d7e6 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Tue, 31 Oct 2017 15:24:55 -0400
Subject: [PATCH 16/22] fix tests in `librustc_driver`

---
 src/librustc_driver/test.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 35d2205cf33f3..665a71a90898d 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -444,7 +444,8 @@ fn sub_free_bound_false_infer() {
     //! does NOT hold for any instantiation of `_#1`.
 
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
+        let t_infer1 = env.infcx.next_ty_var(ty::UniverseIndex::ROOT,
+                                             TypeVariableOrigin::MiscVariable(DUMMY_SP));
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
         env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize),
                           env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));

From 755bdaa19084c3ae116ad8320b99a6932fa7f0b1 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Mon, 29 Jan 2018 13:45:12 -0700
Subject: [PATCH 17/22] change skolemizations to use universe index

These changes were meant to be in
2b18d8fe9dc05415a8e6b7cadf879c7f7ebe020a (rebased from
12a230562ece9b0d29018a436676141054dc53b7), but I messed up the rebase a
bit as the file had been moved.
---
 src/Cargo.lock                               | 10 ++++
 src/librustc/infer/region_constraints/mod.rs | 48 ++++++++++----------
 2 files changed, 34 insertions(+), 24 deletions(-)

diff --git a/src/Cargo.lock b/src/Cargo.lock
index 53744dca0a012..d70631fa519d8 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -598,6 +598,14 @@ name = "either"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "ena"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "endian-type"
 version = "0.1.2"
@@ -1866,6 +1874,7 @@ name = "rustc_data_structures"
 version = "0.0.0"
 dependencies = [
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ena 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2861,6 +2870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e45aa15fe0a8a8f511e6d834626afd55e49b62e5c8802e18328a87e8a8f6065c"
 "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
+"checksum ena 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb80e4764284ff0ec7054cb05c557f5ba01ccf65ff0c265e981c0b303d0ffc"
 "checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index be196192371fd..4a75037aa5035 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -18,7 +18,7 @@ use super::unify_key;
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::unify::{self, UnificationTable};
+use rustc_data_structures::unify as ut;
 use ty::{self, Ty, TyCtxt};
 use ty::{Region, RegionVid};
 use ty::ReStatic;
@@ -48,7 +48,7 @@ pub struct RegionConstraintCollector<'tcx> {
     glbs: CombineMap<'tcx>,
 
     /// Number of skolemized variables currently active.
-    skolemization_count: u32,
+    skolemization_count: ty::UniverseIndex,
 
     /// Global counter used during the GLB algorithm to create unique
     /// names for fresh bound regions
@@ -73,7 +73,7 @@ pub struct RegionConstraintCollector<'tcx> {
     /// is iterating to a fixed point, because otherwise we sometimes
     /// would wind up with a fresh stream of region variables that
     /// have been equated but appear distinct.
-    unification_table: UnificationTable<ty::RegionVid>,
+    unification_table: ut::UnificationTable<ut::InPlace<ty::RegionVid>>,
 }
 
 pub type VarOrigins = IndexVec<RegionVid, RegionVariableOrigin>;
@@ -232,8 +232,8 @@ type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>;
 
 pub struct RegionSnapshot {
     length: usize,
-    region_snapshot: unify::Snapshot<ty::RegionVid>,
-    skolemization_count: u32,
+    region_snapshot: ut::Snapshot<ut::InPlace<ty::RegionVid>>,
+    skolemization_count: ty::UniverseIndex,
 }
 
 /// When working with skolemized regions, we often wish to find all of
@@ -277,10 +277,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
             data: RegionConstraintData::default(),
             lubs: FxHashMap(),
             glbs: FxHashMap(),
-            skolemization_count: 0,
+            skolemization_count: ty::UniverseIndex::ROOT,
             bound_count: 0,
             undo_log: Vec::new(),
-            unification_table: UnificationTable::new(),
+            unification_table: ut::UnificationTable::new(),
         }
     }
 
@@ -329,7 +329,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
             unification_table,
         } = self;
 
-        assert_eq!(*skolemization_count, 0);
+        assert_eq!(skolemization_count.as_usize(), 0);
 
         // Clear the tables of (lubs, glbs), so that we will create
         // fresh regions if we do a LUB operation. As it happens,
@@ -342,7 +342,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
         // un-unified" state. Note that when we unify `a` and `b`, we
         // also insert `a <= b` and a `b <= a` edges, so the
         // `RegionConstraintData` contains the relationship here.
-        *unification_table = UnificationTable::new();
+        *unification_table = ut::UnificationTable::new();
         for vid in var_origins.indices() {
             unification_table.new_key(unify_key::RegionVidKey { min_vid: vid });
         }
@@ -371,7 +371,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
         assert!(self.undo_log[snapshot.length] == OpenSnapshot);
         assert!(
             self.skolemization_count == snapshot.skolemization_count,
-            "failed to pop skolemized regions: {} now vs {} at start",
+            "failed to pop skolemized regions: {:?} now vs {:?} at start",
             self.skolemization_count,
             snapshot.skolemization_count
         );
@@ -479,9 +479,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
         assert!(self.in_snapshot());
         assert!(self.undo_log[snapshot.length] == OpenSnapshot);
 
-        let sc = self.skolemization_count;
-        self.skolemization_count = sc + 1;
-        tcx.mk_region(ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br))
+        let universe = self.skolemization_count.subuniverse();
+        self.skolemization_count = universe;
+        tcx.mk_region(ReSkolemized(universe, br))
     }
 
     /// Removes all the edges to/from the skolemized regions that are
@@ -499,20 +499,20 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
         assert!(self.in_snapshot());
         assert!(self.undo_log[snapshot.length] == OpenSnapshot);
         assert!(
-            self.skolemization_count as usize >= skols.len(),
+            self.skolemization_count.as_usize() >= skols.len(),
             "popping more skolemized variables than actually exist, \
              sc now = {}, skols.len = {}",
-            self.skolemization_count,
+            self.skolemization_count.as_usize(),
             skols.len()
         );
 
-        let last_to_pop = self.skolemization_count;
-        let first_to_pop = last_to_pop - (skols.len() as u32);
+        let last_to_pop = self.skolemization_count.subuniverse();
+        let first_to_pop = ty::UniverseIndex::from(last_to_pop.as_u32() - (skols.len() as u32));
 
         assert!(
             first_to_pop >= snapshot.skolemization_count,
             "popping more regions than snapshot contains, \
-             sc now = {}, sc then = {}, skols.len = {}",
+             sc now = {:?}, sc then = {:?}, skols.len = {}",
             self.skolemization_count,
             snapshot.skolemization_count,
             skols.len()
@@ -520,13 +520,13 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
         debug_assert! {
             skols.iter()
                  .all(|&k| match *k {
-                     ty::ReSkolemized(index, _) =>
-                         index.index >= first_to_pop &&
-                         index.index < last_to_pop,
+                     ty::ReSkolemized(universe, _) =>
+                         universe >= first_to_pop &&
+                         universe < last_to_pop,
                      _ =>
                          false
                  }),
-            "invalid skolemization keys or keys out of range ({}..{}): {:?}",
+            "invalid skolemization keys or keys out of range ({:?}..{:?}): {:?}",
             snapshot.skolemization_count,
             self.skolemization_count,
             skols
@@ -776,7 +776,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
         tcx: TyCtxt<'_, '_, 'tcx>,
         rid: RegionVid,
     ) -> ty::Region<'tcx> {
-        let vid = self.unification_table.find_value(rid).min_vid;
+        let vid = self.unification_table.probe_value(rid).min_vid;
         tcx.mk_region(ty::ReVar(vid))
     }
 
@@ -861,7 +861,7 @@ impl fmt::Debug for RegionSnapshot {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(
             f,
-            "RegionSnapshot(length={},skolemization={})",
+            "RegionSnapshot(length={},skolemization={:?})",
             self.length,
             self.skolemization_count
         )

From c30183873e2be5a23021adce01bacc901ccfff63 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Mon, 29 Jan 2018 13:46:52 -0700
Subject: [PATCH 18/22] Remove dead code

These modules were replaced with re-exports from ena
---
 src/librustc_data_structures/snapshot_vec.rs | 230 ------------
 src/librustc_data_structures/unify/mod.rs    | 363 -------------------
 src/librustc_data_structures/unify/tests.rs  | 205 -----------
 3 files changed, 798 deletions(-)
 delete mode 100644 src/librustc_data_structures/snapshot_vec.rs
 delete mode 100644 src/librustc_data_structures/unify/mod.rs
 delete mode 100644 src/librustc_data_structures/unify/tests.rs

diff --git a/src/librustc_data_structures/snapshot_vec.rs b/src/librustc_data_structures/snapshot_vec.rs
deleted file mode 100644
index 2da91918288ba..0000000000000
--- a/src/librustc_data_structures/snapshot_vec.rs
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A utility class for implementing "snapshottable" things; a snapshottable data structure permits
-//! you to take a snapshot (via `start_snapshot`) and then, after making some changes, elect either
-//! to rollback to the start of the snapshot or commit those changes.
-//!
-//! This vector is intended to be used as part of an abstraction, not serve as a complete
-//! abstraction on its own. As such, while it will roll back most changes on its own, it also
-//! supports a `get_mut` operation that gives you an arbitrary mutable pointer into the vector. To
-//! ensure that any changes you make this with this pointer are rolled back, you must invoke
-//! `record` to record any changes you make and also supplying a delegate capable of reversing
-//! those changes.
-use self::UndoLog::*;
-
-use std::mem;
-use std::ops;
-
-pub enum UndoLog<D: SnapshotVecDelegate> {
-    /// Indicates where a snapshot started.
-    OpenSnapshot,
-
-    /// Indicates a snapshot that has been committed.
-    CommittedSnapshot,
-
-    /// New variable with given index was created.
-    NewElem(usize),
-
-    /// Variable with given index was changed *from* the given value.
-    SetElem(usize, D::Value),
-
-    /// Extensible set of actions
-    Other(D::Undo),
-}
-
-pub struct SnapshotVec<D: SnapshotVecDelegate> {
-    values: Vec<D::Value>,
-    undo_log: Vec<UndoLog<D>>,
-}
-
-// Snapshots are tokens that should be created/consumed linearly.
-pub struct Snapshot {
-    // Length of the undo log at the time the snapshot was taken.
-    length: usize,
-}
-
-pub trait SnapshotVecDelegate {
-    type Value;
-    type Undo;
-
-    fn reverse(values: &mut Vec<Self::Value>, action: Self::Undo);
-}
-
-impl<D: SnapshotVecDelegate> SnapshotVec<D> {
-    pub fn new() -> SnapshotVec<D> {
-        SnapshotVec {
-            values: Vec::new(),
-            undo_log: Vec::new(),
-        }
-    }
-
-    pub fn with_capacity(n: usize) -> SnapshotVec<D> {
-        SnapshotVec {
-            values: Vec::with_capacity(n),
-            undo_log: Vec::new(),
-        }
-    }
-
-    fn in_snapshot(&self) -> bool {
-        !self.undo_log.is_empty()
-    }
-
-    pub fn record(&mut self, action: D::Undo) {
-        if self.in_snapshot() {
-            self.undo_log.push(Other(action));
-        }
-    }
-
-    pub fn len(&self) -> usize {
-        self.values.len()
-    }
-
-    pub fn push(&mut self, elem: D::Value) -> usize {
-        let len = self.values.len();
-        self.values.push(elem);
-
-        if self.in_snapshot() {
-            self.undo_log.push(NewElem(len));
-        }
-
-        len
-    }
-
-    pub fn get(&self, index: usize) -> &D::Value {
-        &self.values[index]
-    }
-
-    /// Returns a mutable pointer into the vec; whatever changes you make here cannot be undone
-    /// automatically, so you should be sure call `record()` with some sort of suitable undo
-    /// action.
-    pub fn get_mut(&mut self, index: usize) -> &mut D::Value {
-        &mut self.values[index]
-    }
-
-    /// Updates the element at the given index. The old value will saved (and perhaps restored) if
-    /// a snapshot is active.
-    pub fn set(&mut self, index: usize, new_elem: D::Value) {
-        let old_elem = mem::replace(&mut self.values[index], new_elem);
-        if self.in_snapshot() {
-            self.undo_log.push(SetElem(index, old_elem));
-        }
-    }
-
-    pub fn start_snapshot(&mut self) -> Snapshot {
-        let length = self.undo_log.len();
-        self.undo_log.push(OpenSnapshot);
-        Snapshot { length: length }
-    }
-
-    pub fn actions_since_snapshot(&self, snapshot: &Snapshot) -> &[UndoLog<D>] {
-        &self.undo_log[snapshot.length..]
-    }
-
-    fn assert_open_snapshot(&self, snapshot: &Snapshot) {
-        // Or else there was a failure to follow a stack discipline:
-        assert!(self.undo_log.len() > snapshot.length);
-
-        // Invariant established by start_snapshot():
-        assert!(match self.undo_log[snapshot.length] {
-            OpenSnapshot => true,
-            _ => false,
-        });
-    }
-
-    pub fn rollback_to(&mut self, snapshot: Snapshot) {
-        debug!("rollback_to({})", snapshot.length);
-
-        self.assert_open_snapshot(&snapshot);
-
-        while self.undo_log.len() > snapshot.length + 1 {
-            match self.undo_log.pop().unwrap() {
-                OpenSnapshot => {
-                    // This indicates a failure to obey the stack discipline.
-                    panic!("Cannot rollback an uncommitted snapshot");
-                }
-
-                CommittedSnapshot => {
-                    // This occurs when there are nested snapshots and
-                    // the inner is committed but outer is rolled back.
-                }
-
-                NewElem(i) => {
-                    self.values.pop();
-                    assert!(self.values.len() == i);
-                }
-
-                SetElem(i, v) => {
-                    self.values[i] = v;
-                }
-
-                Other(u) => {
-                    D::reverse(&mut self.values, u);
-                }
-            }
-        }
-
-        let v = self.undo_log.pop().unwrap();
-        assert!(match v {
-            OpenSnapshot => true,
-            _ => false,
-        });
-        assert!(self.undo_log.len() == snapshot.length);
-    }
-
-    /// Commits all changes since the last snapshot. Of course, they
-    /// can still be undone if there is a snapshot further out.
-    pub fn commit(&mut self, snapshot: Snapshot) {
-        debug!("commit({})", snapshot.length);
-
-        self.assert_open_snapshot(&snapshot);
-
-        if snapshot.length == 0 {
-            // The root snapshot.
-            self.undo_log.truncate(0);
-        } else {
-            self.undo_log[snapshot.length] = CommittedSnapshot;
-        }
-    }
-}
-
-impl<D: SnapshotVecDelegate> ops::Deref for SnapshotVec<D> {
-    type Target = [D::Value];
-    fn deref(&self) -> &[D::Value] {
-        &*self.values
-    }
-}
-
-impl<D: SnapshotVecDelegate> ops::DerefMut for SnapshotVec<D> {
-    fn deref_mut(&mut self) -> &mut [D::Value] {
-        &mut *self.values
-    }
-}
-
-impl<D: SnapshotVecDelegate> ops::Index<usize> for SnapshotVec<D> {
-    type Output = D::Value;
-    fn index(&self, index: usize) -> &D::Value {
-        self.get(index)
-    }
-}
-
-impl<D: SnapshotVecDelegate> ops::IndexMut<usize> for SnapshotVec<D> {
-    fn index_mut(&mut self, index: usize) -> &mut D::Value {
-        self.get_mut(index)
-    }
-}
-
-impl<D: SnapshotVecDelegate> Extend<D::Value> for SnapshotVec<D> {
-    fn extend<T>(&mut self, iterable: T) where T: IntoIterator<Item=D::Value> {
-        for item in iterable {
-            self.push(item);
-        }
-    }
-}
diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs
deleted file mode 100644
index 5411ae0257a4b..0000000000000
--- a/src/librustc_data_structures/unify/mod.rs
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::marker;
-use std::fmt::Debug;
-use std::marker::PhantomData;
-use snapshot_vec as sv;
-
-#[cfg(test)]
-mod tests;
-
-/// This trait is implemented by any type that can serve as a type
-/// variable. We call such variables *unification keys*. For example,
-/// this trait is implemented by `IntVid`, which represents integral
-/// variables.
-///
-/// Each key type has an associated value type `V`. For example, for
-/// `IntVid`, this is `Option<IntVarValue>`, representing some
-/// (possibly not yet known) sort of integer.
-///
-/// Clients are expected to provide implementations of this trait; you
-/// can see some examples in the `test` module.
-pub trait UnifyKey: Copy + Clone + Debug + PartialEq {
-    type Value: Clone + PartialEq + Debug;
-
-    fn index(&self) -> u32;
-
-    fn from_index(u: u32) -> Self;
-
-    fn tag(k: Option<Self>) -> &'static str;
-}
-
-/// This trait is implemented for unify values that can be
-/// combined. This relation should be a monoid.
-pub trait Combine {
-    fn combine(&self, other: &Self) -> Self;
-}
-
-impl Combine for () {
-    fn combine(&self, _other: &()) {}
-}
-
-/// Value of a unification key. We implement Tarjan's union-find
-/// algorithm: when two keys are unified, one of them is converted
-/// into a "redirect" pointing at the other. These redirects form a
-/// DAG: the roots of the DAG (nodes that are not redirected) are each
-/// associated with a value of type `V` and a rank. The rank is used
-/// to keep the DAG relatively balanced, which helps keep the running
-/// time of the algorithm under control. For more information, see
-/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
-#[derive(PartialEq,Clone,Debug)]
-pub struct VarValue<K: UnifyKey> {
-    parent: K, // if equal to self, this is a root
-    value: K::Value, // value assigned (only relevant to root)
-    rank: u32, // max depth (only relevant to root)
-}
-
-/// Table of unification keys and their values.
-pub struct UnificationTable<K: UnifyKey> {
-    /// Indicates the current value of each key.
-    values: sv::SnapshotVec<Delegate<K>>,
-}
-
-/// At any time, users may snapshot a unification table.  The changes
-/// made during the snapshot may either be *committed* or *rolled back*.
-pub struct Snapshot<K: UnifyKey> {
-    // Link snapshot to the key type `K` of the table.
-    marker: marker::PhantomData<K>,
-    snapshot: sv::Snapshot,
-}
-
-#[derive(Copy, Clone)]
-struct Delegate<K>(PhantomData<K>);
-
-impl<K: UnifyKey> VarValue<K> {
-    fn new_var(key: K, value: K::Value) -> VarValue<K> {
-        VarValue::new(key, value, 0)
-    }
-
-    fn new(parent: K, value: K::Value, rank: u32) -> VarValue<K> {
-        VarValue {
-            parent: parent, // this is a root
-            value,
-            rank,
-        }
-    }
-
-    fn redirect(self, to: K) -> VarValue<K> {
-        VarValue { parent: to, ..self }
-    }
-
-    fn root(self, rank: u32, value: K::Value) -> VarValue<K> {
-        VarValue {
-            rank,
-            value,
-            ..self
-        }
-    }
-
-    /// Returns the key of this node. Only valid if this is a root
-    /// node, which you yourself must ensure.
-    fn key(&self) -> K {
-        self.parent
-    }
-
-    fn parent(&self, self_key: K) -> Option<K> {
-        self.if_not_self(self.parent, self_key)
-    }
-
-    fn if_not_self(&self, key: K, self_key: K) -> Option<K> {
-        if key == self_key { None } else { Some(key) }
-    }
-}
-
-/// We can't use V:LatticeValue, much as I would like to,
-/// because frequently the pattern is that V=Option<U> for some
-/// other type parameter U, and we have no way to say
-/// Option<U>:LatticeValue.
-
-impl<K: UnifyKey> UnificationTable<K> {
-    pub fn new() -> UnificationTable<K> {
-        UnificationTable { values: sv::SnapshotVec::new() }
-    }
-
-    /// Starts a new snapshot. Each snapshot must be either
-    /// rolled back or committed in a "LIFO" (stack) order.
-    pub fn snapshot(&mut self) -> Snapshot<K> {
-        Snapshot {
-            marker: marker::PhantomData::<K>,
-            snapshot: self.values.start_snapshot(),
-        }
-    }
-
-    /// Reverses all changes since the last snapshot. Also
-    /// removes any keys that have been created since then.
-    pub fn rollback_to(&mut self, snapshot: Snapshot<K>) {
-        debug!("{}: rollback_to()", UnifyKey::tag(None::<K>));
-        self.values.rollback_to(snapshot.snapshot);
-    }
-
-    /// Commits all changes since the last snapshot. Of course, they
-    /// can still be undone if there is a snapshot further out.
-    pub fn commit(&mut self, snapshot: Snapshot<K>) {
-        debug!("{}: commit()", UnifyKey::tag(None::<K>));
-        self.values.commit(snapshot.snapshot);
-    }
-
-    pub fn new_key(&mut self, value: K::Value) -> K {
-        let len = self.values.len();
-        let key: K = UnifyKey::from_index(len as u32);
-        self.values.push(VarValue::new_var(key, value));
-        debug!("{}: created new key: {:?}", UnifyKey::tag(None::<K>), key);
-        key
-    }
-
-    /// Find the root node for `vid`. This uses the standard
-    /// union-find algorithm with path compression:
-    /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
-    ///
-    /// NB. This is a building-block operation and you would probably
-    /// prefer to call `probe` below.
-    fn get(&mut self, vid: K) -> VarValue<K> {
-        let index = vid.index() as usize;
-        let mut value: VarValue<K> = self.values.get(index).clone();
-        match value.parent(vid) {
-            Some(redirect) => {
-                let root: VarValue<K> = self.get(redirect);
-                if root.key() != redirect {
-                    // Path compression
-                    value.parent = root.key();
-                    self.values.set(index, value);
-                }
-                root
-            }
-            None => value,
-        }
-    }
-
-    fn is_root(&self, key: K) -> bool {
-        let index = key.index() as usize;
-        self.values.get(index).parent(key).is_none()
-    }
-
-    /// Sets the value for `vid` to `new_value`. `vid` MUST be a root
-    /// node! This is an internal operation used to impl other things.
-    fn set(&mut self, key: K, new_value: VarValue<K>) {
-        assert!(self.is_root(key));
-
-        debug!("Updating variable {:?} to {:?}", key, new_value);
-
-        let index = key.index() as usize;
-        self.values.set(index, new_value);
-    }
-
-    /// Either redirects `node_a` to `node_b` or vice versa, depending
-    /// on the relative rank. The value associated with the new root
-    /// will be `new_value`.
-    ///
-    /// NB: This is the "union" operation of "union-find". It is
-    /// really more of a building block. If the values associated with
-    /// your key are non-trivial, you would probably prefer to call
-    /// `unify_var_var` below.
-    fn unify(&mut self, root_a: VarValue<K>, root_b: VarValue<K>, new_value: K::Value) -> K {
-        debug!("unify(root_a(id={:?}, rank={:?}), root_b(id={:?}, rank={:?}))",
-               root_a.key(),
-               root_a.rank,
-               root_b.key(),
-               root_b.rank);
-
-        if root_a.rank > root_b.rank {
-            // a has greater rank, so a should become b's parent,
-            // i.e., b should redirect to a.
-            self.redirect_root(root_a.rank, root_b, root_a, new_value)
-        } else if root_a.rank < root_b.rank {
-            // b has greater rank, so a should redirect to b.
-            self.redirect_root(root_b.rank, root_a, root_b, new_value)
-        } else {
-            // If equal, redirect one to the other and increment the
-            // other's rank.
-            self.redirect_root(root_a.rank + 1, root_a, root_b, new_value)
-        }
-    }
-
-    fn redirect_root(&mut self,
-                     new_rank: u32,
-                     old_root: VarValue<K>,
-                     new_root: VarValue<K>,
-                     new_value: K::Value)
-                     -> K {
-        let old_root_key = old_root.key();
-        let new_root_key = new_root.key();
-        self.set(old_root_key, old_root.redirect(new_root_key));
-        self.set(new_root_key, new_root.root(new_rank, new_value));
-        new_root_key
-    }
-}
-
-impl<K: UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
-    type Value = VarValue<K>;
-    type Undo = ();
-
-    fn reverse(_: &mut Vec<VarValue<K>>, _: ()) {}
-}
-
-/// # Base union-find algorithm, where we are just making sets
-
-impl<'tcx, K: UnifyKey> UnificationTable<K>
-    where K::Value: Combine
-{
-    pub fn union(&mut self, a_id: K, b_id: K) -> K {
-        let node_a = self.get(a_id);
-        let node_b = self.get(b_id);
-        let a_id = node_a.key();
-        let b_id = node_b.key();
-        if a_id != b_id {
-            let new_value = node_a.value.combine(&node_b.value);
-            self.unify(node_a, node_b, new_value)
-        } else {
-            a_id
-        }
-    }
-
-    pub fn find(&mut self, id: K) -> K {
-        self.get(id).key()
-    }
-
-    pub fn find_value(&mut self, id: K) -> K::Value {
-        self.get(id).value
-    }
-
-    #[cfg(test)]
-    fn unioned(&mut self, a_id: K, b_id: K) -> bool {
-        self.find(a_id) == self.find(b_id)
-    }
-}
-
-/// # Non-subtyping unification
-///
-/// Code to handle keys which carry a value, like ints,
-/// floats---anything that doesn't have a subtyping relationship we
-/// need to worry about.
-
-impl<'tcx, K, V> UnificationTable<K>
-    where K: UnifyKey<Value = Option<V>>,
-          V: Clone + PartialEq + Debug
-{
-    pub fn unify_var_var(&mut self, a_id: K, b_id: K) -> Result<K, (V, V)> {
-        let node_a = self.get(a_id);
-        let node_b = self.get(b_id);
-        let a_id = node_a.key();
-        let b_id = node_b.key();
-
-        if a_id == b_id {
-            return Ok(a_id);
-        }
-
-        let combined = {
-            match (&node_a.value, &node_b.value) {
-                (&None, &None) => None,
-                (&Some(ref v), &None) |
-                (&None, &Some(ref v)) => Some(v.clone()),
-                (&Some(ref v1), &Some(ref v2)) => {
-                    if *v1 != *v2 {
-                        return Err((v1.clone(), v2.clone()));
-                    }
-                    Some(v1.clone())
-                }
-            }
-        };
-
-        Ok(self.unify(node_a, node_b, combined))
-    }
-
-    /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping
-    /// relationships, if `a_id` already has a value, it must be the same as `b`.
-    pub fn unify_var_value(&mut self, a_id: K, b: V) -> Result<(), (V, V)> {
-        let mut node_a = self.get(a_id);
-
-        match node_a.value {
-            None => {
-                node_a.value = Some(b);
-                self.set(node_a.key(), node_a);
-                Ok(())
-            }
-
-            Some(ref a_t) => {
-                if *a_t == b {
-                    Ok(())
-                } else {
-                    Err((a_t.clone(), b))
-                }
-            }
-        }
-    }
-
-    pub fn has_value(&mut self, id: K) -> bool {
-        self.get(id).value.is_some()
-    }
-
-    pub fn probe(&mut self, a_id: K) -> Option<V> {
-        self.get(a_id).value
-    }
-
-    pub fn unsolved_variables(&mut self) -> Vec<K> {
-        self.values
-            .iter()
-            .filter_map(|vv| {
-                if vv.value.is_some() {
-                    None
-                } else {
-                    Some(vv.key())
-                }
-            })
-            .collect()
-    }
-}
diff --git a/src/librustc_data_structures/unify/tests.rs b/src/librustc_data_structures/unify/tests.rs
deleted file mode 100644
index f29a7132e831b..0000000000000
--- a/src/librustc_data_structures/unify/tests.rs
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(non_snake_case)]
-
-extern crate test;
-use self::test::Bencher;
-use unify::{UnifyKey, UnificationTable};
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-struct UnitKey(u32);
-
-impl UnifyKey for UnitKey {
-    type Value = ();
-    fn index(&self) -> u32 {
-        self.0
-    }
-    fn from_index(u: u32) -> UnitKey {
-        UnitKey(u)
-    }
-    fn tag(_: Option<UnitKey>) -> &'static str {
-        "UnitKey"
-    }
-}
-
-#[test]
-fn basic() {
-    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
-    let k1 = ut.new_key(());
-    let k2 = ut.new_key(());
-    assert_eq!(ut.unioned(k1, k2), false);
-    ut.union(k1, k2);
-    assert_eq!(ut.unioned(k1, k2), true);
-}
-
-#[test]
-fn big_array() {
-    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
-    let mut keys = Vec::new();
-    const MAX: usize = 1 << 15;
-
-    for _ in 0..MAX {
-        keys.push(ut.new_key(()));
-    }
-
-    for i in 1..MAX {
-        let l = keys[i - 1];
-        let r = keys[i];
-        ut.union(l, r);
-    }
-
-    for i in 0..MAX {
-        assert!(ut.unioned(keys[0], keys[i]));
-    }
-}
-
-#[bench]
-fn big_array_bench(b: &mut Bencher) {
-    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
-    let mut keys = Vec::new();
-    const MAX: usize = 1 << 15;
-
-    for _ in 0..MAX {
-        keys.push(ut.new_key(()));
-    }
-
-
-    b.iter(|| {
-        for i in 1..MAX {
-            let l = keys[i - 1];
-            let r = keys[i];
-            ut.union(l, r);
-        }
-
-        for i in 0..MAX {
-            assert!(ut.unioned(keys[0], keys[i]));
-        }
-    })
-}
-
-#[test]
-fn even_odd() {
-    let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
-    let mut keys = Vec::new();
-    const MAX: usize = 1 << 10;
-
-    for i in 0..MAX {
-        let key = ut.new_key(());
-        keys.push(key);
-
-        if i >= 2 {
-            ut.union(key, keys[i - 2]);
-        }
-    }
-
-    for i in 1..MAX {
-        assert!(!ut.unioned(keys[i - 1], keys[i]));
-    }
-
-    for i in 2..MAX {
-        assert!(ut.unioned(keys[i - 2], keys[i]));
-    }
-}
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-struct IntKey(u32);
-
-impl UnifyKey for IntKey {
-    type Value = Option<i32>;
-    fn index(&self) -> u32 {
-        self.0
-    }
-    fn from_index(u: u32) -> IntKey {
-        IntKey(u)
-    }
-    fn tag(_: Option<IntKey>) -> &'static str {
-        "IntKey"
-    }
-}
-
-/// Test unifying a key whose value is `Some(_)`  with a key whose value is `None`.
-/// Afterwards both should be `Some(_)`.
-#[test]
-fn unify_key_Some_key_None() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    let k2 = ut.new_key(None);
-    assert!(ut.unify_var_var(k1, k2).is_ok());
-    assert_eq!(ut.probe(k2), Some(22));
-    assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `None`  with a key whose value is `Some(_)`.
-/// Afterwards both should be `Some(_)`.
-#[test]
-fn unify_key_None_key_Some() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    let k2 = ut.new_key(None);
-    assert!(ut.unify_var_var(k2, k1).is_ok());
-    assert_eq!(ut.probe(k2), Some(22));
-    assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(y)`.
-/// This should yield an error.
-#[test]
-fn unify_key_Some_x_key_Some_y() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    let k2 = ut.new_key(Some(23));
-    assert_eq!(ut.unify_var_var(k1, k2), Err((22, 23)));
-    assert_eq!(ut.unify_var_var(k2, k1), Err((23, 22)));
-    assert_eq!(ut.probe(k1), Some(22));
-    assert_eq!(ut.probe(k2), Some(23));
-}
-
-/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(x)`.
-/// This should be ok.
-#[test]
-fn unify_key_Some_x_key_Some_x() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    let k2 = ut.new_key(Some(22));
-    assert!(ut.unify_var_var(k1, k2).is_ok());
-    assert_eq!(ut.probe(k1), Some(22));
-    assert_eq!(ut.probe(k2), Some(22));
-}
-
-/// Test unifying a key whose value is `None` with a value is `x`.
-/// Afterwards key should be `x`.
-#[test]
-fn unify_key_None_val() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(None);
-    assert!(ut.unify_var_value(k1, 22).is_ok());
-    assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `Some(x)` with the value `y`.
-/// This should yield an error.
-#[test]
-fn unify_key_Some_x_val_y() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    assert_eq!(ut.unify_var_value(k1, 23), Err((22, 23)));
-    assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `Some(x)` with the value `x`.
-/// This should be ok.
-#[test]
-fn unify_key_Some_x_val_x() {
-    let mut ut: UnificationTable<IntKey> = UnificationTable::new();
-    let k1 = ut.new_key(Some(22));
-    assert!(ut.unify_var_value(k1, 22).is_ok());
-    assert_eq!(ut.probe(k1), Some(22));
-}

From 4fb201dee5d5c920950859fe81152fff401de230 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Mon, 29 Jan 2018 14:06:28 -0700
Subject: [PATCH 19/22] Re-add some removed uses of `Kind`

Additional uses of this item were added to these files in #45701 and #46479
---
 src/librustc_typeck/check/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a7001acc495a3..97fa508759546 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -93,7 +93,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
 use rustc::infer::anon_types::AnonTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
 use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
 use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};

From e9eb1a6adc1193a623ad7495f01a4c4125e49ce6 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Mon, 26 Feb 2018 15:14:24 -0700
Subject: [PATCH 20/22] Fix bad rebase

---
 src/librustc_typeck/check/mod.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 97fa508759546..df3d081f898a7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1027,8 +1027,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     let span = body.value.span;
 
     if body.is_generator && can_be_generator.is_some() {
-        let yield_ty = fcx.next_ty_var(fcx.next_ty_var(ty::UniverseIndex::ROOT,
-                                                       TypeVariableOrigin::TypeInference(span)));
+        let yield_ty = fcx.next_ty_var(ty::UniverseIndex::ROOT,
+                                       TypeVariableOrigin::TypeInference(span));
         fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
         fcx.yield_ty = Some(yield_ty);
     }

From a6d85332f4f16167725c12d48700fd96e7acaa2a Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Tue, 27 Feb 2018 12:09:40 -0700
Subject: [PATCH 21/22] Fix breakage in rustdoc

---
 src/librustdoc/clean/auto_trait.rs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 3654de6fb2ed2..370fc9bbca243 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -681,12 +681,17 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
             computed_preds.extend(user_computed_preds.iter().cloned());
             let normalized_preds =
                 traits::elaborate_predicates(tcx, computed_preds.clone().into_iter().collect());
-            new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal);
+            new_env = ty::ParamEnv::new(
+                tcx.mk_predicates(normalized_preds),
+                param_env.reveal,
+                ty::UniverseIndex::ROOT,
+            );
         }
 
         let final_user_env = ty::ParamEnv::new(
             tcx.mk_predicates(user_computed_preds.into_iter()),
             user_env.reveal,
+            ty::UniverseIndex::ROOT,
         );
         debug!(
             "evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \

From fec4d3b71161aa7b2861861cbf9b708c8c393b30 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Wed, 28 Feb 2018 10:27:18 -0700
Subject: [PATCH 22/22] Bump ena

---
 src/Cargo.lock                          | 6 +++---
 src/librustc_data_structures/Cargo.toml | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/Cargo.lock b/src/Cargo.lock
index d70631fa519d8..2cc647c49c627 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -600,7 +600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "ena"
-version = "0.8.0"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1874,7 +1874,7 @@ name = "rustc_data_structures"
 version = "0.0.0"
 dependencies = [
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "ena 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ena 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2870,7 +2870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e45aa15fe0a8a8f511e6d834626afd55e49b62e5c8802e18328a87e8a8f6065c"
 "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
-"checksum ena 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb80e4764284ff0ec7054cb05c557f5ba01ccf65ff0c265e981c0b303d0ffc"
+"checksum ena 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1733e41a3c37b0893685933d09dcb0c30269aa5d14dc5cafebf4bcded1e58225"
 "checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index 40d557ee5e04a..e1f0a74fc683d 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@ path = "lib.rs"
 crate-type = ["dylib"]
 
 [dependencies]
-ena = "0.8.0"
+ena = "0.9.1"
 log = "0.4"
 serialize = { path = "../libserialize" }
 cfg-if = "0.1.2"