From caa10c3bde60ce0d9b5401771c443bff51d2a8e2 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <arielb1@mail.tau.ac.il>
Date: Sun, 6 Sep 2015 18:32:34 +0300
Subject: [PATCH 1/4] move middle::ty and related modules to middle/ty/

---
 src/librustc/lib.rs                           |  8 ------
 src/librustc/middle/astencode.rs              |  2 +-
 src/librustc/middle/check_const.rs            |  2 +-
 src/librustc/middle/free_region.rs            |  2 +-
 src/librustc/middle/implicator.rs             |  2 +-
 src/librustc/middle/infer/bivariate.rs        |  2 +-
 src/librustc/middle/infer/combine.rs          | 19 +++++++------
 src/librustc/middle/infer/equate.rs           |  2 +-
 src/librustc/middle/infer/freshen.rs          |  7 +++--
 src/librustc/middle/infer/glb.rs              |  2 +-
 .../middle/infer/higher_ranked/mod.rs         | 12 ++++-----
 src/librustc/middle/infer/lattice.rs          |  2 +-
 src/librustc/middle/infer/lub.rs              |  3 +--
 src/librustc/middle/infer/mod.rs              | 12 ++++-----
 .../middle/infer/region_inference/mod.rs      |  2 +-
 src/librustc/middle/infer/resolve.rs          | 10 +++----
 src/librustc/middle/infer/sub.rs              |  2 +-
 src/librustc/middle/subst.rs                  |  8 +++---
 src/librustc/middle/traits/error_reporting.rs |  2 +-
 src/librustc/middle/traits/fulfill.rs         |  5 ++--
 src/librustc/middle/traits/mod.rs             |  2 +-
 src/librustc/middle/traits/project.rs         |  4 +--
 src/librustc/middle/traits/select.rs          | 20 +++++++-------
 .../middle/{ty_match.rs => ty/_match.rs}      |  6 ++---
 src/librustc/middle/{ => ty}/cast.rs          |  0
 src/librustc/middle/{ => ty}/fast_reject.rs   |  0
 .../middle/{ty_fold.rs => ty/fold.rs}         |  0
 src/librustc/middle/{ty.rs => ty/mod.rs}      | 27 ++++++++++++-------
 src/librustc/middle/{ => ty}/outlives.rs      |  0
 .../middle/{ty_relate/mod.rs => ty/relate.rs} |  2 +-
 .../middle/{ty_walk.rs => ty/walk.rs}         |  0
 src/librustc/middle/{ => ty}/wf.rs            |  3 +--
 src/librustc/util/ppaux.rs                    |  6 ++---
 src/librustc_driver/test.rs                   |  2 +-
 src/librustc_trans/trans/common.rs            |  9 +++----
 src/librustc_trans/trans/consts.rs            |  2 +-
 src/librustc_trans/trans/expr.rs              |  6 ++---
 src/librustc_trans/trans/monomorphize.rs      |  2 +-
 src/librustc_typeck/astconv.rs                | 11 ++++----
 src/librustc_typeck/check/assoc.rs            |  2 +-
 src/librustc_typeck/check/cast.rs             |  6 ++---
 src/librustc_typeck/check/coercion.rs         |  2 +-
 src/librustc_typeck/check/intrinsic.rs        |  2 +-
 src/librustc_typeck/check/method/confirm.rs   |  2 +-
 src/librustc_typeck/check/method/probe.rs     | 11 ++++----
 src/librustc_typeck/check/mod.rs              |  2 +-
 src/librustc_typeck/check/regionck.rs         | 21 +++++++--------
 src/librustc_typeck/check/wf.rs               |  2 +-
 src/librustc_typeck/check/wfcheck.rs          | 23 ++++++++--------
 src/librustc_typeck/check/writeback.rs        |  2 +-
 src/librustc_typeck/collect.rs                |  4 +--
 src/librustc_typeck/rscope.rs                 |  7 +++--
 52 files changed, 140 insertions(+), 154 deletions(-)
 rename src/librustc/middle/{ty_match.rs => ty/_match.rs} (94%)
 rename src/librustc/middle/{ => ty}/cast.rs (100%)
 rename src/librustc/middle/{ => ty}/fast_reject.rs (100%)
 rename src/librustc/middle/{ty_fold.rs => ty/fold.rs} (100%)
 rename src/librustc/middle/{ty.rs => ty/mod.rs} (99%)
 rename src/librustc/middle/{ => ty}/outlives.rs (100%)
 rename src/librustc/middle/{ty_relate/mod.rs => ty/relate.rs} (99%)
 rename src/librustc/middle/{ty_walk.rs => ty/walk.rs} (100%)
 rename src/librustc/middle/{ => ty}/wf.rs (99%)

diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index b11bf6f80fb7b..cfeab976e24cb 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -107,7 +107,6 @@ pub mod front {
 pub mod middle {
     pub mod astconv_util;
     pub mod astencode;
-    pub mod cast;
     pub mod cfg;
     pub mod check_const;
     pub mod check_static_recursion;
@@ -124,7 +123,6 @@ pub mod middle {
     pub mod effect;
     pub mod entry;
     pub mod expr_use_visitor;
-    pub mod fast_reject;
     pub mod free_region;
     pub mod intrinsicck;
     pub mod infer;
@@ -132,7 +130,6 @@ pub mod middle {
     pub mod lang_items;
     pub mod liveness;
     pub mod mem_categorization;
-    pub mod outlives;
     pub mod pat_util;
     pub mod privacy;
     pub mod reachable;
@@ -143,11 +140,6 @@ pub mod middle {
     pub mod subst;
     pub mod traits;
     pub mod ty;
-    pub mod ty_fold;
-    pub mod ty_match;
-    pub mod ty_relate;
-    pub mod ty_walk;
-    pub mod wf;
     pub mod weak_lang_items;
 }
 
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index abf2d5f3625dc..ac2dd54598253 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -27,7 +27,7 @@ use metadata::tydecode;
 use metadata::tydecode::{DefIdSource, NominalType, TypeWithId};
 use metadata::tydecode::{RegionParameter, ClosureSource};
 use metadata::tyencode;
-use middle::cast;
+use middle::ty::cast;
 use middle::check_const::ConstQualif;
 use middle::def;
 use middle::def_id::{DefId, LOCAL_CRATE};
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 37e144281760f..48c8cca76b056 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -24,7 +24,7 @@
 // - It's not possible to take the address of a static item with unsafe interior. This is enforced
 // by borrowck::gather_loans
 
-use middle::cast::{CastKind};
+use middle::ty::cast::{CastKind};
 use middle::const_eval;
 use middle::const_eval::EvalHint::ExprTypeChecked;
 use middle::def;
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index c39c3fd302712..2e9e5fafb1d9b 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -16,7 +16,7 @@
 //! region outlives another and so forth.
 
 use middle::ty::{self, FreeRegion, Region};
-use middle::wf::ImpliedBound;
+use middle::ty::wf::ImpliedBound;
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 
 #[derive(Clone)]
diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs
index b1a4e0270c2f9..9f33c4df03d41 100644
--- a/src/librustc/middle/implicator.rs
+++ b/src/librustc/middle/implicator.rs
@@ -15,7 +15,7 @@ use middle::infer::{InferCtxt, GenericKind};
 use middle::subst::Substs;
 use middle::traits;
 use middle::ty::{self, RegionEscape, ToPredicate, Ty};
-use middle::ty_fold::{TypeFoldable, TypeFolder};
+use middle::ty::fold::{TypeFoldable, TypeFolder};
 
 use syntax::ast;
 use syntax::codemap::Span;
diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs
index d2268894b20a1..2d9432b75e719 100644
--- a/src/librustc/middle/infer/bivariate.rs
+++ b/src/librustc/middle/infer/bivariate.rs
@@ -30,7 +30,7 @@ use super::type_variable::{BiTo};
 
 use middle::ty::{self, Ty};
 use middle::ty::TyVar;
-use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 
 pub struct Bivariate<'a, 'tcx: 'a> {
     fields: CombineFields<'a, 'tcx>
diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs
index 00edd054aa5b6..3a29fdfae2307 100644
--- a/src/librustc/middle/infer/combine.rs
+++ b/src/librustc/middle/infer/combine.rs
@@ -44,9 +44,8 @@ use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};
 use middle::ty::{TyVar};
 use middle::ty::{IntType, UintType};
 use middle::ty::{self, Ty, TypeError};
-use middle::ty_fold;
-use middle::ty_fold::{TypeFolder, TypeFoldable};
-use middle::ty_relate::{self, Relate, RelateResult, TypeRelation};
+use middle::ty::fold::{TypeFolder, TypeFoldable};
+use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 
 use syntax::codemap::Span;
 use rustc_front::hir;
@@ -56,7 +55,7 @@ pub struct CombineFields<'a, 'tcx: 'a> {
     pub infcx: &'a InferCtxt<'a, 'tcx>,
     pub a_is_expected: bool,
     pub trace: TypeTrace<'tcx>,
-    pub cause: Option<ty_relate::Cause>,
+    pub cause: Option<ty::relate::Cause>,
 }
 
 pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,
@@ -108,12 +107,12 @@ pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,
         // All other cases of inference are errors
         (&ty::TyInfer(_), _) |
         (_, &ty::TyInfer(_)) => {
-            Err(TypeError::Sorts(ty_relate::expected_found(relation, &a, &b)))
+            Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b)))
         }
 
 
         _ => {
-            ty_relate::super_relate_tys(relation, a, b)
+            ty::relate::super_relate_tys(relation, a, b)
         }
     }
 }
@@ -293,7 +292,7 @@ struct Generalizer<'cx, 'tcx:'cx> {
     cycle_detected: bool,
 }
 
-impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
+impl<'cx, 'tcx> ty::fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
     fn tcx(&self) -> &ty::ctxt<'tcx> {
         self.infcx.tcx
     }
@@ -319,7 +318,7 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
                 }
             }
             _ => {
-                ty_fold::super_fold_ty(self, t)
+                ty::fold::super_fold_ty(self, t)
             }
         }
     }
@@ -384,7 +383,7 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int
                                -> ty::TypeError<'tcx>
 {
     let (a, b) = v;
-    TypeError::IntMismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b))
+    TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
 }
 
 fn float_unification_error<'tcx>(a_is_expected: bool,
@@ -392,5 +391,5 @@ fn float_unification_error<'tcx>(a_is_expected: bool,
                                  -> ty::TypeError<'tcx>
 {
     let (a, b) = v;
-    TypeError::FloatMismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b))
+    TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
 }
diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs
index cbbf73d942073..07ce4688c069f 100644
--- a/src/librustc/middle/infer/equate.rs
+++ b/src/librustc/middle/infer/equate.rs
@@ -15,7 +15,7 @@ use super::type_variable::{EqTo};
 
 use middle::ty::{self, Ty};
 use middle::ty::TyVar;
-use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 
 pub struct Equate<'a, 'tcx: 'a> {
     fields: CombineFields<'a, 'tcx>
diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs
index c72a4fc0db309..0bae3cd2d8690 100644
--- a/src/librustc/middle/infer/freshen.rs
+++ b/src/librustc/middle/infer/freshen.rs
@@ -31,9 +31,8 @@
 //! inferencer knows "so far".
 
 use middle::ty::{self, Ty, HasTypeFlags};
-use middle::ty_fold;
-use middle::ty_fold::TypeFoldable;
-use middle::ty_fold::TypeFolder;
+use middle::ty::fold::TypeFoldable;
+use middle::ty::fold::TypeFolder;
 use std::collections::hash_map::{self, Entry};
 
 use super::InferCtxt;
@@ -170,7 +169,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
             ty::TyTuple(..) |
             ty::TyProjection(..) |
             ty::TyParam(..) => {
-                ty_fold::super_fold_ty(self, t)
+                ty::fold::super_fold_ty(self, t)
             }
         }
     }
diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs
index d6b03266b1fe7..0035f31e8db94 100644
--- a/src/librustc/middle/infer/glb.rs
+++ b/src/librustc/middle/infer/glb.rs
@@ -15,7 +15,7 @@ use super::lattice::{self, LatticeDir};
 use super::Subtype;
 
 use middle::ty::{self, Ty};
-use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 
 /// "Greatest lower bound" (common subtype)
 pub struct Glb<'a, 'tcx: 'a> {
diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs
index 0c539a5d0e0c2..10a31f0e657e5 100644
--- a/src/librustc/middle/infer/higher_ranked/mod.rs
+++ b/src/librustc/middle/infer/higher_ranked/mod.rs
@@ -15,8 +15,8 @@ use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
 use super::combine::CombineFields;
 
 use middle::ty::{self, TypeError, Binder};
-use middle::ty_fold::{self, TypeFoldable};
-use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use middle::ty::fold::TypeFoldable;
+use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use syntax::codemap::Span;
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
@@ -358,7 +358,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
     where T: TypeFoldable<'tcx>,
           F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
 {
-    ty_fold::fold_regions(tcx, unbound_value, &mut false, |region, current_depth| {
+    ty::fold::fold_regions(tcx, unbound_value, &mut false, |region, current_depth| {
         // we should only be encountering "escaping" late-bound regions here,
         // because the ones at the current level should have been replaced
         // with fresh variables
@@ -438,7 +438,7 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
 
         let mut escaping_region_vars = FnvHashSet();
         for ty in &escaping_types {
-            ty_fold::collect_regions(self.tcx, ty, &mut escaping_region_vars);
+            ty::fold::collect_regions(self.tcx, ty, &mut escaping_region_vars);
         }
 
         region_vars.retain(|&region_vid| {
@@ -468,7 +468,7 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
      * details.
      */
 
-    let (result, map) = ty_fold::replace_late_bound_regions(infcx.tcx, binder, |br| {
+    let (result, map) = ty::fold::replace_late_bound_regions(infcx.tcx, binder, |br| {
         infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot)
     });
 
@@ -590,7 +590,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
     // binder is that we encountered in `value`. The caller is
     // responsible for ensuring that (a) `value` contains at least one
     // binder and (b) that binder is the one we want to use.
-    let result = ty_fold::fold_regions(infcx.tcx, &value, &mut false, |r, current_depth| {
+    let result = ty::fold::fold_regions(infcx.tcx, &value, &mut false, |r, current_depth| {
         match inv_skol_map.get(&r) {
             None => r,
             Some(br) => {
diff --git a/src/librustc/middle/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs
index 7b34fda24064e..2a560ec8a1d23 100644
--- a/src/librustc/middle/infer/lattice.rs
+++ b/src/librustc/middle/infer/lattice.rs
@@ -34,7 +34,7 @@ use super::InferCtxt;
 
 use middle::ty::TyVar;
 use middle::ty::{self, Ty};
-use middle::ty_relate::{RelateResult, TypeRelation};
+use middle::ty::relate::{RelateResult, TypeRelation};
 
 pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> {
     fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs
index 9d993ead5ca20..238dad65ef0d9 100644
--- a/src/librustc/middle/infer/lub.rs
+++ b/src/librustc/middle/infer/lub.rs
@@ -15,7 +15,7 @@ use super::lattice::{self, LatticeDir};
 use super::Subtype;
 
 use middle::ty::{self, Ty};
-use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 
 /// "Least upper bound" (common supertype)
 pub struct Lub<'a, 'tcx: 'a> {
@@ -83,4 +83,3 @@ impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> {
         Ok(())
     }
 }
-
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 4ef96c0f3b450..5b94f5311fd0f 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -32,8 +32,8 @@ use middle::traits::{self, FulfillmentContext, Normalized,
                      SelectionContext, ObligationCause};
 use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
 use middle::ty::{self, Ty, TypeError, HasTypeFlags};
-use middle::ty_fold::{self, TypeFolder, TypeFoldable};
-use middle::ty_relate::{Relate, RelateResult, TypeRelation};
+use middle::ty::fold::{TypeFolder, TypeFoldable};
+use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_data_structures::unify::{self, UnificationTable};
 use std::cell::{RefCell, Ref};
 use std::fmt;
@@ -583,7 +583,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
 /// Returns an equivalent value with all free regions removed (note
 /// that late-bound regions remain, because they are important for
 /// subtyping, but they are anonymized and normalized as well). This
-/// is a stronger, caching version of `ty_fold::erase_regions`.
+/// is a stronger, caching version of `ty::fold::erase_regions`.
 pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
     where T : TypeFoldable<'tcx>
 {
@@ -603,7 +603,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
                 Some(u) => return u
             }
 
-            let t_norm = ty_fold::super_fold_ty(self, ty);
+            let t_norm = ty::fold::super_fold_ty(self, ty);
             self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
             return t_norm;
         }
@@ -612,7 +612,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
             where T : TypeFoldable<'tcx>
         {
             let u = self.tcx().anonymize_late_bound_regions(t);
-            ty_fold::super_fold_binder(self, &u)
+            ty::fold::super_fold_binder(self, &u)
         }
 
         fn fold_region(&mut self, r: ty::Region) -> ty::Region {
@@ -1406,7 +1406,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         -> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
         where T : TypeFoldable<'tcx>
     {
-        ty_fold::replace_late_bound_regions(
+        ty::fold::replace_late_bound_regions(
             self.tcx,
             value,
             |br| self.next_region_var(LateBoundRegion(span, br, lbrct)))
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index d81f8e0ae9093..a62fd8890baf6 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -27,7 +27,7 @@ use middle::ty::{self, Ty, TypeError};
 use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
 use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound};
 use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
-use middle::ty_relate::RelateResult;
+use middle::ty::relate::RelateResult;
 use util::common::indenter;
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs
index 9cc9f148ce183..4bcceade77599 100644
--- a/src/librustc/middle/infer/resolve.rs
+++ b/src/librustc/middle/infer/resolve.rs
@@ -10,7 +10,7 @@
 
 use super::{InferCtxt, FixupError, FixupResult};
 use middle::ty::{self, Ty, HasTypeFlags};
-use middle::ty_fold::{self, TypeFoldable};
+use middle::ty::fold::{TypeFoldable};
 
 ///////////////////////////////////////////////////////////////////////////
 // OPPORTUNISTIC TYPE RESOLVER
@@ -30,7 +30,7 @@ impl<'a, 'tcx> OpportunisticTypeResolver<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> {
+impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> {
     fn tcx(&self) -> &ty::ctxt<'tcx> {
         self.infcx.tcx
     }
@@ -40,7 +40,7 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx>
             t // micro-optimize -- if there is nothing in this type that this fold affects...
         } else {
             let t0 = self.infcx.shallow_resolve(t);
-            ty_fold::super_fold_ty(self, t0)
+            ty::fold::super_fold_ty(self, t0)
         }
     }
 }
@@ -69,7 +69,7 @@ struct FullTypeResolver<'a, 'tcx:'a> {
     err: Option<FixupError>,
 }
 
-impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
     fn tcx(&self) -> &ty::ctxt<'tcx> {
         self.infcx.tcx
     }
@@ -98,7 +98,7 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
                                 t));
                 }
                 _ => {
-                    ty_fold::super_fold_ty(self, t)
+                    ty::fold::super_fold_ty(self, t)
                 }
             }
         }
diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs
index 4d76d613392ee..155f5f44002f4 100644
--- a/src/librustc/middle/infer/sub.rs
+++ b/src/librustc/middle/infer/sub.rs
@@ -15,7 +15,7 @@ use super::type_variable::{SubtypeOf, SupertypeOf};
 
 use middle::ty::{self, Ty};
 use middle::ty::TyVar;
-use middle::ty_relate::{Cause, Relate, RelateResult, TypeRelation};
+use middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
 use std::mem;
 
 /// "Greatest lower bound" (common subtype)
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index 7d8a20c42e36e..c44891de0a055 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -14,7 +14,7 @@ pub use self::ParamSpace::*;
 pub use self::RegionSubsts::*;
 
 use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
-use middle::ty_fold::{self, TypeFoldable, TypeFolder};
+use middle::ty::fold::{TypeFoldable, TypeFolder};
 
 use std::fmt;
 use std::iter::IntoIterator;
@@ -643,7 +643,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
                 self.ty_for_param(p, t)
             }
             _ => {
-                ty_fold::super_fold_ty(self, t)
+                ty::fold::super_fold_ty(self, t)
             }
         };
 
@@ -731,13 +731,13 @@ impl<'a,'tcx> SubstFolder<'a,'tcx> {
             return ty;
         }
 
-        let result = ty_fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
+        let result = ty::fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
         debug!("shift_regions: shifted result = {:?}", result);
 
         result
     }
 
     fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region {
-        ty_fold::shift_region(region, self.region_binders_passed)
+        ty::fold::shift_region(region, self.region_binders_passed)
     }
 }
diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
index a3a903c33933e..5322a571ed91e 100644
--- a/src/librustc/middle/traits/error_reporting.rs
+++ b/src/librustc/middle/traits/error_reporting.rs
@@ -27,7 +27,7 @@ use fmt_macros::{Parser, Piece, Position};
 use middle::def_id::DefId;
 use middle::infer::InferCtxt;
 use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef, Ty};
-use middle::ty_fold::TypeFoldable;
+use middle::ty::fold::TypeFoldable;
 use std::collections::HashMap;
 use std::fmt;
 use syntax::codemap::Span;
diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index 99e12b7428d2a..6271dd211662e 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -10,7 +10,6 @@
 
 use middle::infer::InferCtxt;
 use middle::ty::{self, RegionEscape, Ty, HasTypeFlags};
-use middle::wf;
 
 use std::fmt;
 use syntax::ast;
@@ -496,8 +495,8 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                 ObligationCauseCode::RFC1214(_) => true,
                 _ => false,
             };
-            match wf::obligations(selcx.infcx(), obligation.cause.body_id,
-                                  ty, obligation.cause.span, rfc1214) {
+            match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
+                                      ty, obligation.cause.span, rfc1214) {
                 Some(obligations) => {
                     new_obligations.extend(obligations);
                     true
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 667cad8fc88ae..6c581a701a27e 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -19,7 +19,7 @@ use middle::def_id::DefId;
 use middle::free_region::FreeRegionMap;
 use middle::subst;
 use middle::ty::{self, HasTypeFlags, Ty};
-use middle::ty_fold::TypeFoldable;
+use middle::ty::fold::TypeFoldable;
 use middle::infer::{self, fixup_err_to_string, InferCtxt};
 use std::rc::Rc;
 use syntax::ast;
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index cacefbb1a8551..0d320989cbc7f 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -24,7 +24,7 @@ use super::util;
 use middle::infer;
 use middle::subst::Subst;
 use middle::ty::{self, ToPredicate, RegionEscape, HasTypeFlags, ToPolyTraitRef, Ty};
-use middle::ty_fold::{self, TypeFoldable, TypeFolder};
+use middle::ty::fold::{TypeFoldable, TypeFolder};
 use syntax::parse::token;
 use util::common::FN_OUTPUT_NAME;
 
@@ -265,7 +265,7 @@ impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> {
         // normalize it when we instantiate those bound regions (which
         // should occur eventually).
 
-        let ty = ty_fold::super_fold_ty(self, ty);
+        let ty = ty::fold::super_fold_ty(self, ty);
         match ty.sty {
             ty::TyProjection(ref data) if !data.has_escaping_regions() => { // (*)
 
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index ccdb271d43f85..6f422018c13d5 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -38,15 +38,13 @@ use super::object_safety;
 use super::util;
 
 use middle::def_id::{DefId, LOCAL_CRATE};
-use middle::fast_reject;
-use middle::subst::{Subst, Substs, TypeSpace};
-use middle::ty::{self, ToPredicate, RegionEscape, ToPolyTraitRef, Ty, HasTypeFlags};
 use middle::infer;
 use middle::infer::{InferCtxt, TypeFreshener};
-use middle::ty_fold::TypeFoldable;
-use middle::ty_match;
-use middle::ty_relate::TypeRelation;
-use middle::wf;
+use middle::subst::{Subst, Substs, TypeSpace};
+use middle::ty::{self, ToPredicate, RegionEscape, ToPolyTraitRef, Ty, HasTypeFlags};
+use middle::ty::fast_reject;
+use middle::ty::fold::TypeFoldable;
+use middle::ty::relate::TypeRelation;
 
 use std::cell::RefCell;
 use std::fmt;
@@ -471,9 +469,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             ty::Predicate::WellFormed(ty) => {
-                match wf::obligations(self.infcx, obligation.cause.body_id,
-                                      ty, obligation.cause.span,
-                                      obligation.cause.code.is_rfc1214()) {
+                match ty::wf::obligations(self.infcx, obligation.cause.body_id,
+                                          ty, obligation.cause.span,
+                                          obligation.cause.code.is_rfc1214()) {
                     Some(obligations) =>
                         self.evaluate_predicates_recursively(previous_stack, obligations.iter()),
                     None =>
@@ -2824,7 +2822,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                               current: &ty::PolyTraitRef<'tcx>)
                               -> bool
     {
-        let mut matcher = ty_match::Match::new(self.tcx());
+        let mut matcher = ty::_match::Match::new(self.tcx());
         matcher.relate(previous, current).is_ok()
     }
 
diff --git a/src/librustc/middle/ty_match.rs b/src/librustc/middle/ty/_match.rs
similarity index 94%
rename from src/librustc/middle/ty_match.rs
rename to src/librustc/middle/ty/_match.rs
index 4aa0e553a7aa6..2ebb23369bd01 100644
--- a/src/librustc/middle/ty_match.rs
+++ b/src/librustc/middle/ty/_match.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use middle::ty::{self, Ty};
-use middle::ty_relate::{self, Relate, TypeRelation, RelateResult};
+use middle::ty::relate::{self, Relate, TypeRelation, RelateResult};
 
 /// A type "A" *matches* "B" if the fresh types in B could be
 /// substituted with values so as to make it equal to A. Matching is
@@ -73,7 +73,7 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> {
 
             (&ty::TyInfer(_), _) |
             (_, &ty::TyInfer(_)) => {
-                Err(ty::TypeError::Sorts(ty_relate::expected_found(self, &a, &b)))
+                Err(ty::TypeError::Sorts(relate::expected_found(self, &a, &b)))
             }
 
             (&ty::TyError, _) | (_, &ty::TyError) => {
@@ -81,7 +81,7 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> {
             }
 
             _ => {
-                ty_relate::super_relate_tys(self, a, b)
+                relate::super_relate_tys(self, a, b)
             }
         }
     }
diff --git a/src/librustc/middle/cast.rs b/src/librustc/middle/ty/cast.rs
similarity index 100%
rename from src/librustc/middle/cast.rs
rename to src/librustc/middle/ty/cast.rs
diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/ty/fast_reject.rs
similarity index 100%
rename from src/librustc/middle/fast_reject.rs
rename to src/librustc/middle/ty/fast_reject.rs
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty/fold.rs
similarity index 100%
rename from src/librustc/middle/ty_fold.rs
rename to src/librustc/middle/ty/fold.rs
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty/mod.rs
similarity index 99%
rename from src/librustc/middle/ty.rs
rename to src/librustc/middle/ty/mod.rs
index 7f61526a8f903..21f068ca887a0 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -43,13 +43,11 @@ use front::map as ast_map;
 use front::map::LinkedPath;
 use metadata::csearch;
 use middle;
-use middle::cast;
 use middle::check_const;
 use middle::const_eval::{self, ConstVal, ErrKind};
 use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def::{self, DefMap, ExportMap};
 use middle::def_id::{DefId, LOCAL_CRATE};
-use middle::fast_reject;
 use middle::free_region::FreeRegionMap;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::region;
@@ -62,8 +60,8 @@ use middle::stability;
 use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
 use middle::traits;
 use middle::ty;
-use middle::ty_fold::{self, TypeFoldable, TypeFolder};
-use middle::ty_walk::{self, TypeWalker};
+use middle::ty::fold::{TypeFoldable, TypeFolder};
+use middle::ty::walk::{TypeWalker};
 use util::common::{memoized, ErrorReported};
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
 use util::nodemap::FnvHashMap;
@@ -96,6 +94,15 @@ use rustc_front::hir::{ItemImpl, ItemTrait};
 use rustc_front::hir::{MutImmutable, MutMutable, Visibility};
 use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
 
+pub mod cast;
+pub mod fast_reject;
+pub mod fold;
+pub mod _match;
+pub mod outlives;
+pub mod relate;
+pub mod walk;
+pub mod wf;
+
 pub type Disr = u64;
 
 pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
@@ -4252,7 +4259,7 @@ impl<'tcx> TyS<'tcx> {
     /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
     /// (but not `i32`, like `walk`).
     pub fn walk_shallow(&'tcx self) -> IntoIter<Ty<'tcx>> {
-        ty_walk::walk_shallow(self)
+        walk::walk_shallow(self)
     }
 
     pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
@@ -6879,7 +6886,7 @@ impl<'tcx> ctxt<'tcx> {
         -> T
         where T : TypeFoldable<'tcx>
     {
-        ty_fold::replace_late_bound_regions(
+        fold::replace_late_bound_regions(
             self, value,
             |br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
     }
@@ -6891,8 +6898,8 @@ impl<'tcx> ctxt<'tcx> {
         where T: TypeFoldable<'tcx>
     {
         let bound0_value = bound2_value.skip_binder().skip_binder();
-        let value = ty_fold::fold_regions(self, bound0_value, &mut false,
-                                          |region, current_depth| {
+        let value = fold::fold_regions(self, bound0_value, &mut false,
+                                       |region, current_depth| {
             match region {
                 ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
                     // should be true if no escaping regions from bound2_value
@@ -6922,7 +6929,7 @@ impl<'tcx> ctxt<'tcx> {
     pub fn erase_late_bound_regions<T>(&self, value: &Binder<T>) -> T
         where T : TypeFoldable<'tcx>
     {
-        ty_fold::replace_late_bound_regions(self, value, |_| ty::ReStatic).0
+        fold::replace_late_bound_regions(self, value, |_| ty::ReStatic).0
     }
 
     /// Rewrite any late-bound regions so that they are anonymous.  Region numbers are
@@ -6937,7 +6944,7 @@ impl<'tcx> ctxt<'tcx> {
         where T : TypeFoldable<'tcx>,
     {
         let mut counter = 0;
-        ty::Binder(ty_fold::replace_late_bound_regions(self, sig, |_| {
+        ty::Binder(fold::replace_late_bound_regions(self, sig, |_| {
             counter += 1;
             ReLateBound(ty::DebruijnIndex::new(1), BrAnon(counter))
         }).0)
diff --git a/src/librustc/middle/outlives.rs b/src/librustc/middle/ty/outlives.rs
similarity index 100%
rename from src/librustc/middle/outlives.rs
rename to src/librustc/middle/ty/outlives.rs
diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty/relate.rs
similarity index 99%
rename from src/librustc/middle/ty_relate/mod.rs
rename to src/librustc/middle/ty/relate.rs
index d2d612ece6f80..7baf075cc69ba 100644
--- a/src/librustc/middle/ty_relate/mod.rs
+++ b/src/librustc/middle/ty/relate.rs
@@ -16,7 +16,7 @@
 use middle::def_id::DefId;
 use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
 use middle::ty::{self, HasTypeFlags, Ty, TypeError};
-use middle::ty_fold::TypeFoldable;
+use middle::ty::fold::TypeFoldable;
 use std::rc::Rc;
 use syntax::abi;
 use rustc_front::hir as ast;
diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty/walk.rs
similarity index 100%
rename from src/librustc/middle/ty_walk.rs
rename to src/librustc/middle/ty/walk.rs
diff --git a/src/librustc/middle/wf.rs b/src/librustc/middle/ty/wf.rs
similarity index 99%
rename from src/librustc/middle/wf.rs
rename to src/librustc/middle/ty/wf.rs
index 96942756b9882..20534f72666db 100644
--- a/src/librustc/middle/wf.rs
+++ b/src/librustc/middle/ty/wf.rs
@@ -10,7 +10,7 @@
 
 use middle::def_id::DefId;
 use middle::infer::InferCtxt;
-use middle::outlives::{self, Component};
+use middle::ty::outlives::{self, Component};
 use middle::subst::Substs;
 use middle::traits;
 use middle::ty::{self, RegionEscape, ToPredicate, Ty};
@@ -544,4 +544,3 @@ pub fn object_region_bounds<'tcx>(
 
     tcx.required_region_bounds(open_ty, predicates)
 }
-
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index a0701d852bc04..222de42643297 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -21,7 +21,7 @@ use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple};
 use middle::ty::TyClosure;
 use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
 use middle::ty::{self, TypeAndMut, Ty, HasTypeFlags};
-use middle::ty_fold::{self, TypeFoldable};
+use middle::ty::fold::{self, TypeFoldable};
 
 use std::fmt;
 use syntax::abi;
@@ -219,7 +219,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter,
         }
     };
 
-    let new_value = ty_fold::replace_late_bound_regions(tcx, &value, |br| {
+    let new_value = fold::replace_late_bound_regions(tcx, &value, |br| {
         let _ = start_or_continue(f, "for<", ", ");
         ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
             ty::BrNamed(_, name) => {
@@ -255,7 +255,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter,
 struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>, Vec<ty::ProjectionPredicate<'tcx>>);
 
 impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> {
-    fn fold_with<F:ty_fold::TypeFolder<'tcx>>(&self, folder: &mut F)
+    fn fold_with<F: fold::TypeFolder<'tcx>>(&self, folder: &mut F)
                                               -> TraitAndProjections<'tcx> {
         TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder))
     }
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index c96495fcfc986..96d9572b48591 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -24,7 +24,7 @@ use rustc_typeck::middle::stability;
 use rustc_typeck::middle::subst;
 use rustc_typeck::middle::subst::Subst;
 use rustc_typeck::middle::ty::{self, Ty, RegionEscape};
-use rustc_typeck::middle::ty_relate::TypeRelation;
+use rustc_typeck::middle::ty::relate::TypeRelation;
 use rustc_typeck::middle::infer;
 use rustc_typeck::middle::infer::lub::Lub;
 use rustc_typeck::middle::infer::glb::Glb;
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 6843e4cab83e9..044e96db04de5 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -38,8 +38,7 @@ use trans::type_::Type;
 use trans::type_of;
 use middle::traits;
 use middle::ty::{self, HasTypeFlags, Ty};
-use middle::ty_fold;
-use middle::ty_fold::{TypeFolder, TypeFoldable};
+use middle::ty::fold::{TypeFolder, TypeFoldable};
 use rustc::front::map::{PathElem, PathName};
 use rustc_front::hir;
 use util::nodemap::{FnvHashMap, NodeMap};
@@ -60,7 +59,7 @@ pub use trans::context::CrateContext;
 /// Returns an equivalent value with all free regions removed (note
 /// that late-bound regions remain, because they are important for
 /// subtyping, but they are anonymized and normalized as well). This
-/// is a stronger, caching version of `ty_fold::erase_regions`.
+/// is a stronger, caching version of `ty::fold::erase_regions`.
 pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
     where T : TypeFoldable<'tcx>
 {
@@ -80,7 +79,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
                 Some(u) => return u
             }
 
-            let t_norm = ty_fold::super_fold_ty(self, ty);
+            let t_norm = ty::fold::super_fold_ty(self, ty);
             self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
             return t_norm;
         }
@@ -89,7 +88,7 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
             where T : TypeFoldable<'tcx>
         {
             let u = self.tcx().anonymize_late_bound_regions(t);
-            ty_fold::super_fold_binder(self, &u)
+            ty::fold::super_fold_binder(self, &u)
         }
 
         fn fold_region(&mut self, r: ty::Region) -> ty::Region {
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index a3ba174a6e5a4..c98760ce02a26 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -33,9 +33,9 @@ use trans::declare;
 use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of;
-use middle::cast::{CastTy,IntTy};
 use middle::subst::Substs;
 use middle::ty::{self, Ty};
+use middle::ty::cast::{CastTy,IntTy};
 use util::nodemap::NodeMap;
 
 use rustc_front::hir;
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 3a7fa040e4f8c..59040b9cafef5 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -71,10 +71,10 @@ use trans::machine;
 use trans::meth;
 use trans::tvec;
 use trans::type_of;
-use middle::cast::{CastKind, CastTy};
 use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
 use middle::ty::{self, Ty};
 use middle::ty::MethodCall;
+use middle::ty::cast::{CastKind, CastTy};
 use util::common::indenter;
 use trans::machine::{llsize_of, llsize_of_alloc};
 use trans::type_::Type;
@@ -2045,8 +2045,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                               id: ast::NodeId)
                               -> DatumBlock<'blk, 'tcx, Expr>
 {
-    use middle::cast::CastTy::*;
-    use middle::cast::IntTy::*;
+    use middle::ty::cast::CastTy::*;
+    use middle::ty::cast::IntTy::*;
 
     fn int_cast(bcx: Block,
                 lldsttype: Type,
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index ae425f29132fa..1ef9981a0a46a 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -17,7 +17,7 @@ use middle::infer;
 use middle::subst;
 use middle::subst::{Subst, Substs};
 use middle::traits;
-use middle::ty_fold::{TypeFolder, TypeFoldable};
+use middle::ty::fold::{TypeFolder, TypeFoldable};
 use trans::attributes;
 use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
 use trans::base::trans_fn;
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index fb61f1ef42d7b..e6f9b1f9d6dec 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -53,13 +53,12 @@ use middle::const_eval::{self, ConstVal};
 use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def;
 use middle::def_id::{DefId, LOCAL_CRATE};
-use middle::wf::object_region_bounds;
 use middle::resolve_lifetime as rl;
 use middle::privacy::{AllPublic, LastMod};
 use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
 use middle::traits;
 use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags};
-use middle::ty_fold;
+use middle::ty::wf::object_region_bounds;
 use require_c_abi_if_variadic;
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
              ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
@@ -535,9 +534,9 @@ fn find_implied_output_region<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     for (input_type, input_pat) in input_tys.iter().zip(input_pats) {
         let mut regions = FnvHashSet();
-        let have_bound_regions = ty_fold::collect_regions(tcx,
-                                                          input_type,
-                                                          &mut regions);
+        let have_bound_regions = ty::fold::collect_regions(tcx,
+                                                           input_type,
+                                                           &mut regions);
 
         debug!("find_implied_output_regions: collected {:?} from {:?} \
                 have_bound_regions={:?}", &regions, input_type, have_bound_regions);
@@ -2249,7 +2248,7 @@ impl<'tcx> Bounds<'tcx> {
         for &region_bound in &self.region_bounds {
             // account for the binder being introduced below; no need to shift `param_ty`
             // because, at present at least, it can only refer to early-bound regions
-            let region_bound = ty_fold::shift_region(region_bound, 1);
+            let region_bound = ty::fold::shift_region(region_bound, 1);
             vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate());
         }
 
diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs
index c80c48a96922d..8dc95562e44af 100644
--- a/src/librustc_typeck/check/assoc.rs
+++ b/src/librustc_typeck/check/assoc.rs
@@ -12,7 +12,7 @@ use middle::infer::InferCtxt;
 use middle::traits::{self, FulfillmentContext, Normalized, MiscObligation,
                      SelectionContext, ObligationCause};
 use middle::ty::HasTypeFlags;
-use middle::ty_fold::TypeFoldable;
+use middle::ty::fold::TypeFoldable;
 use syntax::ast;
 use syntax::codemap::Span;
 
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 799a3e86a7519..98c8c0a319946 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -44,9 +44,9 @@ use super::FnCtxt;
 use super::structurally_resolved_type;
 
 use lint;
-use middle::cast::{CastKind, CastTy};
 use middle::def_id::DefId;
 use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::cast::{CastKind, CastTy};
 use syntax::codemap::Span;
 use rustc_front::hir;
 use rustc_front::hir::UintTy::TyU8;
@@ -226,8 +226,8 @@ impl<'tcx> CastCheck<'tcx> {
     /// can return Ok and create type errors in the fcx rather than returning
     /// directly. coercion-cast is handled in check instead of here.
     fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
-        use middle::cast::IntTy::*;
-        use middle::cast::CastTy::*;
+        use middle::ty::cast::IntTy::*;
+        use middle::ty::cast::CastTy::*;
 
         let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty),
                                       CastTy::from_ty(self.cast_ty)) {
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 65409afa52d10..d3a292676c5ef 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -67,7 +67,7 @@ use middle::traits::{self, ObligationCause};
 use middle::traits::{predicate_for_trait_def, report_selection_error};
 use middle::ty::{AutoDerefRef, AdjustDerefRef};
 use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TypeError};
-use middle::ty_relate::RelateResult;
+use middle::ty::relate::RelateResult;
 use util::common::indent;
 
 use std::cell::RefCell;
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index d1f898d82fdd3..e7c7b5831d0fc 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -17,7 +17,7 @@ use middle::def_id::DefId;
 use middle::subst;
 use middle::ty::FnSig;
 use middle::ty::{self, Ty};
-use middle::ty_fold::TypeFolder;
+use middle::ty::fold::TypeFolder;
 use {CrateCtxt, require_same_types};
 
 use std::collections::{HashMap};
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 040e644a94d1f..048a2b62bcaa3 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -16,7 +16,7 @@ use middle::def_id::DefId;
 use middle::subst::{self};
 use middle::traits;
 use middle::ty::{self, NoPreference, PreferMutLvalue, Ty};
-use middle::ty_fold::TypeFoldable;
+use middle::ty::fold::TypeFoldable;
 use middle::infer;
 use middle::infer::InferCtxt;
 use syntax::codemap::Span;
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index b04899f5ecdc7..f65602d9aaccb 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -16,13 +16,12 @@ use super::suggest;
 use check;
 use check::{FnCtxt, UnresolvedTypeAction};
 use middle::def_id::DefId;
-use middle::fast_reject;
 use middle::subst;
 use middle::subst::Subst;
 use middle::traits;
 use middle::ty::{self, NoPreference, RegionEscape, Ty, ToPolyTraitRef, TraitRef};
 use middle::ty::HasTypeFlags;
-use middle::ty_fold::TypeFoldable;
+use middle::ty::fold::TypeFoldable;
 use middle::infer;
 use middle::infer::InferCtxt;
 use syntax::ast;
@@ -41,7 +40,7 @@ struct ProbeContext<'a, 'tcx:'a> {
     mode: Mode,
     item_name: ast::Name,
     steps: Rc<Vec<CandidateStep<'tcx>>>,
-    opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
+    opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>,
     inherent_candidates: Vec<Candidate<'tcx>>,
     extension_candidates: Vec<Candidate<'tcx>>,
     impl_dups: HashSet<DefId>,
@@ -163,7 +162,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // Create a list of simplified self types, if we can.
     let mut simplified_steps = Vec::new();
     for step in &steps {
-        match fast_reject::simplify_type(fcx.tcx(), step.self_ty, true) {
+        match ty::fast_reject::simplify_type(fcx.tcx(), step.self_ty, true) {
             None => { break; }
             Some(simplified_type) => { simplified_steps.push(simplified_type); }
         }
@@ -236,7 +235,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
            mode: Mode,
            item_name: ast::Name,
            steps: Vec<CandidateStep<'tcx>>,
-           opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
+           opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>)
            -> ProbeContext<'a,'tcx>
     {
         ProbeContext {
@@ -684,7 +683,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
         let impl_type = self.tcx().lookup_item_type(impl_def_id);
         let impl_simplified_type =
-            match fast_reject::simplify_type(self.tcx(), impl_type.ty, false) {
+            match ty::fast_reject::simplify_type(self.tcx(), impl_type.ty, false) {
                 Some(simplified_type) => simplified_type,
                 None => { return true; }
             };
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b1fbf97d1a74b..dc433786ae4d6 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -97,7 +97,7 @@ use middle::ty::{Disr, ParamTy, ParameterEnvironment};
 use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
 use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
 use middle::ty::{MethodCall, MethodCallee};
-use middle::ty_fold::{TypeFolder, TypeFoldable};
+use middle::ty::fold::{TypeFolder, TypeFoldable};
 use require_c_abi_if_variadic;
 use rscope::{ElisionFailureInfo, RegionScope};
 use session::Session;
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 844e143b9fa5b..b6ff7b529c556 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -88,14 +88,13 @@ use check::FnCtxt;
 use middle::free_region::FreeRegionMap;
 use middle::implicator::{self, Implication};
 use middle::mem_categorization as mc;
-use middle::outlives;
 use middle::region::CodeExtent;
 use middle::subst::Substs;
 use middle::traits;
 use middle::ty::{self, RegionEscape, ReScope, Ty, MethodCall, HasTypeFlags};
 use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, VerifyBound};
 use middle::pat_util;
-use middle::wf::{self, ImpliedBound};
+use middle::ty::wf::ImpliedBound;
 
 use std::mem;
 use std::rc::Rc;
@@ -420,7 +419,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
         for &ty in fn_sig_tys {
             let ty = self.resolve_type(ty);
             debug!("relate_free_regions(t={:?})", ty);
-            let implied_bounds = wf::implied_bounds(self.fcx.infcx(), body_id, ty, span);
+            let implied_bounds = ty::wf::implied_bounds(self.fcx.infcx(), body_id, ty, span);
 
             // Record any relations between free regions that we observe into the free-region-map.
             self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds);
@@ -1527,31 +1526,31 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
 
     assert!(!ty.has_escaping_regions());
 
-    let components = outlives::components(rcx.infcx(), ty);
+    let components = ty::outlives::components(rcx.infcx(), ty);
     components_must_outlive(rcx, origin, components, region);
 }
 
 fn components_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                                      origin: infer::SubregionOrigin<'tcx>,
-                                     components: Vec<outlives::Component<'tcx>>,
+                                     components: Vec<ty::outlives::Component<'tcx>>,
                                      region: ty::Region)
 {
     for component in components {
         let origin = origin.clone();
         match component {
-            outlives::Component::Region(region1) => {
+            ty::outlives::Component::Region(region1) => {
                 rcx.fcx.mk_subr(origin, region, region1);
             }
-            outlives::Component::Param(param_ty) => {
+            ty::outlives::Component::Param(param_ty) => {
                 param_ty_must_outlive(rcx, origin, region, param_ty);
             }
-            outlives::Component::Projection(projection_ty) => {
+            ty::outlives::Component::Projection(projection_ty) => {
                 projection_must_outlive(rcx, origin, region, projection_ty);
             }
-            outlives::Component::EscapingProjection(subcomponents) => {
+            ty::outlives::Component::EscapingProjection(subcomponents) => {
                 components_must_outlive(rcx, origin, subcomponents, region);
             }
-            outlives::Component::UnresolvedInferenceVariable(v) => {
+            ty::outlives::Component::UnresolvedInferenceVariable(v) => {
                 // ignore this, we presume it will yield an error
                 // later, since if a type variable is not resolved by
                 // this point it never will be
@@ -1559,7 +1558,7 @@ fn components_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
                     origin.span(),
                     &format!("unresolved inference variable in outlives: {:?}", v));
             }
-            outlives::Component::RFC1214(subcomponents) => {
+            ty::outlives::Component::RFC1214(subcomponents) => {
                 let suborigin = infer::RFC1214Subregion(Rc::new(origin));
                 components_must_outlive(rcx, suborigin, subcomponents, region);
             }
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index 99cb12813077c..2c931e7830d59 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -17,7 +17,7 @@ use middle::region;
 use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
 use middle::traits;
 use middle::ty::{self, Ty};
-use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty};
+use middle::ty::fold::{TypeFolder, TypeFoldable, super_fold_ty};
 
 use std::cell::RefCell;
 use std::collections::HashSet;
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index a53f15ce2aa84..06dd80c57ada8 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -16,8 +16,7 @@ use middle::def_id::DefId;
 use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
 use middle::traits;
 use middle::ty::{self, Ty};
-use middle::ty_fold::{TypeFolder};
-use middle::wf;
+use middle::ty::fold::{TypeFolder};
 
 use std::cell::RefCell;
 use std::collections::HashSet;
@@ -309,11 +308,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                         fcx.instantiate_type_scheme(
                             ast_trait_ref.path.span, free_substs, &trait_ref);
                     let obligations =
-                        wf::trait_obligations(fcx.infcx(),
-                                              fcx.body_id,
-                                              &trait_ref,
-                                              ast_trait_ref.path.span,
-                                              true);
+                        ty::wf::trait_obligations(fcx.infcx(),
+                                                  fcx.body_id,
+                                                  &trait_ref,
+                                                  ast_trait_ref.path.span,
+                                                  true);
                     for obligation in obligations {
                         fcx.register_predicate(obligation);
                     }
@@ -341,11 +340,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         let obligations =
             predicates.predicates
                       .iter()
-                      .flat_map(|p| wf::predicate_obligations(fcx.infcx(),
-                                                              fcx.body_id,
-                                                              p,
-                                                              span,
-                                                              true));
+                      .flat_map(|p| ty::wf::predicate_obligations(fcx.infcx(),
+                                                                  fcx.body_id,
+                                                                  p,
+                                                                  span,
+                                                                  true));
 
         for obligation in obligations {
             fcx.register_predicate(obligation);
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 94c01eb70e88a..de841a0cc0022 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -18,7 +18,7 @@ use check::FnCtxt;
 use middle::def_id::DefId;
 use middle::pat_util;
 use middle::ty::{self, Ty, MethodCall, MethodCallee};
-use middle::ty_fold::{TypeFolder,TypeFoldable};
+use middle::ty::fold::{TypeFolder,TypeFoldable};
 use middle::infer;
 use write_substs_to_tcx;
 use write_ty_to_tcx;
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index f0b68e5e9025f..930eb431f4957 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -78,7 +78,7 @@ use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerPar
 use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
 use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme, IntTypeExt};
 use middle::ty::{VariantKind};
-use middle::ty_fold::{self, TypeFolder, TypeFoldable};
+use middle::ty::fold::{TypeFolder, TypeFoldable};
 use middle::infer;
 use rscope::*;
 use rustc::front::map as hir_map;
@@ -2374,7 +2374,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
          * before we really have a `ParameterEnvironment` to check.
          */
 
-        ty_fold::fold_regions(tcx, value, &mut false, |region, _| {
+        ty::fold::fold_regions(tcx, value, &mut false, |region, _| {
             match region {
                 ty::ReEarlyBound(data) => {
                     let def_id = DefId::local(data.param_id);
diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs
index 28403ab22826c..1b02c736dce3b 100644
--- a/src/librustc_typeck/rscope.rs
+++ b/src/librustc_typeck/rscope.rs
@@ -10,7 +10,6 @@
 
 
 use middle::ty;
-use middle::ty_fold;
 
 use std::cell::Cell;
 use syntax::codemap::Span;
@@ -239,11 +238,11 @@ impl<'r> ShiftedRscope<'r> {
 impl<'r> RegionScope for ShiftedRscope<'r> {
     fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
         self.base_scope.object_lifetime_default(span)
-            .map(|r| ty_fold::shift_region(r, 1))
+            .map(|r| ty::fold::shift_region(r, 1))
     }
 
     fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
-        ty_fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1)
+        ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1)
     }
 
     fn anon_regions(&self,
@@ -254,7 +253,7 @@ impl<'r> RegionScope for ShiftedRscope<'r> {
         match self.base_scope.anon_regions(span, count) {
             Ok(mut v) => {
                 for r in &mut v {
-                    *r = ty_fold::shift_region(*r, 1);
+                    *r = ty::fold::shift_region(*r, 1);
                 }
                 Ok(v)
             }

From 5f564fbbe46ee609e841062dad1817f17f90943c Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <arielb1@mail.tau.ac.il>
Date: Sun, 6 Sep 2015 21:51:58 +0300
Subject: [PATCH 2/4] split ty.rs into smaller parts

---
 src/librustc/middle/infer/combine.rs          |   11 +-
 src/librustc/middle/infer/error_reporting.rs  |   27 +-
 .../middle/infer/higher_ranked/mod.rs         |   11 +-
 src/librustc/middle/infer/mod.rs              |   39 +-
 .../middle/infer/region_inference/mod.rs      |    5 +-
 src/librustc/middle/traits/mod.rs             |    2 +-
 src/librustc/middle/traits/project.rs         |    2 +-
 src/librustc/middle/ty/_match.rs              |    3 +-
 src/librustc/middle/ty/contents.rs            |  269 ++
 src/librustc/middle/ty/context.rs             |  964 +++++
 src/librustc/middle/ty/error.rs               |  342 ++
 src/librustc/middle/ty/flags.rs               |  205 +
 src/librustc/middle/ty/fold.rs                |  585 +--
 src/librustc/middle/ty/ivar.rs                |   72 +
 src/librustc/middle/ty/mod.rs                 | 3748 +----------------
 src/librustc/middle/ty/relate.rs              |   13 +-
 src/librustc/middle/ty/structural_impls.rs    |  895 ++++
 src/librustc/middle/ty/sty.rs                 | 1129 +++++
 src/librustc/util/ppaux.rs                    |  155 +-
 src/librustc_typeck/astconv.rs                |    4 +-
 src/librustc_typeck/check/coercion.rs         |    3 +-
 src/librustc_typeck/check/demand.rs           |    2 +-
 src/librustc_typeck/check/mod.rs              |   20 +-
 src/librustc_typeck/coherence/mod.rs          |    2 +-
 src/librustc_typeck/collect.rs                |    2 +-
 25 files changed, 4355 insertions(+), 4155 deletions(-)
 create mode 100644 src/librustc/middle/ty/contents.rs
 create mode 100644 src/librustc/middle/ty/context.rs
 create mode 100644 src/librustc/middle/ty/error.rs
 create mode 100644 src/librustc/middle/ty/flags.rs
 create mode 100644 src/librustc/middle/ty/ivar.rs
 create mode 100644 src/librustc/middle/ty/structural_impls.rs
 create mode 100644 src/librustc/middle/ty/sty.rs

diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs
index 3a29fdfae2307..2447a8cee7bbb 100644
--- a/src/librustc/middle/infer/combine.rs
+++ b/src/librustc/middle/infer/combine.rs
@@ -43,7 +43,8 @@ use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};
 
 use middle::ty::{TyVar};
 use middle::ty::{IntType, UintType};
-use middle::ty::{self, Ty, TypeError};
+use middle::ty::{self, Ty};
+use middle::ty::error::TypeError;
 use middle::ty::fold::{TypeFolder, TypeFoldable};
 use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 
@@ -362,12 +363,12 @@ impl<'cx, 'tcx> ty::fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
 
 pub trait RelateResultCompare<'tcx, T> {
     fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
-        F: FnOnce() -> ty::TypeError<'tcx>;
+        F: FnOnce() -> TypeError<'tcx>;
 }
 
 impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> {
     fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> where
-        F: FnOnce() -> ty::TypeError<'tcx>,
+        F: FnOnce() -> TypeError<'tcx>,
     {
         self.clone().and_then(|s| {
             if s == t {
@@ -380,7 +381,7 @@ impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'t
 }
 
 fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue))
-                               -> ty::TypeError<'tcx>
+                               -> TypeError<'tcx>
 {
     let (a, b) = v;
     TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
@@ -388,7 +389,7 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int
 
 fn float_unification_error<'tcx>(a_is_expected: bool,
                                  v: (hir::FloatTy, hir::FloatTy))
-                                 -> ty::TypeError<'tcx>
+                                 -> TypeError<'tcx>
 {
     let (a, b) = v;
     TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index 7ec39ac851574..f0fa7d7cdf851 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -82,8 +82,9 @@ use middle::def_id::DefId;
 use middle::infer;
 use middle::region;
 use middle::subst;
-use middle::ty::{self, Ty, TypeError, HasTypeFlags};
+use middle::ty::{self, Ty, HasTypeFlags};
 use middle::ty::{Region, ReFree};
+use middle::ty::error::TypeError;
 
 use std::cell::{Cell, RefCell};
 use std::char::from_u32;
@@ -225,19 +226,19 @@ pub trait ErrorReporting<'tcx> {
     fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
                       -> Vec<RegionResolutionError<'tcx>>;
 
-    fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::TypeError<'tcx>);
+    fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>);
 
-    fn check_and_note_conflicting_crates(&self, terr: &ty::TypeError<'tcx>, sp: Span);
+    fn check_and_note_conflicting_crates(&self, terr: &TypeError<'tcx>, sp: Span);
 
     fn report_and_explain_type_error(&self,
                                      trace: TypeTrace<'tcx>,
-                                     terr: &ty::TypeError<'tcx>);
+                                     terr: &TypeError<'tcx>);
 
     fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
 
     fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + HasTypeFlags>(
         &self,
-        exp_found: &ty::ExpectedFound<T>)
+        exp_found: &ty::error::ExpectedFound<T>)
         -> Option<String>;
 
     fn report_concrete_failure(&self,
@@ -266,7 +267,7 @@ pub trait ErrorReporting<'tcx> {
 
     fn report_processed_errors(&self,
                                var_origin: &[RegionVariableOrigin],
-                               trace_origin: &[(TypeTrace<'tcx>, ty::TypeError<'tcx>)],
+                               trace_origin: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
                                same_regions: &[SameRegions]);
 
     fn give_suggestion(&self, same_regions: &[SameRegions]);
@@ -473,7 +474,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
         }
     }
 
-    fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::TypeError<'tcx>) {
+    fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) {
         let expected_found_str = match self.values_str(&trace.values) {
             Some(v) => v,
             None => {
@@ -497,7 +498,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
     }
 
     /// Adds a note if the types come from similarly named crates
-    fn check_and_note_conflicting_crates(&self, terr: &ty::TypeError<'tcx>, sp: Span) {
+    fn check_and_note_conflicting_crates(&self, terr: &TypeError<'tcx>, sp: Span) {
         let report_path_match = |did1: DefId, did2: DefId| {
             // Only external crates, if either is from a local
             // module we could have false positives
@@ -520,7 +521,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
             }
         };
         match *terr {
-            ty::TypeError::Sorts(ref exp_found) => {
+            TypeError::Sorts(ref exp_found) => {
                 // if they are both "path types", there's a chance of ambiguity
                 // due to different versions of the same crate
                 match (&exp_found.expected.sty, &exp_found.found.sty) {
@@ -533,7 +534,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                     _ => ()
                 }
             },
-            ty::TypeError::Traits(ref exp_found) => {
+            TypeError::Traits(ref exp_found) => {
                 self.tcx.sess.note("errrr0");
                 report_path_match(exp_found.expected, exp_found.found);
             },
@@ -543,7 +544,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
 
     fn report_and_explain_type_error(&self,
                                      trace: TypeTrace<'tcx>,
-                                     terr: &ty::TypeError<'tcx>) {
+                                     terr: &TypeError<'tcx>) {
         let span = trace.origin.span();
         self.report_type_error(trace, terr);
         self.tcx.note_and_explain_type_err(terr, span);
@@ -561,7 +562,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
 
     fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + HasTypeFlags>(
         &self,
-        exp_found: &ty::ExpectedFound<T>)
+        exp_found: &ty::error::ExpectedFound<T>)
         -> Option<String>
     {
         let expected = exp_found.expected.resolve(self);
@@ -975,7 +976,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
 
     fn report_processed_errors(&self,
                                var_origins: &[RegionVariableOrigin],
-                               trace_origins: &[(TypeTrace<'tcx>, ty::TypeError<'tcx>)],
+                               trace_origins: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
                                same_regions: &[SameRegions]) {
         for vo in var_origins {
             self.report_inference_failure(vo.clone());
diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs
index 10a31f0e657e5..b0fce71d3f061 100644
--- a/src/librustc/middle/infer/higher_ranked/mod.rs
+++ b/src/librustc/middle/infer/higher_ranked/mod.rs
@@ -14,7 +14,8 @@
 use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
 use super::combine::CombineFields;
 
-use middle::ty::{self, TypeError, Binder};
+use middle::ty::{self, Binder};
+use middle::ty::error::TypeError;
 use middle::ty::fold::TypeFoldable;
 use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use syntax::codemap::Span;
@@ -358,7 +359,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
     where T: TypeFoldable<'tcx>,
           F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
 {
-    ty::fold::fold_regions(tcx, unbound_value, &mut false, |region, current_depth| {
+    tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
         // we should only be encountering "escaping" late-bound regions here,
         // because the ones at the current level should have been replaced
         // with fresh variables
@@ -438,7 +439,7 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
 
         let mut escaping_region_vars = FnvHashSet();
         for ty in &escaping_types {
-            ty::fold::collect_regions(self.tcx, ty, &mut escaping_region_vars);
+            self.tcx.collect_regions(ty, &mut escaping_region_vars);
         }
 
         region_vars.retain(|&region_vid| {
@@ -468,7 +469,7 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
      * details.
      */
 
-    let (result, map) = ty::fold::replace_late_bound_regions(infcx.tcx, binder, |br| {
+    let (result, map) = infcx.tcx.replace_late_bound_regions(binder, |br| {
         infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot)
     });
 
@@ -590,7 +591,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
     // binder is that we encountered in `value`. The caller is
     // responsible for ensuring that (a) `value` contains at least one
     // binder and (b) that binder is the one we want to use.
-    let result = ty::fold::fold_regions(infcx.tcx, &value, &mut false, |r, current_depth| {
+    let result = infcx.tcx.fold_regions(&value, &mut false, |r, current_depth| {
         match inv_skol_map.get(&r) {
             None => r,
             Some(br) => {
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 5b94f5311fd0f..b9e9ee5e24497 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -30,8 +30,9 @@ use middle::subst::Substs;
 use middle::subst::Subst;
 use middle::traits::{self, FulfillmentContext, Normalized,
                      SelectionContext, ObligationCause};
-use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
-use middle::ty::{self, Ty, TypeError, HasTypeFlags};
+use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
+use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use middle::ty::fold::{TypeFolder, TypeFoldable};
 use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_data_structures::unify::{self, UnificationTable};
@@ -171,9 +172,9 @@ impl fmt::Display for TypeOrigin {
 /// See `error_reporting.rs` for more details
 #[derive(Clone, Debug)]
 pub enum ValuePairs<'tcx> {
-    Types(ty::ExpectedFound<Ty<'tcx>>),
-    TraitRefs(ty::ExpectedFound<ty::TraitRef<'tcx>>),
-    PolyTraitRefs(ty::ExpectedFound<ty::PolyTraitRef<'tcx>>),
+    Types(ExpectedFound<Ty<'tcx>>),
+    TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
+    PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
 }
 
 /// The trace designates the path through inference that we took to
@@ -479,12 +480,12 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
 fn expected_found<T>(a_is_expected: bool,
                      a: T,
                      b: T)
-                     -> ty::ExpectedFound<T>
+                     -> ExpectedFound<T>
 {
     if a_is_expected {
-        ty::ExpectedFound {expected: a, found: b}
+        ExpectedFound {expected: a, found: b}
     } else {
-        ty::ExpectedFound {expected: b, found: a}
+        ExpectedFound {expected: b, found: a}
     }
 }
 
@@ -656,7 +657,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric {
-        use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat};
+        use middle::ty::error::UnconstrainedNumeric::Neither;
+        use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
         match ty.sty {
             ty::TyInfer(ty::IntVar(vid)) => {
                 if self.int_unification_table.borrow_mut().has_value(vid) {
@@ -1312,7 +1314,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                      sp: Span,
                                      mk_msg: M,
                                      actual_ty: String,
-                                     err: Option<&ty::TypeError<'tcx>>) where
+                                     err: Option<&TypeError<'tcx>>) where
         M: FnOnce(Option<String>, String) -> String,
     {
         self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
@@ -1323,7 +1325,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                                    mk_msg: M,
                                                    expected_ty: Option<Ty<'tcx>>,
                                                    actual_ty: String,
-                                                   err: Option<&ty::TypeError<'tcx>>) where
+                                                   err: Option<&TypeError<'tcx>>) where
         M: FnOnce(Option<String>, String) -> String,
     {
         debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty);
@@ -1349,7 +1351,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                  sp: Span,
                                  mk_msg: M,
                                  actual_ty: Ty<'tcx>,
-                                 err: Option<&ty::TypeError<'tcx>>) where
+                                 err: Option<&TypeError<'tcx>>) where
         M: FnOnce(String) -> String,
     {
         let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
@@ -1368,10 +1370,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                    span: Span,
                                    expected: Ty<'tcx>,
                                    actual: Ty<'tcx>,
-                                   err: &ty::TypeError<'tcx>) {
+                                   err: &TypeError<'tcx>) {
         let trace = TypeTrace {
             origin: Misc(span),
-            values: Types(ty::ExpectedFound {
+            values: Types(ExpectedFound {
                 expected: expected,
                 found: actual
             })
@@ -1385,14 +1387,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                             actual: type_variable::Default<'tcx>) {
         let trace = TypeTrace {
             origin: Misc(span),
-            values: Types(ty::ExpectedFound {
+            values: Types(ExpectedFound {
                 expected: expected.ty,
                 found: actual.ty
             })
         };
 
         self.report_and_explain_type_error(trace,
-            &TypeError::TyParamDefaultMismatch(ty::ExpectedFound {
+            &TypeError::TyParamDefaultMismatch(ExpectedFound {
                 expected: expected,
                 found: actual
         }));
@@ -1406,8 +1408,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         -> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
         where T : TypeFoldable<'tcx>
     {
-        ty::fold::replace_late_bound_regions(
-            self.tcx,
+        self.tcx.replace_late_bound_regions(
             value,
             |br| self.next_region_var(LateBoundRegion(span, br, lbrct)))
     }
@@ -1555,7 +1556,7 @@ impl<'tcx> TypeTrace<'tcx> {
     pub fn dummy(tcx: &ty::ctxt<'tcx>) -> TypeTrace<'tcx> {
         TypeTrace {
             origin: Misc(codemap::DUMMY_SP),
-            values: Types(ty::ExpectedFound {
+            values: Types(ExpectedFound {
                 expected: tcx.types.err,
                 found: tcx.types.err,
             })
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index a62fd8890baf6..1fc5294877065 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -23,10 +23,11 @@ use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
 use rustc_data_structures::graph::{self, Direction, NodeIndex};
 use middle::free_region::FreeRegionMap;
 use middle::region;
-use middle::ty::{self, Ty, TypeError};
+use middle::ty::{self, Ty};
 use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
 use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound};
 use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
+use middle::ty::error::TypeError;
 use middle::ty::relate::RelateResult;
 use util::common::indenter;
 use util::nodemap::{FnvHashMap, FnvHashSet};
@@ -157,7 +158,7 @@ pub enum RegionResolutionError<'tcx> {
     /// should put a lifetime. In those cases we process and put those errors
     /// into `ProcessedErrors` before we do any reporting.
     ProcessedErrors(Vec<RegionVariableOrigin>,
-                    Vec<(TypeTrace<'tcx>, ty::TypeError<'tcx>)>,
+                    Vec<(TypeTrace<'tcx>, TypeError<'tcx>)>,
                     Vec<SameRegions>),
 }
 
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 6c581a701a27e..a79837e7fb14f 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -168,7 +168,7 @@ pub enum SelectionError<'tcx> {
     Unimplemented,
     OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
                                 ty::PolyTraitRef<'tcx>,
-                                ty::TypeError<'tcx>),
+                                ty::error::TypeError<'tcx>),
     TraitNotObjectSafe(DefId),
 }
 
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index 0d320989cbc7f..f13b81ccdb22f 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -51,7 +51,7 @@ pub enum ProjectionTyError<'tcx> {
 
 #[derive(Clone)]
 pub struct MismatchedProjectionTypes<'tcx> {
-    pub err: ty::TypeError<'tcx>
+    pub err: ty::error::TypeError<'tcx>
 }
 
 #[derive(PartialEq, Eq, Debug)]
diff --git a/src/librustc/middle/ty/_match.rs b/src/librustc/middle/ty/_match.rs
index 2ebb23369bd01..5a3ad9095ad2c 100644
--- a/src/librustc/middle/ty/_match.rs
+++ b/src/librustc/middle/ty/_match.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use middle::ty::{self, Ty};
+use middle::ty::error::TypeError;
 use middle::ty::relate::{self, Relate, TypeRelation, RelateResult};
 
 /// A type "A" *matches* "B" if the fresh types in B could be
@@ -73,7 +74,7 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> {
 
             (&ty::TyInfer(_), _) |
             (_, &ty::TyInfer(_)) => {
-                Err(ty::TypeError::Sorts(relate::expected_found(self, &a, &b)))
+                Err(TypeError::Sorts(relate::expected_found(self, &a, &b)))
             }
 
             (&ty::TyError, _) | (_, &ty::TyError) => {
diff --git a/src/librustc/middle/ty/contents.rs b/src/librustc/middle/ty/contents.rs
new file mode 100644
index 0000000000000..bcce9e8ea5476
--- /dev/null
+++ b/src/librustc/middle/ty/contents.rs
@@ -0,0 +1,269 @@
+// Copyright 2012-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.
+
+use middle::def_id::{DefId};
+use middle::ty::{self, Ty};
+use util::common::{memoized};
+use util::nodemap::FnvHashMap;
+
+use std::fmt;
+use std::ops;
+
+use rustc_front::hir;
+
+/// Type contents is how the type checker reasons about kinds.
+/// They track what kinds of things are found within a type.  You can
+/// think of them as kind of an "anti-kind".  They track the kinds of values
+/// and thinks that are contained in types.  Having a larger contents for
+/// a type tends to rule that type *out* from various kinds.  For example,
+/// a type that contains a reference is not sendable.
+///
+/// The reason we compute type contents and not kinds is that it is
+/// easier for me (nmatsakis) to think about what is contained within
+/// a type than to think about what is *not* contained within a type.
+#[derive(Clone, Copy)]
+pub struct TypeContents {
+    pub bits: u64
+}
+
+macro_rules! def_type_content_sets {
+    (mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
+        #[allow(non_snake_case)]
+        mod $mname {
+            use super::TypeContents;
+            $(
+                #[allow(non_upper_case_globals)]
+                pub const $name: TypeContents = TypeContents { bits: $bits };
+             )+
+        }
+    }
+}
+
+def_type_content_sets! {
+    mod TC {
+        None                                = 0b0000_0000__0000_0000__0000,
+
+        // Things that are interior to the value (first nibble):
+        InteriorUnsafe                      = 0b0000_0000__0000_0000__0010,
+        InteriorParam                       = 0b0000_0000__0000_0000__0100,
+        // InteriorAll                         = 0b00000000__00000000__1111,
+
+        // Things that are owned by the value (second and third nibbles):
+        OwnsOwned                           = 0b0000_0000__0000_0001__0000,
+        OwnsDtor                            = 0b0000_0000__0000_0010__0000,
+        OwnsAll                             = 0b0000_0000__1111_1111__0000,
+
+        // Things that mean drop glue is necessary
+        NeedsDrop                           = 0b0000_0000__0000_0111__0000,
+
+        // All bits
+        All                                 = 0b1111_1111__1111_1111__1111
+    }
+}
+
+impl TypeContents {
+    pub fn when(&self, cond: bool) -> TypeContents {
+        if cond {*self} else {TC::None}
+    }
+
+    pub fn intersects(&self, tc: TypeContents) -> bool {
+        (self.bits & tc.bits) != 0
+    }
+
+    pub fn owns_owned(&self) -> bool {
+        self.intersects(TC::OwnsOwned)
+    }
+
+    pub fn interior_param(&self) -> bool {
+        self.intersects(TC::InteriorParam)
+    }
+
+    pub fn interior_unsafe(&self) -> bool {
+        self.intersects(TC::InteriorUnsafe)
+    }
+
+    pub fn needs_drop(&self, _: &ty::ctxt) -> bool {
+        self.intersects(TC::NeedsDrop)
+    }
+
+    /// Includes only those bits that still apply when indirected through a `Box` pointer
+    pub fn owned_pointer(&self) -> TypeContents {
+        TC::OwnsOwned | (*self & TC::OwnsAll)
+    }
+
+    pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
+        F: FnMut(&T) -> TypeContents,
+    {
+        v.iter().fold(TC::None, |tc, ty| tc | f(ty))
+    }
+
+    pub fn has_dtor(&self) -> bool {
+        self.intersects(TC::OwnsDtor)
+    }
+}
+
+impl ops::BitOr for TypeContents {
+    type Output = TypeContents;
+
+    fn bitor(self, other: TypeContents) -> TypeContents {
+        TypeContents {bits: self.bits | other.bits}
+    }
+}
+
+impl ops::BitAnd for TypeContents {
+    type Output = TypeContents;
+
+    fn bitand(self, other: TypeContents) -> TypeContents {
+        TypeContents {bits: self.bits & other.bits}
+    }
+}
+
+impl ops::Sub for TypeContents {
+    type Output = TypeContents;
+
+    fn sub(self, other: TypeContents) -> TypeContents {
+        TypeContents {bits: self.bits & !other.bits}
+    }
+}
+
+impl fmt::Debug for TypeContents {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TypeContents({:b})", self.bits)
+    }
+}
+
+impl<'tcx> ty::TyS<'tcx> {
+    pub fn type_contents(&'tcx self, cx: &ty::ctxt<'tcx>) -> TypeContents {
+        return memoized(&cx.tc_cache, self, |ty| {
+            tc_ty(cx, ty, &mut FnvHashMap())
+        });
+
+        fn tc_ty<'tcx>(cx: &ty::ctxt<'tcx>,
+                       ty: Ty<'tcx>,
+                       cache: &mut FnvHashMap<Ty<'tcx>, TypeContents>) -> TypeContents
+        {
+            // Subtle: Note that we are *not* using cx.tc_cache here but rather a
+            // private cache for this walk.  This is needed in the case of cyclic
+            // types like:
+            //
+            //     struct List { next: Box<Option<List>>, ... }
+            //
+            // When computing the type contents of such a type, we wind up deeply
+            // recursing as we go.  So when we encounter the recursive reference
+            // to List, we temporarily use TC::None as its contents.  Later we'll
+            // patch up the cache with the correct value, once we've computed it
+            // (this is basically a co-inductive process, if that helps).  So in
+            // the end we'll compute TC::OwnsOwned, in this case.
+            //
+            // The problem is, as we are doing the computation, we will also
+            // compute an *intermediate* contents for, e.g., Option<List> of
+            // TC::None.  This is ok during the computation of List itself, but if
+            // we stored this intermediate value into cx.tc_cache, then later
+            // requests for the contents of Option<List> would also yield TC::None
+            // which is incorrect.  This value was computed based on the crutch
+            // value for the type contents of list.  The correct value is
+            // TC::OwnsOwned.  This manifested as issue #4821.
+            match cache.get(&ty) {
+                Some(tc) => { return *tc; }
+                None => {}
+            }
+            match cx.tc_cache.borrow().get(&ty) {    // Must check both caches!
+                Some(tc) => { return *tc; }
+                None => {}
+            }
+            cache.insert(ty, TC::None);
+
+            let result = match ty.sty {
+                // usize and isize are ffi-unsafe
+                ty::TyUint(hir::TyUs) | ty::TyInt(hir::TyIs) => {
+                    TC::None
+                }
+
+                // Scalar and unique types are sendable, and durable
+                ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
+                ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
+                ty::TyBareFn(..) | ty::TyChar => {
+                    TC::None
+                }
+
+                ty::TyBox(typ) => {
+                    tc_ty(cx, typ, cache).owned_pointer()
+                }
+
+                ty::TyTrait(_) => {
+                    TC::All - TC::InteriorParam
+                }
+
+                ty::TyRawPtr(_) => {
+                    TC::None
+                }
+
+                ty::TyRef(_, _) => {
+                    TC::None
+                }
+
+                ty::TyArray(ty, _) => {
+                    tc_ty(cx, ty, cache)
+                }
+
+                ty::TySlice(ty) => {
+                    tc_ty(cx, ty, cache)
+                }
+                ty::TyStr => TC::None,
+
+                ty::TyClosure(_, ref substs) => {
+                    TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache))
+                }
+
+                ty::TyTuple(ref tys) => {
+                    TypeContents::union(&tys[..],
+                                        |ty| tc_ty(cx, *ty, cache))
+                }
+
+                ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+                    let mut res =
+                        TypeContents::union(&def.variants, |v| {
+                            TypeContents::union(&v.fields, |f| {
+                                tc_ty(cx, f.ty(cx, substs), cache)
+                            })
+                        });
+
+                    if def.has_dtor() {
+                        res = res | TC::OwnsDtor;
+                    }
+
+                    apply_lang_items(cx, def.did, res)
+                }
+
+                ty::TyProjection(..) |
+                ty::TyParam(_) => {
+                    TC::All
+                }
+
+                ty::TyInfer(_) |
+                ty::TyError => {
+                    cx.sess.bug("asked to compute contents of error type");
+                }
+            };
+
+            cache.insert(ty, result);
+            result
+        }
+
+        fn apply_lang_items(cx: &ty::ctxt, did: DefId, tc: TypeContents)
+                            -> TypeContents {
+            if Some(did) == cx.lang_items.unsafe_cell_type() {
+                tc | TC::InteriorUnsafe
+            } else {
+                tc
+            }
+        }
+    }
+}
diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs
new file mode 100644
index 0000000000000..4d57e0980ef54
--- /dev/null
+++ b/src/librustc/middle/ty/context.rs
@@ -0,0 +1,964 @@
+// Copyright 2012-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.
+
+//! type context book-keeping
+
+// FIXME: (@jroesch) @eddyb should remove this when he renames ctxt
+#![allow(non_camel_case_types)]
+
+use front::map as ast_map;
+use session::Session;
+use lint;
+use middle;
+use middle::def::DefMap;
+use middle::def_id::DefId;
+use middle::free_region::FreeRegionMap;
+use middle::region::RegionMaps;
+use middle::resolve_lifetime;
+use middle::stability;
+use middle::subst::{self, Subst, Substs};
+use middle::traits;
+use middle::ty::{self, TraitRef, Ty, TypeAndMut};
+use middle::ty::{TyS, TypeVariants};
+use middle::ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region};
+use middle::ty::{FreevarMap, GenericPredicates};
+use middle::ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
+use middle::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
+use middle::ty::TypeVariants::*;
+use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
+use util::nodemap::FnvHashMap;
+
+use arena::TypedArena;
+use std::borrow::Borrow;
+use std::cell::{Cell, RefCell, Ref};
+use std::hash::{Hash, Hasher};
+use std::rc::Rc;
+use syntax::abi;
+use syntax::ast::{Name, NodeId};
+use syntax::parse::token::special_idents;
+
+use rustc_front::hir;
+use rustc_front::attr;
+
+/// Internal storage
+pub struct CtxtArenas<'tcx> {
+    // internings
+    type_: TypedArena<TyS<'tcx>>,
+    substs: TypedArena<Substs<'tcx>>,
+    bare_fn: TypedArena<BareFnTy<'tcx>>,
+    region: TypedArena<Region>,
+    stability: TypedArena<attr::Stability>,
+
+    // references
+    trait_defs: TypedArena<ty::TraitDef<'tcx>>,
+    adt_defs: TypedArena<ty::AdtDefData<'tcx, 'tcx>>,
+}
+
+impl<'tcx> CtxtArenas<'tcx> {
+    pub fn new() -> CtxtArenas<'tcx> {
+        CtxtArenas {
+            type_: TypedArena::new(),
+            substs: TypedArena::new(),
+            bare_fn: TypedArena::new(),
+            region: TypedArena::new(),
+            stability: TypedArena::new(),
+
+            trait_defs: TypedArena::new(),
+            adt_defs: TypedArena::new()
+        }
+    }
+}
+
+pub struct CommonTypes<'tcx> {
+    pub bool: Ty<'tcx>,
+    pub char: Ty<'tcx>,
+    pub isize: Ty<'tcx>,
+    pub i8: Ty<'tcx>,
+    pub i16: Ty<'tcx>,
+    pub i32: Ty<'tcx>,
+    pub i64: Ty<'tcx>,
+    pub usize: Ty<'tcx>,
+    pub u8: Ty<'tcx>,
+    pub u16: Ty<'tcx>,
+    pub u32: Ty<'tcx>,
+    pub u64: Ty<'tcx>,
+    pub f32: Ty<'tcx>,
+    pub f64: Ty<'tcx>,
+    pub err: Ty<'tcx>,
+}
+
+pub struct Tables<'tcx> {
+    /// Stores the types for various nodes in the AST.  Note that this table
+    /// is not guaranteed to be populated until after typeck.  See
+    /// typeck::check::fn_ctxt for details.
+    pub node_types: NodeMap<Ty<'tcx>>,
+
+    /// Stores the type parameters which were substituted to obtain the type
+    /// of this node.  This only applies to nodes that refer to entities
+    /// parameterized by type parameters, such as generic fns, types, or
+    /// other items.
+    pub item_substs: NodeMap<ty::ItemSubsts<'tcx>>,
+
+    pub adjustments: NodeMap<ty::AutoAdjustment<'tcx>>,
+
+    pub method_map: ty::MethodMap<'tcx>,
+
+    /// Borrows
+    pub upvar_capture_map: ty::UpvarCaptureMap,
+
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_tys: DefIdMap<ty::ClosureTy<'tcx>>,
+
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_kinds: DefIdMap<ty::ClosureKind>,
+}
+
+impl<'tcx> Tables<'tcx> {
+    pub fn empty() -> Tables<'tcx> {
+        Tables {
+            node_types: FnvHashMap(),
+            item_substs: NodeMap(),
+            adjustments: NodeMap(),
+            method_map: FnvHashMap(),
+            upvar_capture_map: FnvHashMap(),
+            closure_tys: DefIdMap(),
+            closure_kinds: DefIdMap(),
+        }
+    }
+}
+
+impl<'tcx> CommonTypes<'tcx> {
+    fn new(arena: &'tcx TypedArena<TyS<'tcx>>,
+           interner: &RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>)
+           -> CommonTypes<'tcx>
+    {
+        let mk = |sty| ctxt::intern_ty(arena, interner, sty);
+        CommonTypes {
+            bool: mk(TyBool),
+            char: mk(TyChar),
+            err: mk(TyError),
+            isize: mk(TyInt(hir::TyIs)),
+            i8: mk(TyInt(hir::TyI8)),
+            i16: mk(TyInt(hir::TyI16)),
+            i32: mk(TyInt(hir::TyI32)),
+            i64: mk(TyInt(hir::TyI64)),
+            usize: mk(TyUint(hir::TyUs)),
+            u8: mk(TyUint(hir::TyU8)),
+            u16: mk(TyUint(hir::TyU16)),
+            u32: mk(TyUint(hir::TyU32)),
+            u64: mk(TyUint(hir::TyU64)),
+            f32: mk(TyFloat(hir::TyF32)),
+            f64: mk(TyFloat(hir::TyF64)),
+        }
+    }
+}
+
+/// The data structure to keep track of all the information that typechecker
+/// generates so that so that it can be reused and doesn't have to be redone
+/// later on.
+pub struct ctxt<'tcx> {
+    /// The arenas that types etc are allocated from.
+    arenas: &'tcx CtxtArenas<'tcx>,
+
+    /// Specifically use a speedy hash algorithm for this hash map, it's used
+    /// quite often.
+    // FIXME(eddyb) use a FnvHashSet<InternedTy<'tcx>> when equivalent keys can
+    // queried from a HashSet.
+    interner: RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>,
+
+    // FIXME as above, use a hashset if equivalent elements can be queried.
+    substs_interner: RefCell<FnvHashMap<&'tcx Substs<'tcx>, &'tcx Substs<'tcx>>>,
+    bare_fn_interner: RefCell<FnvHashMap<&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>>>,
+    region_interner: RefCell<FnvHashMap<&'tcx Region, &'tcx Region>>,
+    stability_interner: RefCell<FnvHashMap<&'tcx attr::Stability, &'tcx attr::Stability>>,
+
+    /// Common types, pre-interned for your convenience.
+    pub types: CommonTypes<'tcx>,
+
+    pub sess: Session,
+    pub def_map: DefMap,
+
+    pub named_region_map: resolve_lifetime::NamedRegionMap,
+
+    pub region_maps: RegionMaps,
+
+    // For each fn declared in the local crate, type check stores the
+    // free-region relationships that were deduced from its where
+    // clauses and parameter types. These are then read-again by
+    // borrowck. (They are not used during trans, and hence are not
+    // serialized or needed for cross-crate fns.)
+    free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
+    // FIXME: jroesch make this a refcell
+
+    pub tables: RefCell<Tables<'tcx>>,
+
+    /// Maps from a trait item to the trait item "descriptor"
+    pub impl_or_trait_items: RefCell<DefIdMap<ty::ImplOrTraitItem<'tcx>>>,
+
+    /// Maps from a trait def-id to a list of the def-ids of its trait items
+    pub trait_item_def_ids: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItemId>>>>,
+
+    /// A cache for the trait_items() routine
+    pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItem<'tcx>>>>>,
+
+    pub impl_trait_refs: RefCell<DefIdMap<Option<TraitRef<'tcx>>>>,
+    pub trait_defs: RefCell<DefIdMap<&'tcx ty::TraitDef<'tcx>>>,
+    pub adt_defs: RefCell<DefIdMap<ty::AdtDefMaster<'tcx>>>,
+
+    /// Maps from the def-id of an item (trait/struct/enum/fn) to its
+    /// associated predicates.
+    pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
+
+    /// Maps from the def-id of a trait to the list of
+    /// super-predicates. This is a subset of the full list of
+    /// predicates. We store these in a separate map because we must
+    /// evaluate them even during type conversion, often before the
+    /// full predicates are available (note that supertraits have
+    /// additional acyclicity requirements).
+    pub super_predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
+
+    pub map: ast_map::Map<'tcx>,
+    pub freevars: RefCell<FreevarMap>,
+    pub tcache: RefCell<DefIdMap<ty::TypeScheme<'tcx>>>,
+    pub rcache: RefCell<FnvHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
+    pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
+    pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
+    pub ty_param_defs: RefCell<NodeMap<ty::TypeParameterDef<'tcx>>>,
+    pub normalized_cache: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
+    pub lang_items: middle::lang_items::LanguageItems,
+    /// A mapping of fake provided method def_ids to the default implementation
+    pub provided_method_sources: RefCell<DefIdMap<DefId>>,
+
+    /// Maps from def-id of a type or region parameter to its
+    /// (inferred) variance.
+    pub item_variance_map: RefCell<DefIdMap<Rc<ty::ItemVariances>>>,
+
+    /// True if the variance has been computed yet; false otherwise.
+    pub variance_computed: Cell<bool>,
+
+    /// A method will be in this list if and only if it is a destructor.
+    pub destructors: RefCell<DefIdSet>,
+
+    /// Maps a DefId of a type to a list of its inherent impls.
+    /// Contains implementations of methods that are inherent to a type.
+    /// Methods in these implementations don't need to be exported.
+    pub inherent_impls: RefCell<DefIdMap<Rc<Vec<DefId>>>>,
+
+    /// Maps a DefId of an impl to a list of its items.
+    /// Note that this contains all of the impls that we know about,
+    /// including ones in other crates. It's not clear that this is the best
+    /// way to do it.
+    pub impl_items: RefCell<DefIdMap<Vec<ty::ImplOrTraitItemId>>>,
+
+    /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
+    /// present in this set can be warned about.
+    pub used_unsafe: RefCell<NodeSet>,
+
+    /// Set of nodes which mark locals as mutable which end up getting used at
+    /// some point. Local variable definitions not in this set can be warned
+    /// about.
+    pub used_mut_nodes: RefCell<NodeSet>,
+
+    /// The set of external nominal types whose implementations have been read.
+    /// This is used for lazy resolution of methods.
+    pub populated_external_types: RefCell<DefIdSet>,
+    /// The set of external primitive types whose implementations have been read.
+    /// FIXME(arielb1): why is this separate from populated_external_types?
+    pub populated_external_primitive_impls: RefCell<DefIdSet>,
+
+    /// These caches are used by const_eval when decoding external constants.
+    pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
+    pub extern_const_variants: RefCell<DefIdMap<NodeId>>,
+    pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
+
+    pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
+                                              lint::LevelSource>>,
+
+    /// The types that must be asserted to be the same size for `transmute`
+    /// to be valid. We gather up these restrictions in the intrinsicck pass
+    /// and check them in trans.
+    pub transmute_restrictions: RefCell<Vec<ty::TransmuteRestriction<'tcx>>>,
+
+    /// Maps any item's def-id to its stability index.
+    pub stability: RefCell<stability::Index<'tcx>>,
+
+    /// Caches the results of trait selection. This cache is used
+    /// for things that do not have to do with the parameters in scope.
+    pub selection_cache: traits::SelectionCache<'tcx>,
+
+    /// A set of predicates that have been fulfilled *somewhere*.
+    /// This is used to avoid duplicate work. Predicates are only
+    /// added to this set when they mention only "global" names
+    /// (i.e., no type or lifetime parameters).
+    pub fulfilled_predicates: RefCell<traits::FulfilledPredicates<'tcx>>,
+
+    /// Caches the representation hints for struct definitions.
+    pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
+
+    /// Maps Expr NodeId's to their constant qualification.
+    pub const_qualif_map: RefCell<NodeMap<middle::check_const::ConstQualif>>,
+
+    /// Caches CoerceUnsized kinds for impls on custom types.
+    pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::CustomCoerceUnsized>>,
+
+    /// Maps a cast expression to its kind. This is keyed on the
+    /// *from* expression of the cast, not the cast itself.
+    pub cast_kinds: RefCell<NodeMap<ty::cast::CastKind>>,
+
+    /// Maps Fn items to a collection of fragment infos.
+    ///
+    /// The main goal is to identify data (each of which may be moved
+    /// or assigned) whose subparts are not moved nor assigned
+    /// (i.e. their state is *unfragmented*) and corresponding ast
+    /// nodes where the path to that data is moved or assigned.
+    ///
+    /// In the long term, unfragmented values will have their
+    /// destructor entirely driven by a single stack-local drop-flag,
+    /// and their parents, the collections of the unfragmented values
+    /// (or more simply, "fragmented values"), are mapped to the
+    /// corresponding collections of stack-local drop-flags.
+    ///
+    /// (However, in the short term that is not the case; e.g. some
+    /// unfragmented paths still need to be zeroed, namely when they
+    /// reference parent data from an outer scope that was not
+    /// entirely moved, and therefore that needs to be zeroed so that
+    /// we do not get double-drop when we hit the end of the parent
+    /// scope.)
+    ///
+    /// Also: currently the table solely holds keys for node-ids of
+    /// unfragmented values (see `FragmentInfo` enum definition), but
+    /// longer-term we will need to also store mappings from
+    /// fragmented data to the set of unfragmented pieces that
+    /// constitute it.
+    pub fragment_infos: RefCell<DefIdMap<Vec<ty::FragmentInfo>>>,
+}
+impl<'tcx> ctxt<'tcx> {
+    pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind {
+        *self.tables.borrow().closure_kinds.get(&def_id).unwrap()
+    }
+
+    pub fn closure_type(&self,
+                        def_id: DefId,
+                        substs: &ClosureSubsts<'tcx>)
+                        -> ty::ClosureTy<'tcx>
+    {
+        self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, &substs.func_substs)
+    }
+
+    pub fn type_parameter_def(&self,
+                              node_id: NodeId)
+                              -> ty::TypeParameterDef<'tcx>
+    {
+        self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
+    }
+
+    pub fn node_types(&self) -> Ref<NodeMap<Ty<'tcx>>> {
+        fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap<Ty<'tcx>> {
+            &tables.node_types
+        }
+
+        Ref::map(self.tables.borrow(), projection)
+    }
+
+    pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
+        self.tables.borrow_mut().node_types.insert(id, ty);
+    }
+
+    pub fn intern_trait_def(&self, def: ty::TraitDef<'tcx>)
+                            -> &'tcx ty::TraitDef<'tcx> {
+        let did = def.trait_ref.def_id;
+        let interned = self.arenas.trait_defs.alloc(def);
+        self.trait_defs.borrow_mut().insert(did, interned);
+        interned
+    }
+
+    pub fn alloc_trait_def(&self, def: ty::TraitDef<'tcx>)
+                           -> &'tcx ty::TraitDef<'tcx> {
+        self.arenas.trait_defs.alloc(def)
+    }
+
+    pub fn intern_adt_def(&self,
+                          did: DefId,
+                          kind: ty::AdtKind,
+                          variants: Vec<ty::VariantDefData<'tcx, 'tcx>>)
+                          -> ty::AdtDefMaster<'tcx> {
+        let def = ty::AdtDefData::new(self, did, kind, variants);
+        let interned = self.arenas.adt_defs.alloc(def);
+        // this will need a transmute when reverse-variance is removed
+        self.adt_defs.borrow_mut().insert(did, interned);
+        interned
+    }
+
+    pub fn intern_stability(&self, stab: attr::Stability) -> &'tcx attr::Stability {
+        if let Some(st) = self.stability_interner.borrow().get(&stab) {
+            return st;
+        }
+
+        let interned = self.arenas.stability.alloc(stab);
+        self.stability_interner.borrow_mut().insert(interned, interned);
+        interned
+    }
+
+    pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
+        self.free_region_maps.borrow_mut()
+                             .insert(id, map);
+    }
+
+    pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap {
+        self.free_region_maps.borrow()[&id].clone()
+    }
+
+    pub fn lift<T: ?Sized + Lift<'tcx>>(&self, value: &T) -> Option<T::Lifted> {
+        value.lift_to_tcx(self)
+    }
+
+    /// Create a type context and call the closure with a `&ty::ctxt` reference
+    /// to the context. The closure enforces that the type context and any interned
+    /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
+    /// reference to the context, to allow formatting values that need it.
+    pub fn create_and_enter<F, R>(s: Session,
+                                 arenas: &'tcx CtxtArenas<'tcx>,
+                                 def_map: DefMap,
+                                 named_region_map: resolve_lifetime::NamedRegionMap,
+                                 map: ast_map::Map<'tcx>,
+                                 freevars: RefCell<FreevarMap>,
+                                 region_maps: RegionMaps,
+                                 lang_items: middle::lang_items::LanguageItems,
+                                 stability: stability::Index<'tcx>,
+                                 f: F) -> (Session, R)
+                                 where F: FnOnce(&ctxt<'tcx>) -> R
+    {
+        let interner = RefCell::new(FnvHashMap());
+        let common_types = CommonTypes::new(&arenas.type_, &interner);
+
+        tls::enter(ctxt {
+            arenas: arenas,
+            interner: interner,
+            substs_interner: RefCell::new(FnvHashMap()),
+            bare_fn_interner: RefCell::new(FnvHashMap()),
+            region_interner: RefCell::new(FnvHashMap()),
+            stability_interner: RefCell::new(FnvHashMap()),
+            types: common_types,
+            named_region_map: named_region_map,
+            region_maps: region_maps,
+            free_region_maps: RefCell::new(FnvHashMap()),
+            item_variance_map: RefCell::new(DefIdMap()),
+            variance_computed: Cell::new(false),
+            sess: s,
+            def_map: def_map,
+            tables: RefCell::new(Tables::empty()),
+            impl_trait_refs: RefCell::new(DefIdMap()),
+            trait_defs: RefCell::new(DefIdMap()),
+            adt_defs: RefCell::new(DefIdMap()),
+            predicates: RefCell::new(DefIdMap()),
+            super_predicates: RefCell::new(DefIdMap()),
+            fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()),
+            map: map,
+            freevars: freevars,
+            tcache: RefCell::new(DefIdMap()),
+            rcache: RefCell::new(FnvHashMap()),
+            tc_cache: RefCell::new(FnvHashMap()),
+            ast_ty_to_ty_cache: RefCell::new(NodeMap()),
+            impl_or_trait_items: RefCell::new(DefIdMap()),
+            trait_item_def_ids: RefCell::new(DefIdMap()),
+            trait_items_cache: RefCell::new(DefIdMap()),
+            ty_param_defs: RefCell::new(NodeMap()),
+            normalized_cache: RefCell::new(FnvHashMap()),
+            lang_items: lang_items,
+            provided_method_sources: RefCell::new(DefIdMap()),
+            destructors: RefCell::new(DefIdSet()),
+            inherent_impls: RefCell::new(DefIdMap()),
+            impl_items: RefCell::new(DefIdMap()),
+            used_unsafe: RefCell::new(NodeSet()),
+            used_mut_nodes: RefCell::new(NodeSet()),
+            populated_external_types: RefCell::new(DefIdSet()),
+            populated_external_primitive_impls: RefCell::new(DefIdSet()),
+            extern_const_statics: RefCell::new(DefIdMap()),
+            extern_const_variants: RefCell::new(DefIdMap()),
+            extern_const_fns: RefCell::new(DefIdMap()),
+            node_lint_levels: RefCell::new(FnvHashMap()),
+            transmute_restrictions: RefCell::new(Vec::new()),
+            stability: RefCell::new(stability),
+            selection_cache: traits::SelectionCache::new(),
+            repr_hint_cache: RefCell::new(DefIdMap()),
+            const_qualif_map: RefCell::new(NodeMap()),
+            custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
+            cast_kinds: RefCell::new(NodeMap()),
+            fragment_infos: RefCell::new(DefIdMap()),
+       }, f)
+    }
+}
+
+/// A trait implemented for all X<'a> types which can be safely and
+/// efficiently converted to X<'tcx> as long as they are part of the
+/// provided ty::ctxt<'tcx>.
+/// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx>
+/// by looking them up in their respective interners.
+/// None is returned if the value or one of the components is not part
+/// of the provided context.
+/// For Ty, None can be returned if either the type interner doesn't
+/// contain the TypeVariants key or if the address of the interned
+/// pointer differs. The latter case is possible if a primitive type,
+/// e.g. `()` or `u8`, was interned in a different context.
+pub trait Lift<'tcx> {
+    type Lifted;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted>;
+}
+
+impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
+    type Lifted = Ty<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Ty<'tcx>> {
+        if let Some(&ty) = tcx.interner.borrow().get(&self.sty) {
+            if *self as *const _ == ty as *const _ {
+                return Some(ty);
+            }
+        }
+        None
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
+    type Lifted = &'tcx Substs<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<&'tcx Substs<'tcx>> {
+        if let Some(&substs) = tcx.substs_interner.borrow().get(*self) {
+            if *self as *const _ == substs as *const _ {
+                return Some(substs);
+            }
+        }
+        None
+    }
+}
+
+
+pub mod tls {
+    use middle::ty;
+    use session::Session;
+
+    use std::fmt;
+    use syntax::codemap;
+
+    /// Marker type used for the scoped TLS slot.
+    /// The type context cannot be used directly because the scoped TLS
+    /// in libstd doesn't allow types generic over lifetimes.
+    struct ThreadLocalTyCx;
+
+    scoped_thread_local!(static TLS_TCX: ThreadLocalTyCx);
+
+    fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result {
+        with(|tcx| {
+            write!(f, "{}", tcx.sess.codemap().span_to_string(span))
+        })
+    }
+
+    pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F)
+                                                           -> (Session, R) {
+        let result = codemap::SPAN_DEBUG.with(|span_dbg| {
+            let original_span_debug = span_dbg.get();
+            span_dbg.set(span_debug);
+            let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx;
+            let result = TLS_TCX.set(unsafe { &*tls_ptr }, || f(&tcx));
+            span_dbg.set(original_span_debug);
+            result
+        });
+        (tcx.sess, result)
+    }
+
+    pub fn with<F: FnOnce(&ty::ctxt) -> R, R>(f: F) -> R {
+        TLS_TCX.with(|tcx| f(unsafe { &*(tcx as *const _ as *const ty::ctxt) }))
+    }
+
+    pub fn with_opt<F: FnOnce(Option<&ty::ctxt>) -> R, R>(f: F) -> R {
+        if TLS_TCX.is_set() {
+            with(|v| f(Some(v)))
+        } else {
+            f(None)
+        }
+    }
+}
+
+macro_rules! sty_debug_print {
+    ($ctxt: expr, $($variant: ident),*) => {{
+        // curious inner module to allow variant names to be used as
+        // variable names.
+        #[allow(non_snake_case)]
+        mod inner {
+            use middle::ty;
+            #[derive(Copy, Clone)]
+            struct DebugStat {
+                total: usize,
+                region_infer: usize,
+                ty_infer: usize,
+                both_infer: usize,
+            }
+
+            pub fn go(tcx: &ty::ctxt) {
+                let mut total = DebugStat {
+                    total: 0,
+                    region_infer: 0, ty_infer: 0, both_infer: 0,
+                };
+                $(let mut $variant = total;)*
+
+
+                for (_, t) in tcx.interner.borrow().iter() {
+                    let variant = match t.sty {
+                        ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
+                            ty::TyFloat(..) | ty::TyStr => continue,
+                        ty::TyError => /* unimportant */ continue,
+                        $(ty::$variant(..) => &mut $variant,)*
+                    };
+                    let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER);
+                    let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER);
+
+                    variant.total += 1;
+                    total.total += 1;
+                    if region { total.region_infer += 1; variant.region_infer += 1 }
+                    if ty { total.ty_infer += 1; variant.ty_infer += 1 }
+                    if region && ty { total.both_infer += 1; variant.both_infer += 1 }
+                }
+                println!("Ty interner             total           ty region  both");
+                $(println!("    {:18}: {uses:6} {usespc:4.1}%, \
+{ty:4.1}% {region:5.1}% {both:4.1}%",
+                           stringify!($variant),
+                           uses = $variant.total,
+                           usespc = $variant.total as f64 * 100.0 / total.total as f64,
+                           ty = $variant.ty_infer as f64 * 100.0  / total.total as f64,
+                           region = $variant.region_infer as f64 * 100.0  / total.total as f64,
+                           both = $variant.both_infer as f64 * 100.0  / total.total as f64);
+                  )*
+                println!("                  total {uses:6}        \
+{ty:4.1}% {region:5.1}% {both:4.1}%",
+                         uses = total.total,
+                         ty = total.ty_infer as f64 * 100.0  / total.total as f64,
+                         region = total.region_infer as f64 * 100.0  / total.total as f64,
+                         both = total.both_infer as f64 * 100.0  / total.total as f64)
+            }
+        }
+
+        inner::go($ctxt)
+    }}
+}
+
+impl<'tcx> ctxt<'tcx> {
+    pub fn print_debug_stats(&self) {
+        sty_debug_print!(
+            self,
+            TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyBareFn, TyTrait,
+            TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);
+
+        println!("Substs interner: #{}", self.substs_interner.borrow().len());
+        println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
+        println!("Region interner: #{}", self.region_interner.borrow().len());
+        println!("Stability interner: #{}", self.stability_interner.borrow().len());
+    }
+}
+
+
+/// An entry in the type interner.
+pub struct InternedTy<'tcx> {
+    ty: Ty<'tcx>
+}
+
+// NB: An InternedTy compares and hashes as a sty.
+impl<'tcx> PartialEq for InternedTy<'tcx> {
+    fn eq(&self, other: &InternedTy<'tcx>) -> bool {
+        self.ty.sty == other.ty.sty
+    }
+}
+
+impl<'tcx> Eq for InternedTy<'tcx> {}
+
+impl<'tcx> Hash for InternedTy<'tcx> {
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        self.ty.sty.hash(s)
+    }
+}
+
+impl<'tcx> Borrow<TypeVariants<'tcx>> for InternedTy<'tcx> {
+    fn borrow<'a>(&'a self) -> &'a TypeVariants<'tcx> {
+        &self.ty.sty
+    }
+}
+
+fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
+    bounds.is_empty() ||
+        bounds[1..].iter().enumerate().all(
+            |(index, bound)| bounds[index].sort_key() <= bound.sort_key())
+}
+
+impl<'tcx> ctxt<'tcx> {
+    // Type constructors
+    pub fn mk_substs(&self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> {
+        if let Some(substs) = self.substs_interner.borrow().get(&substs) {
+            return *substs;
+        }
+
+        let substs = self.arenas.substs.alloc(substs);
+        self.substs_interner.borrow_mut().insert(substs, substs);
+        substs
+    }
+
+    /// Create an unsafe fn ty based on a safe fn ty.
+    pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
+        assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
+        let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy {
+            unsafety: hir::Unsafety::Unsafe,
+            abi: bare_fn.abi,
+            sig: bare_fn.sig.clone()
+        });
+        self.mk_fn(None, unsafe_fn_ty_a)
+    }
+
+    pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
+        if let Some(bare_fn) = self.bare_fn_interner.borrow().get(&bare_fn) {
+            return *bare_fn;
+        }
+
+        let bare_fn = self.arenas.bare_fn.alloc(bare_fn);
+        self.bare_fn_interner.borrow_mut().insert(bare_fn, bare_fn);
+        bare_fn
+    }
+
+    pub fn mk_region(&self, region: Region) -> &'tcx Region {
+        if let Some(region) = self.region_interner.borrow().get(&region) {
+            return *region;
+        }
+
+        let region = self.arenas.region.alloc(region);
+        self.region_interner.borrow_mut().insert(region, region);
+        region
+    }
+
+    fn intern_ty(type_arena: &'tcx TypedArena<TyS<'tcx>>,
+                 interner: &RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>,
+                 st: TypeVariants<'tcx>)
+                 -> Ty<'tcx> {
+        let ty: Ty /* don't be &mut TyS */ = {
+            let mut interner = interner.borrow_mut();
+            match interner.get(&st) {
+                Some(ty) => return *ty,
+                _ => ()
+            }
+
+            let flags = super::flags::FlagComputation::for_sty(&st);
+
+            let ty = match () {
+                () => type_arena.alloc(TyS { sty: st,
+                                             flags: Cell::new(flags.flags),
+                                             region_depth: flags.depth, }),
+            };
+
+            interner.insert(InternedTy { ty: ty }, ty);
+            ty
+        };
+
+        debug!("Interned type: {:?} Pointer: {:?}",
+            ty, ty as *const TyS);
+        ty
+    }
+
+    // Interns a type/name combination, stores the resulting box in cx.interner,
+    // and returns the box as cast to an unsafe ptr (see comments for Ty above).
+    pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
+        ctxt::intern_ty(&self.arenas.type_, &self.interner, st)
+    }
+
+    pub fn mk_mach_int(&self, tm: hir::IntTy) -> Ty<'tcx> {
+        match tm {
+            hir::TyIs   => self.types.isize,
+            hir::TyI8   => self.types.i8,
+            hir::TyI16  => self.types.i16,
+            hir::TyI32  => self.types.i32,
+            hir::TyI64  => self.types.i64,
+        }
+    }
+
+    pub fn mk_mach_uint(&self, tm: hir::UintTy) -> Ty<'tcx> {
+        match tm {
+            hir::TyUs   => self.types.usize,
+            hir::TyU8   => self.types.u8,
+            hir::TyU16  => self.types.u16,
+            hir::TyU32  => self.types.u32,
+            hir::TyU64  => self.types.u64,
+        }
+    }
+
+    pub fn mk_mach_float(&self, tm: hir::FloatTy) -> Ty<'tcx> {
+        match tm {
+            hir::TyF32  => self.types.f32,
+            hir::TyF64  => self.types.f64,
+        }
+    }
+
+    pub fn mk_str(&self) -> Ty<'tcx> {
+        self.mk_ty(TyStr)
+    }
+
+    pub fn mk_static_str(&self) -> Ty<'tcx> {
+        self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str())
+    }
+
+    pub fn mk_enum(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
+        // take a copy of substs so that we own the vectors inside
+        self.mk_ty(TyEnum(def, substs))
+    }
+
+    pub fn mk_box(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(TyBox(ty))
+    }
+
+    pub fn mk_ptr(&self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(TyRawPtr(tm))
+    }
+
+    pub fn mk_ref(&self, r: &'tcx Region, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(TyRef(r, tm))
+    }
+
+    pub fn mk_mut_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutMutable})
+    }
+
+    pub fn mk_imm_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutImmutable})
+    }
+
+    pub fn mk_mut_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutMutable})
+    }
+
+    pub fn mk_imm_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutImmutable})
+    }
+
+    pub fn mk_nil_ptr(&self) -> Ty<'tcx> {
+        self.mk_imm_ptr(self.mk_nil())
+    }
+
+    pub fn mk_array(&self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> {
+        self.mk_ty(TyArray(ty, n))
+    }
+
+    pub fn mk_slice(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(TySlice(ty))
+    }
+
+    pub fn mk_tup(&self, ts: Vec<Ty<'tcx>>) -> Ty<'tcx> {
+        self.mk_ty(TyTuple(ts))
+    }
+
+    pub fn mk_nil(&self) -> Ty<'tcx> {
+        self.mk_tup(Vec::new())
+    }
+
+    pub fn mk_bool(&self) -> Ty<'tcx> {
+        self.mk_ty(TyBool)
+    }
+
+    pub fn mk_fn(&self,
+                 opt_def_id: Option<DefId>,
+                 fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(TyBareFn(opt_def_id, fty))
+    }
+
+    pub fn mk_ctor_fn(&self,
+                      def_id: DefId,
+                      input_tys: &[Ty<'tcx>],
+                      output: Ty<'tcx>) -> Ty<'tcx> {
+        let input_args = input_tys.iter().cloned().collect();
+        self.mk_fn(Some(def_id), self.mk_bare_fn(BareFnTy {
+            unsafety: hir::Unsafety::Normal,
+            abi: abi::Rust,
+            sig: ty::Binder(ty::FnSig {
+                inputs: input_args,
+                output: ty::FnConverging(output),
+                variadic: false
+            })
+        }))
+    }
+
+    pub fn mk_trait(&self,
+                    principal: ty::PolyTraitRef<'tcx>,
+                    bounds: ExistentialBounds<'tcx>)
+                    -> Ty<'tcx>
+    {
+        assert!(bound_list_is_sorted(&bounds.projection_bounds));
+
+        let inner = box TraitTy {
+            principal: principal,
+            bounds: bounds
+        };
+        self.mk_ty(TyTrait(inner))
+    }
+
+    pub fn mk_projection(&self,
+                         trait_ref: TraitRef<'tcx>,
+                         item_name: Name)
+                         -> Ty<'tcx> {
+        // take a copy of substs so that we own the vectors inside
+        let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name };
+        self.mk_ty(TyProjection(inner))
+    }
+
+    pub fn mk_struct(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
+        // take a copy of substs so that we own the vectors inside
+        self.mk_ty(TyStruct(def, substs))
+    }
+
+    pub fn mk_closure(&self,
+                      closure_id: DefId,
+                      substs: &'tcx Substs<'tcx>,
+                      tys: Vec<Ty<'tcx>>)
+                      -> Ty<'tcx> {
+        self.mk_closure_from_closure_substs(closure_id, Box::new(ClosureSubsts {
+            func_substs: substs,
+            upvar_tys: tys
+        }))
+    }
+
+    pub fn mk_closure_from_closure_substs(&self,
+                                          closure_id: DefId,
+                                          closure_substs: Box<ClosureSubsts<'tcx>>)
+                                          -> Ty<'tcx> {
+        self.mk_ty(TyClosure(closure_id, closure_substs))
+    }
+
+    pub fn mk_var(&self, v: TyVid) -> Ty<'tcx> {
+        self.mk_infer(TyVar(v))
+    }
+
+    pub fn mk_int_var(&self, v: IntVid) -> Ty<'tcx> {
+        self.mk_infer(IntVar(v))
+    }
+
+    pub fn mk_float_var(&self, v: FloatVid) -> Ty<'tcx> {
+        self.mk_infer(FloatVar(v))
+    }
+
+    pub fn mk_infer(&self, it: InferTy) -> Ty<'tcx> {
+        self.mk_ty(TyInfer(it))
+    }
+
+    pub fn mk_param(&self,
+                    space: subst::ParamSpace,
+                    index: u32,
+                    name: Name) -> Ty<'tcx> {
+        self.mk_ty(TyParam(ParamTy { space: space, idx: index, name: name }))
+    }
+
+    pub fn mk_self_type(&self) -> Ty<'tcx> {
+        self.mk_param(subst::SelfSpace, 0, special_idents::type_self.name)
+    }
+
+    pub fn mk_param_from_def(&self, def: &ty::TypeParameterDef) -> Ty<'tcx> {
+        self.mk_param(def.space, def.index, def.name)
+    }
+}
diff --git a/src/librustc/middle/ty/error.rs b/src/librustc/middle/ty/error.rs
new file mode 100644
index 0000000000000..72c4366c5bcd5
--- /dev/null
+++ b/src/librustc/middle/ty/error.rs
@@ -0,0 +1,342 @@
+// Copyright 2012-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.
+
+use middle::def_id::DefId;
+use middle::subst;
+use middle::infer::type_variable;
+use middle::ty::{self, BoundRegion, Region, Ty};
+
+use std::fmt;
+use syntax::abi;
+use syntax::ast::Name;
+use syntax::codemap::Span;
+
+use rustc_front::hir;
+
+#[derive(Clone, Copy, Debug)]
+pub struct ExpectedFound<T> {
+    pub expected: T,
+    pub found: T
+}
+
+// Data structures used in type unification
+#[derive(Clone, Debug)]
+pub enum TypeError<'tcx> {
+    Mismatch,
+    UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
+    AbiMismatch(ExpectedFound<abi::Abi>),
+    Mutability,
+    BoxMutability,
+    PtrMutability,
+    RefMutability,
+    VecMutability,
+    TupleSize(ExpectedFound<usize>),
+    FixedArraySize(ExpectedFound<usize>),
+    TyParamSize(ExpectedFound<usize>),
+    ArgCount,
+    RegionsDoesNotOutlive(Region, Region),
+    RegionsNotSame(Region, Region),
+    RegionsNoOverlap(Region, Region),
+    RegionsInsufficientlyPolymorphic(BoundRegion, Region),
+    RegionsOverlyPolymorphic(BoundRegion, Region),
+    Sorts(ExpectedFound<Ty<'tcx>>),
+    IntegerAsChar,
+    IntMismatch(ExpectedFound<ty::IntVarValue>),
+    FloatMismatch(ExpectedFound<hir::FloatTy>),
+    Traits(ExpectedFound<DefId>),
+    BuiltinBoundsMismatch(ExpectedFound<ty::BuiltinBounds>),
+    VariadicMismatch(ExpectedFound<bool>),
+    CyclicTy,
+    ConvergenceMismatch(ExpectedFound<bool>),
+    ProjectionNameMismatched(ExpectedFound<Name>),
+    ProjectionBoundsLength(ExpectedFound<usize>),
+    TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>)
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
+pub enum UnconstrainedNumeric {
+    UnconstrainedFloat,
+    UnconstrainedInt,
+    Neither,
+}
+
+/// Explains the source of a type err in a short, human readable way. This is meant to be placed
+/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
+/// afterwards to present additional details, particularly when it comes to lifetime-related
+/// errors.
+impl<'tcx> fmt::Display for TypeError<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::TypeError::*;
+        fn report_maybe_different(f: &mut fmt::Formatter,
+                                  expected: String, found: String) -> fmt::Result {
+            // A naive approach to making sure that we're not reporting silly errors such as:
+            // (expected closure, found closure).
+            if expected == found {
+                write!(f, "expected {}, found a different {}", expected, found)
+            } else {
+                write!(f, "expected {}, found {}", expected, found)
+            }
+        }
+
+        match *self {
+            CyclicTy => write!(f, "cyclic type of infinite size"),
+            Mismatch => write!(f, "types differ"),
+            UnsafetyMismatch(values) => {
+                write!(f, "expected {} fn, found {} fn",
+                       values.expected,
+                       values.found)
+            }
+            AbiMismatch(values) => {
+                write!(f, "expected {} fn, found {} fn",
+                       values.expected,
+                       values.found)
+            }
+            Mutability => write!(f, "values differ in mutability"),
+            BoxMutability => {
+                write!(f, "boxed values differ in mutability")
+            }
+            VecMutability => write!(f, "vectors differ in mutability"),
+            PtrMutability => write!(f, "pointers differ in mutability"),
+            RefMutability => write!(f, "references differ in mutability"),
+            TyParamSize(values) => {
+                write!(f, "expected a type with {} type params, \
+                           found one with {} type params",
+                       values.expected,
+                       values.found)
+            }
+            FixedArraySize(values) => {
+                write!(f, "expected an array with a fixed size of {} elements, \
+                           found one with {} elements",
+                       values.expected,
+                       values.found)
+            }
+            TupleSize(values) => {
+                write!(f, "expected a tuple with {} elements, \
+                           found one with {} elements",
+                       values.expected,
+                       values.found)
+            }
+            ArgCount => {
+                write!(f, "incorrect number of function parameters")
+            }
+            RegionsDoesNotOutlive(..) => {
+                write!(f, "lifetime mismatch")
+            }
+            RegionsNotSame(..) => {
+                write!(f, "lifetimes are not the same")
+            }
+            RegionsNoOverlap(..) => {
+                write!(f, "lifetimes do not intersect")
+            }
+            RegionsInsufficientlyPolymorphic(br, _) => {
+                write!(f, "expected bound lifetime parameter {}, \
+                           found concrete lifetime", br)
+            }
+            RegionsOverlyPolymorphic(br, _) => {
+                write!(f, "expected concrete lifetime, \
+                           found bound lifetime parameter {}", br)
+            }
+            Sorts(values) => ty::tls::with(|tcx| {
+                report_maybe_different(f, values.expected.sort_string(tcx),
+                                       values.found.sort_string(tcx))
+            }),
+            Traits(values) => ty::tls::with(|tcx| {
+                report_maybe_different(f,
+                                       format!("trait `{}`",
+                                               tcx.item_path_str(values.expected)),
+                                       format!("trait `{}`",
+                                               tcx.item_path_str(values.found)))
+            }),
+            BuiltinBoundsMismatch(values) => {
+                if values.expected.is_empty() {
+                    write!(f, "expected no bounds, found `{}`",
+                           values.found)
+                } else if values.found.is_empty() {
+                    write!(f, "expected bounds `{}`, found no bounds",
+                           values.expected)
+                } else {
+                    write!(f, "expected bounds `{}`, found bounds `{}`",
+                           values.expected,
+                           values.found)
+                }
+            }
+            IntegerAsChar => {
+                write!(f, "expected an integral type, found `char`")
+            }
+            IntMismatch(ref values) => {
+                write!(f, "expected `{:?}`, found `{:?}`",
+                       values.expected,
+                       values.found)
+            }
+            FloatMismatch(ref values) => {
+                write!(f, "expected `{:?}`, found `{:?}`",
+                       values.expected,
+                       values.found)
+            }
+            VariadicMismatch(ref values) => {
+                write!(f, "expected {} fn, found {} function",
+                       if values.expected { "variadic" } else { "non-variadic" },
+                       if values.found { "variadic" } else { "non-variadic" })
+            }
+            ConvergenceMismatch(ref values) => {
+                write!(f, "expected {} fn, found {} function",
+                       if values.expected { "converging" } else { "diverging" },
+                       if values.found { "converging" } else { "diverging" })
+            }
+            ProjectionNameMismatched(ref values) => {
+                write!(f, "expected {}, found {}",
+                       values.expected,
+                       values.found)
+            }
+            ProjectionBoundsLength(ref values) => {
+                write!(f, "expected {} associated type bindings, found {}",
+                       values.expected,
+                       values.found)
+            },
+            TyParamDefaultMismatch(ref values) => {
+                write!(f, "conflicting type parameter defaults `{}` and `{}`",
+                       values.expected.ty,
+                       values.found.ty)
+            }
+        }
+    }
+}
+
+impl<'tcx> ty::TyS<'tcx> {
+    fn sort_string(&self, cx: &ty::ctxt) -> String {
+        match self.sty {
+            ty::TyBool | ty::TyChar | ty::TyInt(_) |
+            ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr => self.to_string(),
+            ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(),
+
+            ty::TyEnum(def, _) => format!("enum `{}`", cx.item_path_str(def.did)),
+            ty::TyBox(_) => "box".to_string(),
+            ty::TyArray(_, n) => format!("array of {} elements", n),
+            ty::TySlice(_) => "slice".to_string(),
+            ty::TyRawPtr(_) => "*-ptr".to_string(),
+            ty::TyRef(_, _) => "&-ptr".to_string(),
+            ty::TyBareFn(Some(_), _) => format!("fn item"),
+            ty::TyBareFn(None, _) => "fn pointer".to_string(),
+            ty::TyTrait(ref inner) => {
+                format!("trait {}", cx.item_path_str(inner.principal_def_id()))
+            }
+            ty::TyStruct(def, _) => {
+                format!("struct `{}`", cx.item_path_str(def.did))
+            }
+            ty::TyClosure(..) => "closure".to_string(),
+            ty::TyTuple(_) => "tuple".to_string(),
+            ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
+            ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),
+            ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(),
+            ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(),
+            ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(),
+            ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
+            ty::TyProjection(_) => "associated type".to_string(),
+            ty::TyParam(ref p) => {
+                if p.space == subst::SelfSpace {
+                    "Self".to_string()
+                } else {
+                    "type parameter".to_string()
+                }
+            }
+            ty::TyError => "type error".to_string(),
+        }
+    }
+}
+
+impl<'tcx> ty::ctxt<'tcx> {
+    pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) {
+        use self::TypeError::*;
+
+        match err.clone() {
+            RegionsDoesNotOutlive(subregion, superregion) => {
+                self.note_and_explain_region("", subregion, "...");
+                self.note_and_explain_region("...does not necessarily outlive ",
+                                           superregion, "");
+            }
+            RegionsNotSame(region1, region2) => {
+                self.note_and_explain_region("", region1, "...");
+                self.note_and_explain_region("...is not the same lifetime as ",
+                                           region2, "");
+            }
+            RegionsNoOverlap(region1, region2) => {
+                self.note_and_explain_region("", region1, "...");
+                self.note_and_explain_region("...does not overlap ",
+                                           region2, "");
+            }
+            RegionsInsufficientlyPolymorphic(_, conc_region) => {
+                self.note_and_explain_region("concrete lifetime that was found is ",
+                                           conc_region, "");
+            }
+            RegionsOverlyPolymorphic(_, ty::ReVar(_)) => {
+                // don't bother to print out the message below for
+                // inference variables, it's not very illuminating.
+            }
+            RegionsOverlyPolymorphic(_, conc_region) => {
+                self.note_and_explain_region("expected concrete lifetime is ",
+                                           conc_region, "");
+            }
+            Sorts(values) => {
+                let expected_str = values.expected.sort_string(self);
+                let found_str = values.found.sort_string(self);
+                if expected_str == found_str && expected_str == "closure" {
+                    self.sess.span_note(sp,
+                        &format!("no two closures, even if identical, have the same type"));
+                    self.sess.span_help(sp,
+                        &format!("consider boxing your closure and/or \
+                                  using it as a trait object"));
+                }
+            },
+            TyParamDefaultMismatch(values) => {
+                let expected = values.expected;
+                let found = values.found;
+                self.sess.span_note(sp,
+                                    &format!("conflicting type parameter defaults `{}` and `{}`",
+                                             expected.ty,
+                                             found.ty));
+
+                match (expected.def_id.is_local(),
+                       self.map.opt_span(expected.def_id.node)) {
+                    (true, Some(span)) => {
+                        self.sess.span_note(span,
+                                            &format!("a default was defined here..."));
+                    }
+                    (_, _) => {
+                        self.sess.note(
+                            &format!("a default is defined on `{}`",
+                                     self.item_path_str(expected.def_id)));
+                    }
+                }
+
+                self.sess.span_note(
+                    expected.origin_span,
+                    &format!("...that was applied to an unconstrained type variable here"));
+
+                match (found.def_id.is_local(),
+                       self.map.opt_span(found.def_id.node)) {
+                    (true, Some(span)) => {
+                        self.sess.span_note(span,
+                                            &format!("a second default was defined here..."));
+                    }
+                    (_, _) => {
+                        self.sess.note(
+                            &format!("a second default is defined on `{}`",
+                                     self.item_path_str(found.def_id)));
+                    }
+                }
+
+                self.sess.span_note(
+                    found.origin_span,
+                    &format!("...that also applies to the same type variable here"));
+            }
+            _ => {}
+        }
+    }
+}
diff --git a/src/librustc/middle/ty/flags.rs b/src/librustc/middle/ty/flags.rs
new file mode 100644
index 0000000000000..94a50e3cac7f7
--- /dev/null
+++ b/src/librustc/middle/ty/flags.rs
@@ -0,0 +1,205 @@
+// Copyright 2012-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.
+
+use middle::subst;
+use middle::ty::{self, HasTypeFlags, Ty, TypeFlags};
+
+pub struct FlagComputation {
+    pub flags: TypeFlags,
+
+    // maximum depth of any bound region that we have seen thus far
+    pub depth: u32,
+}
+
+impl FlagComputation {
+    fn new() -> FlagComputation {
+        FlagComputation { flags: TypeFlags::empty(), depth: 0 }
+    }
+
+    pub fn for_sty(st: &ty::TypeVariants) -> FlagComputation {
+        let mut result = FlagComputation::new();
+        result.add_sty(st);
+        result
+    }
+
+    fn add_flags(&mut self, flags: TypeFlags) {
+        self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
+    }
+
+    fn add_depth(&mut self, depth: u32) {
+        if depth > self.depth {
+            self.depth = depth;
+        }
+    }
+
+    /// Adds the flags/depth from a set of types that appear within the current type, but within a
+    /// region binder.
+    fn add_bound_computation(&mut self, computation: &FlagComputation) {
+        self.add_flags(computation.flags);
+
+        // The types that contributed to `computation` occurred within
+        // a region binder, so subtract one from the region depth
+        // within when adding the depth to `self`.
+        let depth = computation.depth;
+        if depth > 0 {
+            self.add_depth(depth - 1);
+        }
+    }
+
+    fn add_sty(&mut self, st: &ty::TypeVariants) {
+        match st {
+            &ty::TyBool |
+            &ty::TyChar |
+            &ty::TyInt(_) |
+            &ty::TyFloat(_) |
+            &ty::TyUint(_) |
+            &ty::TyStr => {
+            }
+
+            // You might think that we could just return TyError for
+            // any type containing TyError as a component, and get
+            // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
+            // the exception of function types that return bot).
+            // But doing so caused sporadic memory corruption, and
+            // neither I (tjc) nor nmatsakis could figure out why,
+            // so we're doing it this way.
+            &ty::TyError => {
+                self.add_flags(TypeFlags::HAS_TY_ERR)
+            }
+
+            &ty::TyParam(ref p) => {
+                self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+                if p.space == subst::SelfSpace {
+                    self.add_flags(TypeFlags::HAS_SELF);
+                } else {
+                    self.add_flags(TypeFlags::HAS_PARAMS);
+                }
+            }
+
+            &ty::TyClosure(_, ref substs) => {
+                self.add_flags(TypeFlags::HAS_TY_CLOSURE);
+                self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+                self.add_substs(&substs.func_substs);
+                self.add_tys(&substs.upvar_tys);
+            }
+
+            &ty::TyInfer(_) => {
+                self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
+                self.add_flags(TypeFlags::HAS_TY_INFER)
+            }
+
+            &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => {
+                self.add_substs(substs);
+            }
+
+            &ty::TyProjection(ref data) => {
+                self.add_flags(TypeFlags::HAS_PROJECTION);
+                self.add_projection_ty(data);
+            }
+
+            &ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => {
+                let mut computation = FlagComputation::new();
+                computation.add_substs(principal.0.substs);
+                for projection_bound in &bounds.projection_bounds {
+                    let mut proj_computation = FlagComputation::new();
+                    proj_computation.add_projection_predicate(&projection_bound.0);
+                    self.add_bound_computation(&proj_computation);
+                }
+                self.add_bound_computation(&computation);
+
+                self.add_bounds(bounds);
+            }
+
+            &ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => {
+                self.add_ty(tt)
+            }
+
+            &ty::TyRawPtr(ref m) => {
+                self.add_ty(m.ty);
+            }
+
+            &ty::TyRef(r, ref m) => {
+                self.add_region(*r);
+                self.add_ty(m.ty);
+            }
+
+            &ty::TyTuple(ref ts) => {
+                self.add_tys(&ts[..]);
+            }
+
+            &ty::TyBareFn(_, ref f) => {
+                self.add_fn_sig(&f.sig);
+            }
+        }
+    }
+
+    fn add_ty(&mut self, ty: Ty) {
+        self.add_flags(ty.flags.get());
+        self.add_depth(ty.region_depth);
+    }
+
+    fn add_tys(&mut self, tys: &[Ty]) {
+        for &ty in tys {
+            self.add_ty(ty);
+        }
+    }
+
+    fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) {
+        let mut computation = FlagComputation::new();
+
+        computation.add_tys(&fn_sig.0.inputs);
+
+        if let ty::FnConverging(output) = fn_sig.0.output {
+            computation.add_ty(output);
+        }
+
+        self.add_bound_computation(&computation);
+    }
+
+    fn add_region(&mut self, r: ty::Region) {
+        match r {
+            ty::ReVar(..) |
+            ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
+            ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
+            ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
+            ty::ReStatic => {}
+            _ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); }
+        }
+
+        if !r.is_global() {
+            self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+        }
+    }
+
+    fn add_projection_predicate(&mut self, projection_predicate: &ty::ProjectionPredicate) {
+        self.add_projection_ty(&projection_predicate.projection_ty);
+        self.add_ty(projection_predicate.ty);
+    }
+
+    fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy) {
+        self.add_substs(projection_ty.trait_ref.substs);
+    }
+
+    fn add_substs(&mut self, substs: &subst::Substs) {
+        self.add_tys(substs.types.as_slice());
+        match substs.regions {
+            subst::ErasedRegions => {}
+            subst::NonerasedRegions(ref regions) => {
+                for &r in regions {
+                    self.add_region(r);
+                }
+            }
+        }
+    }
+
+    fn add_bounds(&mut self, bounds: &ty::ExistentialBounds) {
+        self.add_region(bounds.region_bound);
+    }
+}
diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs
index c6d213583af20..9de58369a63f8 100644
--- a/src/librustc/middle/ty/fold.rs
+++ b/src/librustc/middle/ty/fold.rs
@@ -34,16 +34,11 @@
 //! If you ever *do* need an override that doesn't exist, it's not hard
 //! to convert the degenerate pattern into the proper thing.
 
+use middle::region;
 use middle::subst;
-use middle::subst::VecPerParamSpace;
-use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
-use middle::traits;
+use middle::ty::{self, Binder, Ty, HasTypeFlags, RegionEscape};
 
 use std::fmt;
-use std::rc::Rc;
-use syntax::abi;
-use rustc_front::hir;
-use syntax::owned_slice::OwnedSlice;
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
 ///////////////////////////////////////////////////////////////////////////
@@ -74,7 +69,7 @@ pub trait TypeFolder<'tcx> : Sized {
     /// track the Debruijn index nesting level.
     fn exit_region_binder(&mut self) { }
 
-    fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+    fn fold_binder<T>(&mut self, t: &Binder<T>) -> Binder<T>
         where T : TypeFoldable<'tcx>
     {
         // FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`.
@@ -142,428 +137,18 @@ pub trait TypeFolder<'tcx> : Sized {
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// TypeFoldable implementations.
-//
-// Ideally, each type should invoke `folder.fold_foo(self)` and
-// nothing else. In some cases, though, we haven't gotten around to
-// adding methods on the `folder` yet, and thus the folding is
-// hard-coded here. This is less-flexible, because folders cannot
-// override the behavior, but there are a lot of random types and one
-// can easily refactor the folding into the TypeFolder trait as
-// needed.
-
-macro_rules! CopyImpls {
-    ($($ty:ty),+) => {
-        $(
-            impl<'tcx> TypeFoldable<'tcx> for $ty {
-                fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> $ty {
-                    *self
-                }
-            }
-        )+
-    }
-}
-
-CopyImpls! { (), hir::Unsafety, abi::Abi }
-
-impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
-        (self.0.fold_with(folder), self.1.fold_with(folder))
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Option<T> {
-        self.as_ref().map(|t| t.fold_with(folder))
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Rc<T> {
-        Rc::new((**self).fold_with(folder))
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Box<T> {
-        let content: T = (**self).fold_with(folder);
-        box content
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Vec<T> {
-        self.iter().map(|t| t.fold_with(folder)).collect()
-    }
-}
-
-impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
-        folder.fold_binder(self)
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for OwnedSlice<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> OwnedSlice<T> {
-        self.iter().map(|t| t.fold_with(folder)).collect()
-    }
-}
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> VecPerParamSpace<T> {
-
-        // Things in the Fn space take place under an additional level
-        // of region binding relative to the other spaces. This is
-        // because those entries are attached to a method, and methods
-        // always introduce a level of region binding.
-
-        let result = self.map_enumerated(|(space, index, elem)| {
-            if space == subst::FnSpace && index == 0 {
-                // enter new level when/if we reach the first thing in fn space
-                folder.enter_region_binder();
-            }
-            elem.fold_with(folder)
-        });
-        if result.len(subst::FnSpace) > 0 {
-            // if there was anything in fn space, exit the region binding level
-            folder.exit_region_binder();
-        }
-        result
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Ty<'tcx> {
-        folder.fold_ty(*self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::BareFnTy<'tcx> {
-        folder.fold_bare_fn_ty(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureTy<'tcx> {
-        folder.fold_closure_ty(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeAndMut<'tcx> {
-        folder.fold_mt(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnOutput<'tcx> {
-        folder.fold_output(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnSig<'tcx> {
-        folder.fold_fn_sig(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitRef<'tcx> {
-        folder.fold_trait_ref(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Region {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Region {
-        folder.fold_region(*self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> subst::Substs<'tcx> {
-        folder.fold_substs(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureSubsts<'tcx> {
-        let func_substs = self.func_substs.fold_with(folder);
-        ty::ClosureSubsts {
-            func_substs: folder.tcx().mk_substs(func_substs),
-            upvar_tys: self.upvar_tys.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ItemSubsts<'tcx> {
-        ty::ItemSubsts {
-            substs: self.substs.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::AutoRef<'tcx> {
-        folder.fold_autoref(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> ty::BuiltinBounds {
-        *self
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ExistentialBounds<'tcx> {
-        folder.fold_existential_bounds(self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeParameterDef<'tcx> {
-        ty::TypeParameterDef {
-            name: self.name,
-            def_id: self.def_id,
-            space: self.space,
-            index: self.index,
-            default: self.default.fold_with(folder),
-            default_def_id: self.default_def_id,
-            object_lifetime_default: self.object_lifetime_default.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ObjectLifetimeDefault {
-        match *self {
-            ty::ObjectLifetimeDefault::Ambiguous =>
-                ty::ObjectLifetimeDefault::Ambiguous,
-
-            ty::ObjectLifetimeDefault::BaseDefault =>
-                ty::ObjectLifetimeDefault::BaseDefault,
-
-            ty::ObjectLifetimeDefault::Specific(r) =>
-                ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::RegionParameterDef {
-        ty::RegionParameterDef {
-            name: self.name,
-            def_id: self.def_id,
-            space: self.space,
-            index: self.index,
-            bounds: self.bounds.fold_with(folder)
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Generics<'tcx> {
-        ty::Generics {
-            types: self.types.fold_with(folder),
-            regions: self.regions.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::GenericPredicates<'tcx> {
-        ty::GenericPredicates {
-            predicates: self.predicates.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Predicate<'tcx> {
-        match *self {
-            ty::Predicate::Trait(ref a) =>
-                ty::Predicate::Trait(a.fold_with(folder)),
-            ty::Predicate::Equate(ref binder) =>
-                ty::Predicate::Equate(binder.fold_with(folder)),
-            ty::Predicate::RegionOutlives(ref binder) =>
-                ty::Predicate::RegionOutlives(binder.fold_with(folder)),
-            ty::Predicate::TypeOutlives(ref binder) =>
-                ty::Predicate::TypeOutlives(binder.fold_with(folder)),
-            ty::Predicate::Projection(ref binder) =>
-                ty::Predicate::Projection(binder.fold_with(folder)),
-            ty::Predicate::WellFormed(data) =>
-                ty::Predicate::WellFormed(data.fold_with(folder)),
-            ty::Predicate::ObjectSafe(trait_def_id) =>
-                ty::Predicate::ObjectSafe(trait_def_id),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionPredicate<'tcx> {
-        ty::ProjectionPredicate {
-            projection_ty: self.projection_ty.fold_with(folder),
-            ty: self.ty.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionTy<'tcx> {
-        ty::ProjectionTy {
-            trait_ref: self.trait_ref.fold_with(folder),
-            item_name: self.item_name,
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::InstantiatedPredicates<'tcx> {
-        ty::InstantiatedPredicates {
-            predicates: self.predicates.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
-    where O : TypeFoldable<'tcx>
-{
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> {
-        traits::Obligation {
-            cause: self.cause.clone(),
-            recursion_depth: self.recursion_depth,
-            predicate: self.predicate.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableImplData<'tcx, N> {
-        traits::VtableImplData {
-            impl_def_id: self.impl_def_id,
-            substs: self.substs.fold_with(folder),
-            nested: self.nested.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableClosureData<'tcx, N> {
-        traits::VtableClosureData {
-            closure_def_id: self.closure_def_id,
-            substs: self.substs.fold_with(folder),
-            nested: self.nested.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
-        traits::VtableDefaultImplData {
-            trait_def_id: self.trait_def_id,
-            nested: self.nested.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> {
-        traits::VtableBuiltinData {
-            nested: self.nested.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> {
-        match *self {
-            traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
-            traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
-            traits::VtableClosure(ref d) => {
-                traits::VtableClosure(d.fold_with(folder))
-            }
-            traits::VtableFnPointer(ref d) => {
-                traits::VtableFnPointer(d.fold_with(folder))
-            }
-            traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
-            traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
-            traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
-        traits::VtableObjectData {
-            upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
-            vtable_base: self.vtable_base
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> {
-        ty::EquatePredicate(self.0.fold_with(folder),
-                            self.1.fold_with(folder))
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitPredicate<'tcx> {
-        ty::TraitPredicate {
-            trait_ref: self.trait_ref.fold_with(folder)
-        }
-    }
-}
-
-impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
-    where T : TypeFoldable<'tcx>,
-          U : TypeFoldable<'tcx>,
-{
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::OutlivesPredicate<T,U> {
-        ty::OutlivesPredicate(self.0.fold_with(folder),
-                              self.1.fold_with(folder))
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureUpvar<'tcx> {
-        ty::ClosureUpvar {
-            def: self.def,
-            span: self.span,
-            ty: self.ty.fold_with(folder),
-        }
-    }
-}
-
-impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParameterEnvironment<'a, 'tcx> {
-        ty::ParameterEnvironment {
-            tcx: self.tcx,
-            free_substs: self.free_substs.fold_with(folder),
-            implicit_region_bound: self.implicit_region_bound.fold_with(folder),
-            caller_bounds: self.caller_bounds.fold_with(folder),
-            selection_cache: traits::SelectionCache::new(),
-            free_id: self.free_id,
-        }
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // "super" routines: these are the default implementations for TypeFolder.
 //
 // They should invoke `foo.fold_with()` to do recursive folding.
 
 pub fn super_fold_binder<'tcx, T, U>(this: &mut T,
-                                     binder: &ty::Binder<U>)
-                                     -> ty::Binder<U>
+                                     binder: &Binder<U>)
+                                     -> Binder<U>
     where T : TypeFolder<'tcx>, U : TypeFoldable<'tcx>
 {
     this.enter_region_binder();
-    let result = ty::Binder(binder.0.fold_with(this));
+    let result = Binder(binder.0.fold_with(this));
     this.exit_region_binder();
     result
 }
@@ -754,6 +339,36 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where
 ///////////////////////////////////////////////////////////////////////////
 // Region folder
 
+impl<'tcx> ty::ctxt<'tcx> {
+    /// Collects the free and escaping regions in `value` into `region_set`. Returns
+    /// whether any late-bound regions were skipped
+    pub fn collect_regions<T>(&self,
+        value: &T,
+        region_set: &mut FnvHashSet<ty::Region>)
+        -> bool
+        where T : TypeFoldable<'tcx>
+    {
+        let mut have_bound_regions = false;
+        self.fold_regions(value, &mut have_bound_regions,
+                          |r, d| { region_set.insert(r.from_depth(d)); r });
+        have_bound_regions
+    }
+
+    /// Folds the escaping and free regions in `value` using `f`, and
+    /// sets `skipped_regions` to true if any late-bound region was found
+    /// and skipped.
+    pub fn fold_regions<T,F>(&self,
+        value: &T,
+        skipped_regions: &mut bool,
+        mut f: F)
+        -> T
+        where F : FnMut(ty::Region, u32) -> ty::Region,
+              T : TypeFoldable<'tcx>,
+    {
+        value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
+    }
+}
+
 /// Folds over the substructure of a type, visiting its component
 /// types and all regions that occur *free* within it.
 ///
@@ -785,33 +400,6 @@ impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
     }
 }
 
-/// Collects the free and escaping regions in `value` into `region_set`. Returns
-/// whether any late-bound regions were skipped
-pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>,
-                               value: &T,
-                               region_set: &mut FnvHashSet<ty::Region>) -> bool
-    where T : TypeFoldable<'tcx>
-{
-    let mut have_bound_regions = false;
-    fold_regions(tcx, value, &mut have_bound_regions,
-                 |r, d| { region_set.insert(r.from_depth(d)); r });
-    have_bound_regions
-}
-
-/// Folds the escaping and free regions in `value` using `f`, and
-/// sets `skipped_regions` to true if any late-bound region was found
-/// and skipped.
-pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
-                              value: &T,
-                              skipped_regions: &mut bool,
-                              mut f: F)
-                              -> T
-    where F : FnMut(ty::Region, u32) -> ty::Region,
-          T : TypeFoldable<'tcx>,
-{
-    value.fold_with(&mut RegionFolder::new(tcx, skipped_regions, &mut f))
-}
-
 impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
 {
     fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
@@ -853,6 +441,94 @@ struct RegionReplacer<'a, 'tcx: 'a> {
     map: FnvHashMap<ty::BoundRegion, ty::Region>
 }
 
+impl<'tcx> ty::ctxt<'tcx> {
+    pub fn replace_late_bound_regions<T,F>(&self,
+        value: &Binder<T>,
+        mut f: F)
+        -> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
+        where F : FnMut(ty::BoundRegion) -> ty::Region,
+              T : TypeFoldable<'tcx>,
+    {
+        debug!("replace_late_bound_regions({:?})", value);
+        let mut replacer = RegionReplacer::new(self, &mut f);
+        let result = value.skip_binder().fold_with(&mut replacer);
+        (result, replacer.map)
+    }
+
+
+    /// Replace any late-bound regions bound in `value` with free variants attached to scope-id
+    /// `scope_id`.
+    pub fn liberate_late_bound_regions<T>(&self,
+        all_outlive_scope: region::CodeExtent,
+        value: &Binder<T>)
+        -> T
+        where T : TypeFoldable<'tcx>
+    {
+        self.replace_late_bound_regions(value, |br| {
+            ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})
+        }).0
+    }
+
+    /// Flattens two binding levels into one. So `for<'a> for<'b> Foo`
+    /// becomes `for<'a,'b> Foo`.
+    pub fn flatten_late_bound_regions<T>(&self, bound2_value: &Binder<Binder<T>>)
+                                         -> Binder<T>
+        where T: TypeFoldable<'tcx>
+    {
+        let bound0_value = bound2_value.skip_binder().skip_binder();
+        let value = self.fold_regions(bound0_value, &mut false,
+                                      |region, current_depth| {
+            match region {
+                ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
+                    // should be true if no escaping regions from bound2_value
+                    assert!(debruijn.depth - current_depth <= 1);
+                    ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br)
+                }
+                _ => {
+                    region
+                }
+            }
+        });
+        Binder(value)
+    }
+
+    pub fn no_late_bound_regions<T>(&self, value: &Binder<T>) -> Option<T>
+        where T : TypeFoldable<'tcx> + RegionEscape
+    {
+        if value.0.has_escaping_regions() {
+            None
+        } else {
+            Some(value.0.clone())
+        }
+    }
+
+    /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
+    /// method lookup and a few other places where precise region relationships are not required.
+    pub fn erase_late_bound_regions<T>(&self, value: &Binder<T>) -> T
+        where T : TypeFoldable<'tcx>
+    {
+        self.replace_late_bound_regions(value, |_| ty::ReStatic).0
+    }
+
+    /// Rewrite any late-bound regions so that they are anonymous.  Region numbers are
+    /// assigned starting at 1 and increasing monotonically in the order traversed
+    /// by the fold operation.
+    ///
+    /// The chief purpose of this function is to canonicalize regions so that two
+    /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
+    /// structurally identical.  For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and
+    /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization.
+    pub fn anonymize_late_bound_regions<T>(&self, sig: &Binder<T>) -> Binder<T>
+        where T : TypeFoldable<'tcx>,
+    {
+        let mut counter = 0;
+        Binder(self.replace_late_bound_regions(sig, |_| {
+            counter += 1;
+            ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter))
+        }).0)
+    }
+}
+
 impl<'a, 'tcx> RegionReplacer<'a, 'tcx> {
     fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'tcx>
         where F : FnMut(ty::BoundRegion) -> ty::Region
@@ -866,19 +542,6 @@ impl<'a, 'tcx> RegionReplacer<'a, 'tcx> {
     }
 }
 
-pub fn replace_late_bound_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
-                                            value: &ty::Binder<T>,
-                                            mut f: F)
-                                            -> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
-    where F : FnMut(ty::BoundRegion) -> ty::Region,
-          T : TypeFoldable<'tcx>,
-{
-    debug!("replace_late_bound_regions({:?})", value);
-    let mut replacer = RegionReplacer::new(tcx, &mut f);
-    let result = value.skip_binder().fold_with(&mut replacer);
-    (result, replacer.map)
-}
-
 impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx>
 {
     fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
diff --git a/src/librustc/middle/ty/ivar.rs b/src/librustc/middle/ty/ivar.rs
new file mode 100644
index 0000000000000..73d567d0acf40
--- /dev/null
+++ b/src/librustc/middle/ty/ivar.rs
@@ -0,0 +1,72 @@
+// 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.
+
+use middle::ty::{Ty, TyS};
+
+use rustc_data_structures::ivar;
+
+use std::fmt;
+use std::marker::PhantomData;
+use core::nonzero::NonZero;
+
+/// An IVar that contains a Ty. 'lt is a (reverse-variant) upper bound
+/// on the lifetime of the IVar. This is required because of variance
+/// problems: the IVar needs to be variant with respect to 'tcx (so
+/// it can be referred to from Ty) but can only be modified if its
+/// lifetime is exactly 'tcx.
+///
+/// Safety invariants:
+///     (A) self.0, if fulfilled, is a valid Ty<'tcx>
+///     (B) no aliases to this value with a 'tcx longer than this
+///         value's 'lt exist
+///
+/// NonZero is used rather than Unique because Unique isn't Copy.
+pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar<NonZero<*const TyS<'static>>>,
+                                   PhantomData<fn(TyS<'lt>)->TyS<'tcx>>);
+
+impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
+    #[inline]
+    pub fn new() -> Self {
+        // Invariant (A) satisfied because the IVar is unfulfilled
+        // Invariant (B) because 'lt : 'tcx
+        TyIVar(ivar::Ivar::new(), PhantomData)
+    }
+
+    #[inline]
+    pub fn get(&self) -> Option<Ty<'tcx>> {
+        match self.0.get() {
+            None => None,
+            // valid because of invariant (A)
+            Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) })
+        }
+    }
+    #[inline]
+    pub fn unwrap(&self) -> Ty<'tcx> {
+        self.get().unwrap()
+    }
+
+    pub fn fulfill(&self, value: Ty<'lt>) {
+        // Invariant (A) is fulfilled, because by (B), every alias
+        // of this has a 'tcx longer than 'lt.
+        let value: *const TyS<'lt> = value;
+        // FIXME(27214): unneeded [as *const ()]
+        let value = value as *const () as *const TyS<'static>;
+        self.0.fulfill(unsafe { NonZero::new(value) })
+    }
+}
+
+impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self.get() {
+            Some(val) => write!(f, "TyIVar({:?})", val),
+            None => f.write_str("TyIVar(<unfulfilled>)")
+        }
+    }
+}
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index 21f068ca887a0..ab1160d7deb02 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,10 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// FIXME: (@jroesch) @eddyb should remove this when he renames ctxt
-#![allow(non_camel_case_types)]
-
-pub use self::InferTy::*;
 pub use self::ImplOrTraitItemId::*;
 pub use self::ClosureKind::*;
 pub use self::Variance::*;
@@ -20,71 +16,44 @@ pub use self::Representability::*;
 pub use self::AutoRef::*;
 pub use self::DtorKind::*;
 pub use self::ExplicitSelfCategory::*;
-pub use self::FnOutput::*;
-pub use self::Region::*;
 pub use self::ImplOrTraitItemContainer::*;
 pub use self::BorrowKind::*;
 pub use self::ImplOrTraitItem::*;
-pub use self::BoundRegion::*;
-pub use self::TypeVariants::*;
 pub use self::IntVarValue::*;
 pub use self::CopyImplementationError::*;
 pub use self::LvaluePreference::*;
 
-pub use self::BuiltinBound::Send as BoundSend;
-pub use self::BuiltinBound::Sized as BoundSized;
-pub use self::BuiltinBound::Copy as BoundCopy;
-pub use self::BuiltinBound::Sync as BoundSync;
-
 use back::svh::Svh;
-use session::Session;
-use lint;
 use front::map as ast_map;
 use front::map::LinkedPath;
 use metadata::csearch;
 use middle;
-use middle::check_const;
 use middle::const_eval::{self, ConstVal, ErrKind};
 use middle::const_eval::EvalHint::UncheckedExprHint;
-use middle::def::{self, DefMap, ExportMap};
+use middle::def::{self, ExportMap};
 use middle::def_id::{DefId, LOCAL_CRATE};
-use middle::free_region::FreeRegionMap;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
-use middle::region;
-use middle::resolve_lifetime;
 use middle::infer;
-use middle::infer::type_variable;
 use middle::pat_util;
-use middle::region::RegionMaps;
-use middle::stability;
 use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
 use middle::traits;
 use middle::ty;
-use middle::ty::fold::{TypeFoldable, TypeFolder};
-use middle::ty::walk::{TypeWalker};
-use util::common::{memoized, ErrorReported};
-use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
+use middle::ty::fold::TypeFolder;
+use middle::ty::walk::TypeWalker;
+use util::common::memoized;
+use util::nodemap::{NodeMap, NodeSet, DefIdMap};
 use util::nodemap::FnvHashMap;
 use util::num::ToPrimitive;
 
-use arena::TypedArena;
 use std::borrow::{Borrow, Cow};
-use std::cell::{Cell, RefCell, Ref};
+use std::cell::{Cell, RefCell};
 use std::cmp;
-use std::fmt;
 use std::hash::{Hash, SipHasher, Hasher};
 use std::iter;
-use std::marker::PhantomData;
-use std::mem;
-use std::ops;
 use std::rc::Rc;
 use std::slice;
 use std::vec::IntoIter;
-use collections::enum_set::{self, EnumSet, CLike};
-use core::nonzero::NonZero;
 use std::collections::{HashMap, HashSet};
-use rustc_data_structures::ivar;
-use syntax::abi;
 use syntax::ast::{self, CrateNum, Name, NodeId};
 use syntax::codemap::Span;
 use syntax::parse::token::{InternedString, special_idents};
@@ -94,7 +63,31 @@ use rustc_front::hir::{ItemImpl, ItemTrait};
 use rustc_front::hir::{MutImmutable, MutMutable, Visibility};
 use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
 
+pub use self::sty::{Binder, DebruijnIndex};
+pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds};
+pub use self::sty::{BareFnTy, FnSig, PolyFnSig, FnOutput, PolyFnOutput};
+pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitTy};
+pub use self::sty::{ClosureSubsts, TypeAndMut};
+pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
+pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
+pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
+pub use self::sty::BoundRegion::*;
+pub use self::sty::FnOutput::*;
+pub use self::sty::InferTy::*;
+pub use self::sty::Region::*;
+pub use self::sty::TypeVariants::*;
+
+pub use self::sty::BuiltinBound::Send as BoundSend;
+pub use self::sty::BuiltinBound::Sized as BoundSized;
+pub use self::sty::BuiltinBound::Copy as BoundCopy;
+pub use self::sty::BuiltinBound::Sync as BoundSync;
+
+pub use self::contents::TypeContents;
+pub use self::context::{ctxt, tls};
+pub use self::context::{CtxtArenas, Lift, Tables};
+
 pub mod cast;
+pub mod error;
 pub mod fast_reject;
 pub mod fold;
 pub mod _match;
@@ -103,6 +96,13 @@ pub mod relate;
 pub mod walk;
 pub mod wf;
 
+mod contents;
+mod context;
+mod flags;
+mod ivar;
+mod structural_impls;
+mod sty;
+
 pub type Disr = u64;
 
 pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
@@ -421,13 +421,6 @@ pub struct AssociatedType<'tcx> {
     pub container: ImplOrTraitItemContainer,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub struct TypeAndMut<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub mutbl: hir::Mutability,
-}
-
-
 #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
 pub struct ItemVariances {
     pub types: VecPerParamSpace<Variance>,
@@ -442,17 +435,6 @@ pub enum Variance {
     Bivariant,      // T<A> <: T<B>            -- e.g., unused type parameter
 }
 
-impl fmt::Debug for Variance {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str(match *self {
-            Covariant => "+",
-            Contravariant => "-",
-            Invariant => "o",
-            Bivariant => "*",
-        })
-    }
-}
-
 #[derive(Copy, Clone)]
 pub enum AutoAdjustment<'tcx> {
     AdjustReifyFnPointer,   // go from a fn-item type to a fn-pointer type
@@ -638,275 +620,6 @@ pub struct TransmuteRestriction<'tcx> {
     pub id: NodeId,
 }
 
-/// Internal storage
-pub struct CtxtArenas<'tcx> {
-    // internings
-    type_: TypedArena<TyS<'tcx>>,
-    substs: TypedArena<Substs<'tcx>>,
-    bare_fn: TypedArena<BareFnTy<'tcx>>,
-    region: TypedArena<Region>,
-    stability: TypedArena<attr::Stability>,
-
-    // references
-    trait_defs: TypedArena<TraitDef<'tcx>>,
-    adt_defs: TypedArena<AdtDefData<'tcx, 'tcx>>,
-}
-
-impl<'tcx> CtxtArenas<'tcx> {
-    pub fn new() -> CtxtArenas<'tcx> {
-        CtxtArenas {
-            type_: TypedArena::new(),
-            substs: TypedArena::new(),
-            bare_fn: TypedArena::new(),
-            region: TypedArena::new(),
-            stability: TypedArena::new(),
-
-            trait_defs: TypedArena::new(),
-            adt_defs: TypedArena::new()
-        }
-    }
-}
-
-pub struct CommonTypes<'tcx> {
-    pub bool: Ty<'tcx>,
-    pub char: Ty<'tcx>,
-    pub isize: Ty<'tcx>,
-    pub i8: Ty<'tcx>,
-    pub i16: Ty<'tcx>,
-    pub i32: Ty<'tcx>,
-    pub i64: Ty<'tcx>,
-    pub usize: Ty<'tcx>,
-    pub u8: Ty<'tcx>,
-    pub u16: Ty<'tcx>,
-    pub u32: Ty<'tcx>,
-    pub u64: Ty<'tcx>,
-    pub f32: Ty<'tcx>,
-    pub f64: Ty<'tcx>,
-    pub err: Ty<'tcx>,
-}
-
-pub struct Tables<'tcx> {
-    /// Stores the types for various nodes in the AST.  Note that this table
-    /// is not guaranteed to be populated until after typeck.  See
-    /// typeck::check::fn_ctxt for details.
-    pub node_types: NodeMap<Ty<'tcx>>,
-
-    /// Stores the type parameters which were substituted to obtain the type
-    /// of this node.  This only applies to nodes that refer to entities
-    /// parameterized by type parameters, such as generic fns, types, or
-    /// other items.
-    pub item_substs: NodeMap<ItemSubsts<'tcx>>,
-
-    pub adjustments: NodeMap<ty::AutoAdjustment<'tcx>>,
-
-    pub method_map: MethodMap<'tcx>,
-
-    /// Borrows
-    pub upvar_capture_map: UpvarCaptureMap,
-
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_tys: DefIdMap<ClosureTy<'tcx>>,
-
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_kinds: DefIdMap<ClosureKind>,
-}
-
-impl<'tcx> Tables<'tcx> {
-    pub fn empty() -> Tables<'tcx> {
-        Tables {
-            node_types: FnvHashMap(),
-            item_substs: NodeMap(),
-            adjustments: NodeMap(),
-            method_map: FnvHashMap(),
-            upvar_capture_map: FnvHashMap(),
-            closure_tys: DefIdMap(),
-            closure_kinds: DefIdMap(),
-        }
-    }
-}
-
-/// The data structure to keep track of all the information that typechecker
-/// generates so that so that it can be reused and doesn't have to be redone
-/// later on.
-pub struct ctxt<'tcx> {
-    /// The arenas that types etc are allocated from.
-    arenas: &'tcx CtxtArenas<'tcx>,
-
-    /// Specifically use a speedy hash algorithm for this hash map, it's used
-    /// quite often.
-    // FIXME(eddyb) use a FnvHashSet<InternedTy<'tcx>> when equivalent keys can
-    // queried from a HashSet.
-    interner: RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>,
-
-    // FIXME as above, use a hashset if equivalent elements can be queried.
-    substs_interner: RefCell<FnvHashMap<&'tcx Substs<'tcx>, &'tcx Substs<'tcx>>>,
-    bare_fn_interner: RefCell<FnvHashMap<&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>>>,
-    region_interner: RefCell<FnvHashMap<&'tcx Region, &'tcx Region>>,
-    stability_interner: RefCell<FnvHashMap<&'tcx attr::Stability, &'tcx attr::Stability>>,
-
-    /// Common types, pre-interned for your convenience.
-    pub types: CommonTypes<'tcx>,
-
-    pub sess: Session,
-    pub def_map: DefMap,
-
-    pub named_region_map: resolve_lifetime::NamedRegionMap,
-
-    pub region_maps: RegionMaps,
-
-    // For each fn declared in the local crate, type check stores the
-    // free-region relationships that were deduced from its where
-    // clauses and parameter types. These are then read-again by
-    // borrowck. (They are not used during trans, and hence are not
-    // serialized or needed for cross-crate fns.)
-    free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
-    // FIXME: jroesch make this a refcell
-
-    pub tables: RefCell<Tables<'tcx>>,
-
-    /// Maps from a trait item to the trait item "descriptor"
-    pub impl_or_trait_items: RefCell<DefIdMap<ImplOrTraitItem<'tcx>>>,
-
-    /// Maps from a trait def-id to a list of the def-ids of its trait items
-    pub trait_item_def_ids: RefCell<DefIdMap<Rc<Vec<ImplOrTraitItemId>>>>,
-
-    /// A cache for the trait_items() routine
-    pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ImplOrTraitItem<'tcx>>>>>,
-
-    pub impl_trait_refs: RefCell<DefIdMap<Option<TraitRef<'tcx>>>>,
-    pub trait_defs: RefCell<DefIdMap<&'tcx TraitDef<'tcx>>>,
-    pub adt_defs: RefCell<DefIdMap<AdtDefMaster<'tcx>>>,
-
-    /// Maps from the def-id of an item (trait/struct/enum/fn) to its
-    /// associated predicates.
-    pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
-
-    /// Maps from the def-id of a trait to the list of
-    /// super-predicates. This is a subset of the full list of
-    /// predicates. We store these in a separate map because we must
-    /// evaluate them even during type conversion, often before the
-    /// full predicates are available (note that supertraits have
-    /// additional acyclicity requirements).
-    pub super_predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
-
-    pub map: ast_map::Map<'tcx>,
-    pub freevars: RefCell<FreevarMap>,
-    pub tcache: RefCell<DefIdMap<TypeScheme<'tcx>>>,
-    pub rcache: RefCell<FnvHashMap<CReaderCacheKey, Ty<'tcx>>>,
-    pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, TypeContents>>,
-    pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
-    pub ty_param_defs: RefCell<NodeMap<TypeParameterDef<'tcx>>>,
-    pub normalized_cache: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
-    pub lang_items: middle::lang_items::LanguageItems,
-    /// A mapping of fake provided method def_ids to the default implementation
-    pub provided_method_sources: RefCell<DefIdMap<DefId>>,
-
-    /// Maps from def-id of a type or region parameter to its
-    /// (inferred) variance.
-    pub item_variance_map: RefCell<DefIdMap<Rc<ItemVariances>>>,
-
-    /// True if the variance has been computed yet; false otherwise.
-    pub variance_computed: Cell<bool>,
-
-    /// A method will be in this list if and only if it is a destructor.
-    pub destructors: RefCell<DefIdSet>,
-
-    /// Maps a DefId of a type to a list of its inherent impls.
-    /// Contains implementations of methods that are inherent to a type.
-    /// Methods in these implementations don't need to be exported.
-    pub inherent_impls: RefCell<DefIdMap<Rc<Vec<DefId>>>>,
-
-    /// Maps a DefId of an impl to a list of its items.
-    /// Note that this contains all of the impls that we know about,
-    /// including ones in other crates. It's not clear that this is the best
-    /// way to do it.
-    pub impl_items: RefCell<DefIdMap<Vec<ImplOrTraitItemId>>>,
-
-    /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
-    /// present in this set can be warned about.
-    pub used_unsafe: RefCell<NodeSet>,
-
-    /// Set of nodes which mark locals as mutable which end up getting used at
-    /// some point. Local variable definitions not in this set can be warned
-    /// about.
-    pub used_mut_nodes: RefCell<NodeSet>,
-
-    /// The set of external nominal types whose implementations have been read.
-    /// This is used for lazy resolution of methods.
-    pub populated_external_types: RefCell<DefIdSet>,
-    /// The set of external primitive types whose implementations have been read.
-    /// FIXME(arielb1): why is this separate from populated_external_types?
-    pub populated_external_primitive_impls: RefCell<DefIdSet>,
-
-    /// These caches are used by const_eval when decoding external constants.
-    pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
-    pub extern_const_variants: RefCell<DefIdMap<NodeId>>,
-    pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
-
-    pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
-                                              lint::LevelSource>>,
-
-    /// The types that must be asserted to be the same size for `transmute`
-    /// to be valid. We gather up these restrictions in the intrinsicck pass
-    /// and check them in trans.
-    pub transmute_restrictions: RefCell<Vec<TransmuteRestriction<'tcx>>>,
-
-    /// Maps any item's def-id to its stability index.
-    pub stability: RefCell<stability::Index<'tcx>>,
-
-    /// Caches the results of trait selection. This cache is used
-    /// for things that do not have to do with the parameters in scope.
-    pub selection_cache: traits::SelectionCache<'tcx>,
-
-    /// A set of predicates that have been fulfilled *somewhere*.
-    /// This is used to avoid duplicate work. Predicates are only
-    /// added to this set when they mention only "global" names
-    /// (i.e., no type or lifetime parameters).
-    pub fulfilled_predicates: RefCell<traits::FulfilledPredicates<'tcx>>,
-
-    /// Caches the representation hints for struct definitions.
-    pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
-
-    /// Maps Expr NodeId's to their constant qualification.
-    pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
-
-    /// Caches CoerceUnsized kinds for impls on custom types.
-    pub custom_coerce_unsized_kinds: RefCell<DefIdMap<CustomCoerceUnsized>>,
-
-    /// Maps a cast expression to its kind. This is keyed on the
-    /// *from* expression of the cast, not the cast itself.
-    pub cast_kinds: RefCell<NodeMap<cast::CastKind>>,
-
-    /// Maps Fn items to a collection of fragment infos.
-    ///
-    /// The main goal is to identify data (each of which may be moved
-    /// or assigned) whose subparts are not moved nor assigned
-    /// (i.e. their state is *unfragmented*) and corresponding ast
-    /// nodes where the path to that data is moved or assigned.
-    ///
-    /// In the long term, unfragmented values will have their
-    /// destructor entirely driven by a single stack-local drop-flag,
-    /// and their parents, the collections of the unfragmented values
-    /// (or more simply, "fragmented values"), are mapped to the
-    /// corresponding collections of stack-local drop-flags.
-    ///
-    /// (However, in the short term that is not the case; e.g. some
-    /// unfragmented paths still need to be zeroed, namely when they
-    /// reference parent data from an outer scope that was not
-    /// entirely moved, and therefore that needs to be zeroed so that
-    /// we do not get double-drop when we hit the end of the parent
-    /// scope.)
-    ///
-    /// Also: currently the table solely holds keys for node-ids of
-    /// unfragmented values (see `FragmentInfo` enum definition), but
-    /// longer-term we will need to also store mappings from
-    /// fragmented data to the set of unfragmented pieces that
-    /// constitute it.
-    pub fragment_infos: RefCell<DefIdMap<Vec<FragmentInfo>>>,
-}
-
 /// Describes the fragment-state associated with a NodeId.
 ///
 /// Currently only unfragmented paths have entries in the table,
@@ -918,232 +631,6 @@ pub enum FragmentInfo {
     Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId },
 }
 
-impl<'tcx> ctxt<'tcx> {
-    pub fn node_types(&self) -> Ref<NodeMap<Ty<'tcx>>> {
-        fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) ->  &'a NodeMap<Ty<'tcx>> {
-            &tables.node_types
-        }
-
-        Ref::map(self.tables.borrow(), projection)
-    }
-
-    pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
-        self.tables.borrow_mut().node_types.insert(id, ty);
-    }
-
-    pub fn intern_trait_def(&self, def: TraitDef<'tcx>) -> &'tcx TraitDef<'tcx> {
-        let did = def.trait_ref.def_id;
-        let interned = self.arenas.trait_defs.alloc(def);
-        self.trait_defs.borrow_mut().insert(did, interned);
-        interned
-    }
-
-    pub fn intern_adt_def(&self,
-                          did: DefId,
-                          kind: AdtKind,
-                          variants: Vec<VariantDefData<'tcx, 'tcx>>)
-                          -> AdtDefMaster<'tcx> {
-        let def = AdtDefData::new(self, did, kind, variants);
-        let interned = self.arenas.adt_defs.alloc(def);
-        // this will need a transmute when reverse-variance is removed
-        self.adt_defs.borrow_mut().insert(did, interned);
-        interned
-    }
-
-    pub fn intern_stability(&self, stab: attr::Stability) -> &'tcx attr::Stability {
-        if let Some(st) = self.stability_interner.borrow().get(&stab) {
-            return st;
-        }
-
-        let interned = self.arenas.stability.alloc(stab);
-        self.stability_interner.borrow_mut().insert(interned, interned);
-        interned
-    }
-
-    pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
-        self.free_region_maps.borrow_mut()
-                             .insert(id, map);
-    }
-
-    pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap {
-        self.free_region_maps.borrow()[&id].clone()
-    }
-
-    pub fn lift<T: ?Sized + Lift<'tcx>>(&self, value: &T) -> Option<T::Lifted> {
-        value.lift_to_tcx(self)
-    }
-}
-
-/// A trait implemented for all X<'a> types which can be safely and
-/// efficiently converted to X<'tcx> as long as they are part of the
-/// provided ty::ctxt<'tcx>.
-/// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx>
-/// by looking them up in their respective interners.
-/// None is returned if the value or one of the components is not part
-/// of the provided context.
-/// For Ty, None can be returned if either the type interner doesn't
-/// contain the TypeVariants key or if the address of the interned
-/// pointer differs. The latter case is possible if a primitive type,
-/// e.g. `()` or `u8`, was interned in a different context.
-pub trait Lift<'tcx> {
-    type Lifted;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted>;
-}
-
-impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
-    type Lifted = (A::Lifted, B::Lifted);
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b)))
-    }
-}
-
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
-    type Lifted = Vec<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
-        let mut result = Vec::with_capacity(self.len());
-        for x in self {
-            if let Some(value) = tcx.lift(x) {
-                result.push(value);
-            } else {
-                return None;
-            }
-        }
-        Some(result)
-    }
-}
-
-impl<'tcx> Lift<'tcx> for Region {
-    type Lifted = Self;
-    fn lift_to_tcx(&self, _: &ctxt<'tcx>) -> Option<Region> {
-        Some(*self)
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
-    type Lifted = Ty<'tcx>;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Ty<'tcx>> {
-        if let Some(&ty) = tcx.interner.borrow().get(&self.sty) {
-            if *self as *const _ == ty as *const _ {
-                return Some(ty);
-            }
-        }
-        None
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
-    type Lifted = &'tcx Substs<'tcx>;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<&'tcx Substs<'tcx>> {
-        if let Some(&substs) = tcx.substs_interner.borrow().get(*self) {
-            if *self as *const _ == substs as *const _ {
-                return Some(substs);
-            }
-        }
-        None
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> {
-    type Lifted = TraitRef<'tcx>;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<TraitRef<'tcx>> {
-        tcx.lift(&self.substs).map(|substs| TraitRef {
-            def_id: self.def_id,
-            substs: substs
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for TraitPredicate<'a> {
-    type Lifted = TraitPredicate<'tcx>;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<TraitPredicate<'tcx>> {
-        tcx.lift(&self.trait_ref).map(|trait_ref| TraitPredicate {
-            trait_ref: trait_ref
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for EquatePredicate<'a> {
-    type Lifted = EquatePredicate<'tcx>;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<EquatePredicate<'tcx>> {
-        tcx.lift(&(self.0, self.1)).map(|(a, b)| EquatePredicate(a, b))
-    }
-}
-
-impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for OutlivesPredicate<A, B> {
-    type Lifted = OutlivesPredicate<A::Lifted, B::Lifted>;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&(self.0, self.1)).map(|(a, b)| OutlivesPredicate(a, b))
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ProjectionPredicate<'a> {
-    type Lifted = ProjectionPredicate<'tcx>;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<ProjectionPredicate<'tcx>> {
-        tcx.lift(&(self.projection_ty.trait_ref, self.ty)).map(|(trait_ref, ty)| {
-            ProjectionPredicate {
-                projection_ty: ProjectionTy {
-                    trait_ref: trait_ref,
-                    item_name: self.projection_ty.item_name
-                },
-                ty: ty
-            }
-        })
-    }
-}
-
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Binder<T> {
-    type Lifted = Binder<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.0).map(|x| Binder(x))
-    }
-}
-
-pub mod tls {
-    use middle::ty;
-    use session::Session;
-
-    use std::fmt;
-    use syntax::codemap;
-
-    /// Marker type used for the scoped TLS slot.
-    /// The type context cannot be used directly because the scoped TLS
-    /// in libstd doesn't allow types generic over lifetimes.
-    struct ThreadLocalTyCx;
-
-    scoped_thread_local!(static TLS_TCX: ThreadLocalTyCx);
-
-    fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result {
-        with(|tcx| {
-            write!(f, "{}", tcx.sess.codemap().span_to_string(span))
-        })
-    }
-
-    pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F)
-                                                           -> (Session, R) {
-        let result = codemap::SPAN_DEBUG.with(|span_dbg| {
-            let original_span_debug = span_dbg.get();
-            span_dbg.set(span_debug);
-            let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx;
-            let result = TLS_TCX.set(unsafe { &*tls_ptr }, || f(&tcx));
-            span_dbg.set(original_span_debug);
-            result
-        });
-        (tcx.sess, result)
-    }
-
-    pub fn with<F: FnOnce(&ty::ctxt) -> R, R>(f: F) -> R {
-        TLS_TCX.with(|tcx| f(unsafe { &*(tcx as *const _ as *const ty::ctxt) }))
-    }
-
-    pub fn with_opt<F: FnOnce(Option<&ty::ctxt>) -> R, R>(f: F) -> R {
-        if TLS_TCX.is_set() {
-            with(|v| f(Some(v)))
-        } else {
-            f(None)
-        }
-    }
-}
-
 // Flags that we track on types. These flags are propagated upwards
 // through the type during type construction, so that we can quickly
 // check whether the type has various kinds of types in it without
@@ -1190,82 +677,6 @@ bitflags! {
     }
 }
 
-macro_rules! sty_debug_print {
-    ($ctxt: expr, $($variant: ident),*) => {{
-        // curious inner module to allow variant names to be used as
-        // variable names.
-        #[allow(non_snake_case)]
-        mod inner {
-            use middle::ty;
-            #[derive(Copy, Clone)]
-            struct DebugStat {
-                total: usize,
-                region_infer: usize,
-                ty_infer: usize,
-                both_infer: usize,
-            }
-
-            pub fn go(tcx: &ty::ctxt) {
-                let mut total = DebugStat {
-                    total: 0,
-                    region_infer: 0, ty_infer: 0, both_infer: 0,
-                };
-                $(let mut $variant = total;)*
-
-
-                for (_, t) in tcx.interner.borrow().iter() {
-                    let variant = match t.sty {
-                        ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
-                            ty::TyFloat(..) | ty::TyStr => continue,
-                        ty::TyError => /* unimportant */ continue,
-                        $(ty::$variant(..) => &mut $variant,)*
-                    };
-                    let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER);
-                    let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER);
-
-                    variant.total += 1;
-                    total.total += 1;
-                    if region { total.region_infer += 1; variant.region_infer += 1 }
-                    if ty { total.ty_infer += 1; variant.ty_infer += 1 }
-                    if region && ty { total.both_infer += 1; variant.both_infer += 1 }
-                }
-                println!("Ty interner             total           ty region  both");
-                $(println!("    {:18}: {uses:6} {usespc:4.1}%, \
-{ty:4.1}% {region:5.1}% {both:4.1}%",
-                           stringify!($variant),
-                           uses = $variant.total,
-                           usespc = $variant.total as f64 * 100.0 / total.total as f64,
-                           ty = $variant.ty_infer as f64 * 100.0  / total.total as f64,
-                           region = $variant.region_infer as f64 * 100.0  / total.total as f64,
-                           both = $variant.both_infer as f64 * 100.0  / total.total as f64);
-                  )*
-                println!("                  total {uses:6}        \
-{ty:4.1}% {region:5.1}% {both:4.1}%",
-                         uses = total.total,
-                         ty = total.ty_infer as f64 * 100.0  / total.total as f64,
-                         region = total.region_infer as f64 * 100.0  / total.total as f64,
-                         both = total.both_infer as f64 * 100.0  / total.total as f64)
-            }
-        }
-
-        inner::go($ctxt)
-    }}
-}
-
-impl<'tcx> ctxt<'tcx> {
-    pub fn print_debug_stats(&self) {
-        sty_debug_print!(
-            self,
-            TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyBareFn, TyTrait,
-            TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);
-
-        println!("Substs interner: #{}", self.substs_interner.borrow().len());
-        println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
-        println!("Region interner: #{}", self.region_interner.borrow().len());
-        println!("Stability interner: #{}", self.stability_interner.borrow().len());
-    }
-}
-
 pub struct TyS<'tcx> {
     pub sty: TypeVariants<'tcx>,
     pub flags: Cell<TypeFlags>,
@@ -1274,12 +685,6 @@ pub struct TyS<'tcx> {
     region_depth: u32,
 }
 
-impl fmt::Debug for TypeFlags {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.bits)
-    }
-}
-
 impl<'tcx> PartialEq for TyS<'tcx> {
     #[inline]
     fn eq(&self, other: &TyS<'tcx>) -> bool {
@@ -1297,323 +702,6 @@ impl<'tcx> Hash for TyS<'tcx> {
 
 pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
-/// An IVar that contains a Ty. 'lt is a (reverse-variant) upper bound
-/// on the lifetime of the IVar. This is required because of variance
-/// problems: the IVar needs to be variant with respect to 'tcx (so
-/// it can be referred to from Ty) but can only be modified if its
-/// lifetime is exactly 'tcx.
-///
-/// Safety invariants:
-///     (A) self.0, if fulfilled, is a valid Ty<'tcx>
-///     (B) no aliases to this value with a 'tcx longer than this
-///         value's 'lt exist
-///
-/// NonZero is used rather than Unique because Unique isn't Copy.
-pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar<NonZero<*const TyS<'static>>>,
-                                   PhantomData<fn(TyS<'lt>)->TyS<'tcx>>);
-
-impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
-    #[inline]
-    pub fn new() -> Self {
-        // Invariant (A) satisfied because the IVar is unfulfilled
-        // Invariant (B) because 'lt : 'tcx
-        TyIVar(ivar::Ivar::new(), PhantomData)
-    }
-
-    #[inline]
-    pub fn get(&self) -> Option<Ty<'tcx>> {
-        match self.0.get() {
-            None => None,
-            // valid because of invariant (A)
-            Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) })
-        }
-    }
-    #[inline]
-    pub fn unwrap(&self) -> Ty<'tcx> {
-        self.get().unwrap()
-    }
-
-    pub fn fulfill(&self, value: Ty<'lt>) {
-        // Invariant (A) is fulfilled, because by (B), every alias
-        // of this has a 'tcx longer than 'lt.
-        let value: *const TyS<'lt> = value;
-        // FIXME(27214): unneeded [as *const ()]
-        let value = value as *const () as *const TyS<'static>;
-        self.0.fulfill(unsafe { NonZero::new(value) })
-    }
-}
-
-impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self.get() {
-            Some(val) => write!(f, "TyIVar({:?})", val),
-            None => f.write_str("TyIVar(<unfulfilled>)")
-        }
-    }
-}
-
-/// An entry in the type interner.
-pub struct InternedTy<'tcx> {
-    ty: Ty<'tcx>
-}
-
-// NB: An InternedTy compares and hashes as a sty.
-impl<'tcx> PartialEq for InternedTy<'tcx> {
-    fn eq(&self, other: &InternedTy<'tcx>) -> bool {
-        self.ty.sty == other.ty.sty
-    }
-}
-
-impl<'tcx> Eq for InternedTy<'tcx> {}
-
-impl<'tcx> Hash for InternedTy<'tcx> {
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        self.ty.sty.hash(s)
-    }
-}
-
-impl<'tcx> Borrow<TypeVariants<'tcx>> for InternedTy<'tcx> {
-    fn borrow<'a>(&'a self) -> &'a TypeVariants<'tcx> {
-        &self.ty.sty
-    }
-}
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct BareFnTy<'tcx> {
-    pub unsafety: hir::Unsafety,
-    pub abi: abi::Abi,
-    pub sig: PolyFnSig<'tcx>,
-}
-
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub struct ClosureTy<'tcx> {
-    pub unsafety: hir::Unsafety,
-    pub abi: abi::Abi,
-    pub sig: PolyFnSig<'tcx>,
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub enum FnOutput<'tcx> {
-    FnConverging(Ty<'tcx>),
-    FnDiverging
-}
-
-impl<'tcx> FnOutput<'tcx> {
-    pub fn diverges(&self) -> bool {
-        *self == FnDiverging
-    }
-
-    pub fn unwrap(self) -> Ty<'tcx> {
-        match self {
-            ty::FnConverging(t) => t,
-            ty::FnDiverging => unreachable!()
-        }
-    }
-
-    pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> {
-        match self {
-            ty::FnConverging(t) => t,
-            ty::FnDiverging => def
-        }
-    }
-}
-
-pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
-
-impl<'tcx> PolyFnOutput<'tcx> {
-    pub fn diverges(&self) -> bool {
-        self.0.diverges()
-    }
-}
-
-/// Signature of a function type, which I have arbitrarily
-/// decided to use to refer to the input/output types.
-///
-/// - `inputs` is the list of arguments and their modes.
-/// - `output` is the return type.
-/// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub struct FnSig<'tcx> {
-    pub inputs: Vec<Ty<'tcx>>,
-    pub output: FnOutput<'tcx>,
-    pub variadic: bool
-}
-
-pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
-
-impl<'tcx> PolyFnSig<'tcx> {
-    pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
-        self.map_bound_ref(|fn_sig| fn_sig.inputs.clone())
-    }
-    pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
-        self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
-    }
-    pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
-        self.map_bound_ref(|fn_sig| fn_sig.output.clone())
-    }
-    pub fn variadic(&self) -> bool {
-        self.skip_binder().variadic
-    }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct ParamTy {
-    pub space: subst::ParamSpace,
-    pub idx: u32,
-    pub name: Name,
-}
-
-/// A [De Bruijn index][dbi] is a standard means of representing
-/// regions (and perhaps later types) in a higher-ranked setting. In
-/// particular, imagine a type like this:
-///
-///     for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
-///     ^          ^            |        |         |
-///     |          |            |        |         |
-///     |          +------------+ 1      |         |
-///     |                                |         |
-///     +--------------------------------+ 2       |
-///     |                                          |
-///     +------------------------------------------+ 1
-///
-/// In this type, there are two binders (the outer fn and the inner
-/// fn). We need to be able to determine, for any given region, which
-/// fn type it is bound by, the inner or the outer one. There are
-/// various ways you can do this, but a De Bruijn index is one of the
-/// more convenient and has some nice properties. The basic idea is to
-/// count the number of binders, inside out. Some examples should help
-/// clarify what I mean.
-///
-/// Let's start with the reference type `&'b isize` that is the first
-/// argument to the inner function. This region `'b` is assigned a De
-/// Bruijn index of 1, meaning "the innermost binder" (in this case, a
-/// fn). The region `'a` that appears in the second argument type (`&'a
-/// isize`) would then be assigned a De Bruijn index of 2, meaning "the
-/// second-innermost binder". (These indices are written on the arrays
-/// in the diagram).
-///
-/// What is interesting is that De Bruijn index attached to a particular
-/// variable will vary depending on where it appears. For example,
-/// the final type `&'a char` also refers to the region `'a` declared on
-/// the outermost fn. But this time, this reference is not nested within
-/// any other binders (i.e., it is not an argument to the inner fn, but
-/// rather the outer one). Therefore, in this case, it is assigned a
-/// De Bruijn index of 1, because the innermost binder in that location
-/// is the outer fn.
-///
-/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy)]
-pub struct DebruijnIndex {
-    // We maintain the invariant that this is never 0. So 1 indicates
-    // the innermost binder. To ensure this, create with `DebruijnIndex::new`.
-    pub depth: u32,
-}
-
-/// Representation of regions.
-///
-/// Unlike types, most region variants are "fictitious", not concrete,
-/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only
-/// ones representing concrete regions.
-///
-/// ## Bound Regions
-///
-/// These are regions that are stored behind a binder and must be substituted
-/// with some concrete region before being used. There are 2 kind of
-/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef,
-/// and are substituted by a Substs,  and late-bound, which are part of
-/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by
-/// the likes of `liberate_late_bound_regions`. The distinction exists
-/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
-///
-/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild"
-/// outside their binder, e.g. in types passed to type inference, and
-/// should first be substituted (by skolemized regions, free regions,
-/// or region variables).
-///
-/// ## Skolemized and Free Regions
-///
-/// One often wants to work with bound regions without knowing their precise
-/// identity. For example, when checking a function, the lifetime of a borrow
-/// can end up being assigned to some region parameter. In these cases,
-/// it must be ensured that bounds on the region can't be accidentally
-/// assumed without being checked.
-///
-/// The process of doing that is called "skolemization". The bound regions
-/// are replaced by skolemized markers, which don't satisfy any relation
-/// not explicity provided.
-///
-/// There are 2 kinds of skolemized regions in rustc: `ReFree` and
-/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed
-/// to be used. These also support explicit bounds: both the internally-stored
-/// *scope*, which the region is assumed to outlive, as well as other
-/// relations stored in the `FreeRegionMap`. Note that these relations
-/// aren't checked when you `make_subregion` (or `mk_eqty`), only by
-/// `resolve_regions_and_report_errors`.
-///
-/// When working with higher-ranked types, some region relations aren't
-/// yet known, so you can't just call `resolve_regions_and_report_errors`.
-/// `ReSkolemized` is designed for this purpose. In these contexts,
-/// there's also the risk that some inference variable laying around will
-/// get unified with your skolemized region: if you want to check whether
-/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
-/// with a skolemized region `'%a`, the variable `'_` would just be
-/// instantiated to the skolemized region `'%a`, which is wrong because
-/// the inference variable is supposed to satisfy the relation
-/// *for every value of the skolemized region*. To ensure that doesn't
-/// happen, you can use `leak_check`. This is more clearly explained
-/// by infer/higher_ranked/README.md.
-///
-/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
-/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
-#[derive(Clone, PartialEq, Eq, Hash, Copy)]
-pub enum Region {
-    // Region bound in a type or fn declaration which will be
-    // substituted 'early' -- that is, at the same time when type
-    // parameters are substituted.
-    ReEarlyBound(EarlyBoundRegion),
-
-    // Region bound in a function scope, which will be substituted when the
-    // function is called.
-    ReLateBound(DebruijnIndex, BoundRegion),
-
-    /// When checking a function body, the types of all arguments and so forth
-    /// that refer to bound region parameters are modified to refer to free
-    /// region parameters.
-    ReFree(FreeRegion),
-
-    /// A concrete region naming some statically determined extent
-    /// (e.g. an expression or sequence of statements) within the
-    /// current function.
-    ReScope(region::CodeExtent),
-
-    /// Static data that has an "infinite" lifetime. Top in the region lattice.
-    ReStatic,
-
-    /// A region variable.  Should not exist after typeck.
-    ReVar(RegionVid),
-
-    /// A skolemized region - basically the higher-ranked version of ReFree.
-    /// Should not exist after typeck.
-    ReSkolemized(SkolemizedRegionVid, BoundRegion),
-
-    /// Empty lifetime is for data that is never accessed.
-    /// Bottom in the region lattice. We treat ReEmpty somewhat
-    /// specially; at least right now, we do not generate instances of
-    /// it during the GLB computations, but rather
-    /// generate an error instead. This is to improve error messages.
-    /// The only way to get an instance of ReEmpty is to have a region
-    /// variable with no constraints.
-    ReEmpty,
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
-pub struct EarlyBoundRegion {
-    pub param_id: NodeId,
-    pub space: subst::ParamSpace,
-    pub index: u32,
-    pub name: Name,
-}
-
 /// Upvars do not get their own node-id. Instead, we use the pair of
 /// the original var id (that is, the root variable that is referenced
 /// by the upvar) and the id of the closure expression.
@@ -1702,628 +790,12 @@ pub struct ClosureUpvar<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
-impl Region {
-    pub fn is_bound(&self) -> bool {
-        match *self {
-            ty::ReEarlyBound(..) => true,
-            ty::ReLateBound(..) => true,
-            _ => false
-        }
-    }
-
-    pub fn needs_infer(&self) -> bool {
-        match *self {
-            ty::ReVar(..) | ty::ReSkolemized(..) => true,
-            _ => false
-        }
-    }
-
-    pub fn escapes_depth(&self, depth: u32) -> bool {
-        match *self {
-            ty::ReLateBound(debruijn, _) => debruijn.depth > depth,
-            _ => false,
-        }
-    }
-
-    /// Returns the depth of `self` from the (1-based) binding level `depth`
-    pub fn from_depth(&self, depth: u32) -> Region {
-        match *self {
-            ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
-                depth: debruijn.depth - (depth - 1)
-            }, r),
-            r => r
-        }
-    }
-}
-
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
-         RustcEncodable, RustcDecodable, Copy)]
-/// A "free" region `fr` can be interpreted as "some region
-/// at least as big as the scope `fr.scope`".
-pub struct FreeRegion {
-    pub scope: region::CodeExtent,
-    pub bound_region: BoundRegion
-}
-
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
-         RustcEncodable, RustcDecodable, Copy)]
-pub enum BoundRegion {
-    /// An anonymous region parameter for a given fn (&T)
-    BrAnon(u32),
-
-    /// Named region parameters for functions (a in &'a T)
-    ///
-    /// The def-id is needed to distinguish free regions in
-    /// the event of shadowing.
-    BrNamed(DefId, Name),
-
-    /// Fresh bound identifiers created during GLB computations.
-    BrFresh(u32),
-
-    // Anonymous region for the implicit env pointer parameter
-    // to a closure
-    BrEnv
-}
-
-// NB: If you change this, you'll probably want to change the corresponding
-// AST structure in libsyntax/ast.rs as well.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub enum TypeVariants<'tcx> {
-    /// The primitive boolean type. Written as `bool`.
-    TyBool,
-
-    /// The primitive character type; holds a Unicode scalar value
-    /// (a non-surrogate code point).  Written as `char`.
-    TyChar,
-
-    /// A primitive signed integer type. For example, `i32`.
-    TyInt(hir::IntTy),
-
-    /// A primitive unsigned integer type. For example, `u32`.
-    TyUint(hir::UintTy),
-
-    /// A primitive floating-point type. For example, `f64`.
-    TyFloat(hir::FloatTy),
-
-    /// An enumerated type, defined with `enum`.
-    ///
-    /// Substs here, possibly against intuition, *may* contain `TyParam`s.
-    /// That is, even after substitution it is possible that there are type
-    /// variables. This happens when the `TyEnum` corresponds to an enum
-    /// definition and not a concrete use of it. To get the correct `TyEnum`
-    /// from the tcx, use the `NodeId` from the `hir::Ty` and look it up in
-    /// the `ast_ty_to_ty_cache`. This is probably true for `TyStruct` as
-    /// well.
-    TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>),
-
-    /// A structure type, defined with `struct`.
-    ///
-    /// See warning about substitutions for enumerated types.
-    TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>),
-
-    /// `Box<T>`; this is nominally a struct in the documentation, but is
-    /// special-cased internally. For example, it is possible to implicitly
-    /// move the contents of a box out of that box, and methods of any type
-    /// can have type `Box<Self>`.
-    TyBox(Ty<'tcx>),
-
-    /// The pointee of a string slice. Written as `str`.
-    TyStr,
-
-    /// An array with the given length. Written as `[T; n]`.
-    TyArray(Ty<'tcx>, usize),
-
-    /// The pointee of an array slice.  Written as `[T]`.
-    TySlice(Ty<'tcx>),
-
-    /// A raw pointer. Written as `*mut T` or `*const T`
-    TyRawPtr(TypeAndMut<'tcx>),
-
-    /// A reference; a pointer with an associated lifetime. Written as
-    /// `&a mut T` or `&'a T`.
-    TyRef(&'tcx Region, TypeAndMut<'tcx>),
-
-    /// If the def-id is Some(_), then this is the type of a specific
-    /// fn item. Otherwise, if None(_), it a fn pointer type.
-    ///
-    /// FIXME: Conflating function pointers and the type of a
-    /// function is probably a terrible idea; a function pointer is a
-    /// value with a specific type, but a function can be polymorphic
-    /// or dynamically dispatched.
-    TyBareFn(Option<DefId>, &'tcx BareFnTy<'tcx>),
-
-    /// A trait, defined with `trait`.
-    TyTrait(Box<TraitTy<'tcx>>),
-
-    /// The anonymous type of a closure. Used to represent the type of
-    /// `|a| a`.
-    TyClosure(DefId, Box<ClosureSubsts<'tcx>>),
-
-    /// A tuple type.  For example, `(i32, bool)`.
-    TyTuple(Vec<Ty<'tcx>>),
-
-    /// The projection of an associated type.  For example,
-    /// `<T as Trait<..>>::N`.
-    TyProjection(ProjectionTy<'tcx>),
-
-    /// A type parameter; for example, `T` in `fn f<T>(x: T) {}
-    TyParam(ParamTy),
-
-    /// A type variable used during type-checking.
-    TyInfer(InferTy),
-
-    /// A placeholder for a type which could not be computed; this is
-    /// propagated to avoid useless error messages.
-    TyError,
-}
-
-/// A closure can be modeled as a struct that looks like:
-///
-///     struct Closure<'l0...'li, T0...Tj, U0...Uk> {
-///         upvar0: U0,
-///         ...
-///         upvark: Uk
-///     }
-///
-/// where 'l0...'li and T0...Tj are the lifetime and type parameters
-/// in scope on the function that defined the closure, and U0...Uk are
-/// type parameters representing the types of its upvars (borrowed, if
-/// appropriate).
-///
-/// So, for example, given this function:
-///
-///     fn foo<'a, T>(data: &'a mut T) {
-///          do(|| data.count += 1)
-///     }
-///
-/// the type of the closure would be something like:
-///
-///     struct Closure<'a, T, U0> {
-///         data: U0
-///     }
-///
-/// Note that the type of the upvar is not specified in the struct.
-/// You may wonder how the impl would then be able to use the upvar,
-/// if it doesn't know it's type? The answer is that the impl is
-/// (conceptually) not fully generic over Closure but rather tied to
-/// instances with the expected upvar types:
-///
-///     impl<'b, 'a, T> FnMut() for Closure<'a, T, &'b mut &'a mut T> {
-///         ...
-///     }
-///
-/// You can see that the *impl* fully specified the type of the upvar
-/// and thus knows full well that `data` has type `&'b mut &'a mut T`.
-/// (Here, I am assuming that `data` is mut-borrowed.)
-///
-/// Now, the last question you may ask is: Why include the upvar types
-/// as extra type parameters? The reason for this design is that the
-/// upvar types can reference lifetimes that are internal to the
-/// creating function. In my example above, for example, the lifetime
-/// `'b` represents the extent of the closure itself; this is some
-/// subset of `foo`, probably just the extent of the call to the to
-/// `do()`. If we just had the lifetime/type parameters from the
-/// enclosing function, we couldn't name this lifetime `'b`. Note that
-/// there can also be lifetimes in the types of the upvars themselves,
-/// if one of them happens to be a reference to something that the
-/// creating fn owns.
-///
-/// OK, you say, so why not create a more minimal set of parameters
-/// that just includes the extra lifetime parameters? The answer is
-/// primarily that it would be hard --- we don't know at the time when
-/// we create the closure type what the full types of the upvars are,
-/// nor do we know which are borrowed and which are not. In this
-/// design, we can just supply a fresh type parameter and figure that
-/// out later.
-///
-/// All right, you say, but why include the type parameters from the
-/// original function then? The answer is that trans may need them
-/// when monomorphizing, and they may not appear in the upvars.  A
-/// closure could capture no variables but still make use of some
-/// in-scope type parameter with a bound (e.g., if our example above
-/// had an extra `U: Default`, and the closure called `U::default()`).
-///
-/// There is another reason. This design (implicitly) prohibits
-/// closures from capturing themselves (except via a trait
-/// object). This simplifies closure inference considerably, since it
-/// means that when we infer the kind of a closure or its upvars, we
-/// don't have to handle cycles where the decisions we make for
-/// closure C wind up influencing the decisions we ought to make for
-/// closure C (which would then require fixed point iteration to
-/// handle). Plus it fixes an ICE. :P
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct ClosureSubsts<'tcx> {
-    /// Lifetime and type parameters from the enclosing function.
-    /// These are separated out because trans wants to pass them around
-    /// when monomorphizing.
-    pub func_substs: &'tcx Substs<'tcx>,
-
-    /// The types of the upvars. The list parallels the freevars and
-    /// `upvar_borrows` lists. These are kept distinct so that we can
-    /// easily index into them.
-    pub upvar_tys: Vec<Ty<'tcx>>
-}
-
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub struct TraitTy<'tcx> {
-    pub principal: ty::PolyTraitRef<'tcx>,
-    pub bounds: ExistentialBounds<'tcx>,
-}
-
-impl<'tcx> TraitTy<'tcx> {
-    pub fn principal_def_id(&self) -> DefId {
-        self.principal.0.def_id
-    }
-
-    /// Object types don't have a self-type specified. Therefore, when
-    /// we convert the principal trait-ref into a normal trait-ref,
-    /// you must give *some* self-type. A common choice is `mk_err()`
-    /// or some skolemized type.
-    pub fn principal_trait_ref_with_self_ty(&self,
-                                            tcx: &ctxt<'tcx>,
-                                            self_ty: Ty<'tcx>)
-                                            -> ty::PolyTraitRef<'tcx>
-    {
-        // otherwise the escaping regions would be captured by the binder
-        assert!(!self_ty.has_escaping_regions());
-
-        ty::Binder(TraitRef {
-            def_id: self.principal.0.def_id,
-            substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)),
-        })
-    }
-
-    pub fn projection_bounds_with_self_ty(&self,
-                                          tcx: &ctxt<'tcx>,
-                                          self_ty: Ty<'tcx>)
-                                          -> Vec<ty::PolyProjectionPredicate<'tcx>>
-    {
-        // otherwise the escaping regions would be captured by the binders
-        assert!(!self_ty.has_escaping_regions());
-
-        self.bounds.projection_bounds.iter()
-            .map(|in_poly_projection_predicate| {
-                let in_projection_ty = &in_poly_projection_predicate.0.projection_ty;
-                let substs = tcx.mk_substs(in_projection_ty.trait_ref.substs.with_self_ty(self_ty));
-                let trait_ref = ty::TraitRef::new(in_projection_ty.trait_ref.def_id,
-                                              substs);
-                let projection_ty = ty::ProjectionTy {
-                    trait_ref: trait_ref,
-                    item_name: in_projection_ty.item_name
-                };
-                ty::Binder(ty::ProjectionPredicate {
-                    projection_ty: projection_ty,
-                    ty: in_poly_projection_predicate.0.ty
-                })
-            })
-            .collect()
-    }
-}
-
-/// A complete reference to a trait. These take numerous guises in syntax,
-/// but perhaps the most recognizable form is in a where clause:
-///
-///     T : Foo<U>
-///
-/// This would be represented by a trait-reference where the def-id is the
-/// def-id for the trait `Foo` and the substs defines `T` as parameter 0 in the
-/// `SelfSpace` and `U` as parameter 0 in the `TypeSpace`.
-///
-/// Trait references also appear in object types like `Foo<U>`, but in
-/// that case the `Self` parameter is absent from the substitutions.
-///
-/// Note that a `TraitRef` introduces a level of region binding, to
-/// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
-/// U>` or higher-ranked object types.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct TraitRef<'tcx> {
-    pub def_id: DefId,
-    pub substs: &'tcx Substs<'tcx>,
-}
-
-pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
-
-impl<'tcx> PolyTraitRef<'tcx> {
-    pub fn self_ty(&self) -> Ty<'tcx> {
-        self.0.self_ty()
-    }
-
-    pub fn def_id(&self) -> DefId {
-        self.0.def_id
-    }
-
-    pub fn substs(&self) -> &'tcx Substs<'tcx> {
-        // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
-        self.0.substs
-    }
-
-    pub fn input_types(&self) -> &[Ty<'tcx>] {
-        // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
-        self.0.input_types()
-    }
-
-    pub fn to_poly_trait_predicate(&self) -> PolyTraitPredicate<'tcx> {
-        // Note that we preserve binding levels
-        Binder(TraitPredicate { trait_ref: self.0.clone() })
-    }
-}
-
-/// Binder is a binder for higher-ranked lifetimes. It is part of the
-/// compiler's representation for things like `for<'a> Fn(&'a isize)`
-/// (which would be represented by the type `PolyTraitRef ==
-/// Binder<TraitRef>`). Note that when we skolemize, instantiate,
-/// erase, or otherwise "discharge" these bound regions, we change the
-/// type from `Binder<T>` to just `T` (see
-/// e.g. `liberate_late_bound_regions`).
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub struct Binder<T>(pub T);
-
-impl<T> Binder<T> {
-    /// Skips the binder and returns the "bound" value. This is a
-    /// risky thing to do because it's easy to get confused about
-    /// debruijn indices and the like. It is usually better to
-    /// discharge the binder using `no_late_bound_regions` or
-    /// `replace_late_bound_regions` or something like
-    /// that. `skip_binder` is only valid when you are either
-    /// extracting data that has nothing to do with bound regions, you
-    /// are doing some sort of test that does not involve bound
-    /// regions, or you are being very careful about your depth
-    /// accounting.
-    ///
-    /// Some examples where `skip_binder` is reasonable:
-    /// - extracting the def-id from a PolyTraitRef;
-    /// - comparing the self type of a PolyTraitRef to see if it is equal to
-    ///   a type parameter `X`, since the type `X`  does not reference any regions
-    pub fn skip_binder(&self) -> &T {
-        &self.0
-    }
-
-    pub fn as_ref(&self) -> Binder<&T> {
-        ty::Binder(&self.0)
-    }
-
-    pub fn map_bound_ref<F,U>(&self, f: F) -> Binder<U>
-        where F: FnOnce(&T) -> U
-    {
-        self.as_ref().map_bound(f)
-    }
-
-    pub fn map_bound<F,U>(self, f: F) -> Binder<U>
-        where F: FnOnce(T) -> U
-    {
-        ty::Binder(f(self.0))
-    }
-}
-
 #[derive(Clone, Copy, PartialEq)]
 pub enum IntVarValue {
     IntType(hir::IntTy),
     UintType(hir::UintTy),
 }
 
-#[derive(Clone, Copy, Debug)]
-pub struct ExpectedFound<T> {
-    pub expected: T,
-    pub found: T
-}
-
-// Data structures used in type unification
-#[derive(Clone, Debug)]
-pub enum TypeError<'tcx> {
-    Mismatch,
-    UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
-    AbiMismatch(ExpectedFound<abi::Abi>),
-    Mutability,
-    BoxMutability,
-    PtrMutability,
-    RefMutability,
-    VecMutability,
-    TupleSize(ExpectedFound<usize>),
-    FixedArraySize(ExpectedFound<usize>),
-    TyParamSize(ExpectedFound<usize>),
-    ArgCount,
-    RegionsDoesNotOutlive(Region, Region),
-    RegionsNotSame(Region, Region),
-    RegionsNoOverlap(Region, Region),
-    RegionsInsufficientlyPolymorphic(BoundRegion, Region),
-    RegionsOverlyPolymorphic(BoundRegion, Region),
-    Sorts(ExpectedFound<Ty<'tcx>>),
-    IntegerAsChar,
-    IntMismatch(ExpectedFound<IntVarValue>),
-    FloatMismatch(ExpectedFound<hir::FloatTy>),
-    Traits(ExpectedFound<DefId>),
-    BuiltinBoundsMismatch(ExpectedFound<BuiltinBounds>),
-    VariadicMismatch(ExpectedFound<bool>),
-    CyclicTy,
-    ConvergenceMismatch(ExpectedFound<bool>),
-    ProjectionNameMismatched(ExpectedFound<Name>),
-    ProjectionBoundsLength(ExpectedFound<usize>),
-    TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>)
-}
-
-/// Bounds suitable for an existentially quantified type parameter
-/// such as those that appear in object types or closure types.
-#[derive(PartialEq, Eq, Hash, Clone)]
-pub struct ExistentialBounds<'tcx> {
-    pub region_bound: ty::Region,
-    pub builtin_bounds: BuiltinBounds,
-    pub projection_bounds: Vec<PolyProjectionPredicate<'tcx>>,
-}
-
-impl<'tcx> ExistentialBounds<'tcx> {
-    pub fn new(region_bound: ty::Region,
-               builtin_bounds: BuiltinBounds,
-               projection_bounds: Vec<PolyProjectionPredicate<'tcx>>)
-               -> Self {
-        let mut projection_bounds = projection_bounds;
-        ty::sort_bounds_list(&mut projection_bounds);
-        ExistentialBounds {
-            region_bound: region_bound,
-            builtin_bounds: builtin_bounds,
-            projection_bounds: projection_bounds
-        }
-    }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub struct BuiltinBounds(EnumSet<BuiltinBound>);
-
-impl BuiltinBounds {
-    pub fn empty() -> BuiltinBounds {
-        BuiltinBounds(EnumSet::new())
-    }
-
-    pub fn iter(&self) -> enum_set::Iter<BuiltinBound> {
-        self.into_iter()
-    }
-
-    pub fn to_predicates<'tcx>(&self,
-                               tcx: &ty::ctxt<'tcx>,
-                               self_ty: Ty<'tcx>) -> Vec<Predicate<'tcx>> {
-        self.iter().filter_map(|builtin_bound|
-            match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, self_ty) {
-                Ok(trait_ref) => Some(trait_ref.to_predicate()),
-                Err(ErrorReported) => { None }
-            }
-        ).collect()
-    }
-}
-
-impl ops::Deref for BuiltinBounds {
-    type Target = EnumSet<BuiltinBound>;
-    fn deref(&self) -> &Self::Target { &self.0 }
-}
-
-impl ops::DerefMut for BuiltinBounds {
-    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
-}
-
-impl<'a> IntoIterator for &'a BuiltinBounds {
-    type Item = BuiltinBound;
-    type IntoIter = enum_set::Iter<BuiltinBound>;
-    fn into_iter(self) -> Self::IntoIter {
-        (**self).into_iter()
-    }
-}
-
-#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
-           Debug, Copy)]
-#[repr(usize)]
-pub enum BuiltinBound {
-    Send,
-    Sized,
-    Copy,
-    Sync,
-}
-
-impl CLike for BuiltinBound {
-    fn to_usize(&self) -> usize {
-        *self as usize
-    }
-    fn from_usize(v: usize) -> BuiltinBound {
-        unsafe { mem::transmute(v) }
-    }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct TyVid {
-    pub index: u32
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct IntVid {
-    pub index: u32
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct FloatVid {
-    pub index: u32
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
-pub struct RegionVid {
-    pub index: u32
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct SkolemizedRegionVid {
-    pub index: u32
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub enum InferTy {
-    TyVar(TyVid),
-    IntVar(IntVid),
-    FloatVar(FloatVid),
-
-    /// A `FreshTy` is one that is generated as a replacement for an
-    /// unbound type variable. This is convenient for caching etc. See
-    /// `middle::infer::freshen` for more details.
-    FreshTy(u32),
-    FreshIntTy(u32),
-    FreshFloatTy(u32)
-}
-
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
-pub enum UnconstrainedNumeric {
-    UnconstrainedFloat,
-    UnconstrainedInt,
-    Neither,
-}
-
-
-impl fmt::Debug for TyVid {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "_#{}t", self.index)
-    }
-}
-
-impl fmt::Debug for IntVid {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "_#{}i", self.index)
-    }
-}
-
-impl fmt::Debug for FloatVid {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "_#{}f", self.index)
-    }
-}
-
-impl fmt::Debug for RegionVid {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "'_#{}r", self.index)
-    }
-}
-
-impl<'tcx> fmt::Debug for FnSig<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "({:?}; variadic: {})->{:?}", self.inputs, self.variadic, self.output)
-    }
-}
-
-impl fmt::Debug for InferTy {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            TyVar(ref v) => v.fmt(f),
-            IntVar(ref v) => v.fmt(f),
-            FloatVar(ref v) => v.fmt(f),
-            FreshTy(v) => write!(f, "FreshTy({:?})", v),
-            FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
-            FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
-        }
-    }
-}
-
-impl fmt::Debug for IntVarValue {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            IntType(ref v) => v.fmt(f),
-            UintType(ref v) => v.fmt(f),
-        }
-    }
-}
-
 /// Default region to use for the bound of objects that are
 /// supplied as the value for this type parameter. This is derived
 /// from `T:'a` annotations appearing in the type definition.  If
@@ -2620,23 +1092,6 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
     }
 }
 
-/// Represents the projection of an associated type. In explicit UFCS
-/// form this would be written `<T as Trait<..>>::N`.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub struct ProjectionTy<'tcx> {
-    /// The trait reference `T as Trait<..>`.
-    pub trait_ref: ty::TraitRef<'tcx>,
-
-    /// The name `N` of the associated type.
-    pub item_name: Name,
-}
-
-impl<'tcx> ProjectionTy<'tcx> {
-    pub fn sort_key(&self) -> (DefId, Name) {
-        (self.trait_ref.def_id, self.item_name)
-    }
-}
-
 pub trait ToPolyTraitRef<'tcx> {
     fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
 }
@@ -3314,7 +1769,7 @@ pub struct FieldDefData<'tcx, 'container: 'tcx> {
     pub vis: hir::Visibility,
     /// TyIVar is used here to allow for variance (see the doc at
     /// AdtDefData).
-    ty: TyIVar<'tcx, 'container>
+    ty: ivar::TyIVar<'tcx, 'container>
 }
 
 /// The definition of an abstract data type - a struct or enum.
@@ -3572,7 +2027,7 @@ impl<'tcx, 'container> FieldDefData<'tcx, 'container> {
             did: did,
             name: name,
             vis: vis,
-            ty: TyIVar::new()
+            ty: ivar::TyIVar::new()
         }
     }
 
@@ -3638,656 +2093,64 @@ impl ClosureKind {
     }
 }
 
-impl<'tcx> CommonTypes<'tcx> {
-    fn new(arena: &'tcx TypedArena<TyS<'tcx>>,
-           interner: &RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>)
-           -> CommonTypes<'tcx>
-    {
-        let mk = |sty| ctxt::intern_ty(arena, interner, sty);
-        CommonTypes {
-            bool: mk(TyBool),
-            char: mk(TyChar),
-            err: mk(TyError),
-            isize: mk(TyInt(hir::TyIs)),
-            i8: mk(TyInt(hir::TyI8)),
-            i16: mk(TyInt(hir::TyI16)),
-            i32: mk(TyInt(hir::TyI32)),
-            i64: mk(TyInt(hir::TyI64)),
-            usize: mk(TyUint(hir::TyUs)),
-            u8: mk(TyUint(hir::TyU8)),
-            u16: mk(TyUint(hir::TyU16)),
-            u32: mk(TyUint(hir::TyU32)),
-            u64: mk(TyUint(hir::TyU64)),
-            f32: mk(TyFloat(hir::TyF32)),
-            f64: mk(TyFloat(hir::TyF64)),
-        }
+impl<'tcx> ctxt<'tcx> {
+    pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option<hir::Mutability> {
+        pat_util::pat_contains_ref_binding(&self.def_map, pat)
     }
-}
-
-struct FlagComputation {
-    flags: TypeFlags,
-
-    // maximum depth of any bound region that we have seen thus far
-    depth: u32,
-}
 
-impl FlagComputation {
-    fn new() -> FlagComputation {
-        FlagComputation { flags: TypeFlags::empty(), depth: 0 }
+    pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option<hir::Mutability> {
+        pat_util::arm_contains_ref_binding(&self.def_map, arm)
     }
+}
 
-    fn for_sty(st: &TypeVariants) -> FlagComputation {
-        let mut result = FlagComputation::new();
-        result.add_sty(st);
-        result
+impl<'tcx> TyS<'tcx> {
+    /// Iterator that walks `self` and any types reachable from
+    /// `self`, in depth-first order. Note that just walks the types
+    /// that appear in `self`, it does not descend into the fields of
+    /// structs or variants. For example:
+    ///
+    /// ```notrust
+    /// isize => { isize }
+    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+    /// [isize] => { [isize], isize }
+    /// ```
+    pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
+        TypeWalker::new(self)
     }
 
-    fn add_flags(&mut self, flags: TypeFlags) {
-        self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
+    /// Iterator that walks the immediate children of `self`.  Hence
+    /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
+    /// (but not `i32`, like `walk`).
+    pub fn walk_shallow(&'tcx self) -> IntoIter<Ty<'tcx>> {
+        walk::walk_shallow(self)
     }
 
-    fn add_depth(&mut self, depth: u32) {
-        if depth > self.depth {
-            self.depth = depth;
+    pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
+        match self.sty {
+            ty::TyParam(ref d) => Some(d.clone()),
+            _ => None,
         }
     }
 
-    /// Adds the flags/depth from a set of types that appear within the current type, but within a
-    /// region binder.
-    fn add_bound_computation(&mut self, computation: &FlagComputation) {
-        self.add_flags(computation.flags);
-
-        // The types that contributed to `computation` occurred within
-        // a region binder, so subtract one from the region depth
-        // within when adding the depth to `self`.
-        let depth = computation.depth;
-        if depth > 0 {
-            self.add_depth(depth - 1);
+    pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
+        match self.sty {
+            ty::TyParam(ref data) => data.space == space && data.idx == index,
+            _ => false,
         }
     }
 
-    fn add_sty(&mut self, st: &TypeVariants) {
-        match st {
-            &TyBool |
-            &TyChar |
-            &TyInt(_) |
-            &TyFloat(_) |
-            &TyUint(_) |
-            &TyStr => {
-            }
-
-            // You might think that we could just return TyError for
-            // any type containing TyError as a component, and get
-            // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
-            // the exception of function types that return bot).
-            // But doing so caused sporadic memory corruption, and
-            // neither I (tjc) nor nmatsakis could figure out why,
-            // so we're doing it this way.
-            &TyError => {
-                self.add_flags(TypeFlags::HAS_TY_ERR)
+    /// Returns the regions directly referenced from this type (but
+    /// not types reachable from this type via `walk_tys`). This
+    /// ignores late-bound regions binders.
+    pub fn regions(&self) -> Vec<ty::Region> {
+        match self.sty {
+            TyRef(region, _) => {
+                vec![*region]
             }
-
-            &TyParam(ref p) => {
-                self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
-                if p.space == subst::SelfSpace {
-                    self.add_flags(TypeFlags::HAS_SELF);
-                } else {
-                    self.add_flags(TypeFlags::HAS_PARAMS);
-                }
-            }
-
-            &TyClosure(_, ref substs) => {
-                self.add_flags(TypeFlags::HAS_TY_CLOSURE);
-                self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
-                self.add_substs(&substs.func_substs);
-                self.add_tys(&substs.upvar_tys);
-            }
-
-            &TyInfer(_) => {
-                self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
-                self.add_flags(TypeFlags::HAS_TY_INFER)
-            }
-
-            &TyEnum(_, substs) | &TyStruct(_, substs) => {
-                self.add_substs(substs);
-            }
-
-            &TyProjection(ref data) => {
-                self.add_flags(TypeFlags::HAS_PROJECTION);
-                self.add_projection_ty(data);
-            }
-
-            &TyTrait(box TraitTy { ref principal, ref bounds }) => {
-                let mut computation = FlagComputation::new();
-                computation.add_substs(principal.0.substs);
-                for projection_bound in &bounds.projection_bounds {
-                    let mut proj_computation = FlagComputation::new();
-                    proj_computation.add_projection_predicate(&projection_bound.0);
-                    self.add_bound_computation(&proj_computation);
-                }
-                self.add_bound_computation(&computation);
-
-                self.add_bounds(bounds);
-            }
-
-            &TyBox(tt) | &TyArray(tt, _) | &TySlice(tt) => {
-                self.add_ty(tt)
-            }
-
-            &TyRawPtr(ref m) => {
-                self.add_ty(m.ty);
-            }
-
-            &TyRef(r, ref m) => {
-                self.add_region(*r);
-                self.add_ty(m.ty);
-            }
-
-            &TyTuple(ref ts) => {
-                self.add_tys(&ts[..]);
-            }
-
-            &TyBareFn(_, ref f) => {
-                self.add_fn_sig(&f.sig);
-            }
-        }
-    }
-
-    fn add_ty(&mut self, ty: Ty) {
-        self.add_flags(ty.flags.get());
-        self.add_depth(ty.region_depth);
-    }
-
-    fn add_tys(&mut self, tys: &[Ty]) {
-        for &ty in tys {
-            self.add_ty(ty);
-        }
-    }
-
-    fn add_fn_sig(&mut self, fn_sig: &PolyFnSig) {
-        let mut computation = FlagComputation::new();
-
-        computation.add_tys(&fn_sig.0.inputs);
-
-        if let ty::FnConverging(output) = fn_sig.0.output {
-            computation.add_ty(output);
-        }
-
-        self.add_bound_computation(&computation);
-    }
-
-    fn add_region(&mut self, r: Region) {
-        match r {
-            ty::ReVar(..) |
-            ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
-            ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
-            ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
-            ty::ReStatic => {}
-            _ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); }
-        }
-
-        if !r.is_global() {
-            self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
-        }
-    }
-
-    fn add_projection_predicate(&mut self, projection_predicate: &ProjectionPredicate) {
-        self.add_projection_ty(&projection_predicate.projection_ty);
-        self.add_ty(projection_predicate.ty);
-    }
-
-    fn add_projection_ty(&mut self, projection_ty: &ProjectionTy) {
-        self.add_substs(projection_ty.trait_ref.substs);
-    }
-
-    fn add_substs(&mut self, substs: &Substs) {
-        self.add_tys(substs.types.as_slice());
-        match substs.regions {
-            subst::ErasedRegions => {}
-            subst::NonerasedRegions(ref regions) => {
-                for &r in regions {
-                    self.add_region(r);
-                }
-            }
-        }
-    }
-
-    fn add_bounds(&mut self, bounds: &ExistentialBounds) {
-        self.add_region(bounds.region_bound);
-    }
-}
-
-impl<'tcx> ctxt<'tcx> {
-    /// Create a type context and call the closure with a `&ty::ctxt` reference
-    /// to the context. The closure enforces that the type context and any interned
-    /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
-    /// reference to the context, to allow formatting values that need it.
-    pub fn create_and_enter<F, R>(s: Session,
-                                 arenas: &'tcx CtxtArenas<'tcx>,
-                                 def_map: DefMap,
-                                 named_region_map: resolve_lifetime::NamedRegionMap,
-                                 map: ast_map::Map<'tcx>,
-                                 freevars: RefCell<FreevarMap>,
-                                 region_maps: RegionMaps,
-                                 lang_items: middle::lang_items::LanguageItems,
-                                 stability: stability::Index<'tcx>,
-                                 f: F) -> (Session, R)
-                                 where F: FnOnce(&ctxt<'tcx>) -> R
-    {
-        let interner = RefCell::new(FnvHashMap());
-        let common_types = CommonTypes::new(&arenas.type_, &interner);
-
-        tls::enter(ctxt {
-            arenas: arenas,
-            interner: interner,
-            substs_interner: RefCell::new(FnvHashMap()),
-            bare_fn_interner: RefCell::new(FnvHashMap()),
-            region_interner: RefCell::new(FnvHashMap()),
-            stability_interner: RefCell::new(FnvHashMap()),
-            types: common_types,
-            named_region_map: named_region_map,
-            region_maps: region_maps,
-            free_region_maps: RefCell::new(FnvHashMap()),
-            item_variance_map: RefCell::new(DefIdMap()),
-            variance_computed: Cell::new(false),
-            sess: s,
-            def_map: def_map,
-            tables: RefCell::new(Tables::empty()),
-            impl_trait_refs: RefCell::new(DefIdMap()),
-            trait_defs: RefCell::new(DefIdMap()),
-            adt_defs: RefCell::new(DefIdMap()),
-            predicates: RefCell::new(DefIdMap()),
-            super_predicates: RefCell::new(DefIdMap()),
-            fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()),
-            map: map,
-            freevars: freevars,
-            tcache: RefCell::new(DefIdMap()),
-            rcache: RefCell::new(FnvHashMap()),
-            tc_cache: RefCell::new(FnvHashMap()),
-            ast_ty_to_ty_cache: RefCell::new(NodeMap()),
-            impl_or_trait_items: RefCell::new(DefIdMap()),
-            trait_item_def_ids: RefCell::new(DefIdMap()),
-            trait_items_cache: RefCell::new(DefIdMap()),
-            ty_param_defs: RefCell::new(NodeMap()),
-            normalized_cache: RefCell::new(FnvHashMap()),
-            lang_items: lang_items,
-            provided_method_sources: RefCell::new(DefIdMap()),
-            destructors: RefCell::new(DefIdSet()),
-            inherent_impls: RefCell::new(DefIdMap()),
-            impl_items: RefCell::new(DefIdMap()),
-            used_unsafe: RefCell::new(NodeSet()),
-            used_mut_nodes: RefCell::new(NodeSet()),
-            populated_external_types: RefCell::new(DefIdSet()),
-            populated_external_primitive_impls: RefCell::new(DefIdSet()),
-            extern_const_statics: RefCell::new(DefIdMap()),
-            extern_const_variants: RefCell::new(DefIdMap()),
-            extern_const_fns: RefCell::new(DefIdMap()),
-            node_lint_levels: RefCell::new(FnvHashMap()),
-            transmute_restrictions: RefCell::new(Vec::new()),
-            stability: RefCell::new(stability),
-            selection_cache: traits::SelectionCache::new(),
-            repr_hint_cache: RefCell::new(DefIdMap()),
-            const_qualif_map: RefCell::new(NodeMap()),
-            custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
-            cast_kinds: RefCell::new(NodeMap()),
-            fragment_infos: RefCell::new(DefIdMap()),
-       }, f)
-    }
-
-    // Type constructors
-
-    pub fn mk_substs(&self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> {
-        if let Some(substs) = self.substs_interner.borrow().get(&substs) {
-            return *substs;
-        }
-
-        let substs = self.arenas.substs.alloc(substs);
-        self.substs_interner.borrow_mut().insert(substs, substs);
-        substs
-    }
-
-    /// Create an unsafe fn ty based on a safe fn ty.
-    pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
-        assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
-        let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy {
-            unsafety: hir::Unsafety::Unsafe,
-            abi: bare_fn.abi,
-            sig: bare_fn.sig.clone()
-        });
-        self.mk_fn(None, unsafe_fn_ty_a)
-    }
-
-    pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
-        if let Some(bare_fn) = self.bare_fn_interner.borrow().get(&bare_fn) {
-            return *bare_fn;
-        }
-
-        let bare_fn = self.arenas.bare_fn.alloc(bare_fn);
-        self.bare_fn_interner.borrow_mut().insert(bare_fn, bare_fn);
-        bare_fn
-    }
-
-    pub fn mk_region(&self, region: Region) -> &'tcx Region {
-        if let Some(region) = self.region_interner.borrow().get(&region) {
-            return *region;
-        }
-
-        let region = self.arenas.region.alloc(region);
-        self.region_interner.borrow_mut().insert(region, region);
-        region
-    }
-
-    pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind {
-        *self.tables.borrow().closure_kinds.get(&def_id).unwrap()
-    }
-
-    pub fn closure_type(&self,
-                        def_id: DefId,
-                        substs: &ClosureSubsts<'tcx>)
-                        -> ty::ClosureTy<'tcx>
-    {
-        self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, &substs.func_substs)
-    }
-
-    pub fn type_parameter_def(&self,
-                              node_id: NodeId)
-                              -> TypeParameterDef<'tcx>
-    {
-        self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
-    }
-
-    pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option<hir::Mutability> {
-        pat_util::pat_contains_ref_binding(&self.def_map, pat)
-    }
-
-    pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option<hir::Mutability> {
-        pat_util::arm_contains_ref_binding(&self.def_map, arm)
-    }
-
-    fn intern_ty(type_arena: &'tcx TypedArena<TyS<'tcx>>,
-                 interner: &RefCell<FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>>,
-                 st: TypeVariants<'tcx>)
-                 -> Ty<'tcx> {
-        let ty: Ty /* don't be &mut TyS */ = {
-            let mut interner = interner.borrow_mut();
-            match interner.get(&st) {
-                Some(ty) => return *ty,
-                _ => ()
-            }
-
-            let flags = FlagComputation::for_sty(&st);
-
-            let ty = match () {
-                () => type_arena.alloc(TyS { sty: st,
-                                             flags: Cell::new(flags.flags),
-                                             region_depth: flags.depth, }),
-            };
-
-            interner.insert(InternedTy { ty: ty }, ty);
-            ty
-        };
-
-        debug!("Interned type: {:?} Pointer: {:?}",
-            ty, ty as *const TyS);
-        ty
-    }
-
-    // Interns a type/name combination, stores the resulting box in cx.interner,
-    // and returns the box as cast to an unsafe ptr (see comments for Ty above).
-    pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
-        ctxt::intern_ty(&self.arenas.type_, &self.interner, st)
-    }
-
-    pub fn mk_mach_int(&self, tm: hir::IntTy) -> Ty<'tcx> {
-        match tm {
-            hir::TyIs   => self.types.isize,
-            hir::TyI8   => self.types.i8,
-            hir::TyI16  => self.types.i16,
-            hir::TyI32  => self.types.i32,
-            hir::TyI64  => self.types.i64,
-        }
-    }
-
-    pub fn mk_mach_uint(&self, tm: hir::UintTy) -> Ty<'tcx> {
-        match tm {
-            hir::TyUs   => self.types.usize,
-            hir::TyU8   => self.types.u8,
-            hir::TyU16  => self.types.u16,
-            hir::TyU32  => self.types.u32,
-            hir::TyU64  => self.types.u64,
-        }
-    }
-
-    pub fn mk_mach_float(&self, tm: hir::FloatTy) -> Ty<'tcx> {
-        match tm {
-            hir::TyF32  => self.types.f32,
-            hir::TyF64  => self.types.f64,
-        }
-    }
-
-    pub fn mk_str(&self) -> Ty<'tcx> {
-        self.mk_ty(TyStr)
-    }
-
-    pub fn mk_static_str(&self) -> Ty<'tcx> {
-        self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str())
-    }
-
-    pub fn mk_enum(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
-        // take a copy of substs so that we own the vectors inside
-        self.mk_ty(TyEnum(def, substs))
-    }
-
-    pub fn mk_box(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(TyBox(ty))
-    }
-
-    pub fn mk_ptr(&self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(TyRawPtr(tm))
-    }
-
-    pub fn mk_ref(&self, r: &'tcx Region, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(TyRef(r, tm))
-    }
-
-    pub fn mk_mut_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutMutable})
-    }
-
-    pub fn mk_imm_ref(&self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutImmutable})
-    }
-
-    pub fn mk_mut_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutMutable})
-    }
-
-    pub fn mk_imm_ptr(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ptr(TypeAndMut {ty: ty, mutbl: hir::MutImmutable})
-    }
-
-    pub fn mk_nil_ptr(&self) -> Ty<'tcx> {
-        self.mk_imm_ptr(self.mk_nil())
-    }
-
-    pub fn mk_array(&self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> {
-        self.mk_ty(TyArray(ty, n))
-    }
-
-    pub fn mk_slice(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(TySlice(ty))
-    }
-
-    pub fn mk_tup(&self, ts: Vec<Ty<'tcx>>) -> Ty<'tcx> {
-        self.mk_ty(TyTuple(ts))
-    }
-
-    pub fn mk_nil(&self) -> Ty<'tcx> {
-        self.mk_tup(Vec::new())
-    }
-
-    pub fn mk_bool(&self) -> Ty<'tcx> {
-        self.mk_ty(TyBool)
-    }
-
-    pub fn mk_fn(&self,
-                 opt_def_id: Option<DefId>,
-                 fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(TyBareFn(opt_def_id, fty))
-    }
-
-    pub fn mk_ctor_fn(&self,
-                      def_id: DefId,
-                      input_tys: &[Ty<'tcx>],
-                      output: Ty<'tcx>) -> Ty<'tcx> {
-        let input_args = input_tys.iter().cloned().collect();
-        self.mk_fn(Some(def_id), self.mk_bare_fn(BareFnTy {
-            unsafety: hir::Unsafety::Normal,
-            abi: abi::Rust,
-            sig: ty::Binder(FnSig {
-                inputs: input_args,
-                output: ty::FnConverging(output),
-                variadic: false
-            })
-        }))
-    }
-
-    pub fn mk_trait(&self,
-                    principal: ty::PolyTraitRef<'tcx>,
-                    bounds: ExistentialBounds<'tcx>)
-                    -> Ty<'tcx>
-    {
-        assert!(bound_list_is_sorted(&bounds.projection_bounds));
-
-        let inner = box TraitTy {
-            principal: principal,
-            bounds: bounds
-        };
-        self.mk_ty(TyTrait(inner))
-    }
-
-    pub fn mk_projection(&self,
-                         trait_ref: TraitRef<'tcx>,
-                         item_name: Name)
-                         -> Ty<'tcx> {
-        // take a copy of substs so that we own the vectors inside
-        let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name };
-        self.mk_ty(TyProjection(inner))
-    }
-
-    pub fn mk_struct(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
-        // take a copy of substs so that we own the vectors inside
-        self.mk_ty(TyStruct(def, substs))
-    }
-
-    pub fn mk_closure(&self,
-                      closure_id: DefId,
-                      substs: &'tcx Substs<'tcx>,
-                      tys: Vec<Ty<'tcx>>)
-                      -> Ty<'tcx> {
-        self.mk_closure_from_closure_substs(closure_id, Box::new(ClosureSubsts {
-            func_substs: substs,
-            upvar_tys: tys
-        }))
-    }
-
-    pub fn mk_closure_from_closure_substs(&self,
-                                          closure_id: DefId,
-                                          closure_substs: Box<ClosureSubsts<'tcx>>)
-                                          -> Ty<'tcx> {
-        self.mk_ty(TyClosure(closure_id, closure_substs))
-    }
-
-    pub fn mk_var(&self, v: TyVid) -> Ty<'tcx> {
-        self.mk_infer(TyVar(v))
-    }
-
-    pub fn mk_int_var(&self, v: IntVid) -> Ty<'tcx> {
-        self.mk_infer(IntVar(v))
-    }
-
-    pub fn mk_float_var(&self, v: FloatVid) -> Ty<'tcx> {
-        self.mk_infer(FloatVar(v))
-    }
-
-    pub fn mk_infer(&self, it: InferTy) -> Ty<'tcx> {
-        self.mk_ty(TyInfer(it))
-    }
-
-    pub fn mk_param(&self,
-                    space: subst::ParamSpace,
-                    index: u32,
-                    name: Name) -> Ty<'tcx> {
-        self.mk_ty(TyParam(ParamTy { space: space, idx: index, name: name }))
-    }
-
-    pub fn mk_self_type(&self) -> Ty<'tcx> {
-        self.mk_param(subst::SelfSpace, 0, special_idents::type_self.name)
-    }
-
-    pub fn mk_param_from_def(&self, def: &TypeParameterDef) -> Ty<'tcx> {
-        self.mk_param(def.space, def.index, def.name)
-    }
-}
-
-fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
-    bounds.is_empty() ||
-        bounds[1..].iter().enumerate().all(
-            |(index, bound)| bounds[index].sort_key() <= bound.sort_key())
-}
-
-pub fn sort_bounds_list(bounds: &mut [ty::PolyProjectionPredicate]) {
-    bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key()))
-}
-
-impl<'tcx> TyS<'tcx> {
-    /// Iterator that walks `self` and any types reachable from
-    /// `self`, in depth-first order. Note that just walks the types
-    /// that appear in `self`, it does not descend into the fields of
-    /// structs or variants. For example:
-    ///
-    /// ```notrust
-    /// isize => { isize }
-    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
-    /// [isize] => { [isize], isize }
-    /// ```
-    pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
-        TypeWalker::new(self)
-    }
-
-    /// Iterator that walks the immediate children of `self`.  Hence
-    /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
-    /// (but not `i32`, like `walk`).
-    pub fn walk_shallow(&'tcx self) -> IntoIter<Ty<'tcx>> {
-        walk::walk_shallow(self)
-    }
-
-    pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
-        match self.sty {
-            ty::TyParam(ref d) => Some(d.clone()),
-            _ => None,
-        }
-    }
-
-    pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
-        match self.sty {
-            ty::TyParam(ref data) => data.space == space && data.idx == index,
-            _ => false,
-        }
-    }
-
-    /// Returns the regions directly referenced from this type (but
-    /// not types reachable from this type via `walk_tys`). This
-    /// ignores late-bound regions binders.
-    pub fn regions(&self) -> Vec<ty::Region> {
-        match self.sty {
-            TyRef(region, _) => {
-                vec![*region]
-            }
-            TyTrait(ref obj) => {
-                let mut v = vec![obj.bounds.region_bound];
-                v.push_all(obj.principal.skip_binder().substs.regions().as_slice());
-                v
+            TyTrait(ref obj) => {
+                let mut v = vec![obj.bounds.region_bound];
+                v.push_all(obj.principal.skip_binder().substs.regions().as_slice());
+                v
             }
             TyEnum(_, substs) |
             TyStruct(_, substs) => {
@@ -4315,457 +2178,63 @@ impl<'tcx> TyS<'tcx> {
             TyInfer(_) |
             TyError => {
                 vec![]
-            }
-        }
-    }
-
-    /// Walks `ty` and any types appearing within `ty`, invoking the
-    /// callback `f` on each type. If the callback returns false, then the
-    /// children of the current type are ignored.
-    ///
-    /// Note: prefer `ty.walk()` where possible.
-    pub fn maybe_walk<F>(&'tcx self, mut f: F)
-        where F : FnMut(Ty<'tcx>) -> bool
-    {
-        let mut walker = self.walk();
-        while let Some(ty) = walker.next() {
-            if !f(ty) {
-                walker.skip_current_subtree();
-            }
-        }
-    }
-}
-
-impl ParamTy {
-    pub fn new(space: subst::ParamSpace,
-               index: u32,
-               name: Name)
-               -> ParamTy {
-        ParamTy { space: space, idx: index, name: name }
-    }
-
-    pub fn for_self() -> ParamTy {
-        ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name)
-    }
-
-    pub fn for_def(def: &TypeParameterDef) -> ParamTy {
-        ParamTy::new(def.space, def.index, def.name)
-    }
-
-    pub fn to_ty<'tcx>(self, tcx: &ctxt<'tcx>) -> Ty<'tcx> {
-        tcx.mk_param(self.space, self.idx, self.name)
-    }
-
-    pub fn is_self(&self) -> bool {
-        self.space == subst::SelfSpace && self.idx == 0
-    }
-}
-
-impl<'tcx> ItemSubsts<'tcx> {
-    pub fn empty() -> ItemSubsts<'tcx> {
-        ItemSubsts { substs: Substs::empty() }
-    }
-
-    pub fn is_noop(&self) -> bool {
-        self.substs.is_noop()
-    }
-}
-
-// Type utilities
-impl<'tcx> TyS<'tcx> {
-    pub fn is_nil(&self) -> bool {
-        match self.sty {
-            TyTuple(ref tys) => tys.is_empty(),
-            _ => false
-        }
-    }
-
-    pub fn is_empty(&self, _cx: &ctxt) -> bool {
-        // FIXME(#24885): be smarter here
-        match self.sty {
-            TyEnum(def, _) | TyStruct(def, _) => def.is_empty(),
-            _ => false
-        }
-    }
-
-    pub fn is_ty_var(&self) -> bool {
-        match self.sty {
-            TyInfer(TyVar(_)) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_bool(&self) -> bool { self.sty == TyBool }
-
-    pub fn is_self(&self) -> bool {
-        match self.sty {
-            TyParam(ref p) => p.space == subst::SelfSpace,
-            _ => false
-        }
-    }
-
-    fn is_slice(&self) -> bool {
-        match self.sty {
-            TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty {
-                TySlice(_) | TyStr => true,
-                _ => false,
-            },
-            _ => false
-        }
-    }
-
-    pub fn is_structural(&self) -> bool {
-        match self.sty {
-            TyStruct(..) | TyTuple(_) | TyEnum(..) |
-            TyArray(..) | TyClosure(..) => true,
-            _ => self.is_slice() | self.is_trait()
-        }
-    }
-
-    #[inline]
-    pub fn is_simd(&self) -> bool {
-        match self.sty {
-            TyStruct(def, _) => def.is_simd(),
-            _ => false
-        }
-    }
-
-    pub fn sequence_element_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> {
-        match self.sty {
-            TyArray(ty, _) | TySlice(ty) => ty,
-            TyStr => cx.mk_mach_uint(hir::TyU8),
-            _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}",
-                                      self)),
-        }
-    }
-
-    pub fn simd_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> {
-        match self.sty {
-            TyStruct(def, substs) => {
-                def.struct_variant().fields[0].ty(cx, substs)
-            }
-            _ => panic!("simd_type called on invalid type")
-        }
-    }
-
-    pub fn simd_size(&self, _cx: &ctxt) -> usize {
-        match self.sty {
-            TyStruct(def, _) => def.struct_variant().fields.len(),
-            _ => panic!("simd_size called on invalid type")
-        }
-    }
-
-    pub fn is_region_ptr(&self) -> bool {
-        match self.sty {
-            TyRef(..) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_unsafe_ptr(&self) -> bool {
-        match self.sty {
-            TyRawPtr(_) => return true,
-            _ => return false
-        }
-    }
-
-    pub fn is_unique(&self) -> bool {
-        match self.sty {
-            TyBox(_) => true,
-            _ => false
-        }
-    }
-
-    /*
-     A scalar type is one that denotes an atomic datum, with no sub-components.
-     (A TyRawPtr is scalar because it represents a non-managed pointer, so its
-     contents are abstract to rustc.)
-    */
-    pub fn is_scalar(&self) -> bool {
-        match self.sty {
-            TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) |
-            TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) |
-            TyBareFn(..) | TyRawPtr(_) => true,
-            _ => false
-        }
-    }
-
-    /// Returns true if this type is a floating point type and false otherwise.
-    pub fn is_floating_point(&self) -> bool {
-        match self.sty {
-            TyFloat(_) |
-            TyInfer(FloatVar(_)) => true,
-            _ => false,
-        }
-    }
-
-    pub fn ty_to_def_id(&self) -> Option<DefId> {
-        match self.sty {
-            TyTrait(ref tt) => Some(tt.principal_def_id()),
-            TyStruct(def, _) |
-            TyEnum(def, _) => Some(def.did),
-            TyClosure(id, _) => Some(id),
-            _ => None
-        }
-    }
-
-    pub fn ty_adt_def(&self) -> Option<AdtDef<'tcx>> {
-        match self.sty {
-            TyStruct(adt, _) | TyEnum(adt, _) => Some(adt),
-            _ => None
-        }
-    }
-}
-
-/// Type contents is how the type checker reasons about kinds.
-/// They track what kinds of things are found within a type.  You can
-/// think of them as kind of an "anti-kind".  They track the kinds of values
-/// and thinks that are contained in types.  Having a larger contents for
-/// a type tends to rule that type *out* from various kinds.  For example,
-/// a type that contains a reference is not sendable.
-///
-/// The reason we compute type contents and not kinds is that it is
-/// easier for me (nmatsakis) to think about what is contained within
-/// a type than to think about what is *not* contained within a type.
-#[derive(Clone, Copy)]
-pub struct TypeContents {
-    pub bits: u64
-}
-
-macro_rules! def_type_content_sets {
-    (mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
-        #[allow(non_snake_case)]
-        mod $mname {
-            use middle::ty::TypeContents;
-            $(
-                #[allow(non_upper_case_globals)]
-                pub const $name: TypeContents = TypeContents { bits: $bits };
-             )+
+            }
         }
     }
-}
-
-def_type_content_sets! {
-    mod TC {
-        None                                = 0b0000_0000__0000_0000__0000,
-
-        // Things that are interior to the value (first nibble):
-        InteriorUnsafe                      = 0b0000_0000__0000_0000__0010,
-        InteriorParam                       = 0b0000_0000__0000_0000__0100,
-        // InteriorAll                         = 0b00000000__00000000__1111,
 
-        // Things that are owned by the value (second and third nibbles):
-        OwnsOwned                           = 0b0000_0000__0000_0001__0000,
-        OwnsDtor                            = 0b0000_0000__0000_0010__0000,
-        OwnsAll                             = 0b0000_0000__1111_1111__0000,
-
-        // Things that mean drop glue is necessary
-        NeedsDrop                           = 0b0000_0000__0000_0111__0000,
-
-        // All bits
-        All                                 = 0b1111_1111__1111_1111__1111
+    /// Walks `ty` and any types appearing within `ty`, invoking the
+    /// callback `f` on each type. If the callback returns false, then the
+    /// children of the current type are ignored.
+    ///
+    /// Note: prefer `ty.walk()` where possible.
+    pub fn maybe_walk<F>(&'tcx self, mut f: F)
+        where F : FnMut(Ty<'tcx>) -> bool
+    {
+        let mut walker = self.walk();
+        while let Some(ty) = walker.next() {
+            if !f(ty) {
+                walker.skip_current_subtree();
+            }
+        }
     }
 }
 
-impl TypeContents {
-    pub fn when(&self, cond: bool) -> TypeContents {
-        if cond {*self} else {TC::None}
-    }
-
-    pub fn intersects(&self, tc: TypeContents) -> bool {
-        (self.bits & tc.bits) != 0
-    }
-
-    pub fn owns_owned(&self) -> bool {
-        self.intersects(TC::OwnsOwned)
-    }
-
-    pub fn interior_param(&self) -> bool {
-        self.intersects(TC::InteriorParam)
-    }
-
-    pub fn interior_unsafe(&self) -> bool {
-        self.intersects(TC::InteriorUnsafe)
-    }
-
-    pub fn needs_drop(&self, _: &ctxt) -> bool {
-        self.intersects(TC::NeedsDrop)
-    }
-
-    /// Includes only those bits that still apply when indirected through a `Box` pointer
-    pub fn owned_pointer(&self) -> TypeContents {
-        TC::OwnsOwned | (*self & TC::OwnsAll)
+impl ParamTy {
+    pub fn new(space: subst::ParamSpace,
+               index: u32,
+               name: Name)
+               -> ParamTy {
+        ParamTy { space: space, idx: index, name: name }
     }
 
-    pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
-        F: FnMut(&T) -> TypeContents,
-    {
-        v.iter().fold(TC::None, |tc, ty| tc | f(ty))
+    pub fn for_self() -> ParamTy {
+        ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name)
     }
 
-    pub fn has_dtor(&self) -> bool {
-        self.intersects(TC::OwnsDtor)
+    pub fn for_def(def: &TypeParameterDef) -> ParamTy {
+        ParamTy::new(def.space, def.index, def.name)
     }
-}
-
-impl ops::BitOr for TypeContents {
-    type Output = TypeContents;
 
-    fn bitor(self, other: TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits | other.bits}
+    pub fn to_ty<'tcx>(self, tcx: &ctxt<'tcx>) -> Ty<'tcx> {
+        tcx.mk_param(self.space, self.idx, self.name)
     }
-}
-
-impl ops::BitAnd for TypeContents {
-    type Output = TypeContents;
 
-    fn bitand(self, other: TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits & other.bits}
+    pub fn is_self(&self) -> bool {
+        self.space == subst::SelfSpace && self.idx == 0
     }
 }
 
-impl ops::Sub for TypeContents {
-    type Output = TypeContents;
-
-    fn sub(self, other: TypeContents) -> TypeContents {
-        TypeContents {bits: self.bits & !other.bits}
+impl<'tcx> ItemSubsts<'tcx> {
+    pub fn empty() -> ItemSubsts<'tcx> {
+        ItemSubsts { substs: Substs::empty() }
     }
-}
 
-impl fmt::Debug for TypeContents {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "TypeContents({:b})", self.bits)
+    pub fn is_noop(&self) -> bool {
+        self.substs.is_noop()
     }
 }
 
 impl<'tcx> TyS<'tcx> {
-    pub fn type_contents(&'tcx self, cx: &ctxt<'tcx>) -> TypeContents {
-        return memoized(&cx.tc_cache, self, |ty| {
-            tc_ty(cx, ty, &mut FnvHashMap())
-        });
-
-        fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
-                       ty: Ty<'tcx>,
-                       cache: &mut FnvHashMap<Ty<'tcx>, TypeContents>) -> TypeContents
-        {
-            // Subtle: Note that we are *not* using cx.tc_cache here but rather a
-            // private cache for this walk.  This is needed in the case of cyclic
-            // types like:
-            //
-            //     struct List { next: Box<Option<List>>, ... }
-            //
-            // When computing the type contents of such a type, we wind up deeply
-            // recursing as we go.  So when we encounter the recursive reference
-            // to List, we temporarily use TC::None as its contents.  Later we'll
-            // patch up the cache with the correct value, once we've computed it
-            // (this is basically a co-inductive process, if that helps).  So in
-            // the end we'll compute TC::OwnsOwned, in this case.
-            //
-            // The problem is, as we are doing the computation, we will also
-            // compute an *intermediate* contents for, e.g., Option<List> of
-            // TC::None.  This is ok during the computation of List itself, but if
-            // we stored this intermediate value into cx.tc_cache, then later
-            // requests for the contents of Option<List> would also yield TC::None
-            // which is incorrect.  This value was computed based on the crutch
-            // value for the type contents of list.  The correct value is
-            // TC::OwnsOwned.  This manifested as issue #4821.
-            match cache.get(&ty) {
-                Some(tc) => { return *tc; }
-                None => {}
-            }
-            match cx.tc_cache.borrow().get(&ty) {    // Must check both caches!
-                Some(tc) => { return *tc; }
-                None => {}
-            }
-            cache.insert(ty, TC::None);
-
-            let result = match ty.sty {
-                // usize and isize are ffi-unsafe
-                TyUint(hir::TyUs) | TyInt(hir::TyIs) => {
-                    TC::None
-                }
-
-                // Scalar and unique types are sendable, and durable
-                TyInfer(ty::FreshIntTy(_)) | TyInfer(ty::FreshFloatTy(_)) |
-                TyBool | TyInt(_) | TyUint(_) | TyFloat(_) |
-                TyBareFn(..) | ty::TyChar => {
-                    TC::None
-                }
-
-                TyBox(typ) => {
-                    tc_ty(cx, typ, cache).owned_pointer()
-                }
-
-                TyTrait(_) => {
-                    TC::All - TC::InteriorParam
-                }
-
-                TyRawPtr(_) => {
-                    TC::None
-                }
-
-                TyRef(_, _) => {
-                    TC::None
-                }
-
-                TyArray(ty, _) => {
-                    tc_ty(cx, ty, cache)
-                }
-
-                TySlice(ty) => {
-                    tc_ty(cx, ty, cache)
-                }
-                TyStr => TC::None,
-
-                TyClosure(_, ref substs) => {
-                    TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache))
-                }
-
-                TyTuple(ref tys) => {
-                    TypeContents::union(&tys[..],
-                                        |ty| tc_ty(cx, *ty, cache))
-                }
-
-                TyStruct(def, substs) | TyEnum(def, substs) => {
-                    let mut res =
-                        TypeContents::union(&def.variants, |v| {
-                            TypeContents::union(&v.fields, |f| {
-                                tc_ty(cx, f.ty(cx, substs), cache)
-                            })
-                        });
-
-                    if def.has_dtor() {
-                        res = res | TC::OwnsDtor;
-                    }
-
-                    apply_lang_items(cx, def.did, res)
-                }
-
-                TyProjection(..) |
-                TyParam(_) => {
-                    TC::All
-                }
-
-                TyInfer(_) |
-                TyError => {
-                    cx.sess.bug("asked to compute contents of error type");
-                }
-            };
-
-            cache.insert(ty, result);
-            result
-        }
-
-        fn apply_lang_items(cx: &ctxt, did: DefId, tc: TypeContents)
-                            -> TypeContents {
-            if Some(did) == cx.lang_items.unsafe_cell_type() {
-                tc | TC::InteriorUnsafe
-            } else {
-                tc
-            }
-        }
-    }
-
     fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
                        bound: ty::BuiltinBound,
                        span: Span)
@@ -5037,143 +2506,6 @@ impl<'tcx> TyS<'tcx> {
         r
     }
 
-    pub fn is_trait(&self) -> bool {
-        match self.sty {
-            TyTrait(..) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_integral(&self) -> bool {
-        match self.sty {
-            TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_fresh(&self) -> bool {
-        match self.sty {
-            TyInfer(FreshTy(_)) => true,
-            TyInfer(FreshIntTy(_)) => true,
-            TyInfer(FreshFloatTy(_)) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_uint(&self) -> bool {
-        match self.sty {
-            TyInfer(IntVar(_)) | TyUint(hir::TyUs) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_char(&self) -> bool {
-        match self.sty {
-            TyChar => true,
-            _ => false
-        }
-    }
-
-    pub fn is_bare_fn(&self) -> bool {
-        match self.sty {
-            TyBareFn(..) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_bare_fn_item(&self) -> bool {
-        match self.sty {
-            TyBareFn(Some(_), _) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_fp(&self) -> bool {
-        match self.sty {
-            TyInfer(FloatVar(_)) | TyFloat(_) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_numeric(&self) -> bool {
-        self.is_integral() || self.is_fp()
-    }
-
-    pub fn is_signed(&self) -> bool {
-        match self.sty {
-            TyInt(_) => true,
-            _ => false
-        }
-    }
-
-    pub fn is_machine(&self) -> bool {
-        match self.sty {
-            TyInt(hir::TyIs) | TyUint(hir::TyUs) => false,
-            TyInt(..) | TyUint(..) | TyFloat(..) => true,
-            _ => false
-        }
-    }
-
-    // Returns the type and mutability of *ty.
-    //
-    // The parameter `explicit` indicates if this is an *explicit* dereference.
-    // Some types---notably unsafe ptrs---can only be dereferenced explicitly.
-    pub fn builtin_deref(&self, explicit: bool, pref: LvaluePreference)
-        -> Option<TypeAndMut<'tcx>>
-    {
-        match self.sty {
-            TyBox(ty) => {
-                Some(TypeAndMut {
-                    ty: ty,
-                    mutbl:
-                        if pref == PreferMutLvalue { hir::MutMutable } else { hir::MutImmutable },
-                })
-            },
-            TyRef(_, mt) => Some(mt),
-            TyRawPtr(mt) if explicit => Some(mt),
-            _ => None
-        }
-    }
-
-    // Returns the type of ty[i]
-    pub fn builtin_index(&self) -> Option<Ty<'tcx>> {
-        match self.sty {
-            TyArray(ty, _) | TySlice(ty) => Some(ty),
-            _ => None
-        }
-    }
-
-    pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
-        match self.sty {
-            TyBareFn(_, ref f) => &f.sig,
-            _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self)
-        }
-    }
-
-    /// Returns the ABI of the given function.
-    pub fn fn_abi(&self) -> abi::Abi {
-        match self.sty {
-            TyBareFn(_, ref f) => f.abi,
-            _ => panic!("Ty::fn_abi() called on non-fn type"),
-        }
-    }
-
-    // Type accessors for substructures of types
-    pub fn fn_args(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
-        self.fn_sig().inputs()
-    }
-
-    pub fn fn_ret(&self) -> Binder<FnOutput<'tcx>> {
-        self.fn_sig().output()
-    }
-
-    pub fn is_fn(&self) -> bool {
-        match self.sty {
-            TyBareFn(..) => true,
-            _ => false
-        }
-    }
-
     /// See `expr_ty_adjusted`
     pub fn adjust<F>(&'tcx self, cx: &ctxt<'tcx>,
                      span: Span,
@@ -5285,187 +2617,6 @@ impl<'tcx> TyS<'tcx> {
         }
     }
 
-    fn sort_string(&self, cx: &ctxt) -> String {
-
-        match self.sty {
-            TyBool | TyChar | TyInt(_) |
-            TyUint(_) | TyFloat(_) | TyStr => self.to_string(),
-            TyTuple(ref tys) if tys.is_empty() => self.to_string(),
-
-            TyEnum(def, _) => format!("enum `{}`", cx.item_path_str(def.did)),
-            TyBox(_) => "box".to_string(),
-            TyArray(_, n) => format!("array of {} elements", n),
-            TySlice(_) => "slice".to_string(),
-            TyRawPtr(_) => "*-ptr".to_string(),
-            TyRef(_, _) => "&-ptr".to_string(),
-            TyBareFn(Some(_), _) => format!("fn item"),
-            TyBareFn(None, _) => "fn pointer".to_string(),
-            TyTrait(ref inner) => {
-                format!("trait {}", cx.item_path_str(inner.principal_def_id()))
-            }
-            TyStruct(def, _) => {
-                format!("struct `{}`", cx.item_path_str(def.did))
-            }
-            TyClosure(..) => "closure".to_string(),
-            TyTuple(_) => "tuple".to_string(),
-            TyInfer(TyVar(_)) => "inferred type".to_string(),
-            TyInfer(IntVar(_)) => "integral variable".to_string(),
-            TyInfer(FloatVar(_)) => "floating-point variable".to_string(),
-            TyInfer(FreshTy(_)) => "skolemized type".to_string(),
-            TyInfer(FreshIntTy(_)) => "skolemized integral type".to_string(),
-            TyInfer(FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
-            TyProjection(_) => "associated type".to_string(),
-            TyParam(ref p) => {
-                if p.space == subst::SelfSpace {
-                    "Self".to_string()
-                } else {
-                    "type parameter".to_string()
-                }
-            }
-            TyError => "type error".to_string(),
-        }
-    }
-}
-/// Explains the source of a type err in a short, human readable way. This is meant to be placed
-/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
-/// afterwards to present additional details, particularly when it comes to lifetime-related
-/// errors.
-impl<'tcx> fmt::Display for TypeError<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::TypeError::*;
-        fn report_maybe_different(f: &mut fmt::Formatter,
-                                  expected: String, found: String) -> fmt::Result {
-            // A naive approach to making sure that we're not reporting silly errors such as:
-            // (expected closure, found closure).
-            if expected == found {
-                write!(f, "expected {}, found a different {}", expected, found)
-            } else {
-                write!(f, "expected {}, found {}", expected, found)
-            }
-        }
-
-        match *self {
-            CyclicTy => write!(f, "cyclic type of infinite size"),
-            Mismatch => write!(f, "types differ"),
-            UnsafetyMismatch(values) => {
-                write!(f, "expected {} fn, found {} fn",
-                       values.expected,
-                       values.found)
-            }
-            AbiMismatch(values) => {
-                write!(f, "expected {} fn, found {} fn",
-                       values.expected,
-                       values.found)
-            }
-            Mutability => write!(f, "values differ in mutability"),
-            BoxMutability => {
-                write!(f, "boxed values differ in mutability")
-            }
-            VecMutability => write!(f, "vectors differ in mutability"),
-            PtrMutability => write!(f, "pointers differ in mutability"),
-            RefMutability => write!(f, "references differ in mutability"),
-            TyParamSize(values) => {
-                write!(f, "expected a type with {} type params, \
-                           found one with {} type params",
-                       values.expected,
-                       values.found)
-            }
-            FixedArraySize(values) => {
-                write!(f, "expected an array with a fixed size of {} elements, \
-                           found one with {} elements",
-                       values.expected,
-                       values.found)
-            }
-            TupleSize(values) => {
-                write!(f, "expected a tuple with {} elements, \
-                           found one with {} elements",
-                       values.expected,
-                       values.found)
-            }
-            ArgCount => {
-                write!(f, "incorrect number of function parameters")
-            }
-            RegionsDoesNotOutlive(..) => {
-                write!(f, "lifetime mismatch")
-            }
-            RegionsNotSame(..) => {
-                write!(f, "lifetimes are not the same")
-            }
-            RegionsNoOverlap(..) => {
-                write!(f, "lifetimes do not intersect")
-            }
-            RegionsInsufficientlyPolymorphic(br, _) => {
-                write!(f, "expected bound lifetime parameter {}, \
-                           found concrete lifetime", br)
-            }
-            RegionsOverlyPolymorphic(br, _) => {
-                write!(f, "expected concrete lifetime, \
-                           found bound lifetime parameter {}", br)
-            }
-            Sorts(values) => tls::with(|tcx| {
-                report_maybe_different(f, values.expected.sort_string(tcx),
-                                       values.found.sort_string(tcx))
-            }),
-            Traits(values) => tls::with(|tcx| {
-                report_maybe_different(f,
-                                       format!("trait `{}`",
-                                               tcx.item_path_str(values.expected)),
-                                       format!("trait `{}`",
-                                               tcx.item_path_str(values.found)))
-            }),
-            BuiltinBoundsMismatch(values) => {
-                if values.expected.is_empty() {
-                    write!(f, "expected no bounds, found `{}`",
-                           values.found)
-                } else if values.found.is_empty() {
-                    write!(f, "expected bounds `{}`, found no bounds",
-                           values.expected)
-                } else {
-                    write!(f, "expected bounds `{}`, found bounds `{}`",
-                           values.expected,
-                           values.found)
-                }
-            }
-            IntegerAsChar => {
-                write!(f, "expected an integral type, found `char`")
-            }
-            IntMismatch(ref values) => {
-                write!(f, "expected `{:?}`, found `{:?}`",
-                       values.expected,
-                       values.found)
-            }
-            FloatMismatch(ref values) => {
-                write!(f, "expected `{:?}`, found `{:?}`",
-                       values.expected,
-                       values.found)
-            }
-            VariadicMismatch(ref values) => {
-                write!(f, "expected {} fn, found {} function",
-                       if values.expected { "variadic" } else { "non-variadic" },
-                       if values.found { "variadic" } else { "non-variadic" })
-            }
-            ConvergenceMismatch(ref values) => {
-                write!(f, "expected {} fn, found {} function",
-                       if values.expected { "converging" } else { "diverging" },
-                       if values.found { "converging" } else { "diverging" })
-            }
-            ProjectionNameMismatched(ref values) => {
-                write!(f, "expected {}, found {}",
-                       values.expected,
-                       values.found)
-            }
-            ProjectionBoundsLength(ref values) => {
-                write!(f, "expected {} associated type bindings, found {}",
-                       values.expected,
-                       values.found)
-            },
-            TyParamDefaultMismatch(ref values) => {
-                write!(f, "conflicting type parameter defaults `{}` and `{}`",
-                       values.expected.ty,
-                       values.found.ty)
-            }
-        }
-    }
 }
 
 /// Helper for looking things up in the various maps that are populated during
@@ -5724,102 +2875,14 @@ impl<'tcx> ctxt<'tcx> {
             hir::ExprAssignOp(..) |
             hir::ExprLit(_) |
             hir::ExprUnary(..) |
-            hir::ExprBox(..) |
-            hir::ExprAddrOf(..) |
-            hir::ExprBinary(..) |
-            hir::ExprCast(..) => {
-                false
-            }
-
-            hir::ExprParen(ref e) => self.expr_is_lval(e),
-        }
-    }
-
-    pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) {
-        use self::TypeError::*;
-
-        match err.clone() {
-            RegionsDoesNotOutlive(subregion, superregion) => {
-                self.note_and_explain_region("", subregion, "...");
-                self.note_and_explain_region("...does not necessarily outlive ",
-                                           superregion, "");
-            }
-            RegionsNotSame(region1, region2) => {
-                self.note_and_explain_region("", region1, "...");
-                self.note_and_explain_region("...is not the same lifetime as ",
-                                           region2, "");
-            }
-            RegionsNoOverlap(region1, region2) => {
-                self.note_and_explain_region("", region1, "...");
-                self.note_and_explain_region("...does not overlap ",
-                                           region2, "");
-            }
-            RegionsInsufficientlyPolymorphic(_, conc_region) => {
-                self.note_and_explain_region("concrete lifetime that was found is ",
-                                           conc_region, "");
-            }
-            RegionsOverlyPolymorphic(_, ty::ReVar(_)) => {
-                // don't bother to print out the message below for
-                // inference variables, it's not very illuminating.
-            }
-            RegionsOverlyPolymorphic(_, conc_region) => {
-                self.note_and_explain_region("expected concrete lifetime is ",
-                                           conc_region, "");
-            }
-            Sorts(values) => {
-                let expected_str = values.expected.sort_string(self);
-                let found_str = values.found.sort_string(self);
-                if expected_str == found_str && expected_str == "closure" {
-                    self.sess.span_note(sp,
-                        &format!("no two closures, even if identical, have the same type"));
-                    self.sess.span_help(sp,
-                        &format!("consider boxing your closure and/or \
-                                  using it as a trait object"));
-                }
-            },
-            TyParamDefaultMismatch(values) => {
-                let expected = values.expected;
-                let found = values.found;
-                self.sess.span_note(sp,
-                                    &format!("conflicting type parameter defaults `{}` and `{}`",
-                                             expected.ty,
-                                             found.ty));
-
-                match (expected.def_id.is_local(),
-                       self.map.opt_span(expected.def_id.node)) {
-                    (true, Some(span)) => {
-                        self.sess.span_note(span,
-                                            &format!("a default was defined here..."));
-                    }
-                    (_, _) => {
-                        self.sess.note(
-                            &format!("a default is defined on `{}`",
-                                     self.item_path_str(expected.def_id)));
-                    }
-                }
-
-                self.sess.span_note(
-                    expected.origin_span,
-                    &format!("...that was applied to an unconstrained type variable here"));
-
-                match (found.def_id.is_local(),
-                       self.map.opt_span(found.def_id.node)) {
-                    (true, Some(span)) => {
-                        self.sess.span_note(span,
-                                            &format!("a second default was defined here..."));
-                    }
-                    (_, _) => {
-                        self.sess.note(
-                            &format!("a second default is defined on `{}`",
-                                     self.item_path_str(found.def_id)));
-                    }
-                }
-
-                self.sess.span_note(
-                    found.origin_span,
-                    &format!("...that also applies to the same type variable here"));
+            hir::ExprBox(..) |
+            hir::ExprAddrOf(..) |
+            hir::ExprBinary(..) |
+            hir::ExprCast(..) => {
+                false
             }
-            _ => {}
+
+            hir::ExprParen(ref e) => self.expr_is_lval(e),
         }
     }
 
@@ -5986,22 +3049,6 @@ impl<'tcx> ctxt<'tcx> {
         self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id()
     }
 
-    pub fn try_add_builtin_trait(&self,
-                                 trait_def_id: DefId,
-                                 builtin_bounds: &mut EnumSet<BuiltinBound>)
-                                 -> bool
-    {
-        //! Checks whether `trait_ref` refers to one of the builtin
-        //! traits, like `Send`, and adds the corresponding
-        //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
-        //! is a builtin trait.
-
-        match self.lang_items.to_builtin_kind(trait_def_id) {
-            Some(bound) => { builtin_bounds.insert(bound); true }
-            None => false
-        }
-    }
-
     pub fn item_path_str(&self, id: DefId) -> String {
         self.with_path(id, |path| ast_map::path_to_string(path))
     }
@@ -6070,7 +3117,7 @@ impl<'tcx> ctxt<'tcx> {
     pub fn lookup_trait_def(&self, did: DefId) -> &'tcx TraitDef<'tcx> {
         lookup_locally_or_in_crate_store(
             "trait_defs", did, &self.trait_defs,
-            || self.arenas.trait_defs.alloc(csearch::get_trait_def(self, did))
+            || self.alloc_trait_def(csearch::get_trait_def(self, did))
         )
     }
 
@@ -6878,78 +3925,6 @@ impl<'tcx> ctxt<'tcx> {
         }
     }
 
-    /// Replace any late-bound regions bound in `value` with free variants attached to scope-id
-    /// `scope_id`.
-    pub fn liberate_late_bound_regions<T>(&self,
-        all_outlive_scope: region::CodeExtent,
-        value: &Binder<T>)
-        -> T
-        where T : TypeFoldable<'tcx>
-    {
-        fold::replace_late_bound_regions(
-            self, value,
-            |br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
-    }
-
-    /// Flattens two binding levels into one. So `for<'a> for<'b> Foo`
-    /// becomes `for<'a,'b> Foo`.
-    pub fn flatten_late_bound_regions<T>(&self, bound2_value: &Binder<Binder<T>>)
-                                         -> Binder<T>
-        where T: TypeFoldable<'tcx>
-    {
-        let bound0_value = bound2_value.skip_binder().skip_binder();
-        let value = fold::fold_regions(self, bound0_value, &mut false,
-                                       |region, current_depth| {
-            match region {
-                ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
-                    // should be true if no escaping regions from bound2_value
-                    assert!(debruijn.depth - current_depth <= 1);
-                    ty::ReLateBound(DebruijnIndex::new(current_depth), br)
-                }
-                _ => {
-                    region
-                }
-            }
-        });
-        Binder(value)
-    }
-
-    pub fn no_late_bound_regions<T>(&self, value: &Binder<T>) -> Option<T>
-        where T : TypeFoldable<'tcx> + RegionEscape
-    {
-        if value.0.has_escaping_regions() {
-            None
-        } else {
-            Some(value.0.clone())
-        }
-    }
-
-    /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
-    /// method lookup and a few other places where precise region relationships are not required.
-    pub fn erase_late_bound_regions<T>(&self, value: &Binder<T>) -> T
-        where T : TypeFoldable<'tcx>
-    {
-        fold::replace_late_bound_regions(self, value, |_| ty::ReStatic).0
-    }
-
-    /// Rewrite any late-bound regions so that they are anonymous.  Region numbers are
-    /// assigned starting at 1 and increasing monotonically in the order traversed
-    /// by the fold operation.
-    ///
-    /// The chief purpose of this function is to canonicalize regions so that two
-    /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
-    /// structurally identical.  For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and
-    /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization.
-    pub fn anonymize_late_bound_regions<T>(&self, sig: &Binder<T>) -> Binder<T>
-        where T : TypeFoldable<'tcx>,
-    {
-        let mut counter = 0;
-        ty::Binder(fold::replace_late_bound_regions(self, sig, |_| {
-            counter += 1;
-            ReLateBound(ty::DebruijnIndex::new(1), BrAnon(counter))
-        }).0)
-    }
-
     pub fn make_substs_for_receiver_types(&self,
                                           trait_ref: &ty::TraitRef<'tcx>,
                                           method: &ty::Method<'tcx>)
@@ -6975,67 +3950,6 @@ impl<'tcx> ctxt<'tcx> {
     }
 }
 
-impl DebruijnIndex {
-    pub fn new(depth: u32) -> DebruijnIndex {
-        assert!(depth > 0);
-        DebruijnIndex { depth: depth }
-    }
-
-    pub fn shifted(&self, amount: u32) -> DebruijnIndex {
-        DebruijnIndex { depth: self.depth + amount }
-    }
-}
-
-impl<'tcx> fmt::Debug for AutoAdjustment<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            AdjustReifyFnPointer => {
-                write!(f, "AdjustReifyFnPointer")
-            }
-            AdjustUnsafeFnPointer => {
-                write!(f, "AdjustUnsafeFnPointer")
-            }
-            AdjustDerefRef(ref data) => {
-                write!(f, "{:?}", data)
-            }
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for AutoDerefRef<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
-               self.autoderefs, self.unsize, self.autoref)
-    }
-}
-
-impl<'tcx> fmt::Debug for TraitTy<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "TraitTy({:?},{:?})",
-               self.principal,
-               self.bounds)
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Predicate::Trait(ref a) => write!(f, "{:?}", a),
-            Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
-            Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
-            Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
-            Predicate::Projection(ref pair) => write!(f, "{:?}", pair),
-            Predicate::WellFormed(ty) => write!(f, "WF({:?})", ty),
-            Predicate::ObjectSafe(trait_def_id) => write!(f, "ObjectSafe({:?})", trait_def_id),
-        }
-    }
-}
-
-// FIXME(#20298) -- all of these traits basically walk various
-// structures to test whether types/regions are reachable with various
-// properties. It should be possible to express them in terms of one
-// common "walker" trait or something.
-
 /// An "escaping region" is a bound region whose binder is not part of `t`.
 ///
 /// So, for example, consider a type like the following, which has two binders:
@@ -7066,167 +3980,6 @@ pub trait RegionEscape {
     fn has_regions_escaping_depth(&self, depth: u32) -> bool;
 }
 
-impl<'tcx> RegionEscape for Ty<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.region_depth > depth
-    }
-}
-
-impl<'tcx> RegionEscape for TraitTy<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.principal.has_regions_escaping_depth(depth) ||
-            self.bounds.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for ExistentialBounds<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.region_bound.has_regions_escaping_depth(depth) ||
-            self.projection_bounds.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for Substs<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.types.has_regions_escaping_depth(depth) ||
-            self.regions.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for ClosureSubsts<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.func_substs.has_regions_escaping_depth(depth) ||
-            self.upvar_tys.iter().any(|t| t.has_regions_escaping_depth(depth))
-    }
-}
-
-impl<T:RegionEscape> RegionEscape for Vec<T> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.iter().any(|t| t.has_regions_escaping_depth(depth))
-    }
-}
-
-impl<'tcx> RegionEscape for FnSig<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.inputs.has_regions_escaping_depth(depth) ||
-            self.output.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.iter_enumerated().any(|(space, _, t)| {
-            if space == subst::FnSpace {
-                t.has_regions_escaping_depth(depth+1)
-            } else {
-                t.has_regions_escaping_depth(depth)
-            }
-        })
-    }
-}
-
-impl<'tcx> RegionEscape for TypeScheme<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.ty.has_regions_escaping_depth(depth)
-    }
-}
-
-impl RegionEscape for Region {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.escapes_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for GenericPredicates<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.predicates.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for Predicate<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        match *self {
-            Predicate::Trait(ref data) => data.has_regions_escaping_depth(depth),
-            Predicate::Equate(ref data) => data.has_regions_escaping_depth(depth),
-            Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth),
-            Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth),
-            Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth),
-            Predicate::WellFormed(ty) => ty.has_regions_escaping_depth(depth),
-            Predicate::ObjectSafe(_trait_def_id) => false,
-        }
-    }
-}
-
-impl<'tcx,P:RegionEscape> RegionEscape for traits::Obligation<'tcx,P> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.predicate.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for TraitRef<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
-            self.substs.regions.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for subst::RegionSubsts {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        match *self {
-            subst::ErasedRegions => false,
-            subst::NonerasedRegions(ref r) => {
-                r.iter().any(|t| t.has_regions_escaping_depth(depth))
-            }
-        }
-    }
-}
-
-impl<'tcx,T:RegionEscape> RegionEscape for Binder<T> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.0.has_regions_escaping_depth(depth + 1)
-    }
-}
-
-impl<'tcx> RegionEscape for FnOutput<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        match *self {
-            FnConverging(t) => t.has_regions_escaping_depth(depth),
-            FnDiverging => false
-        }
-    }
-}
-
-impl<'tcx> RegionEscape for EquatePredicate<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for TraitPredicate<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.trait_ref.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<T:RegionEscape,U:RegionEscape> RegionEscape for OutlivesPredicate<T,U> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for ProjectionPredicate<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.projection_ty.has_regions_escaping_depth(depth) ||
-            self.ty.has_regions_escaping_depth(depth)
-    }
-}
-
-impl<'tcx> RegionEscape for ProjectionTy<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.trait_ref.has_regions_escaping_depth(depth)
-    }
-}
-
 pub trait HasTypeFlags {
     fn has_type_flags(&self, flags: TypeFlags) -> bool;
     fn has_projection_types(&self) -> bool {
@@ -7266,254 +4019,3 @@ pub trait HasTypeFlags {
         !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES)
     }
 }
-
-impl<'tcx,T:HasTypeFlags> HasTypeFlags for Vec<T> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self[..].has_type_flags(flags)
-    }
-}
-
-impl<'tcx,T:HasTypeFlags> HasTypeFlags for [T] {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.iter().any(|p| p.has_type_flags(flags))
-    }
-}
-
-impl<'tcx,T:HasTypeFlags> HasTypeFlags for VecPerParamSpace<T> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.iter().any(|p| p.has_type_flags(flags))
-    }
-}
-
-impl HasTypeFlags for abi::Abi {
-    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
-        false
-    }
-}
-
-impl HasTypeFlags for hir::Unsafety {
-    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
-        false
-    }
-}
-
-impl HasTypeFlags for BuiltinBounds {
-    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
-        false
-    }
-}
-
-impl<'tcx> HasTypeFlags for ClosureTy<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.sig.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for ClosureUpvar<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.ty.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for ExistentialBounds<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.projection_bounds.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for ty::InstantiatedPredicates<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.predicates.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for Predicate<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        match *self {
-            Predicate::Trait(ref data) => data.has_type_flags(flags),
-            Predicate::Equate(ref data) => data.has_type_flags(flags),
-            Predicate::RegionOutlives(ref data) => data.has_type_flags(flags),
-            Predicate::TypeOutlives(ref data) => data.has_type_flags(flags),
-            Predicate::Projection(ref data) => data.has_type_flags(flags),
-            Predicate::WellFormed(data) => data.has_type_flags(flags),
-            Predicate::ObjectSafe(_trait_def_id) => false,
-        }
-    }
-}
-
-impl<'tcx> HasTypeFlags for TraitPredicate<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.trait_ref.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for EquatePredicate<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.0.has_type_flags(flags) || self.1.has_type_flags(flags)
-    }
-}
-
-impl HasTypeFlags for Region {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        if flags.intersects(TypeFlags::HAS_LOCAL_NAMES) {
-            // does this represent a region that cannot be named in a global
-            // way? used in fulfillment caching.
-            match *self {
-                ty::ReStatic | ty::ReEmpty => {}
-                _ => return true
-            }
-        }
-        if flags.intersects(TypeFlags::HAS_RE_INFER) {
-            match *self {
-                ty::ReVar(_) | ty::ReSkolemized(..) => { return true }
-                _ => {}
-            }
-        }
-        false
-    }
-}
-
-impl<T:HasTypeFlags,U:HasTypeFlags> HasTypeFlags for OutlivesPredicate<T,U> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.0.has_type_flags(flags) || self.1.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for ProjectionPredicate<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.projection_ty.has_type_flags(flags) || self.ty.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for ProjectionTy<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.trait_ref.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for Ty<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.flags.get().intersects(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for TypeAndMut<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.ty.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for TraitRef<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.substs.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for subst::Substs<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.types.has_type_flags(flags) || match self.regions {
-            subst::ErasedRegions => false,
-            subst::NonerasedRegions(ref r) => r.has_type_flags(flags)
-        }
-    }
-}
-
-impl<'tcx,T> HasTypeFlags for Option<T>
-    where T : HasTypeFlags
-{
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.iter().any(|t| t.has_type_flags(flags))
-    }
-}
-
-impl<'tcx,T> HasTypeFlags for Rc<T>
-    where T : HasTypeFlags
-{
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        (**self).has_type_flags(flags)
-    }
-}
-
-impl<'tcx,T> HasTypeFlags for Box<T>
-    where T : HasTypeFlags
-{
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        (**self).has_type_flags(flags)
-    }
-}
-
-impl<T> HasTypeFlags for Binder<T>
-    where T : HasTypeFlags
-{
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.0.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for FnOutput<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        match *self {
-            FnConverging(t) => t.has_type_flags(flags),
-            FnDiverging => false,
-        }
-    }
-}
-
-impl<'tcx> HasTypeFlags for FnSig<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.inputs.iter().any(|t| t.has_type_flags(flags)) ||
-            self.output.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for BareFnTy<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.sig.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for ClosureSubsts<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.func_substs.has_type_flags(flags) ||
-            self.upvar_tys.iter().any(|t| t.has_type_flags(flags))
-    }
-}
-
-impl<'tcx> fmt::Debug for ClosureTy<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ClosureTy({},{:?},{})",
-               self.unsafety,
-               self.sig,
-               self.abi)
-    }
-}
-
-impl<'tcx> fmt::Debug for ClosureUpvar<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ClosureUpvar({:?},{:?})",
-               self.def,
-               self.ty)
-    }
-}
-
-impl<'a, 'tcx> fmt::Debug for ParameterEnvironment<'a, 'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ParameterEnvironment(\
-            free_substs={:?}, \
-            implicit_region_bound={:?}, \
-            caller_bounds={:?})",
-            self.free_substs,
-            self.implicit_region_bound,
-            self.caller_bounds)
-    }
-}
-
-impl<'tcx> fmt::Debug for ObjectLifetimeDefault {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
-            ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
-            ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
-        }
-    }
-}
diff --git a/src/librustc/middle/ty/relate.rs b/src/librustc/middle/ty/relate.rs
index 7baf075cc69ba..ff0a9789cf1f8 100644
--- a/src/librustc/middle/ty/relate.rs
+++ b/src/librustc/middle/ty/relate.rs
@@ -15,13 +15,14 @@
 
 use middle::def_id::DefId;
 use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
-use middle::ty::{self, HasTypeFlags, Ty, TypeError};
+use middle::ty::{self, HasTypeFlags, Ty};
+use middle::ty::error::{ExpectedFound, TypeError};
 use middle::ty::fold::TypeFoldable;
 use std::rc::Rc;
 use syntax::abi;
 use rustc_front::hir as ast;
 
-pub type RelateResult<'tcx, T> = Result<T, ty::TypeError<'tcx>>;
+pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
 
 #[derive(Clone, Debug)]
 pub enum Cause {
@@ -662,7 +663,7 @@ impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box<T>
 pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R,
                                       a: &T,
                                       b: &T)
-                                      -> ty::ExpectedFound<T>
+                                      -> ExpectedFound<T>
     where R: TypeRelation<'a,'tcx>, T: Clone
 {
     expected_found_bool(relation.a_is_expected(), a, b)
@@ -671,14 +672,14 @@ pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R,
 pub fn expected_found_bool<T>(a_is_expected: bool,
                               a: &T,
                               b: &T)
-                              -> ty::ExpectedFound<T>
+                              -> ExpectedFound<T>
     where T: Clone
 {
     let a = a.clone();
     let b = b.clone();
     if a_is_expected {
-        ty::ExpectedFound {expected: a, found: b}
+        ExpectedFound {expected: a, found: b}
     } else {
-        ty::ExpectedFound {expected: b, found: a}
+        ExpectedFound {expected: b, found: a}
     }
 }
diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs
new file mode 100644
index 0000000000000..55d064844b13d
--- /dev/null
+++ b/src/librustc/middle/ty/structural_impls.rs
@@ -0,0 +1,895 @@
+// Copyright 2012-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.
+
+use middle::subst::{self, VecPerParamSpace};
+use middle::traits;
+use middle::ty::{self, TraitRef, Ty, TypeAndMut};
+use middle::ty::{HasTypeFlags, Lift, TypeFlags, RegionEscape};
+use middle::ty::fold::{TypeFoldable, TypeFolder};
+
+use std::rc::Rc;
+use syntax::abi;
+use syntax::owned_slice::OwnedSlice;
+
+use rustc_front::hir;
+
+// FIXME(#20298) -- all of these traits basically walk various
+// structures to test whether types/regions are reachable with various
+// properties. It should be possible to express them in terms of one
+// common "walker" trait or something.
+
+impl<'tcx> RegionEscape for Ty<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.region_depth > depth
+    }
+}
+
+impl<'tcx> RegionEscape for ty::TraitTy<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.principal.has_regions_escaping_depth(depth) ||
+            self.bounds.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for ty::ExistentialBounds<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.region_bound.has_regions_escaping_depth(depth) ||
+            self.projection_bounds.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for subst::Substs<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.types.has_regions_escaping_depth(depth) ||
+            self.regions.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for ty::ClosureSubsts<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.func_substs.has_regions_escaping_depth(depth) ||
+            self.upvar_tys.iter().any(|t| t.has_regions_escaping_depth(depth))
+    }
+}
+
+impl<T:RegionEscape> RegionEscape for Vec<T> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.iter().any(|t| t.has_regions_escaping_depth(depth))
+    }
+}
+
+impl<'tcx> RegionEscape for ty::FnSig<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.inputs.has_regions_escaping_depth(depth) ||
+            self.output.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.iter_enumerated().any(|(space, _, t)| {
+            if space == subst::FnSpace {
+                t.has_regions_escaping_depth(depth+1)
+            } else {
+                t.has_regions_escaping_depth(depth)
+            }
+        })
+    }
+}
+
+impl<'tcx> RegionEscape for ty::TypeScheme<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.ty.has_regions_escaping_depth(depth)
+    }
+}
+
+impl RegionEscape for ty::Region {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.escapes_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for ty::GenericPredicates<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.predicates.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for ty::Predicate<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        match *self {
+            ty::Predicate::Trait(ref data) => data.has_regions_escaping_depth(depth),
+            ty::Predicate::Equate(ref data) => data.has_regions_escaping_depth(depth),
+            ty::Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth),
+            ty::Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth),
+            ty::Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth),
+            ty::Predicate::WellFormed(ty) => ty.has_regions_escaping_depth(depth),
+            ty::Predicate::ObjectSafe(_trait_def_id) => false,
+        }
+    }
+}
+
+impl<'tcx,P:RegionEscape> RegionEscape for traits::Obligation<'tcx,P> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.predicate.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for TraitRef<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
+            self.substs.regions.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for subst::RegionSubsts {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        match *self {
+            subst::ErasedRegions => false,
+            subst::NonerasedRegions(ref r) => {
+                r.iter().any(|t| t.has_regions_escaping_depth(depth))
+            }
+        }
+    }
+}
+
+impl<'tcx,T:RegionEscape> RegionEscape for ty::Binder<T> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.0.has_regions_escaping_depth(depth + 1)
+    }
+}
+
+impl<'tcx> RegionEscape for ty::FnOutput<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        match *self {
+            ty::FnConverging(t) => t.has_regions_escaping_depth(depth),
+            ty::FnDiverging => false
+        }
+    }
+}
+
+impl<'tcx> RegionEscape for ty::EquatePredicate<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for ty::TraitPredicate<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.trait_ref.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<T:RegionEscape,U:RegionEscape> RegionEscape for ty::OutlivesPredicate<T,U> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for ty::ProjectionPredicate<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.projection_ty.has_regions_escaping_depth(depth) ||
+            self.ty.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for ty::ProjectionTy<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.trait_ref.has_regions_escaping_depth(depth)
+    }
+}
+impl<'tcx,T:HasTypeFlags> HasTypeFlags for Vec<T> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self[..].has_type_flags(flags)
+    }
+}
+
+impl<'tcx,T:HasTypeFlags> HasTypeFlags for [T] {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.iter().any(|p| p.has_type_flags(flags))
+    }
+}
+
+impl<'tcx,T:HasTypeFlags> HasTypeFlags for VecPerParamSpace<T> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.iter().any(|p| p.has_type_flags(flags))
+    }
+}
+
+impl HasTypeFlags for abi::Abi {
+    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+        false
+    }
+}
+
+impl HasTypeFlags for hir::Unsafety {
+    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+        false
+    }
+}
+
+impl HasTypeFlags for ty::BuiltinBounds {
+    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+        false
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::ClosureTy<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.sig.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::ClosureUpvar<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.ty.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::ExistentialBounds<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.projection_bounds.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::InstantiatedPredicates<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.predicates.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::Predicate<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        match *self {
+            ty::Predicate::Trait(ref data) => data.has_type_flags(flags),
+            ty::Predicate::Equate(ref data) => data.has_type_flags(flags),
+            ty::Predicate::RegionOutlives(ref data) => data.has_type_flags(flags),
+            ty::Predicate::TypeOutlives(ref data) => data.has_type_flags(flags),
+            ty::Predicate::Projection(ref data) => data.has_type_flags(flags),
+            ty::Predicate::WellFormed(data) => data.has_type_flags(flags),
+            ty::Predicate::ObjectSafe(_trait_def_id) => false,
+        }
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::TraitPredicate<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.trait_ref.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::EquatePredicate<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.0.has_type_flags(flags) || self.1.has_type_flags(flags)
+    }
+}
+
+impl HasTypeFlags for ty::Region {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        if flags.intersects(TypeFlags::HAS_LOCAL_NAMES) {
+            // does this represent a region that cannot be named in a global
+            // way? used in fulfillment caching.
+            match *self {
+                ty::ReStatic | ty::ReEmpty => {}
+                _ => return true
+            }
+        }
+        if flags.intersects(TypeFlags::HAS_RE_INFER) {
+            match *self {
+                ty::ReVar(_) | ty::ReSkolemized(..) => { return true }
+                _ => {}
+            }
+        }
+        false
+    }
+}
+
+impl<T:HasTypeFlags,U:HasTypeFlags> HasTypeFlags for ty::OutlivesPredicate<T,U> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.0.has_type_flags(flags) || self.1.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::ProjectionPredicate<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.projection_ty.has_type_flags(flags) || self.ty.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::ProjectionTy<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.trait_ref.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for Ty<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.flags.get().intersects(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for TypeAndMut<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.ty.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for TraitRef<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.substs.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for subst::Substs<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.types.has_type_flags(flags) || match self.regions {
+            subst::ErasedRegions => false,
+            subst::NonerasedRegions(ref r) => r.has_type_flags(flags)
+        }
+    }
+}
+
+impl<'tcx,T> HasTypeFlags for Option<T>
+    where T : HasTypeFlags
+{
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.iter().any(|t| t.has_type_flags(flags))
+    }
+}
+
+impl<'tcx,T> HasTypeFlags for Rc<T>
+    where T : HasTypeFlags
+{
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        (**self).has_type_flags(flags)
+    }
+}
+
+impl<'tcx,T> HasTypeFlags for Box<T>
+    where T : HasTypeFlags
+{
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        (**self).has_type_flags(flags)
+    }
+}
+
+impl<T> HasTypeFlags for ty::Binder<T>
+    where T : HasTypeFlags
+{
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.0.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::FnOutput<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        match *self {
+            ty::FnConverging(t) => t.has_type_flags(flags),
+            ty::FnDiverging => false,
+        }
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::FnSig<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.inputs.iter().any(|t| t.has_type_flags(flags)) ||
+            self.output.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::BareFnTy<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.sig.has_type_flags(flags)
+    }
+}
+
+impl<'tcx> HasTypeFlags for ty::ClosureSubsts<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.func_substs.has_type_flags(flags) ||
+            self.upvar_tys.iter().any(|t| t.has_type_flags(flags))
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Lift implementations
+
+impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
+    type Lifted = (A::Lifted, B::Lifted);
+    fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b)))
+    }
+}
+
+impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
+    type Lifted = Vec<T::Lifted>;
+    fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
+        let mut result = Vec::with_capacity(self.len());
+        for x in self {
+            if let Some(value) = tcx.lift(x) {
+                result.push(value);
+            } else {
+                return None;
+            }
+        }
+        Some(result)
+    }
+}
+
+impl<'tcx> Lift<'tcx> for ty::Region {
+    type Lifted = Self;
+    fn lift_to_tcx(&self, _: &ty::ctxt<'tcx>) -> Option<ty::Region> {
+        Some(*self)
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> {
+    type Lifted = TraitRef<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<TraitRef<'tcx>> {
+        tcx.lift(&self.substs).map(|substs| TraitRef {
+            def_id: self.def_id,
+            substs: substs
+        })
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
+    type Lifted = ty::TraitPredicate<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
+        tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate {
+            trait_ref: trait_ref
+        })
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::EquatePredicate<'a> {
+    type Lifted = ty::EquatePredicate<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<ty::EquatePredicate<'tcx>> {
+        tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::EquatePredicate(a, b))
+    }
+}
+
+impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> {
+    type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>;
+    fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b))
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
+    type Lifted = ty::ProjectionPredicate<'tcx>;
+    fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
+        tcx.lift(&(self.projection_ty.trait_ref, self.ty)).map(|(trait_ref, ty)| {
+            ty::ProjectionPredicate {
+                projection_ty: ty::ProjectionTy {
+                    trait_ref: trait_ref,
+                    item_name: self.projection_ty.item_name
+                },
+                ty: ty
+            }
+        })
+    }
+}
+
+impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
+    type Lifted = ty::Binder<T::Lifted>;
+    fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&self.0).map(|x| ty::Binder(x))
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// TypeFoldable implementations.
+//
+// Ideally, each type should invoke `folder.fold_foo(self)` and
+// nothing else. In some cases, though, we haven't gotten around to
+// adding methods on the `folder` yet, and thus the folding is
+// hard-coded here. This is less-flexible, because folders cannot
+// override the behavior, but there are a lot of random types and one
+// can easily refactor the folding into the TypeFolder trait as
+// needed.
+
+macro_rules! CopyImpls {
+    ($($ty:ty),+) => {
+        $(
+            impl<'tcx> TypeFoldable<'tcx> for $ty {
+                fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> $ty {
+                    *self
+                }
+            }
+        )+
+    }
+}
+
+CopyImpls! { (), hir::Unsafety, abi::Abi }
+
+impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
+        (self.0.fold_with(folder), self.1.fold_with(folder))
+    }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option<T> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Option<T> {
+        self.as_ref().map(|t| t.fold_with(folder))
+    }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Rc<T> {
+        Rc::new((**self).fold_with(folder))
+    }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Box<T> {
+        let content: T = (**self).fold_with(folder);
+        box content
+    }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Vec<T> {
+        self.iter().map(|t| t.fold_with(folder)).collect()
+    }
+}
+
+impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
+        folder.fold_binder(self)
+    }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for OwnedSlice<T> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> OwnedSlice<T> {
+        self.iter().map(|t| t.fold_with(folder)).collect()
+    }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace<T> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> VecPerParamSpace<T> {
+
+        // Things in the Fn space take place under an additional level
+        // of region binding relative to the other spaces. This is
+        // because those entries are attached to a method, and methods
+        // always introduce a level of region binding.
+
+        let result = self.map_enumerated(|(space, index, elem)| {
+            if space == subst::FnSpace && index == 0 {
+                // enter new level when/if we reach the first thing in fn space
+                folder.enter_region_binder();
+            }
+            elem.fold_with(folder)
+        });
+        if result.len(subst::FnSpace) > 0 {
+            // if there was anything in fn space, exit the region binding level
+            folder.exit_region_binder();
+        }
+        result
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Ty<'tcx> {
+        folder.fold_ty(*self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::BareFnTy<'tcx> {
+        folder.fold_bare_fn_ty(self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureTy<'tcx> {
+        folder.fold_closure_ty(self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeAndMut<'tcx> {
+        folder.fold_mt(self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnOutput<'tcx> {
+        folder.fold_output(self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnSig<'tcx> {
+        folder.fold_fn_sig(self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitRef<'tcx> {
+        folder.fold_trait_ref(self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Region {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Region {
+        folder.fold_region(*self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> subst::Substs<'tcx> {
+        folder.fold_substs(self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureSubsts<'tcx> {
+        let func_substs = self.func_substs.fold_with(folder);
+        ty::ClosureSubsts {
+            func_substs: folder.tcx().mk_substs(func_substs),
+            upvar_tys: self.upvar_tys.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ItemSubsts<'tcx> {
+        ty::ItemSubsts {
+            substs: self.substs.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::AutoRef<'tcx> {
+        folder.fold_autoref(self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> ty::BuiltinBounds {
+        *self
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ExistentialBounds<'tcx> {
+        folder.fold_existential_bounds(self)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeParameterDef<'tcx> {
+        ty::TypeParameterDef {
+            name: self.name,
+            def_id: self.def_id,
+            space: self.space,
+            index: self.index,
+            default: self.default.fold_with(folder),
+            default_def_id: self.default_def_id,
+            object_lifetime_default: self.object_lifetime_default.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ObjectLifetimeDefault {
+        match *self {
+            ty::ObjectLifetimeDefault::Ambiguous =>
+                ty::ObjectLifetimeDefault::Ambiguous,
+
+            ty::ObjectLifetimeDefault::BaseDefault =>
+                ty::ObjectLifetimeDefault::BaseDefault,
+
+            ty::ObjectLifetimeDefault::Specific(r) =>
+                ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::RegionParameterDef {
+        ty::RegionParameterDef {
+            name: self.name,
+            def_id: self.def_id,
+            space: self.space,
+            index: self.index,
+            bounds: self.bounds.fold_with(folder)
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Generics<'tcx> {
+        ty::Generics {
+            types: self.types.fold_with(folder),
+            regions: self.regions.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::GenericPredicates<'tcx> {
+        ty::GenericPredicates {
+            predicates: self.predicates.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Predicate<'tcx> {
+        match *self {
+            ty::Predicate::Trait(ref a) =>
+                ty::Predicate::Trait(a.fold_with(folder)),
+            ty::Predicate::Equate(ref binder) =>
+                ty::Predicate::Equate(binder.fold_with(folder)),
+            ty::Predicate::RegionOutlives(ref binder) =>
+                ty::Predicate::RegionOutlives(binder.fold_with(folder)),
+            ty::Predicate::TypeOutlives(ref binder) =>
+                ty::Predicate::TypeOutlives(binder.fold_with(folder)),
+            ty::Predicate::Projection(ref binder) =>
+                ty::Predicate::Projection(binder.fold_with(folder)),
+            ty::Predicate::WellFormed(data) =>
+                ty::Predicate::WellFormed(data.fold_with(folder)),
+            ty::Predicate::ObjectSafe(trait_def_id) =>
+                ty::Predicate::ObjectSafe(trait_def_id),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionPredicate<'tcx> {
+        ty::ProjectionPredicate {
+            projection_ty: self.projection_ty.fold_with(folder),
+            ty: self.ty.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionTy<'tcx> {
+        ty::ProjectionTy {
+            trait_ref: self.trait_ref.fold_with(folder),
+            item_name: self.item_name,
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::InstantiatedPredicates<'tcx> {
+        ty::InstantiatedPredicates {
+            predicates: self.predicates.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
+    where O : TypeFoldable<'tcx>
+{
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> {
+        traits::Obligation {
+            cause: self.cause.clone(),
+            recursion_depth: self.recursion_depth,
+            predicate: self.predicate.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableImplData<'tcx, N> {
+        traits::VtableImplData {
+            impl_def_id: self.impl_def_id,
+            substs: self.substs.fold_with(folder),
+            nested: self.nested.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableClosureData<'tcx, N> {
+        traits::VtableClosureData {
+            closure_def_id: self.closure_def_id,
+            substs: self.substs.fold_with(folder),
+            nested: self.nested.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
+        traits::VtableDefaultImplData {
+            trait_def_id: self.trait_def_id,
+            nested: self.nested.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> {
+        traits::VtableBuiltinData {
+            nested: self.nested.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> {
+        match *self {
+            traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
+            traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
+            traits::VtableClosure(ref d) => {
+                traits::VtableClosure(d.fold_with(folder))
+            }
+            traits::VtableFnPointer(ref d) => {
+                traits::VtableFnPointer(d.fold_with(folder))
+            }
+            traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
+            traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
+            traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
+        traits::VtableObjectData {
+            upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
+            vtable_base: self.vtable_base
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> {
+        ty::EquatePredicate(self.0.fold_with(folder),
+                            self.1.fold_with(folder))
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitPredicate<'tcx> {
+        ty::TraitPredicate {
+            trait_ref: self.trait_ref.fold_with(folder)
+        }
+    }
+}
+
+impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
+    where T : TypeFoldable<'tcx>,
+          U : TypeFoldable<'tcx>,
+{
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::OutlivesPredicate<T,U> {
+        ty::OutlivesPredicate(self.0.fold_with(folder),
+                              self.1.fold_with(folder))
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureUpvar<'tcx> {
+        ty::ClosureUpvar {
+            def: self.def,
+            span: self.span,
+            ty: self.ty.fold_with(folder),
+        }
+    }
+}
+
+impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParameterEnvironment<'a, 'tcx> {
+        ty::ParameterEnvironment {
+            tcx: self.tcx,
+            free_substs: self.free_substs.fold_with(folder),
+            implicit_region_bound: self.implicit_region_bound.fold_with(folder),
+            caller_bounds: self.caller_bounds.fold_with(folder),
+            selection_cache: traits::SelectionCache::new(),
+            free_id: self.free_id,
+        }
+    }
+}
diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs
new file mode 100644
index 0000000000000..a04cc89ee18a0
--- /dev/null
+++ b/src/librustc/middle/ty/sty.rs
@@ -0,0 +1,1129 @@
+// Copyright 2012-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.
+
+//! This module contains TypeVariants and its major components
+
+use middle::def_id::DefId;
+use middle::region;
+use middle::subst::{self, Substs};
+use middle::traits;
+use middle::ty::{self, AdtDef, TypeFlags, Ty, TyS};
+use middle::ty::{RegionEscape, ToPredicate};
+use util::common::ErrorReported;
+
+use collections::enum_set::{self, EnumSet, CLike};
+use std::fmt;
+use std::ops;
+use std::mem;
+use syntax::abi;
+use syntax::ast::{Name, NodeId};
+
+use rustc_front::hir;
+
+use self::FnOutput::*;
+use self::InferTy::*;
+use self::TypeVariants::*;
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct TypeAndMut<'tcx> {
+    pub ty: Ty<'tcx>,
+    pub mutbl: hir::Mutability,
+}
+
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
+         RustcEncodable, RustcDecodable, Copy)]
+/// A "free" region `fr` can be interpreted as "some region
+/// at least as big as the scope `fr.scope`".
+pub struct FreeRegion {
+    pub scope: region::CodeExtent,
+    pub bound_region: BoundRegion
+}
+
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
+         RustcEncodable, RustcDecodable, Copy)]
+pub enum BoundRegion {
+    /// An anonymous region parameter for a given fn (&T)
+    BrAnon(u32),
+
+    /// Named region parameters for functions (a in &'a T)
+    ///
+    /// The def-id is needed to distinguish free regions in
+    /// the event of shadowing.
+    BrNamed(DefId, Name),
+
+    /// Fresh bound identifiers created during GLB computations.
+    BrFresh(u32),
+
+    // Anonymous region for the implicit env pointer parameter
+    // to a closure
+    BrEnv
+}
+
+// NB: If you change this, you'll probably want to change the corresponding
+// AST structure in libsyntax/ast.rs as well.
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum TypeVariants<'tcx> {
+    /// The primitive boolean type. Written as `bool`.
+    TyBool,
+
+    /// The primitive character type; holds a Unicode scalar value
+    /// (a non-surrogate code point).  Written as `char`.
+    TyChar,
+
+    /// A primitive signed integer type. For example, `i32`.
+    TyInt(hir::IntTy),
+
+    /// A primitive unsigned integer type. For example, `u32`.
+    TyUint(hir::UintTy),
+
+    /// A primitive floating-point type. For example, `f64`.
+    TyFloat(hir::FloatTy),
+
+    /// An enumerated type, defined with `enum`.
+    ///
+    /// Substs here, possibly against intuition, *may* contain `TyParam`s.
+    /// That is, even after substitution it is possible that there are type
+    /// variables. This happens when the `TyEnum` corresponds to an enum
+    /// definition and not a concrete use of it. To get the correct `TyEnum`
+    /// from the tcx, use the `NodeId` from the `hir::Ty` and look it up in
+    /// the `ast_ty_to_ty_cache`. This is probably true for `TyStruct` as
+    /// well.
+    TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>),
+
+    /// A structure type, defined with `struct`.
+    ///
+    /// See warning about substitutions for enumerated types.
+    TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>),
+
+    /// `Box<T>`; this is nominally a struct in the documentation, but is
+    /// special-cased internally. For example, it is possible to implicitly
+    /// move the contents of a box out of that box, and methods of any type
+    /// can have type `Box<Self>`.
+    TyBox(Ty<'tcx>),
+
+    /// The pointee of a string slice. Written as `str`.
+    TyStr,
+
+    /// An array with the given length. Written as `[T; n]`.
+    TyArray(Ty<'tcx>, usize),
+
+    /// The pointee of an array slice.  Written as `[T]`.
+    TySlice(Ty<'tcx>),
+
+    /// A raw pointer. Written as `*mut T` or `*const T`
+    TyRawPtr(TypeAndMut<'tcx>),
+
+    /// A reference; a pointer with an associated lifetime. Written as
+    /// `&a mut T` or `&'a T`.
+    TyRef(&'tcx Region, TypeAndMut<'tcx>),
+
+    /// If the def-id is Some(_), then this is the type of a specific
+    /// fn item. Otherwise, if None(_), it a fn pointer type.
+    ///
+    /// FIXME: Conflating function pointers and the type of a
+    /// function is probably a terrible idea; a function pointer is a
+    /// value with a specific type, but a function can be polymorphic
+    /// or dynamically dispatched.
+    TyBareFn(Option<DefId>, &'tcx BareFnTy<'tcx>),
+
+    /// A trait, defined with `trait`.
+    TyTrait(Box<TraitTy<'tcx>>),
+
+    /// The anonymous type of a closure. Used to represent the type of
+    /// `|a| a`.
+    TyClosure(DefId, Box<ClosureSubsts<'tcx>>),
+
+    /// A tuple type.  For example, `(i32, bool)`.
+    TyTuple(Vec<Ty<'tcx>>),
+
+    /// The projection of an associated type.  For example,
+    /// `<T as Trait<..>>::N`.
+    TyProjection(ProjectionTy<'tcx>),
+
+    /// A type parameter; for example, `T` in `fn f<T>(x: T) {}
+    TyParam(ParamTy),
+
+    /// A type variable used during type-checking.
+    TyInfer(InferTy),
+
+    /// A placeholder for a type which could not be computed; this is
+    /// propagated to avoid useless error messages.
+    TyError,
+}
+
+/// A closure can be modeled as a struct that looks like:
+///
+///     struct Closure<'l0...'li, T0...Tj, U0...Uk> {
+///         upvar0: U0,
+///         ...
+///         upvark: Uk
+///     }
+///
+/// where 'l0...'li and T0...Tj are the lifetime and type parameters
+/// in scope on the function that defined the closure, and U0...Uk are
+/// type parameters representing the types of its upvars (borrowed, if
+/// appropriate).
+///
+/// So, for example, given this function:
+///
+///     fn foo<'a, T>(data: &'a mut T) {
+///          do(|| data.count += 1)
+///     }
+///
+/// the type of the closure would be something like:
+///
+///     struct Closure<'a, T, U0> {
+///         data: U0
+///     }
+///
+/// Note that the type of the upvar is not specified in the struct.
+/// You may wonder how the impl would then be able to use the upvar,
+/// if it doesn't know it's type? The answer is that the impl is
+/// (conceptually) not fully generic over Closure but rather tied to
+/// instances with the expected upvar types:
+///
+///     impl<'b, 'a, T> FnMut() for Closure<'a, T, &'b mut &'a mut T> {
+///         ...
+///     }
+///
+/// You can see that the *impl* fully specified the type of the upvar
+/// and thus knows full well that `data` has type `&'b mut &'a mut T`.
+/// (Here, I am assuming that `data` is mut-borrowed.)
+///
+/// Now, the last question you may ask is: Why include the upvar types
+/// as extra type parameters? The reason for this design is that the
+/// upvar types can reference lifetimes that are internal to the
+/// creating function. In my example above, for example, the lifetime
+/// `'b` represents the extent of the closure itself; this is some
+/// subset of `foo`, probably just the extent of the call to the to
+/// `do()`. If we just had the lifetime/type parameters from the
+/// enclosing function, we couldn't name this lifetime `'b`. Note that
+/// there can also be lifetimes in the types of the upvars themselves,
+/// if one of them happens to be a reference to something that the
+/// creating fn owns.
+///
+/// OK, you say, so why not create a more minimal set of parameters
+/// that just includes the extra lifetime parameters? The answer is
+/// primarily that it would be hard --- we don't know at the time when
+/// we create the closure type what the full types of the upvars are,
+/// nor do we know which are borrowed and which are not. In this
+/// design, we can just supply a fresh type parameter and figure that
+/// out later.
+///
+/// All right, you say, but why include the type parameters from the
+/// original function then? The answer is that trans may need them
+/// when monomorphizing, and they may not appear in the upvars.  A
+/// closure could capture no variables but still make use of some
+/// in-scope type parameter with a bound (e.g., if our example above
+/// had an extra `U: Default`, and the closure called `U::default()`).
+///
+/// There is another reason. This design (implicitly) prohibits
+/// closures from capturing themselves (except via a trait
+/// object). This simplifies closure inference considerably, since it
+/// means that when we infer the kind of a closure or its upvars, we
+/// don't have to handle cycles where the decisions we make for
+/// closure C wind up influencing the decisions we ought to make for
+/// closure C (which would then require fixed point iteration to
+/// handle). Plus it fixes an ICE. :P
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ClosureSubsts<'tcx> {
+    /// Lifetime and type parameters from the enclosing function.
+    /// These are separated out because trans wants to pass them around
+    /// when monomorphizing.
+    pub func_substs: &'tcx Substs<'tcx>,
+
+    /// The types of the upvars. The list parallels the freevars and
+    /// `upvar_borrows` lists. These are kept distinct so that we can
+    /// easily index into them.
+    pub upvar_tys: Vec<Ty<'tcx>>
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct TraitTy<'tcx> {
+    pub principal: ty::PolyTraitRef<'tcx>,
+    pub bounds: ExistentialBounds<'tcx>,
+}
+
+impl<'tcx> TraitTy<'tcx> {
+    pub fn principal_def_id(&self) -> DefId {
+        self.principal.0.def_id
+    }
+
+    /// Object types don't have a self-type specified. Therefore, when
+    /// we convert the principal trait-ref into a normal trait-ref,
+    /// you must give *some* self-type. A common choice is `mk_err()`
+    /// or some skolemized type.
+    pub fn principal_trait_ref_with_self_ty(&self,
+                                            tcx: &ty::ctxt<'tcx>,
+                                            self_ty: Ty<'tcx>)
+                                            -> ty::PolyTraitRef<'tcx>
+    {
+        // otherwise the escaping regions would be captured by the binder
+        assert!(!self_ty.has_escaping_regions());
+
+        ty::Binder(TraitRef {
+            def_id: self.principal.0.def_id,
+            substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)),
+        })
+    }
+
+    pub fn projection_bounds_with_self_ty(&self,
+                                          tcx: &ty::ctxt<'tcx>,
+                                          self_ty: Ty<'tcx>)
+                                          -> Vec<ty::PolyProjectionPredicate<'tcx>>
+    {
+        // otherwise the escaping regions would be captured by the binders
+        assert!(!self_ty.has_escaping_regions());
+
+        self.bounds.projection_bounds.iter()
+            .map(|in_poly_projection_predicate| {
+                let in_projection_ty = &in_poly_projection_predicate.0.projection_ty;
+                let substs = tcx.mk_substs(in_projection_ty.trait_ref.substs.with_self_ty(self_ty));
+                let trait_ref = ty::TraitRef::new(in_projection_ty.trait_ref.def_id,
+                                              substs);
+                let projection_ty = ty::ProjectionTy {
+                    trait_ref: trait_ref,
+                    item_name: in_projection_ty.item_name
+                };
+                ty::Binder(ty::ProjectionPredicate {
+                    projection_ty: projection_ty,
+                    ty: in_poly_projection_predicate.0.ty
+                })
+            })
+            .collect()
+    }
+}
+
+/// A complete reference to a trait. These take numerous guises in syntax,
+/// but perhaps the most recognizable form is in a where clause:
+///
+///     T : Foo<U>
+///
+/// This would be represented by a trait-reference where the def-id is the
+/// def-id for the trait `Foo` and the substs defines `T` as parameter 0 in the
+/// `SelfSpace` and `U` as parameter 0 in the `TypeSpace`.
+///
+/// Trait references also appear in object types like `Foo<U>`, but in
+/// that case the `Self` parameter is absent from the substitutions.
+///
+/// Note that a `TraitRef` introduces a level of region binding, to
+/// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
+/// U>` or higher-ranked object types.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct TraitRef<'tcx> {
+    pub def_id: DefId,
+    pub substs: &'tcx Substs<'tcx>,
+}
+
+pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
+
+impl<'tcx> PolyTraitRef<'tcx> {
+    pub fn self_ty(&self) -> Ty<'tcx> {
+        self.0.self_ty()
+    }
+
+    pub fn def_id(&self) -> DefId {
+        self.0.def_id
+    }
+
+    pub fn substs(&self) -> &'tcx Substs<'tcx> {
+        // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
+        self.0.substs
+    }
+
+    pub fn input_types(&self) -> &[Ty<'tcx>] {
+        // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
+        self.0.input_types()
+    }
+
+    pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
+        // Note that we preserve binding levels
+        Binder(ty::TraitPredicate { trait_ref: self.0.clone() })
+    }
+}
+
+/// Binder is a binder for higher-ranked lifetimes. It is part of the
+/// compiler's representation for things like `for<'a> Fn(&'a isize)`
+/// (which would be represented by the type `PolyTraitRef ==
+/// Binder<TraitRef>`). Note that when we skolemize, instantiate,
+/// erase, or otherwise "discharge" these bound regions, we change the
+/// type from `Binder<T>` to just `T` (see
+/// e.g. `liberate_late_bound_regions`).
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct Binder<T>(pub T);
+
+impl<T> Binder<T> {
+    /// Skips the binder and returns the "bound" value. This is a
+    /// risky thing to do because it's easy to get confused about
+    /// debruijn indices and the like. It is usually better to
+    /// discharge the binder using `no_late_bound_regions` or
+    /// `replace_late_bound_regions` or something like
+    /// that. `skip_binder` is only valid when you are either
+    /// extracting data that has nothing to do with bound regions, you
+    /// are doing some sort of test that does not involve bound
+    /// regions, or you are being very careful about your depth
+    /// accounting.
+    ///
+    /// Some examples where `skip_binder` is reasonable:
+    /// - extracting the def-id from a PolyTraitRef;
+    /// - comparing the self type of a PolyTraitRef to see if it is equal to
+    ///   a type parameter `X`, since the type `X`  does not reference any regions
+    pub fn skip_binder(&self) -> &T {
+        &self.0
+    }
+
+    pub fn as_ref(&self) -> Binder<&T> {
+        ty::Binder(&self.0)
+    }
+
+    pub fn map_bound_ref<F,U>(&self, f: F) -> Binder<U>
+        where F: FnOnce(&T) -> U
+    {
+        self.as_ref().map_bound(f)
+    }
+
+    pub fn map_bound<F,U>(self, f: F) -> Binder<U>
+        where F: FnOnce(T) -> U
+    {
+        ty::Binder(f(self.0))
+    }
+}
+
+impl fmt::Debug for TypeFlags {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.bits)
+    }
+}
+
+/// Represents the projection of an associated type. In explicit UFCS
+/// form this would be written `<T as Trait<..>>::N`.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ProjectionTy<'tcx> {
+    /// The trait reference `T as Trait<..>`.
+    pub trait_ref: ty::TraitRef<'tcx>,
+
+    /// The name `N` of the associated type.
+    pub item_name: Name,
+}
+
+impl<'tcx> ProjectionTy<'tcx> {
+    pub fn sort_key(&self) -> (DefId, Name) {
+        (self.trait_ref.def_id, self.item_name)
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct BareFnTy<'tcx> {
+    pub unsafety: hir::Unsafety,
+    pub abi: abi::Abi,
+    pub sig: PolyFnSig<'tcx>,
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct ClosureTy<'tcx> {
+    pub unsafety: hir::Unsafety,
+    pub abi: abi::Abi,
+    pub sig: PolyFnSig<'tcx>,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub enum FnOutput<'tcx> {
+    FnConverging(Ty<'tcx>),
+    FnDiverging
+}
+
+impl<'tcx> FnOutput<'tcx> {
+    pub fn diverges(&self) -> bool {
+        *self == FnDiverging
+    }
+
+    pub fn unwrap(self) -> Ty<'tcx> {
+        match self {
+            ty::FnConverging(t) => t,
+            ty::FnDiverging => unreachable!()
+        }
+    }
+
+    pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> {
+        match self {
+            ty::FnConverging(t) => t,
+            ty::FnDiverging => def
+        }
+    }
+}
+
+pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
+
+impl<'tcx> PolyFnOutput<'tcx> {
+    pub fn diverges(&self) -> bool {
+        self.0.diverges()
+    }
+}
+
+/// Signature of a function type, which I have arbitrarily
+/// decided to use to refer to the input/output types.
+///
+/// - `inputs` is the list of arguments and their modes.
+/// - `output` is the return type.
+/// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct FnSig<'tcx> {
+    pub inputs: Vec<Ty<'tcx>>,
+    pub output: FnOutput<'tcx>,
+    pub variadic: bool
+}
+
+pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
+
+impl<'tcx> PolyFnSig<'tcx> {
+    pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
+        self.map_bound_ref(|fn_sig| fn_sig.inputs.clone())
+    }
+    pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
+        self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
+    }
+    pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
+        self.map_bound_ref(|fn_sig| fn_sig.output.clone())
+    }
+    pub fn variadic(&self) -> bool {
+        self.skip_binder().variadic
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ParamTy {
+    pub space: subst::ParamSpace,
+    pub idx: u32,
+    pub name: Name,
+}
+
+/// A [De Bruijn index][dbi] is a standard means of representing
+/// regions (and perhaps later types) in a higher-ranked setting. In
+/// particular, imagine a type like this:
+///
+///     for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
+///     ^          ^            |        |         |
+///     |          |            |        |         |
+///     |          +------------+ 1      |         |
+///     |                                |         |
+///     +--------------------------------+ 2       |
+///     |                                          |
+///     +------------------------------------------+ 1
+///
+/// In this type, there are two binders (the outer fn and the inner
+/// fn). We need to be able to determine, for any given region, which
+/// fn type it is bound by, the inner or the outer one. There are
+/// various ways you can do this, but a De Bruijn index is one of the
+/// more convenient and has some nice properties. The basic idea is to
+/// count the number of binders, inside out. Some examples should help
+/// clarify what I mean.
+///
+/// Let's start with the reference type `&'b isize` that is the first
+/// argument to the inner function. This region `'b` is assigned a De
+/// Bruijn index of 1, meaning "the innermost binder" (in this case, a
+/// fn). The region `'a` that appears in the second argument type (`&'a
+/// isize`) would then be assigned a De Bruijn index of 2, meaning "the
+/// second-innermost binder". (These indices are written on the arrays
+/// in the diagram).
+///
+/// What is interesting is that De Bruijn index attached to a particular
+/// variable will vary depending on where it appears. For example,
+/// the final type `&'a char` also refers to the region `'a` declared on
+/// the outermost fn. But this time, this reference is not nested within
+/// any other binders (i.e., it is not an argument to the inner fn, but
+/// rather the outer one). Therefore, in this case, it is assigned a
+/// De Bruijn index of 1, because the innermost binder in that location
+/// is the outer fn.
+///
+/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index
+#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy)]
+pub struct DebruijnIndex {
+    // We maintain the invariant that this is never 0. So 1 indicates
+    // the innermost binder. To ensure this, create with `DebruijnIndex::new`.
+    pub depth: u32,
+}
+
+/// Representation of regions.
+///
+/// Unlike types, most region variants are "fictitious", not concrete,
+/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only
+/// ones representing concrete regions.
+///
+/// ## Bound Regions
+///
+/// These are regions that are stored behind a binder and must be substituted
+/// with some concrete region before being used. There are 2 kind of
+/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef,
+/// and are substituted by a Substs,  and late-bound, which are part of
+/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by
+/// the likes of `liberate_late_bound_regions`. The distinction exists
+/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
+///
+/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild"
+/// outside their binder, e.g. in types passed to type inference, and
+/// should first be substituted (by skolemized regions, free regions,
+/// or region variables).
+///
+/// ## Skolemized and Free Regions
+///
+/// One often wants to work with bound regions without knowing their precise
+/// identity. For example, when checking a function, the lifetime of a borrow
+/// can end up being assigned to some region parameter. In these cases,
+/// it must be ensured that bounds on the region can't be accidentally
+/// assumed without being checked.
+///
+/// The process of doing that is called "skolemization". The bound regions
+/// are replaced by skolemized markers, which don't satisfy any relation
+/// not explicity provided.
+///
+/// There are 2 kinds of skolemized regions in rustc: `ReFree` and
+/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed
+/// to be used. These also support explicit bounds: both the internally-stored
+/// *scope*, which the region is assumed to outlive, as well as other
+/// relations stored in the `FreeRegionMap`. Note that these relations
+/// aren't checked when you `make_subregion` (or `mk_eqty`), only by
+/// `resolve_regions_and_report_errors`.
+///
+/// When working with higher-ranked types, some region relations aren't
+/// yet known, so you can't just call `resolve_regions_and_report_errors`.
+/// `ReSkolemized` is designed for this purpose. In these contexts,
+/// there's also the risk that some inference variable laying around will
+/// get unified with your skolemized region: if you want to check whether
+/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
+/// with a skolemized region `'%a`, the variable `'_` would just be
+/// instantiated to the skolemized region `'%a`, which is wrong because
+/// the inference variable is supposed to satisfy the relation
+/// *for every value of the skolemized region*. To ensure that doesn't
+/// happen, you can use `leak_check`. This is more clearly explained
+/// by infer/higher_ranked/README.md.
+///
+/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
+/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
+#[derive(Clone, PartialEq, Eq, Hash, Copy)]
+pub enum Region {
+    // Region bound in a type or fn declaration which will be
+    // substituted 'early' -- that is, at the same time when type
+    // parameters are substituted.
+    ReEarlyBound(EarlyBoundRegion),
+
+    // Region bound in a function scope, which will be substituted when the
+    // function is called.
+    ReLateBound(DebruijnIndex, BoundRegion),
+
+    /// When checking a function body, the types of all arguments and so forth
+    /// that refer to bound region parameters are modified to refer to free
+    /// region parameters.
+    ReFree(FreeRegion),
+
+    /// A concrete region naming some statically determined extent
+    /// (e.g. an expression or sequence of statements) within the
+    /// current function.
+    ReScope(region::CodeExtent),
+
+    /// Static data that has an "infinite" lifetime. Top in the region lattice.
+    ReStatic,
+
+    /// A region variable.  Should not exist after typeck.
+    ReVar(RegionVid),
+
+    /// A skolemized region - basically the higher-ranked version of ReFree.
+    /// Should not exist after typeck.
+    ReSkolemized(SkolemizedRegionVid, BoundRegion),
+
+    /// Empty lifetime is for data that is never accessed.
+    /// Bottom in the region lattice. We treat ReEmpty somewhat
+    /// specially; at least right now, we do not generate instances of
+    /// it during the GLB computations, but rather
+    /// generate an error instead. This is to improve error messages.
+    /// The only way to get an instance of ReEmpty is to have a region
+    /// variable with no constraints.
+    ReEmpty,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
+pub struct EarlyBoundRegion {
+    pub param_id: NodeId,
+    pub space: subst::ParamSpace,
+    pub index: u32,
+    pub name: Name,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct TyVid {
+    pub index: u32
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct IntVid {
+    pub index: u32
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct FloatVid {
+    pub index: u32
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
+pub struct RegionVid {
+    pub index: u32
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SkolemizedRegionVid {
+    pub index: u32
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub enum InferTy {
+    TyVar(TyVid),
+    IntVar(IntVid),
+    FloatVar(FloatVid),
+
+    /// A `FreshTy` is one that is generated as a replacement for an
+    /// unbound type variable. This is convenient for caching etc. See
+    /// `middle::infer::freshen` for more details.
+    FreshTy(u32),
+    FreshIntTy(u32),
+    FreshFloatTy(u32)
+}
+
+/// Bounds suitable for an existentially quantified type parameter
+/// such as those that appear in object types or closure types.
+#[derive(PartialEq, Eq, Hash, Clone)]
+pub struct ExistentialBounds<'tcx> {
+    pub region_bound: ty::Region,
+    pub builtin_bounds: BuiltinBounds,
+    pub projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
+}
+
+impl<'tcx> ExistentialBounds<'tcx> {
+    pub fn new(region_bound: ty::Region,
+               builtin_bounds: BuiltinBounds,
+               projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>)
+               -> Self {
+        let mut projection_bounds = projection_bounds;
+        projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key()));
+        ExistentialBounds {
+            region_bound: region_bound,
+            builtin_bounds: builtin_bounds,
+            projection_bounds: projection_bounds
+        }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct BuiltinBounds(EnumSet<BuiltinBound>);
+
+impl BuiltinBounds {
+    pub fn empty() -> BuiltinBounds {
+        BuiltinBounds(EnumSet::new())
+    }
+
+    pub fn iter(&self) -> enum_set::Iter<BuiltinBound> {
+        self.into_iter()
+    }
+
+    pub fn to_predicates<'tcx>(&self,
+                               tcx: &ty::ctxt<'tcx>,
+                               self_ty: Ty<'tcx>) -> Vec<ty::Predicate<'tcx>> {
+        self.iter().filter_map(|builtin_bound|
+            match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, self_ty) {
+                Ok(trait_ref) => Some(trait_ref.to_predicate()),
+                Err(ErrorReported) => { None }
+            }
+        ).collect()
+    }
+}
+
+impl ops::Deref for BuiltinBounds {
+    type Target = EnumSet<BuiltinBound>;
+    fn deref(&self) -> &Self::Target { &self.0 }
+}
+
+impl ops::DerefMut for BuiltinBounds {
+    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
+}
+
+impl<'a> IntoIterator for &'a BuiltinBounds {
+    type Item = BuiltinBound;
+    type IntoIter = enum_set::Iter<BuiltinBound>;
+    fn into_iter(self) -> Self::IntoIter {
+        (**self).into_iter()
+    }
+}
+
+#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
+           Debug, Copy)]
+#[repr(usize)]
+pub enum BuiltinBound {
+    Send,
+    Sized,
+    Copy,
+    Sync,
+}
+
+impl CLike for BuiltinBound {
+    fn to_usize(&self) -> usize {
+        *self as usize
+    }
+    fn from_usize(v: usize) -> BuiltinBound {
+        unsafe { mem::transmute(v) }
+    }
+}
+
+impl<'tcx> ty::ctxt<'tcx> {
+    pub fn try_add_builtin_trait(&self,
+                                 trait_def_id: DefId,
+                                 builtin_bounds: &mut EnumSet<BuiltinBound>)
+                                 -> bool
+    {
+        //! Checks whether `trait_ref` refers to one of the builtin
+        //! traits, like `Send`, and adds the corresponding
+        //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
+        //! is a builtin trait.
+
+        match self.lang_items.to_builtin_kind(trait_def_id) {
+            Some(bound) => { builtin_bounds.insert(bound); true }
+            None => false
+        }
+    }
+}
+
+impl DebruijnIndex {
+    pub fn new(depth: u32) -> DebruijnIndex {
+        assert!(depth > 0);
+        DebruijnIndex { depth: depth }
+    }
+
+    pub fn shifted(&self, amount: u32) -> DebruijnIndex {
+        DebruijnIndex { depth: self.depth + amount }
+    }
+}
+
+// Region utilities
+impl Region {
+    pub fn is_bound(&self) -> bool {
+        match *self {
+            ty::ReEarlyBound(..) => true,
+            ty::ReLateBound(..) => true,
+            _ => false
+        }
+    }
+
+    pub fn needs_infer(&self) -> bool {
+        match *self {
+            ty::ReVar(..) | ty::ReSkolemized(..) => true,
+            _ => false
+        }
+    }
+
+    pub fn escapes_depth(&self, depth: u32) -> bool {
+        match *self {
+            ty::ReLateBound(debruijn, _) => debruijn.depth > depth,
+            _ => false,
+        }
+    }
+
+    /// Returns the depth of `self` from the (1-based) binding level `depth`
+    pub fn from_depth(&self, depth: u32) -> Region {
+        match *self {
+            ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
+                depth: debruijn.depth - (depth - 1)
+            }, r),
+            r => r
+        }
+    }
+}
+
+// Type utilities
+impl<'tcx> TyS<'tcx> {
+    pub fn is_nil(&self) -> bool {
+        match self.sty {
+            TyTuple(ref tys) => tys.is_empty(),
+            _ => false
+        }
+    }
+
+    pub fn is_empty(&self, _cx: &ty::ctxt) -> bool {
+        // FIXME(#24885): be smarter here
+        match self.sty {
+            TyEnum(def, _) | TyStruct(def, _) => def.is_empty(),
+            _ => false
+        }
+    }
+
+    pub fn is_ty_var(&self) -> bool {
+        match self.sty {
+            TyInfer(TyVar(_)) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_bool(&self) -> bool { self.sty == TyBool }
+
+    pub fn is_self(&self) -> bool {
+        match self.sty {
+            TyParam(ref p) => p.space == subst::SelfSpace,
+            _ => false
+        }
+    }
+
+    fn is_slice(&self) -> bool {
+        match self.sty {
+            TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty {
+                TySlice(_) | TyStr => true,
+                _ => false,
+            },
+            _ => false
+        }
+    }
+
+    pub fn is_structural(&self) -> bool {
+        match self.sty {
+            TyStruct(..) | TyTuple(_) | TyEnum(..) |
+            TyArray(..) | TyClosure(..) => true,
+            _ => self.is_slice() | self.is_trait()
+        }
+    }
+
+    #[inline]
+    pub fn is_simd(&self) -> bool {
+        match self.sty {
+            TyStruct(def, _) => def.is_simd(),
+            _ => false
+        }
+    }
+
+    pub fn sequence_element_type(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
+        match self.sty {
+            TyArray(ty, _) | TySlice(ty) => ty,
+            TyStr => cx.mk_mach_uint(hir::TyU8),
+            _ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}",
+                                      self)),
+        }
+    }
+
+    pub fn simd_type(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
+        match self.sty {
+            TyStruct(def, substs) => {
+                def.struct_variant().fields[0].ty(cx, substs)
+            }
+            _ => panic!("simd_type called on invalid type")
+        }
+    }
+
+    pub fn simd_size(&self, _cx: &ty::ctxt) -> usize {
+        match self.sty {
+            TyStruct(def, _) => def.struct_variant().fields.len(),
+            _ => panic!("simd_size called on invalid type")
+        }
+    }
+
+    pub fn is_region_ptr(&self) -> bool {
+        match self.sty {
+            TyRef(..) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_unsafe_ptr(&self) -> bool {
+        match self.sty {
+            TyRawPtr(_) => return true,
+            _ => return false
+        }
+    }
+
+    pub fn is_unique(&self) -> bool {
+        match self.sty {
+            TyBox(_) => true,
+            _ => false
+        }
+    }
+
+    /*
+     A scalar type is one that denotes an atomic datum, with no sub-components.
+     (A TyRawPtr is scalar because it represents a non-managed pointer, so its
+     contents are abstract to rustc.)
+    */
+    pub fn is_scalar(&self) -> bool {
+        match self.sty {
+            TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) |
+            TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) |
+            TyBareFn(..) | TyRawPtr(_) => true,
+            _ => false
+        }
+    }
+
+    /// Returns true if this type is a floating point type and false otherwise.
+    pub fn is_floating_point(&self) -> bool {
+        match self.sty {
+            TyFloat(_) |
+            TyInfer(FloatVar(_)) => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_trait(&self) -> bool {
+        match self.sty {
+            TyTrait(..) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_integral(&self) -> bool {
+        match self.sty {
+            TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_fresh(&self) -> bool {
+        match self.sty {
+            TyInfer(FreshTy(_)) => true,
+            TyInfer(FreshIntTy(_)) => true,
+            TyInfer(FreshFloatTy(_)) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_uint(&self) -> bool {
+        match self.sty {
+            TyInfer(IntVar(_)) | TyUint(hir::TyUs) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_char(&self) -> bool {
+        match self.sty {
+            TyChar => true,
+            _ => false
+        }
+    }
+
+    pub fn is_bare_fn(&self) -> bool {
+        match self.sty {
+            TyBareFn(..) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_bare_fn_item(&self) -> bool {
+        match self.sty {
+            TyBareFn(Some(_), _) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_fp(&self) -> bool {
+        match self.sty {
+            TyInfer(FloatVar(_)) | TyFloat(_) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_numeric(&self) -> bool {
+        self.is_integral() || self.is_fp()
+    }
+
+    pub fn is_signed(&self) -> bool {
+        match self.sty {
+            TyInt(_) => true,
+            _ => false
+        }
+    }
+
+    pub fn is_machine(&self) -> bool {
+        match self.sty {
+            TyInt(hir::TyIs) | TyUint(hir::TyUs) => false,
+            TyInt(..) | TyUint(..) | TyFloat(..) => true,
+            _ => false
+        }
+    }
+
+    // Returns the type and mutability of *ty.
+    //
+    // The parameter `explicit` indicates if this is an *explicit* dereference.
+    // Some types---notably unsafe ptrs---can only be dereferenced explicitly.
+    pub fn builtin_deref(&self, explicit: bool, pref: ty::LvaluePreference)
+        -> Option<TypeAndMut<'tcx>>
+    {
+        match self.sty {
+            TyBox(ty) => {
+                Some(TypeAndMut {
+                    ty: ty,
+                    mutbl: if pref == ty::PreferMutLvalue {
+                        hir::MutMutable
+                    } else {
+                        hir::MutImmutable
+                    },
+                })
+            },
+            TyRef(_, mt) => Some(mt),
+            TyRawPtr(mt) if explicit => Some(mt),
+            _ => None
+        }
+    }
+
+    // Returns the type of ty[i]
+    pub fn builtin_index(&self) -> Option<Ty<'tcx>> {
+        match self.sty {
+            TyArray(ty, _) | TySlice(ty) => Some(ty),
+            _ => None
+        }
+    }
+
+    pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
+        match self.sty {
+            TyBareFn(_, ref f) => &f.sig,
+            _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self)
+        }
+    }
+
+    /// Returns the ABI of the given function.
+    pub fn fn_abi(&self) -> abi::Abi {
+        match self.sty {
+            TyBareFn(_, ref f) => f.abi,
+            _ => panic!("Ty::fn_abi() called on non-fn type"),
+        }
+    }
+
+    // Type accessors for substructures of types
+    pub fn fn_args(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
+        self.fn_sig().inputs()
+    }
+
+    pub fn fn_ret(&self) -> Binder<FnOutput<'tcx>> {
+        self.fn_sig().output()
+    }
+
+    pub fn is_fn(&self) -> bool {
+        match self.sty {
+            TyBareFn(..) => true,
+            _ => false
+        }
+    }
+
+    pub fn ty_to_def_id(&self) -> Option<DefId> {
+        match self.sty {
+            TyTrait(ref tt) => Some(tt.principal_def_id()),
+            TyStruct(def, _) |
+            TyEnum(def, _) => Some(def.did),
+            TyClosure(id, _) => Some(id),
+            _ => None
+        }
+    }
+
+    pub fn ty_adt_def(&self) -> Option<AdtDef<'tcx>> {
+        match self.sty {
+            TyStruct(adt, _) | TyEnum(adt, _) => Some(adt),
+            _ => None
+        }
+    }
+}
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 222de42643297..99e41bd22b8bb 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -21,7 +21,7 @@ use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple};
 use middle::ty::TyClosure;
 use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
 use middle::ty::{self, TypeAndMut, Ty, HasTypeFlags};
-use middle::ty::fold::{self, TypeFoldable};
+use middle::ty::fold::TypeFoldable;
 
 use std::fmt;
 use syntax::abi;
@@ -219,7 +219,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter,
         }
     };
 
-    let new_value = fold::replace_late_bound_regions(tcx, &value, |br| {
+    let new_value = tcx.replace_late_bound_regions(&value, |br| {
         let _ = start_or_continue(f, "for<", ", ");
         ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
             ty::BrNamed(_, name) => {
@@ -255,7 +255,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter,
 struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>, Vec<ty::ProjectionPredicate<'tcx>>);
 
 impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> {
-    fn fold_with<F: fold::TypeFolder<'tcx>>(&self, folder: &mut F)
+    fn fold_with<F:ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F)
                                               -> TraitAndProjections<'tcx> {
         TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder))
     }
@@ -388,6 +388,53 @@ impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> {
     }
 }
 
+impl<'tcx> fmt::Debug for ty::AutoAdjustment<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::AdjustReifyFnPointer => {
+                write!(f, "AdjustReifyFnPointer")
+            }
+            ty::AdjustUnsafeFnPointer => {
+                write!(f, "AdjustUnsafeFnPointer")
+            }
+            ty::AdjustDerefRef(ref data) => {
+                write!(f, "{:?}", data)
+            }
+        }
+    }
+}
+
+impl<'tcx> fmt::Debug for ty::AutoDerefRef<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
+               self.autoderefs, self.unsize, self.autoref)
+    }
+}
+
+impl<'tcx> fmt::Debug for ty::TraitTy<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "TraitTy({:?},{:?})",
+               self.principal,
+               self.bounds)
+    }
+}
+
+impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::Predicate::Trait(ref a) => write!(f, "{:?}", a),
+            ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
+            ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
+            ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
+            ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair),
+            ty::Predicate::WellFormed(ty) => write!(f, "WF({:?})", ty),
+            ty::Predicate::ObjectSafe(trait_def_id) => {
+                write!(f, "ObjectSafe({:?})", trait_def_id)
+            }
+        }
+    }
+}
+
 impl fmt::Display for ty::BoundRegion {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if verbose() {
@@ -452,6 +499,45 @@ impl fmt::Debug for ty::Region {
     }
 }
 
+impl<'tcx> fmt::Debug for ty::ClosureTy<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ClosureTy({},{:?},{})",
+               self.unsafety,
+               self.sig,
+               self.abi)
+    }
+}
+
+impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ClosureUpvar({:?},{:?})",
+               self.def,
+               self.ty)
+    }
+}
+
+impl<'a, 'tcx> fmt::Debug for ty::ParameterEnvironment<'a, 'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "ParameterEnvironment(\
+            free_substs={:?}, \
+            implicit_region_bound={:?}, \
+            caller_bounds={:?})",
+            self.free_substs,
+            self.implicit_region_bound,
+            self.caller_bounds)
+    }
+}
+
+impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
+            ty::ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
+            ty::ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
+        }
+    }
+}
+
 impl fmt::Display for ty::Region {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if verbose() {
@@ -486,6 +572,17 @@ impl fmt::Debug for ty::FreeRegion {
     }
 }
 
+impl fmt::Debug for ty::Variance {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(match *self {
+            ty::Covariant => "+",
+            ty::Contravariant => "-",
+            ty::Invariant => "o",
+            ty::Bivariant => "*",
+        })
+    }
+}
+
 impl fmt::Debug for ty::ItemVariances {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "ItemVariances(types={:?}, regions={:?})",
@@ -570,6 +667,58 @@ impl fmt::Display for ty::BuiltinBounds {
     }
 }
 
+impl fmt::Debug for ty::TyVid {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "_#{}t", self.index)
+    }
+}
+
+impl fmt::Debug for ty::IntVid {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "_#{}i", self.index)
+    }
+}
+
+impl fmt::Debug for ty::FloatVid {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "_#{}f", self.index)
+    }
+}
+
+impl fmt::Debug for ty::RegionVid {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "'_#{}r", self.index)
+    }
+}
+
+impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "({:?}; variadic: {})->{:?}", self.inputs, self.variadic, self.output)
+    }
+}
+
+impl fmt::Debug for ty::InferTy {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::TyVar(ref v) => v.fmt(f),
+            ty::IntVar(ref v) => v.fmt(f),
+            ty::FloatVar(ref v) => v.fmt(f),
+            ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
+            ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
+            ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
+        }
+    }
+}
+
+impl fmt::Debug for ty::IntVarValue {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::IntType(ref v) => v.fmt(f),
+            ty::UintType(ref v) => v.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_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index e6f9b1f9d6dec..a9322bf2197b0 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -534,9 +534,7 @@ fn find_implied_output_region<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     for (input_type, input_pat) in input_tys.iter().zip(input_pats) {
         let mut regions = FnvHashSet();
-        let have_bound_regions = ty::fold::collect_regions(tcx,
-                                                           input_type,
-                                                           &mut regions);
+        let have_bound_regions = tcx.collect_regions(input_type, &mut regions);
 
         debug!("find_implied_output_regions: collected {:?} from {:?} \
                 have_bound_regions={:?}", &regions, input_type, have_bound_regions);
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index d3a292676c5ef..cde188fa41e48 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -66,7 +66,8 @@ use middle::infer::{self, Coercion};
 use middle::traits::{self, ObligationCause};
 use middle::traits::{predicate_for_trait_def, report_selection_error};
 use middle::ty::{AutoDerefRef, AdjustDerefRef};
-use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TypeError};
+use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
+use middle::ty::error::TypeError;
 use middle::ty::relate::RelateResult;
 use util::common::indent;
 
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index c16892d074163..fe822138c9b5b 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -32,7 +32,7 @@ pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                                     ty_a: Ty<'tcx>,
                                     ty_b: Ty<'tcx>,
                                     handle_err: F) where
-    F: FnOnce(Span, Ty<'tcx>, Ty<'tcx>, &ty::TypeError<'tcx>),
+    F: FnOnce(Span, Ty<'tcx>, Ty<'tcx>, &ty::error::TypeError<'tcx>),
 {
     // n.b.: order of actual, expected is reversed
     match infer::mk_subty(fcx.infcx(), b_is_expected, infer::Misc(sp),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index dc433786ae4d6..3160ed3502578 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -97,6 +97,7 @@ use middle::ty::{Disr, ParamTy, ParameterEnvironment};
 use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
 use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
 use middle::ty::{MethodCall, MethodCallee};
+use middle::ty::error::TypeError;
 use middle::ty::fold::{TypeFolder, TypeFoldable};
 use require_c_abi_if_variadic;
 use rscope::{ElisionFailureInfo, RegionScope};
@@ -1627,7 +1628,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     origin: infer::TypeOrigin,
                     sub: Ty<'tcx>,
                     sup: Ty<'tcx>)
-                    -> Result<(), ty::TypeError<'tcx>> {
+                    -> Result<(), TypeError<'tcx>> {
         infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
     }
 
@@ -1636,7 +1637,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                    origin: infer::TypeOrigin,
                    sub: Ty<'tcx>,
                    sup: Ty<'tcx>)
-                   -> Result<(), ty::TypeError<'tcx>> {
+                   -> Result<(), TypeError<'tcx>> {
         infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
     }
 
@@ -1651,7 +1652,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                  sp: Span,
                                  mk_msg: M,
                                  actual_ty: Ty<'tcx>,
-                                 err: Option<&ty::TypeError<'tcx>>) where
+                                 err: Option<&TypeError<'tcx>>) where
         M: FnOnce(String) -> String,
     {
         self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
@@ -1661,7 +1662,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                    sp: Span,
                                    e: Ty<'tcx>,
                                    a: Ty<'tcx>,
-                                   err: &ty::TypeError<'tcx>) {
+                                   err: &TypeError<'tcx>) {
         self.infcx().report_mismatched_types(sp, e, a, err)
     }
 
@@ -1766,7 +1767,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Apply "fallbacks" to some types
     /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64.
     fn default_type_parameters(&self) {
-        use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
+        use middle::ty::error::UnconstrainedNumeric::Neither;
+        use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
         for ty in &self.infcx().unsolved_variables() {
             let resolved = self.infcx().resolve_type_vars_if_possible(ty);
             if self.infcx().type_var_diverges(resolved) {
@@ -1801,9 +1803,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     fn new_select_all_obligations_and_apply_defaults(&self) {
-        use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
+        use middle::ty::error::UnconstrainedNumeric::Neither;
+        use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
 
-            // For the time being this errs on the side of being memory wasteful but provides better
+        // For the time being this errs on the side of being memory wasteful but provides better
         // error reporting.
         // let type_variables = self.infcx().type_variables.clone();
 
@@ -1973,7 +1976,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>,
                                 conflict: Ty<'tcx>)
                                 -> Option<type_variable::Default<'tcx>> {
-        use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
+        use middle::ty::error::UnconstrainedNumeric::Neither;
+        use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
 
         // Ensure that we apply the conflicting default first
         let mut unbound_tyvars = Vec::with_capacity(unbound_vars.len() + 1);
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 8683afe44735a..8048c302f2c78 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -446,7 +446,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
                                mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
                 if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
                     infcx.report_mismatched_types(span, mk_ptr(mt_b.ty),
-                                                  target, &ty::TypeError::Mutability);
+                                                  target, &ty::error::TypeError::Mutability);
                 }
                 (mt_a.ty, mt_b.ty, unsize_trait, None)
             };
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 930eb431f4957..0f71c4d8ceb56 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2374,7 +2374,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
          * before we really have a `ParameterEnvironment` to check.
          */
 
-        ty::fold::fold_regions(tcx, value, &mut false, |region, _| {
+        tcx.fold_regions(value, &mut false, |region, _| {
             match region {
                 ty::ReEarlyBound(data) => {
                     let def_id = DefId::local(data.param_id);

From 2ad5a61fe234e54c9385efac7fb4d04f34a137b1 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Mon, 14 Sep 2015 12:53:53 +0300
Subject: [PATCH 3/4] move traits structural impls to traits::structural_impls

---
 src/librustc/middle/traits/fulfill.rs         |   9 -
 src/librustc/middle/traits/mod.rs             |   1 +
 src/librustc/middle/traits/project.rs         |  26 --
 .../middle/traits/structural_impls.rs         | 235 ++++++++++++++++++
 src/librustc/middle/traits/util.rs            | 111 +--------
 src/librustc/middle/ty/structural_impls.rs    |  82 ------
 6 files changed, 238 insertions(+), 226 deletions(-)
 create mode 100644 src/librustc/middle/traits/structural_impls.rs

diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index 6271dd211662e..29032f0c4719a 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -11,7 +11,6 @@
 use middle::infer::InferCtxt;
 use middle::ty::{self, RegionEscape, Ty, HasTypeFlags};
 
-use std::fmt;
 use syntax::ast;
 use util::common::ErrorReported;
 use util::nodemap::{FnvHashSet, NodeMap};
@@ -509,14 +508,6 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
     }
 }
 
-impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})",
-               self.sub_region,
-               self.sup_type)
-    }
-}
-
 fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
                                     r_b: ty::Region,
                                     cause: ObligationCause<'tcx>,
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index a79837e7fb14f..14765e861c32d 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -63,6 +63,7 @@ mod fulfill;
 mod project;
 mod object_safety;
 mod select;
+mod structural_impls;
 mod util;
 
 /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index f13b81ccdb22f..a2c09f88ab331 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -28,8 +28,6 @@ use middle::ty::fold::{TypeFoldable, TypeFolder};
 use syntax::parse::token;
 use util::common::FN_OUTPUT_NAME;
 
-use std::fmt;
-
 pub type PolyProjectionObligation<'tcx> =
     Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
 
@@ -917,27 +915,3 @@ fn confirm_impl_candidate<'cx,'tcx>(
                               &format!("No associated type for {:?}",
                                        trait_ref));
 }
-
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Normalized<'tcx, T> {
-        Normalized {
-            value: self.value.fold_with(folder),
-            obligations: self.obligations.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, T: HasTypeFlags> HasTypeFlags for Normalized<'tcx, T> {
-    fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
-        self.value.has_type_flags(flags) ||
-            self.obligations.has_type_flags(flags)
-    }
-}
-
-impl<'tcx, T:fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Normalized({:?},{:?})",
-               self.value,
-               self.obligations)
-    }
-}
diff --git a/src/librustc/middle/traits/structural_impls.rs b/src/librustc/middle/traits/structural_impls.rs
new file mode 100644
index 0000000000000..88c219a7c7ace
--- /dev/null
+++ b/src/librustc/middle/traits/structural_impls.rs
@@ -0,0 +1,235 @@
+// Copyright 2012-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.
+
+use middle::traits;
+use middle::traits::project::Normalized;
+use middle::ty::{HasTypeFlags, TypeFlags, RegionEscape};
+use middle::ty::fold::{TypeFoldable, TypeFolder};
+
+use std::fmt;
+
+// structural impls for the structs in middle::traits
+
+impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Normalized({:?},{:?})",
+               self.value,
+               self.obligations)
+    }
+}
+
+impl<'tcx> fmt::Debug for traits::RegionObligation<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})",
+               self.sub_region,
+               self.sup_type)
+    }
+}
+impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Obligation(predicate={:?},depth={})",
+               self.predicate,
+               self.recursion_depth)
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            super::VtableImpl(ref v) =>
+                write!(f, "{:?}", v),
+
+            super::VtableDefaultImpl(ref t) =>
+                write!(f, "{:?}", t),
+
+            super::VtableClosure(ref d) =>
+                write!(f, "{:?}", d),
+
+            super::VtableFnPointer(ref d) =>
+                write!(f, "VtableFnPointer({:?})", d),
+
+            super::VtableObject(ref d) =>
+                write!(f, "{:?}", d),
+
+            super::VtableParam(ref n) =>
+                write!(f, "VtableParam({:?})", n),
+
+            super::VtableBuiltin(ref d) =>
+                write!(f, "{:?}", d)
+        }
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})",
+               self.impl_def_id,
+               self.substs,
+               self.nested)
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})",
+               self.closure_def_id,
+               self.substs,
+               self.nested)
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableBuiltin(nested={:?})", self.nested)
+    }
+}
+
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableDefaultImplData<N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})",
+               self.trait_def_id,
+               self.nested)
+    }
+}
+
+impl<'tcx> fmt::Debug for traits::VtableObjectData<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableObject(upcast={:?}, vtable_base={})",
+               self.upcast_trait_ref,
+               self.vtable_base)
+    }
+}
+
+impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "FulfillmentError({:?},{:?})",
+               self.obligation,
+               self.code)
+    }
+}
+
+impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            super::CodeSelectionError(ref e) => write!(f, "{:?}", e),
+            super::CodeProjectionError(ref e) => write!(f, "{:?}", e),
+            super::CodeAmbiguity => write!(f, "Ambiguity")
+        }
+    }
+}
+
+impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "MismatchedProjectionTypes({:?})", self.err)
+    }
+}
+
+impl<'tcx, P: RegionEscape> RegionEscape for traits::Obligation<'tcx,P> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.predicate.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx, T: HasTypeFlags> HasTypeFlags for traits::Obligation<'tcx, T> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.predicate.has_type_flags(flags)
+    }
+}
+
+impl<'tcx, T: HasTypeFlags> HasTypeFlags for Normalized<'tcx, T> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.value.has_type_flags(flags) ||
+            self.obligations.has_type_flags(flags)
+    }
+}
+
+impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O>
+{
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> {
+        traits::Obligation {
+            cause: self.cause.clone(),
+            recursion_depth: self.recursion_depth,
+            predicate: self.predicate.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableImplData<'tcx, N> {
+        traits::VtableImplData {
+            impl_def_id: self.impl_def_id,
+            substs: self.substs.fold_with(folder),
+            nested: self.nested.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableClosureData<'tcx, N> {
+        traits::VtableClosureData {
+            closure_def_id: self.closure_def_id,
+            substs: self.substs.fold_with(folder),
+            nested: self.nested.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
+        traits::VtableDefaultImplData {
+            trait_def_id: self.trait_def_id,
+            nested: self.nested.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> {
+        traits::VtableBuiltinData {
+            nested: self.nested.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> {
+        match *self {
+            traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
+            traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
+            traits::VtableClosure(ref d) => {
+                traits::VtableClosure(d.fold_with(folder))
+            }
+            traits::VtableFnPointer(ref d) => {
+                traits::VtableFnPointer(d.fold_with(folder))
+            }
+            traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
+            traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
+            traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
+        traits::VtableObjectData {
+            upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
+            vtable_base: self.vtable_base
+        }
+    }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Normalized<'tcx, T> {
+        Normalized {
+            value: self.value.fold_with(folder),
+            obligations: self.obligations.fold_with(folder),
+        }
+    }
+}
diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs
index 40d767d8c5f17..1c5156aab02be 100644
--- a/src/librustc/middle/traits/util.rs
+++ b/src/librustc/middle/traits/util.rs
@@ -11,14 +11,12 @@
 use middle::def_id::DefId;
 use middle::infer::InferCtxt;
 use middle::subst::Substs;
-use middle::ty::{self, HasTypeFlags, Ty, ToPredicate, ToPolyTraitRef};
-use std::fmt;
+use middle::ty::{self, Ty, ToPredicate, ToPolyTraitRef};
 use syntax::codemap::Span;
 use util::common::ErrorReported;
 use util::nodemap::FnvHashSet;
 
-use super::{Obligation, ObligationCause, PredicateObligation,
-            VtableImpl, VtableParam, VtableImplData, VtableDefaultImplData};
+use super::{Obligation, ObligationCause, PredicateObligation};
 
 struct PredicateSet<'a,'tcx:'a> {
     tcx: &'a ty::ctxt<'tcx>,
@@ -477,108 +475,3 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
     };
     ty::Binder((trait_ref, sig.0.output.unwrap_or(tcx.mk_nil())))
 }
-
-impl<'tcx,O:fmt::Debug> fmt::Debug for super::Obligation<'tcx, O> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Obligation(predicate={:?},depth={})",
-               self.predicate,
-               self.recursion_depth)
-    }
-}
-
-impl<'tcx, N:fmt::Debug> fmt::Debug for super::Vtable<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            super::VtableImpl(ref v) =>
-                write!(f, "{:?}", v),
-
-            super::VtableDefaultImpl(ref t) =>
-                write!(f, "{:?}", t),
-
-            super::VtableClosure(ref d) =>
-                write!(f, "{:?}", d),
-
-            super::VtableFnPointer(ref d) =>
-                write!(f, "VtableFnPointer({:?})", d),
-
-            super::VtableObject(ref d) =>
-                write!(f, "{:?}", d),
-
-            super::VtableParam(ref n) =>
-                write!(f, "VtableParam({:?})", n),
-
-            super::VtableBuiltin(ref d) =>
-                write!(f, "{:?}", d)
-        }
-    }
-}
-
-impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableImplData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})",
-               self.impl_def_id,
-               self.substs,
-               self.nested)
-    }
-}
-
-impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableClosureData<'tcx, N> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})",
-               self.closure_def_id,
-               self.substs,
-               self.nested)
-    }
-}
-
-impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableBuiltinData<N> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "VtableBuiltin(nested={:?})", self.nested)
-    }
-}
-
-impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableDefaultImplData<N> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})",
-               self.trait_def_id,
-               self.nested)
-    }
-}
-
-impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "VtableObject(upcast={:?}, vtable_base={})",
-               self.upcast_trait_ref,
-               self.vtable_base)
-    }
-}
-
-impl<'tcx> fmt::Debug for super::FulfillmentError<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "FulfillmentError({:?},{:?})",
-               self.obligation,
-               self.code)
-    }
-}
-
-impl<'tcx> fmt::Debug for super::FulfillmentErrorCode<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            super::CodeSelectionError(ref e) => write!(f, "{:?}", e),
-            super::CodeProjectionError(ref e) => write!(f, "{:?}", e),
-            super::CodeAmbiguity => write!(f, "Ambiguity")
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for super::MismatchedProjectionTypes<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "MismatchedProjectionTypes({:?})", self.err)
-    }
-}
-
-impl<'tcx, T: HasTypeFlags> HasTypeFlags for Obligation<'tcx, T> {
-    fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
-        self.predicate.has_type_flags(flags)
-    }
-}
diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs
index 55d064844b13d..94e4672ea9710 100644
--- a/src/librustc/middle/ty/structural_impls.rs
+++ b/src/librustc/middle/ty/structural_impls.rs
@@ -116,12 +116,6 @@ impl<'tcx> RegionEscape for ty::Predicate<'tcx> {
     }
 }
 
-impl<'tcx,P:RegionEscape> RegionEscape for traits::Obligation<'tcx,P> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.predicate.has_regions_escaping_depth(depth)
-    }
-}
-
 impl<'tcx> RegionEscape for TraitRef<'tcx> {
     fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
@@ -770,82 +764,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
     }
 }
 
-impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
-    where O : TypeFoldable<'tcx>
-{
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation<'tcx, O> {
-        traits::Obligation {
-            cause: self.cause.clone(),
-            recursion_depth: self.recursion_depth,
-            predicate: self.predicate.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableImplData<'tcx, N> {
-        traits::VtableImplData {
-            impl_def_id: self.impl_def_id,
-            substs: self.substs.fold_with(folder),
-            nested: self.nested.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableClosureData<'tcx, N> {
-        traits::VtableClosureData {
-            closure_def_id: self.closure_def_id,
-            substs: self.substs.fold_with(folder),
-            nested: self.nested.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
-        traits::VtableDefaultImplData {
-            trait_def_id: self.trait_def_id,
-            nested: self.nested.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> {
-        traits::VtableBuiltinData {
-            nested: self.nested.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> {
-        match *self {
-            traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
-            traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
-            traits::VtableClosure(ref d) => {
-                traits::VtableClosure(d.fold_with(folder))
-            }
-            traits::VtableFnPointer(ref d) => {
-                traits::VtableFnPointer(d.fold_with(folder))
-            }
-            traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
-            traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
-            traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
-        traits::VtableObjectData {
-            upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
-            vtable_base: self.vtable_base
-        }
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
     fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> {
         ty::EquatePredicate(self.0.fold_with(folder),

From 5a95acb8aba07ea8e5255893aa4e01e5ba5c2349 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda <ariel.byd@gmail.com>
Date: Mon, 14 Sep 2015 14:55:56 +0300
Subject: [PATCH 4/4] split ty::util and ty::adjustment

---
 src/librustc/metadata/csearch.rs            |    8 +-
 src/librustc/metadata/decoder.rs            |    8 +-
 src/librustc/middle/astencode.rs            |   58 +-
 src/librustc/middle/check_const.rs          |    9 +-
 src/librustc/middle/expr_use_visitor.rs     |   15 +-
 src/librustc/middle/infer/mod.rs            |    7 +-
 src/librustc/middle/mem_categorization.rs   |   11 +-
 src/librustc/middle/ty/adjustment.rs        |  249 ++++
 src/librustc/middle/ty/context.rs           |    4 +-
 src/librustc/middle/ty/fold.rs              |   14 +-
 src/librustc/middle/ty/mod.rs               | 1203 +------------------
 src/librustc/middle/ty/structural_impls.rs  |    4 +-
 src/librustc/middle/ty/sty.rs               |   83 ++
 src/librustc/middle/ty/util.rs              |  891 ++++++++++++++
 src/librustc/util/ppaux.rs                  |   10 +-
 src/librustc_lint/builtin.rs                |   11 +-
 src/librustc_mir/tcx/expr.rs                |   10 +-
 src/librustc_trans/trans/consts.rs          |    8 +-
 src/librustc_trans/trans/expr.rs            |    5 +-
 src/librustc_typeck/check/coercion.rs       |   18 +-
 src/librustc_typeck/check/method/confirm.rs |   13 +-
 src/librustc_typeck/check/method/mod.rs     |    5 +-
 src/librustc_typeck/check/mod.rs            |   21 +-
 src/librustc_typeck/check/regionck.rs       |   13 +-
 src/librustc_typeck/check/writeback.rs      |   13 +-
 src/librustc_typeck/coherence/mod.rs        |   13 +-
 src/librustc_typeck/collect.rs              |    3 +-
 27 files changed, 1387 insertions(+), 1320 deletions(-)
 create mode 100644 src/librustc/middle/ty/adjustment.rs
 create mode 100644 src/librustc/middle/ty/util.rs

diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index c539bfc596413..e1cb9bd0e77cf 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -247,9 +247,11 @@ pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>,
     decoder::get_impl_polarity(&*cdata, def.node)
 }
 
-pub fn get_custom_coerce_unsized_kind<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                            def: DefId)
-                                            -> Option<ty::CustomCoerceUnsized> {
+pub fn get_custom_coerce_unsized_kind<'tcx>(
+    tcx: &ty::ctxt<'tcx>,
+    def: DefId)
+    -> Option<ty::adjustment::CustomCoerceUnsized>
+{
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
     decoder::get_custom_coerce_unsized_kind(&*cdata, def.node)
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 309a18feb9aad..e2cf50cf30ad0 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -540,9 +540,11 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd,
     }
 }
 
-pub fn get_custom_coerce_unsized_kind<'tcx>(cdata: Cmd,
-                                            id: ast::NodeId)
-                                            -> Option<ty::CustomCoerceUnsized> {
+pub fn get_custom_coerce_unsized_kind<'tcx>(
+    cdata: Cmd,
+    id: ast::NodeId)
+    -> Option<ty::adjustment::CustomCoerceUnsized>
+{
     let item_doc = cdata.lookup_item(id);
     reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| {
         let mut decoder = reader::Decoder::new(kind_doc);
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index ac2dd54598253..0bd4434857abd 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -27,6 +27,7 @@ use metadata::tydecode;
 use metadata::tydecode::{DefIdSource, NominalType, TypeWithId};
 use metadata::tydecode::{RegionParameter, ClosureSource};
 use metadata::tyencode;
+use middle::ty::adjustment;
 use middle::ty::cast;
 use middle::check_const::ConstQualif;
 use middle::def;
@@ -646,11 +647,11 @@ trait rbml_writer_helpers<'tcx> {
     fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds);
     fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture);
     fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                                adj: &ty::AutoAdjustment<'tcx>);
+                                adj: &adjustment::AutoAdjustment<'tcx>);
     fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                        autoref: &ty::AutoRef<'tcx>);
+                        autoref: &adjustment::AutoRef<'tcx>);
     fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                               auto_deref_ref: &ty::AutoDerefRef<'tcx>);
+                               auto_deref_ref: &adjustment::AutoDerefRef<'tcx>);
 }
 
 impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
@@ -771,22 +772,22 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
     }
 
     fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                                adj: &ty::AutoAdjustment<'tcx>) {
+                                adj: &adjustment::AutoAdjustment<'tcx>) {
         use serialize::Encoder;
 
         self.emit_enum("AutoAdjustment", |this| {
             match *adj {
-                ty::AdjustReifyFnPointer=> {
+                adjustment::AdjustReifyFnPointer=> {
                     this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(()))
                 }
 
-                ty::AdjustUnsafeFnPointer => {
+                adjustment::AdjustUnsafeFnPointer => {
                     this.emit_enum_variant("AdjustUnsafeFnPointer", 2, 0, |_| {
                         Ok(())
                     })
                 }
 
-                ty::AdjustDerefRef(ref auto_deref_ref) => {
+                adjustment::AdjustDerefRef(ref auto_deref_ref) => {
                     this.emit_enum_variant("AdjustDerefRef", 3, 2, |this| {
                         this.emit_enum_variant_arg(0,
                             |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref)))
@@ -797,19 +798,19 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
     }
 
     fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                        autoref: &ty::AutoRef<'tcx>) {
+                        autoref: &adjustment::AutoRef<'tcx>) {
         use serialize::Encoder;
 
         self.emit_enum("AutoRef", |this| {
             match autoref {
-                &ty::AutoPtr(r, m) => {
+                &adjustment::AutoPtr(r, m) => {
                     this.emit_enum_variant("AutoPtr", 0, 2, |this| {
                         this.emit_enum_variant_arg(0,
                             |this| Ok(this.emit_region(ecx, *r)));
                         this.emit_enum_variant_arg(1, |this| m.encode(this))
                     })
                 }
-                &ty::AutoUnsafe(m) => {
+                &adjustment::AutoUnsafe(m) => {
                     this.emit_enum_variant("AutoUnsafe", 1, 1, |this| {
                         this.emit_enum_variant_arg(0, |this| m.encode(this))
                     })
@@ -819,7 +820,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
     }
 
     fn emit_auto_deref_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                               auto_deref_ref: &ty::AutoDerefRef<'tcx>) {
+                               auto_deref_ref: &adjustment::AutoDerefRef<'tcx>) {
         use serialize::Encoder;
 
         self.emit_struct("AutoDerefRef", 2, |this| {
@@ -974,7 +975,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
 
     if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) {
         match *adjustment {
-            ty::AdjustDerefRef(ref adj) => {
+            adjustment::AdjustDerefRef(ref adj) => {
                 for autoderef in 0..adj.autoderefs {
                     let method_call = ty::MethodCall::autoderef(id, autoderef as u32);
                     if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
@@ -1063,7 +1064,7 @@ trait rbml_decoder_decoder_helpers<'tcx> {
     fn read_upvar_capture(&mut self, dcx: &DecodeContext)
                           -> ty::UpvarCapture;
     fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                    -> ty::AutoAdjustment<'tcx>;
+                                    -> adjustment::AutoAdjustment<'tcx>;
     fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                                  -> cast::CastKind;
     fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -1071,9 +1072,9 @@ trait rbml_decoder_decoder_helpers<'tcx> {
     fn read_closure_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                                -> ty::ClosureTy<'tcx>;
     fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                   -> ty::AutoDerefRef<'tcx>;
+                                   -> adjustment::AutoDerefRef<'tcx>;
     fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                            -> ty::AutoRef<'tcx>;
+                            -> adjustment::AutoRef<'tcx>;
     fn convert_def_id(&mut self,
                       dcx: &DecodeContext,
                       source: DefIdSource,
@@ -1246,30 +1247,30 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
         }).unwrap()
     }
     fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                    -> ty::AutoAdjustment<'tcx> {
+                                    -> adjustment::AutoAdjustment<'tcx> {
         self.read_enum("AutoAdjustment", |this| {
             let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"];
             this.read_enum_variant(&variants, |this, i| {
                 Ok(match i {
-                    1 => ty::AdjustReifyFnPointer,
-                    2 => ty::AdjustUnsafeFnPointer,
+                    1 => adjustment::AdjustReifyFnPointer,
+                    2 => adjustment::AdjustUnsafeFnPointer,
                     3 => {
-                        let auto_deref_ref: ty::AutoDerefRef =
+                        let auto_deref_ref: adjustment::AutoDerefRef =
                             this.read_enum_variant_arg(0,
                                 |this| Ok(this.read_auto_deref_ref(dcx))).unwrap();
 
-                        ty::AdjustDerefRef(auto_deref_ref)
+                        adjustment::AdjustDerefRef(auto_deref_ref)
                     }
-                    _ => panic!("bad enum variant for ty::AutoAdjustment")
+                    _ => panic!("bad enum variant for adjustment::AutoAdjustment")
                 })
             })
         }).unwrap()
     }
 
     fn read_auto_deref_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                   -> ty::AutoDerefRef<'tcx> {
+                                   -> adjustment::AutoDerefRef<'tcx> {
         self.read_struct("AutoDerefRef", 2, |this| {
-            Ok(ty::AutoDerefRef {
+            Ok(adjustment::AutoDerefRef {
                 autoderefs: this.read_struct_field("autoderefs", 0, |this| {
                     Decodable::decode(this)
                 }).unwrap(),
@@ -1296,7 +1297,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
     }
 
     fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                            -> ty::AutoRef<'tcx> {
+                            -> adjustment::AutoRef<'tcx> {
         self.read_enum("AutoRef", |this| {
             let variants = ["AutoPtr", "AutoUnsafe"];
             this.read_enum_variant(&variants, |this, i| {
@@ -1311,15 +1312,15 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
                                 Decodable::decode(this)
                             }).unwrap();
 
-                        ty::AutoPtr(dcx.tcx.mk_region(r), m)
+                        adjustment::AutoPtr(dcx.tcx.mk_region(r), m)
                     }
                     1 => {
                         let m: hir::Mutability =
                             this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
 
-                        ty::AutoUnsafe(m)
+                        adjustment::AutoUnsafe(m)
                     }
-                    _ => panic!("bad enum variant for ty::AutoRef")
+                    _ => panic!("bad enum variant for adjustment::AutoRef")
                 })
             })
         }).unwrap()
@@ -1467,7 +1468,8 @@ fn decode_side_tables(dcx: &DecodeContext,
                         dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method);
                     }
                     c::tag_table_adjustments => {
-                        let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(dcx);
+                        let adj =
+                            val_dsr.read_auto_adjustment(dcx);
                         dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj);
                     }
                     c::tag_table_closure_tys => {
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 48c8cca76b056..661299cd7f3fc 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -798,8 +798,13 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
 /// Check the adjustments of an expression
 fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
     match v.tcx.tables.borrow().adjustments.get(&e.id) {
-        None | Some(&ty::AdjustReifyFnPointer) | Some(&ty::AdjustUnsafeFnPointer) => {}
-        Some(&ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs, .. })) => {
+        None |
+        Some(&ty::adjustment::AdjustReifyFnPointer) |
+        Some(&ty::adjustment::AdjustUnsafeFnPointer) => {}
+
+        Some(&ty::adjustment::AdjustDerefRef(
+            ty::adjustment::AutoDerefRef { autoderefs, .. }
+        )) => {
             if (0..autoderefs as u32).any(|autoderef| {
                     v.tcx.is_overloaded_autoderef(e.id, autoderef)
             }) {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index d2bb31f10bd14..a8fed5eab16be 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -25,6 +25,7 @@ use middle::def_id::{DefId};
 use middle::infer;
 use middle::mem_categorization as mc;
 use middle::ty;
+use middle::ty::adjustment;
 
 use rustc_front::hir;
 
@@ -726,8 +727,8 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
         let adj = typer.adjustments().get(&expr.id).map(|x| x.clone());
         if let Some(adjustment) = adj {
             match adjustment {
-                ty::AdjustReifyFnPointer |
-                ty::AdjustUnsafeFnPointer => {
+                adjustment::AdjustReifyFnPointer |
+                adjustment::AdjustUnsafeFnPointer => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
                     debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)");
@@ -735,7 +736,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
                         return_if_err!(self.mc.cat_expr_unadjusted(expr));
                     self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
                 }
-                ty::AdjustDerefRef(ref adj) => {
+                adjustment::AdjustDerefRef(ref adj) => {
                     self.walk_autoderefref(expr, adj);
                 }
             }
@@ -778,7 +779,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
 
     fn walk_autoderefref(&mut self,
                          expr: &hir::Expr,
-                         adj: &ty::AutoDerefRef<'tcx>) {
+                         adj: &adjustment::AutoDerefRef<'tcx>) {
         debug!("walk_autoderefref expr={:?} adj={:?}",
                expr,
                adj);
@@ -809,7 +810,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
     fn walk_autoref(&mut self,
                     expr: &hir::Expr,
                     cmt_base: mc::cmt<'tcx>,
-                    opt_autoref: Option<ty::AutoRef<'tcx>>)
+                    opt_autoref: Option<adjustment::AutoRef<'tcx>>)
                     -> mc::cmt<'tcx>
     {
         debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
@@ -828,7 +829,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
         };
 
         match *autoref {
-            ty::AutoPtr(r, m) => {
+            adjustment::AutoPtr(r, m) => {
                 self.delegate.borrow(expr.id,
                                      expr.span,
                                      cmt_base,
@@ -837,7 +838,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
                                      AutoRef);
             }
 
-            ty::AutoUnsafe(m) => {
+            adjustment::AutoUnsafe(m) => {
                 debug!("walk_autoref: expr.id={} cmt_base={:?}",
                        expr.id,
                        cmt_base);
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index b9e9ee5e24497..ffb631e105b3a 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -30,6 +30,7 @@ use middle::subst::Substs;
 use middle::subst::Subst;
 use middle::traits::{self, FulfillmentContext, Normalized,
                      SelectionContext, ObligationCause};
+use middle::ty::adjustment;
 use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
 use middle::ty::{self, Ty, HasTypeFlags};
 use middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
@@ -1151,7 +1152,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// Apply `adjustment` to the type of `expr`
     pub fn adjust_expr_ty(&self,
                           expr: &hir::Expr,
-                          adjustment: Option<&ty::AutoAdjustment<'tcx>>)
+                          adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
                           -> Ty<'tcx>
     {
         let raw_ty = self.expr_ty(expr);
@@ -1485,9 +1486,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             .map(|method| method.def_id)
     }
 
-    pub fn adjustments(&self) -> Ref<NodeMap<ty::AutoAdjustment<'tcx>>> {
+    pub fn adjustments(&self) -> Ref<NodeMap<adjustment::AutoAdjustment<'tcx>>> {
         fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>)
-                                        -> &'a NodeMap<ty::AutoAdjustment<'tcx>> {
+                                        -> &'a NodeMap<adjustment::AutoAdjustment<'tcx>> {
             &tables.adjustments
         }
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 51005ef8b9770..dd2f48d25b4b0 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -77,6 +77,7 @@ use front::map as ast_map;
 use middle::infer;
 use middle::check_const;
 use middle::def;
+use middle::ty::adjustment;
 use middle::ty::{self, Ty};
 
 use rustc_front::hir::{MutImmutable, MutMutable};
@@ -421,16 +422,16 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
 
             Some(adjustment) => {
                 match *adjustment {
-                    ty::AdjustDerefRef(
-                        ty::AutoDerefRef {
+                    adjustment::AdjustDerefRef(
+                        adjustment::AutoDerefRef {
                             autoref: None, unsize: None, autoderefs, ..}) => {
                         // Equivalent to *expr or something similar.
                         self.cat_expr_autoderefd(expr, autoderefs)
                     }
 
-                    ty::AdjustReifyFnPointer |
-                    ty::AdjustUnsafeFnPointer |
-                    ty::AdjustDerefRef(_) => {
+                    adjustment::AdjustReifyFnPointer |
+                    adjustment::AdjustUnsafeFnPointer |
+                    adjustment::AdjustDerefRef(_) => {
                         debug!("cat_expr({:?}): {:?}",
                                adjustment,
                                expr);
diff --git a/src/librustc/middle/ty/adjustment.rs b/src/librustc/middle/ty/adjustment.rs
new file mode 100644
index 0000000000000..cadab499c0765
--- /dev/null
+++ b/src/librustc/middle/ty/adjustment.rs
@@ -0,0 +1,249 @@
+// Copyright 2012-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.
+
+pub use self::AutoAdjustment::*;
+pub use self::AutoRef::*;
+
+use middle::ty::{self, Ty, TypeAndMut};
+use middle::ty::HasTypeFlags;
+use middle::ty::LvaluePreference::{NoPreference};
+
+use syntax::ast;
+use syntax::codemap::Span;
+
+use rustc_front::hir;
+
+#[derive(Copy, Clone)]
+pub enum AutoAdjustment<'tcx> {
+    AdjustReifyFnPointer,   // go from a fn-item type to a fn-pointer type
+    AdjustUnsafeFnPointer,  // go from a safe fn pointer to an unsafe fn pointer
+    AdjustDerefRef(AutoDerefRef<'tcx>),
+}
+
+/// Represents coercing a pointer to a different kind of pointer - where 'kind'
+/// here means either or both of raw vs borrowed vs unique and fat vs thin.
+///
+/// We transform pointers by following the following steps in order:
+/// 1. Deref the pointer `self.autoderefs` times (may be 0).
+/// 2. If `autoref` is `Some(_)`, then take the address and produce either a
+///    `&` or `*` pointer.
+/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
+///    which will do things like convert thin pointers to fat
+///    pointers, or convert structs containing thin pointers to
+///    structs containing fat pointers, or convert between fat
+///    pointers.  We don't store the details of how the transform is
+///    done (in fact, we don't know that, because it might depend on
+///    the precise type parameters). We just store the target
+///    type. Trans figures out what has to be done at monomorphization
+///    time based on the precise source/target type at hand.
+///
+/// To make that more concrete, here are some common scenarios:
+///
+/// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
+/// Here the pointer will be dereferenced N times (where a dereference can
+/// happen to to raw or borrowed pointers or any smart pointer which implements
+/// Deref, including Box<_>). The number of dereferences is given by
+/// `autoderefs`.  It can then be auto-referenced zero or one times, indicated
+/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
+/// None.
+///
+/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
+/// with a thin pointer, deref a number of times, unsize the underlying data,
+/// then autoref. The 'unsize' phase may change a fixed length array to a
+/// dynamically sized one, a concrete object to a trait object, or statically
+/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
+/// represented by:
+///
+/// ```
+/// AutoDerefRef {
+///     autoderefs: 1,          // &[i32; 4] -> [i32; 4]
+///     autoref: Some(AutoPtr), // [i32] -> &[i32]
+///     unsize: Some([i32]),    // [i32; 4] -> [i32]
+/// }
+/// ```
+///
+/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
+/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
+/// The autoderef and -ref are the same as in the above example, but the type
+/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
+/// the underlying conversions from `[i32; 4]` to `[i32]`.
+///
+/// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case.  In
+/// that case, we have the pointer we need coming in, so there are no
+/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
+/// At some point, of course, `Box` should move out of the compiler, in which
+/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
+/// Box<[i32]> is represented by:
+///
+/// ```
+/// AutoDerefRef {
+///     autoderefs: 0,
+///     autoref: None,
+///     unsize: Some(Box<[i32]>),
+/// }
+/// ```
+#[derive(Copy, Clone)]
+pub struct AutoDerefRef<'tcx> {
+    /// Step 1. Apply a number of dereferences, producing an lvalue.
+    pub autoderefs: usize,
+
+    /// Step 2. Optionally produce a pointer/reference from the value.
+    pub autoref: Option<AutoRef<'tcx>>,
+
+    /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
+    /// `&[T]`. The stored type is the target pointer type. Note that
+    /// the source could be a thin or fat pointer.
+    pub unsize: Option<Ty<'tcx>>,
+}
+
+impl<'tcx> AutoAdjustment<'tcx> {
+    pub fn is_identity(&self) -> bool {
+        match *self {
+            AdjustReifyFnPointer |
+            AdjustUnsafeFnPointer => false,
+            AdjustDerefRef(ref r) => r.is_identity(),
+        }
+    }
+}
+impl<'tcx> AutoDerefRef<'tcx> {
+    pub fn is_identity(&self) -> bool {
+        self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none()
+    }
+}
+
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum AutoRef<'tcx> {
+    /// Convert from T to &T.
+    AutoPtr(&'tcx ty::Region, hir::Mutability),
+
+    /// Convert from T to *T.
+    /// Value to thin pointer.
+    AutoUnsafe(hir::Mutability),
+}
+
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
+pub enum CustomCoerceUnsized {
+    /// Records the index of the field being coerced.
+    Struct(usize)
+}
+
+impl<'tcx> ty::TyS<'tcx> {
+    /// See `expr_ty_adjusted`
+    pub fn adjust<F>(&'tcx self, cx: &ty::ctxt<'tcx>,
+                     span: Span,
+                     expr_id: ast::NodeId,
+                     adjustment: Option<&AutoAdjustment<'tcx>>,
+                     mut method_type: F)
+                     -> Ty<'tcx> where
+        F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>,
+    {
+        if let ty::TyError = self.sty {
+            return self;
+        }
+
+        return match adjustment {
+            Some(adjustment) => {
+                match *adjustment {
+                   AdjustReifyFnPointer => {
+                        match self.sty {
+                            ty::TyBareFn(Some(_), b) => {
+                                cx.mk_fn(None, b)
+                            }
+                            _ => {
+                                cx.sess.bug(
+                                    &format!("AdjustReifyFnPointer adjustment on non-fn-item: \
+                                              {:?}", self));
+                            }
+                        }
+                    }
+
+                   AdjustUnsafeFnPointer => {
+                        match self.sty {
+                            ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b),
+                            ref b => {
+                                cx.sess.bug(
+                                    &format!("AdjustReifyFnPointer adjustment on non-fn-item: \
+                                             {:?}",
+                                            b));
+                            }
+                        }
+                   }
+
+                    AdjustDerefRef(ref adj) => {
+                        let mut adjusted_ty = self;
+
+                        if !adjusted_ty.references_error() {
+                            for i in 0..adj.autoderefs {
+                                adjusted_ty =
+                                    adjusted_ty.adjust_for_autoderef(cx,
+                                                                     expr_id,
+                                                                     span,
+                                                                     i as u32,
+                                                                     &mut method_type);
+                            }
+                        }
+
+                        if let Some(target) = adj.unsize {
+                            target
+                        } else {
+                            adjusted_ty.adjust_for_autoref(cx, adj.autoref)
+                        }
+                    }
+                }
+            }
+            None => self
+        };
+    }
+
+    pub fn adjust_for_autoderef<F>(&'tcx self,
+                                   cx: &ty::ctxt<'tcx>,
+                                   expr_id: ast::NodeId,
+                                   expr_span: Span,
+                                   autoderef: u32, // how many autoderefs so far?
+                                   mut method_type: F)
+                                   -> Ty<'tcx> where
+        F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>,
+    {
+        let method_call = ty::MethodCall::autoderef(expr_id, autoderef);
+        let mut adjusted_ty = self;
+        if let Some(method_ty) = method_type(method_call) {
+            // Method calls always have all late-bound regions
+            // fully instantiated.
+            let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
+            adjusted_ty = fn_ret.unwrap();
+        }
+        match adjusted_ty.builtin_deref(true, NoPreference) {
+            Some(mt) => mt.ty,
+            None => {
+                cx.sess.span_bug(
+                    expr_span,
+                    &format!("the {}th autoderef failed: {}",
+                             autoderef,
+                             adjusted_ty)
+                        );
+            }
+        }
+    }
+
+    pub fn adjust_for_autoref(&'tcx self, cx: &ty::ctxt<'tcx>,
+                              autoref: Option<AutoRef<'tcx>>)
+                              -> Ty<'tcx> {
+        match autoref {
+            None => self,
+            Some(AutoPtr(r, m)) => {
+                cx.mk_ref(r, TypeAndMut { ty: self, mutbl: m })
+            }
+            Some(AutoUnsafe(m)) => {
+                cx.mk_ptr(TypeAndMut { ty: self, mutbl: m })
+            }
+        }
+    }
+}
diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs
index 4d57e0980ef54..e3b6da56680da 100644
--- a/src/librustc/middle/ty/context.rs
+++ b/src/librustc/middle/ty/context.rs
@@ -106,7 +106,7 @@ pub struct Tables<'tcx> {
     /// other items.
     pub item_substs: NodeMap<ty::ItemSubsts<'tcx>>,
 
-    pub adjustments: NodeMap<ty::AutoAdjustment<'tcx>>,
+    pub adjustments: NodeMap<ty::adjustment::AutoAdjustment<'tcx>>,
 
     pub method_map: ty::MethodMap<'tcx>,
 
@@ -308,7 +308,7 @@ pub struct ctxt<'tcx> {
     pub const_qualif_map: RefCell<NodeMap<middle::check_const::ConstQualif>>,
 
     /// Caches CoerceUnsized kinds for impls on custom types.
-    pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::CustomCoerceUnsized>>,
+    pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
 
     /// Maps a cast expression to its kind. This is keyed on the
     /// *from* expression of the cast, not the cast itself.
diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs
index 9de58369a63f8..751bac28ce4c2 100644
--- a/src/librustc/middle/ty/fold.rs
+++ b/src/librustc/middle/ty/fold.rs
@@ -36,6 +36,7 @@
 
 use middle::region;
 use middle::subst;
+use middle::ty::adjustment;
 use middle::ty::{self, Binder, Ty, HasTypeFlags, RegionEscape};
 
 use std::fmt;
@@ -128,7 +129,8 @@ pub trait TypeFolder<'tcx> : Sized {
         super_fold_existential_bounds(self, s)
     }
 
-    fn fold_autoref(&mut self, ar: &ty::AutoRef<'tcx>) -> ty::AutoRef<'tcx> {
+    fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>)
+                    -> adjustment::AutoRef<'tcx> {
         super_fold_autoref(self, ar)
     }
 
@@ -296,15 +298,15 @@ pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>(
 }
 
 pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                     autoref: &ty::AutoRef<'tcx>)
-                                                     -> ty::AutoRef<'tcx>
+                                                     autoref: &adjustment::AutoRef<'tcx>)
+                                                     -> adjustment::AutoRef<'tcx>
 {
     match *autoref {
-        ty::AutoPtr(r, m) => {
+        adjustment::AutoPtr(r, m) => {
             let r = r.fold_with(this);
-            ty::AutoPtr(this.tcx().mk_region(r), m)
+            adjustment::AutoPtr(this.tcx().mk_region(r), m)
         }
-        ty::AutoUnsafe(m) => ty::AutoUnsafe(m)
+        adjustment::AutoUnsafe(m) => adjustment::AutoUnsafe(m)
     }
 }
 
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index ab1160d7deb02..dff423b35dd0a 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -11,30 +11,21 @@
 pub use self::ImplOrTraitItemId::*;
 pub use self::ClosureKind::*;
 pub use self::Variance::*;
-pub use self::AutoAdjustment::*;
-pub use self::Representability::*;
-pub use self::AutoRef::*;
 pub use self::DtorKind::*;
 pub use self::ExplicitSelfCategory::*;
 pub use self::ImplOrTraitItemContainer::*;
 pub use self::BorrowKind::*;
 pub use self::ImplOrTraitItem::*;
 pub use self::IntVarValue::*;
-pub use self::CopyImplementationError::*;
 pub use self::LvaluePreference::*;
 
-use back::svh::Svh;
 use front::map as ast_map;
 use front::map::LinkedPath;
 use metadata::csearch;
 use middle;
-use middle::const_eval::{self, ConstVal, ErrKind};
-use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def::{self, ExportMap};
 use middle::def_id::{DefId, LOCAL_CRATE};
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
-use middle::infer;
-use middle::pat_util;
 use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
 use middle::traits;
 use middle::ty;
@@ -43,12 +34,10 @@ use middle::ty::walk::TypeWalker;
 use util::common::memoized;
 use util::nodemap::{NodeMap, NodeSet, DefIdMap};
 use util::nodemap::FnvHashMap;
-use util::num::ToPrimitive;
 
 use std::borrow::{Borrow, Cow};
 use std::cell::{Cell, RefCell};
-use std::cmp;
-use std::hash::{Hash, SipHasher, Hasher};
+use std::hash::{Hash, Hasher};
 use std::iter;
 use std::rc::Rc;
 use std::slice;
@@ -61,7 +50,7 @@ use syntax::parse::token::{InternedString, special_idents};
 use rustc_front::hir;
 use rustc_front::hir::{ItemImpl, ItemTrait};
 use rustc_front::hir::{MutImmutable, MutMutable, Visibility};
-use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
+use rustc_front::attr::{self, AttrMetaMethods};
 
 pub use self::sty::{Binder, DebruijnIndex};
 pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds};
@@ -86,6 +75,7 @@ pub use self::contents::TypeContents;
 pub use self::context::{ctxt, tls};
 pub use self::context::{CtxtArenas, Lift, Tables};
 
+pub mod adjustment;
 pub mod cast;
 pub mod error;
 pub mod fast_reject;
@@ -95,6 +85,7 @@ pub mod outlives;
 pub mod relate;
 pub mod walk;
 pub mod wf;
+pub mod util;
 
 mod contents;
 mod context;
@@ -104,7 +95,6 @@ mod structural_impls;
 mod sty;
 
 pub type Disr = u64;
-
 pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
 
 // Data types
@@ -143,126 +133,6 @@ impl DtorKind {
     }
 }
 
-pub trait IntTypeExt {
-    fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>;
-    fn i64_to_disr(&self, val: i64) -> Option<Disr>;
-    fn u64_to_disr(&self, val: u64) -> Option<Disr>;
-    fn disr_incr(&self, val: Disr) -> Option<Disr>;
-    fn disr_string(&self, val: Disr) -> String;
-    fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr;
-}
-
-impl IntTypeExt for attr::IntType {
-    fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> {
-        match *self {
-            SignedInt(hir::TyI8)      => cx.types.i8,
-            SignedInt(hir::TyI16)     => cx.types.i16,
-            SignedInt(hir::TyI32)     => cx.types.i32,
-            SignedInt(hir::TyI64)     => cx.types.i64,
-            SignedInt(hir::TyIs)   => cx.types.isize,
-            UnsignedInt(hir::TyU8)    => cx.types.u8,
-            UnsignedInt(hir::TyU16)   => cx.types.u16,
-            UnsignedInt(hir::TyU32)   => cx.types.u32,
-            UnsignedInt(hir::TyU64)   => cx.types.u64,
-            UnsignedInt(hir::TyUs) => cx.types.usize,
-        }
-    }
-
-    fn i64_to_disr(&self, val: i64) -> Option<Disr> {
-        match *self {
-            SignedInt(hir::TyI8)    => val.to_i8()  .map(|v| v as Disr),
-            SignedInt(hir::TyI16)   => val.to_i16() .map(|v| v as Disr),
-            SignedInt(hir::TyI32)   => val.to_i32() .map(|v| v as Disr),
-            SignedInt(hir::TyI64)   => val.to_i64() .map(|v| v as Disr),
-            UnsignedInt(hir::TyU8)  => val.to_u8()  .map(|v| v as Disr),
-            UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr),
-            UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr),
-            UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr),
-
-            UnsignedInt(hir::TyUs) |
-            SignedInt(hir::TyIs) => unreachable!(),
-        }
-    }
-
-    fn u64_to_disr(&self, val: u64) -> Option<Disr> {
-        match *self {
-            SignedInt(hir::TyI8)    => val.to_i8()  .map(|v| v as Disr),
-            SignedInt(hir::TyI16)   => val.to_i16() .map(|v| v as Disr),
-            SignedInt(hir::TyI32)   => val.to_i32() .map(|v| v as Disr),
-            SignedInt(hir::TyI64)   => val.to_i64() .map(|v| v as Disr),
-            UnsignedInt(hir::TyU8)  => val.to_u8()  .map(|v| v as Disr),
-            UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr),
-            UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr),
-            UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr),
-
-            UnsignedInt(hir::TyUs) |
-            SignedInt(hir::TyIs) => unreachable!(),
-        }
-    }
-
-    fn disr_incr(&self, val: Disr) -> Option<Disr> {
-        macro_rules! add1 {
-            ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) }
-        }
-        match *self {
-            // SignedInt repr means we *want* to reinterpret the bits
-            // treating the highest bit of Disr as a sign-bit, so
-            // cast to i64 before range-checking.
-            SignedInt(hir::TyI8)    => add1!((val as i64).to_i8()),
-            SignedInt(hir::TyI16)   => add1!((val as i64).to_i16()),
-            SignedInt(hir::TyI32)   => add1!((val as i64).to_i32()),
-            SignedInt(hir::TyI64)   => add1!(Some(val as i64)),
-
-            UnsignedInt(hir::TyU8)  => add1!(val.to_u8()),
-            UnsignedInt(hir::TyU16) => add1!(val.to_u16()),
-            UnsignedInt(hir::TyU32) => add1!(val.to_u32()),
-            UnsignedInt(hir::TyU64) => add1!(Some(val)),
-
-            UnsignedInt(hir::TyUs) |
-            SignedInt(hir::TyIs) => unreachable!(),
-        }
-    }
-
-    // This returns a String because (1.) it is only used for
-    // rendering an error message and (2.) a string can represent the
-    // full range from `i64::MIN` through `u64::MAX`.
-    fn disr_string(&self, val: Disr) -> String {
-        match *self {
-            SignedInt(hir::TyI8)    => format!("{}", val as i8 ),
-            SignedInt(hir::TyI16)   => format!("{}", val as i16),
-            SignedInt(hir::TyI32)   => format!("{}", val as i32),
-            SignedInt(hir::TyI64)   => format!("{}", val as i64),
-            UnsignedInt(hir::TyU8)  => format!("{}", val as u8 ),
-            UnsignedInt(hir::TyU16) => format!("{}", val as u16),
-            UnsignedInt(hir::TyU32) => format!("{}", val as u32),
-            UnsignedInt(hir::TyU64) => format!("{}", val as u64),
-
-            UnsignedInt(hir::TyUs) |
-            SignedInt(hir::TyIs) => unreachable!(),
-        }
-    }
-
-    fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr {
-        macro_rules! add1 {
-            ($e:expr) => { ($e).wrapping_add(1) as Disr }
-        }
-        let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE);
-        match *self {
-            SignedInt(hir::TyI8)    => add1!(val as i8 ),
-            SignedInt(hir::TyI16)   => add1!(val as i16),
-            SignedInt(hir::TyI32)   => add1!(val as i32),
-            SignedInt(hir::TyI64)   => add1!(val as i64),
-            UnsignedInt(hir::TyU8)  => add1!(val as u8 ),
-            UnsignedInt(hir::TyU16) => add1!(val as u16),
-            UnsignedInt(hir::TyU32) => add1!(val as u32),
-            UnsignedInt(hir::TyU64) => add1!(val as u64),
-
-            UnsignedInt(hir::TyUs) |
-            SignedInt(hir::TyIs) => unreachable!(),
-        }
-    }
-}
-
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum ImplOrTraitItemContainer {
     TraitContainer(DefId),
@@ -435,105 +305,6 @@ pub enum Variance {
     Bivariant,      // T<A> <: T<B>            -- e.g., unused type parameter
 }
 
-#[derive(Copy, Clone)]
-pub enum AutoAdjustment<'tcx> {
-    AdjustReifyFnPointer,   // go from a fn-item type to a fn-pointer type
-    AdjustUnsafeFnPointer,  // go from a safe fn pointer to an unsafe fn pointer
-    AdjustDerefRef(AutoDerefRef<'tcx>),
-}
-
-/// Represents coercing a pointer to a different kind of pointer - where 'kind'
-/// here means either or both of raw vs borrowed vs unique and fat vs thin.
-///
-/// We transform pointers by following the following steps in order:
-/// 1. Deref the pointer `self.autoderefs` times (may be 0).
-/// 2. If `autoref` is `Some(_)`, then take the address and produce either a
-///    `&` or `*` pointer.
-/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
-///    which will do things like convert thin pointers to fat
-///    pointers, or convert structs containing thin pointers to
-///    structs containing fat pointers, or convert between fat
-///    pointers.  We don't store the details of how the transform is
-///    done (in fact, we don't know that, because it might depend on
-///    the precise type parameters). We just store the target
-///    type. Trans figures out what has to be done at monomorphization
-///    time based on the precise source/target type at hand.
-///
-/// To make that more concrete, here are some common scenarios:
-///
-/// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
-/// Here the pointer will be dereferenced N times (where a dereference can
-/// happen to to raw or borrowed pointers or any smart pointer which implements
-/// Deref, including Box<_>). The number of dereferences is given by
-/// `autoderefs`.  It can then be auto-referenced zero or one times, indicated
-/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
-/// None.
-///
-/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
-/// with a thin pointer, deref a number of times, unsize the underlying data,
-/// then autoref. The 'unsize' phase may change a fixed length array to a
-/// dynamically sized one, a concrete object to a trait object, or statically
-/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
-/// represented by:
-///
-/// ```
-/// AutoDerefRef {
-///     autoderefs: 1,          // &[i32; 4] -> [i32; 4]
-///     autoref: Some(AutoPtr), // [i32] -> &[i32]
-///     unsize: Some([i32]),    // [i32; 4] -> [i32]
-/// }
-/// ```
-///
-/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
-/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
-/// The autoderef and -ref are the same as in the above example, but the type
-/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
-/// the underlying conversions from `[i32; 4]` to `[i32]`.
-///
-/// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case.  In
-/// that case, we have the pointer we need coming in, so there are no
-/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
-/// At some point, of course, `Box` should move out of the compiler, in which
-/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
-/// Box<[i32]> is represented by:
-///
-/// ```
-/// AutoDerefRef {
-///     autoderefs: 0,
-///     autoref: None,
-///     unsize: Some(Box<[i32]>),
-/// }
-/// ```
-#[derive(Copy, Clone)]
-pub struct AutoDerefRef<'tcx> {
-    /// Step 1. Apply a number of dereferences, producing an lvalue.
-    pub autoderefs: usize,
-
-    /// Step 2. Optionally produce a pointer/reference from the value.
-    pub autoref: Option<AutoRef<'tcx>>,
-
-    /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
-    /// `&[T]`. The stored type is the target pointer type. Note that
-    /// the source could be a thin or fat pointer.
-    pub unsize: Option<Ty<'tcx>>,
-}
-
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum AutoRef<'tcx> {
-    /// Convert from T to &T.
-    AutoPtr(&'tcx Region, hir::Mutability),
-
-    /// Convert from T to *T.
-    /// Value to thin pointer.
-    AutoUnsafe(hir::Mutability),
-}
-
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
-pub enum CustomCoerceUnsized {
-    /// Records the index of the field being coerced.
-    Struct(usize)
-}
-
 #[derive(Clone, Copy, Debug)]
 pub struct MethodCallee<'tcx> {
     /// Impl method ID, for inherent methods, or trait method ID, otherwise.
@@ -1502,52 +1273,6 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
             }
         }
     }
-
-    pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span)
-                                   -> Result<(),CopyImplementationError> {
-        let tcx = self.tcx;
-
-        // FIXME: (@jroesch) float this code up
-        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()), false);
-
-        let adt = match self_type.sty {
-            ty::TyStruct(struct_def, substs) => {
-                for field in struct_def.all_fields() {
-                    let field_ty = field.ty(tcx, substs);
-                    if infcx.type_moves_by_default(field_ty, span) {
-                        return Err(FieldDoesNotImplementCopy(field.name))
-                    }
-                }
-                struct_def
-            }
-            ty::TyEnum(enum_def, substs) => {
-                for variant in &enum_def.variants {
-                    for field in &variant.fields {
-                        let field_ty = field.ty(tcx, substs);
-                        if infcx.type_moves_by_default(field_ty, span) {
-                            return Err(VariantDoesNotImplementCopy(variant.name))
-                        }
-                    }
-                }
-                enum_def
-            }
-            _ => return Err(TypeIsStructural),
-        };
-
-        if adt.has_dtor() {
-            return Err(TypeHasDestructor)
-        }
-
-        Ok(())
-    }
-}
-
-#[derive(Copy, Clone)]
-pub enum CopyImplementationError {
-    FieldDoesNotImplementCopy(Name),
-    VariantDoesNotImplementCopy(Name),
-    TypeIsStructural,
-    TypeHasDestructor,
 }
 
 /// A "type scheme", in ML terminology, is a type combined with some
@@ -2093,16 +1818,6 @@ impl ClosureKind {
     }
 }
 
-impl<'tcx> ctxt<'tcx> {
-    pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option<hir::Mutability> {
-        pat_util::pat_contains_ref_binding(&self.def_map, pat)
-    }
-
-    pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option<hir::Mutability> {
-        pat_util::arm_contains_ref_binding(&self.def_map, arm)
-    }
-}
-
 impl<'tcx> TyS<'tcx> {
     /// Iterator that walks `self` and any types reachable from
     /// `self`, in depth-first order. Note that just walks the types
@@ -2125,63 +1840,6 @@ impl<'tcx> TyS<'tcx> {
         walk::walk_shallow(self)
     }
 
-    pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
-        match self.sty {
-            ty::TyParam(ref d) => Some(d.clone()),
-            _ => None,
-        }
-    }
-
-    pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
-        match self.sty {
-            ty::TyParam(ref data) => data.space == space && data.idx == index,
-            _ => false,
-        }
-    }
-
-    /// Returns the regions directly referenced from this type (but
-    /// not types reachable from this type via `walk_tys`). This
-    /// ignores late-bound regions binders.
-    pub fn regions(&self) -> Vec<ty::Region> {
-        match self.sty {
-            TyRef(region, _) => {
-                vec![*region]
-            }
-            TyTrait(ref obj) => {
-                let mut v = vec![obj.bounds.region_bound];
-                v.push_all(obj.principal.skip_binder().substs.regions().as_slice());
-                v
-            }
-            TyEnum(_, substs) |
-            TyStruct(_, substs) => {
-                substs.regions().as_slice().to_vec()
-            }
-            TyClosure(_, ref substs) => {
-                substs.func_substs.regions().as_slice().to_vec()
-            }
-            TyProjection(ref data) => {
-                data.trait_ref.substs.regions().as_slice().to_vec()
-            }
-            TyBareFn(..) |
-            TyBool |
-            TyChar |
-            TyInt(_) |
-            TyUint(_) |
-            TyFloat(_) |
-            TyBox(_) |
-            TyStr |
-            TyArray(_, _) |
-            TySlice(_) |
-            TyRawPtr(_) |
-            TyTuple(_) |
-            TyParam(_) |
-            TyInfer(_) |
-            TyError => {
-                vec![]
-            }
-        }
-    }
-
     /// Walks `ty` and any types appearing within `ty`, invoking the
     /// callback `f` on each type. If the callback returns false, then the
     /// children of the current type are ignored.
@@ -2199,31 +1857,6 @@ impl<'tcx> TyS<'tcx> {
     }
 }
 
-impl ParamTy {
-    pub fn new(space: subst::ParamSpace,
-               index: u32,
-               name: Name)
-               -> ParamTy {
-        ParamTy { space: space, idx: index, name: name }
-    }
-
-    pub fn for_self() -> ParamTy {
-        ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name)
-    }
-
-    pub fn for_def(def: &TypeParameterDef) -> ParamTy {
-        ParamTy::new(def.space, def.index, def.name)
-    }
-
-    pub fn to_ty<'tcx>(self, tcx: &ctxt<'tcx>) -> Ty<'tcx> {
-        tcx.mk_param(self.space, self.idx, self.name)
-    }
-
-    pub fn is_self(&self) -> bool {
-        self.space == subst::SelfSpace && self.idx == 0
-    }
-}
-
 impl<'tcx> ItemSubsts<'tcx> {
     pub fn empty() -> ItemSubsts<'tcx> {
         ItemSubsts { substs: Substs::empty() }
@@ -2234,99 +1867,6 @@ impl<'tcx> ItemSubsts<'tcx> {
     }
 }
 
-impl<'tcx> TyS<'tcx> {
-    fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
-                       bound: ty::BuiltinBound,
-                       span: Span)
-                       -> bool
-    {
-        let tcx = param_env.tcx;
-        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()), false);
-
-        let is_impld = traits::type_known_to_meet_builtin_bound(&infcx,
-                                                                self, bound, span);
-
-        debug!("Ty::impls_bound({:?}, {:?}) = {:?}",
-               self, bound, is_impld);
-
-        is_impld
-    }
-
-    // FIXME (@jroesch): I made this public to use it, not sure if should be private
-    pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
-                           span: Span) -> bool {
-        if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) {
-            return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT);
-        }
-
-        assert!(!self.needs_infer());
-
-        // Fast-path for primitive types
-        let result = match self.sty {
-            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
-            TyRawPtr(..) | TyBareFn(..) | TyRef(_, TypeAndMut {
-                mutbl: hir::MutImmutable, ..
-            }) => Some(false),
-
-            TyStr | TyBox(..) | TyRef(_, TypeAndMut {
-                mutbl: hir::MutMutable, ..
-            }) => Some(true),
-
-            TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) |
-            TyClosure(..) | TyEnum(..) | TyStruct(..) |
-            TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
-        }.unwrap_or_else(|| !self.impls_bound(param_env, ty::BoundCopy, span));
-
-        if !self.has_param_types() && !self.has_self_ty() {
-            self.flags.set(self.flags.get() | if result {
-                TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT
-            } else {
-                TypeFlags::MOVENESS_CACHED
-            });
-        }
-
-        result
-    }
-
-    #[inline]
-    pub fn is_sized<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
-                        span: Span) -> bool
-    {
-        if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) {
-            return self.flags.get().intersects(TypeFlags::IS_SIZED);
-        }
-
-        self.is_sized_uncached(param_env, span)
-    }
-
-    fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
-                             span: Span) -> bool {
-        assert!(!self.needs_infer());
-
-        // Fast-path for primitive types
-        let result = match self.sty {
-            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
-            TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) |
-            TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true),
-
-            TyStr | TyTrait(..) | TySlice(_) => Some(false),
-
-            TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) |
-            TyInfer(..) | TyError => None
-        }.unwrap_or_else(|| self.impls_bound(param_env, ty::BoundSized, span));
-
-        if !self.has_param_types() && !self.has_self_ty() {
-            self.flags.set(self.flags.get() | if result {
-                TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED
-            } else {
-                TypeFlags::SIZEDNESS_CACHED
-            });
-        }
-
-        result
-    }
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum LvaluePreference {
     PreferMutLvalue,
@@ -2342,283 +1882,6 @@ impl LvaluePreference {
     }
 }
 
-/// Describes whether a type is representable. For types that are not
-/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
-/// distinguish between types that are recursive with themselves and types that
-/// contain a different recursive type. These cases can therefore be treated
-/// differently when reporting errors.
-///
-/// The ordering of the cases is significant. They are sorted so that cmp::max
-/// will keep the "more erroneous" of two values.
-#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
-pub enum Representability {
-    Representable,
-    ContainsRecursive,
-    SelfRecursive,
-}
-
-impl<'tcx> TyS<'tcx> {
-    /// Check whether a type is representable. This means it cannot contain unboxed
-    /// structural recursion. This check is needed for structs and enums.
-    pub fn is_representable(&'tcx self, cx: &ctxt<'tcx>, sp: Span) -> Representability {
-
-        // Iterate until something non-representable is found
-        fn find_nonrepresentable<'tcx, It: Iterator<Item=Ty<'tcx>>>(cx: &ctxt<'tcx>, sp: Span,
-                                                                    seen: &mut Vec<Ty<'tcx>>,
-                                                                    iter: It)
-                                                                    -> Representability {
-            iter.fold(Representable,
-                      |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty)))
-        }
-
-        fn are_inner_types_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span,
-                                           seen: &mut Vec<Ty<'tcx>>, ty: Ty<'tcx>)
-                                           -> Representability {
-            match ty.sty {
-                TyTuple(ref ts) => {
-                    find_nonrepresentable(cx, sp, seen, ts.iter().cloned())
-                }
-                // Fixed-length vectors.
-                // FIXME(#11924) Behavior undecided for zero-length vectors.
-                TyArray(ty, _) => {
-                    is_type_structurally_recursive(cx, sp, seen, ty)
-                }
-                TyStruct(def, substs) | TyEnum(def, substs) => {
-                    find_nonrepresentable(cx,
-                                          sp,
-                                          seen,
-                                          def.all_fields().map(|f| f.ty(cx, substs)))
-                }
-                TyClosure(..) => {
-                    // this check is run on type definitions, so we don't expect
-                    // to see closure types
-                    cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty))
-                }
-                _ => Representable,
-            }
-        }
-
-        fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: AdtDef<'tcx>) -> bool {
-            match ty.sty {
-                TyStruct(ty_def, _) | TyEnum(ty_def, _) => {
-                     ty_def == def
-                }
-                _ => false
-            }
-        }
-
-        fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
-            match (&a.sty, &b.sty) {
-                (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) |
-                (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => {
-                    if did_a != did_b {
-                        return false;
-                    }
-
-                    let types_a = substs_a.types.get_slice(subst::TypeSpace);
-                    let types_b = substs_b.types.get_slice(subst::TypeSpace);
-
-                    let mut pairs = types_a.iter().zip(types_b);
-
-                    pairs.all(|(&a, &b)| same_type(a, b))
-                }
-                _ => {
-                    a == b
-                }
-            }
-        }
-
-        // Does the type `ty` directly (without indirection through a pointer)
-        // contain any types on stack `seen`?
-        fn is_type_structurally_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span,
-                                                seen: &mut Vec<Ty<'tcx>>,
-                                                ty: Ty<'tcx>) -> Representability {
-            debug!("is_type_structurally_recursive: {:?}", ty);
-
-            match ty.sty {
-                TyStruct(def, _) | TyEnum(def, _) => {
-                    {
-                        // Iterate through stack of previously seen types.
-                        let mut iter = seen.iter();
-
-                        // The first item in `seen` is the type we are actually curious about.
-                        // We want to return SelfRecursive if this type contains itself.
-                        // It is important that we DON'T take generic parameters into account
-                        // for this check, so that Bar<T> in this example counts as SelfRecursive:
-                        //
-                        // struct Foo;
-                        // struct Bar<T> { x: Bar<Foo> }
-
-                        match iter.next() {
-                            Some(&seen_type) => {
-                                if same_struct_or_enum(seen_type, def) {
-                                    debug!("SelfRecursive: {:?} contains {:?}",
-                                           seen_type,
-                                           ty);
-                                    return SelfRecursive;
-                                }
-                            }
-                            None => {}
-                        }
-
-                        // We also need to know whether the first item contains other types
-                        // that are structurally recursive. If we don't catch this case, we
-                        // will recurse infinitely for some inputs.
-                        //
-                        // It is important that we DO take generic parameters into account
-                        // here, so that code like this is considered SelfRecursive, not
-                        // ContainsRecursive:
-                        //
-                        // struct Foo { Option<Option<Foo>> }
-
-                        for &seen_type in iter {
-                            if same_type(ty, seen_type) {
-                                debug!("ContainsRecursive: {:?} contains {:?}",
-                                       seen_type,
-                                       ty);
-                                return ContainsRecursive;
-                            }
-                        }
-                    }
-
-                    // For structs and enums, track all previously seen types by pushing them
-                    // onto the 'seen' stack.
-                    seen.push(ty);
-                    let out = are_inner_types_recursive(cx, sp, seen, ty);
-                    seen.pop();
-                    out
-                }
-                _ => {
-                    // No need to push in other cases.
-                    are_inner_types_recursive(cx, sp, seen, ty)
-                }
-            }
-        }
-
-        debug!("is_type_representable: {:?}", self);
-
-        // To avoid a stack overflow when checking an enum variant or struct that
-        // contains a different, structurally recursive type, maintain a stack
-        // of seen types and check recursion for each of them (issues #3008, #3779).
-        let mut seen: Vec<Ty> = Vec::new();
-        let r = is_type_structurally_recursive(cx, sp, &mut seen, self);
-        debug!("is_type_representable: {:?} is {:?}", self, r);
-        r
-    }
-
-    /// See `expr_ty_adjusted`
-    pub fn adjust<F>(&'tcx self, cx: &ctxt<'tcx>,
-                     span: Span,
-                     expr_id: NodeId,
-                     adjustment: Option<&AutoAdjustment<'tcx>>,
-                     mut method_type: F)
-                     -> Ty<'tcx> where
-        F: FnMut(MethodCall) -> Option<Ty<'tcx>>,
-    {
-        if let TyError = self.sty {
-            return self;
-        }
-
-        return match adjustment {
-            Some(adjustment) => {
-                match *adjustment {
-                   AdjustReifyFnPointer => {
-                        match self.sty {
-                            ty::TyBareFn(Some(_), b) => {
-                                cx.mk_fn(None, b)
-                            }
-                            _ => {
-                                cx.sess.bug(
-                                    &format!("AdjustReifyFnPointer adjustment on non-fn-item: \
-                                              {:?}", self));
-                            }
-                        }
-                    }
-
-                   AdjustUnsafeFnPointer => {
-                        match self.sty {
-                            ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b),
-                            ref b => {
-                                cx.sess.bug(
-                                    &format!("AdjustReifyFnPointer adjustment on non-fn-item: \
-                                             {:?}",
-                                            b));
-                            }
-                        }
-                   }
-
-                    AdjustDerefRef(ref adj) => {
-                        let mut adjusted_ty = self;
-
-                        if !adjusted_ty.references_error() {
-                            for i in 0..adj.autoderefs {
-                                adjusted_ty =
-                                    adjusted_ty.adjust_for_autoderef(cx,
-                                                                     expr_id,
-                                                                     span,
-                                                                     i as u32,
-                                                                     &mut method_type);
-                            }
-                        }
-
-                        if let Some(target) = adj.unsize {
-                            target
-                        } else {
-                            adjusted_ty.adjust_for_autoref(cx, adj.autoref)
-                        }
-                    }
-                }
-            }
-            None => self
-        };
-    }
-
-    pub fn adjust_for_autoderef<F>(&'tcx self,
-                                   cx: &ctxt<'tcx>,
-                                   expr_id: ast::NodeId,
-                                   expr_span: Span,
-                                   autoderef: u32, // how many autoderefs so far?
-                                   mut method_type: F)
-                                   -> Ty<'tcx> where
-        F: FnMut(MethodCall) -> Option<Ty<'tcx>>,
-    {
-        let method_call = MethodCall::autoderef(expr_id, autoderef);
-        let mut adjusted_ty = self;
-        if let Some(method_ty) = method_type(method_call) {
-            // Method calls always have all late-bound regions
-            // fully instantiated.
-            let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
-            adjusted_ty = fn_ret.unwrap();
-        }
-        match adjusted_ty.builtin_deref(true, NoPreference) {
-            Some(mt) => mt.ty,
-            None => {
-                cx.sess.span_bug(
-                    expr_span,
-                    &format!("the {}th autoderef failed: {}",
-                             autoderef,
-                             adjusted_ty)
-                        );
-            }
-        }
-    }
-
-    pub fn adjust_for_autoref(&'tcx self, cx: &ctxt<'tcx>,
-                              autoref: Option<AutoRef<'tcx>>)
-                              -> Ty<'tcx> {
-        match autoref {
-            None => self,
-            Some(AutoPtr(r, m)) => {
-                cx.mk_ref(r, TypeAndMut { ty: self, mutbl: m })
-            }
-            Some(AutoUnsafe(m)) => {
-                cx.mk_ptr(TypeAndMut { ty: self, mutbl: m })
-            }
-        }
-    }
-
-}
-
 /// Helper for looking things up in the various maps that are populated during
 /// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc).  All of
 /// these share the pattern that if the id is local, it should have been loaded
@@ -2679,45 +1942,6 @@ impl BorrowKind {
 }
 
 impl<'tcx> ctxt<'tcx> {
-    /// Returns the type of element at index `i` in tuple or tuple-like type `t`.
-    /// For an enum `t`, `variant` is None only if `t` is a univariant enum.
-    pub fn positional_element_ty(&self,
-                                 ty: Ty<'tcx>,
-                                 i: usize,
-                                 variant: Option<DefId>) -> Option<Ty<'tcx>> {
-        match (&ty.sty, variant) {
-            (&TyStruct(def, substs), None) => {
-                def.struct_variant().fields.get(i).map(|f| f.ty(self, substs))
-            }
-            (&TyEnum(def, substs), Some(vid)) => {
-                def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs))
-            }
-            (&TyEnum(def, substs), None) => {
-                assert!(def.is_univariant());
-                def.variants[0].fields.get(i).map(|f| f.ty(self, substs))
-            }
-            (&TyTuple(ref v), None) => v.get(i).cloned(),
-            _ => None
-        }
-    }
-
-    /// Returns the type of element at field `n` in struct or struct-like type `t`.
-    /// For an enum `t`, `variant` must be some def id.
-    pub fn named_element_ty(&self,
-                            ty: Ty<'tcx>,
-                            n: Name,
-                            variant: Option<DefId>) -> Option<Ty<'tcx>> {
-        match (&ty.sty, variant) {
-            (&TyStruct(def, substs), None) => {
-                def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs))
-            }
-            (&TyEnum(def, substs), Some(vid)) => {
-                def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs))
-            }
-            _ => return None
-        }
-    }
-
     pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> {
         match self.node_id_to_type_opt(id) {
            Some(ty) => ty,
@@ -2992,7 +2216,7 @@ impl<'tcx> ctxt<'tcx> {
         }
     }
 
-    pub fn custom_coerce_unsized_kind(&self, did: DefId) -> CustomCoerceUnsized {
+    pub fn custom_coerce_unsized_kind(&self, did: DefId) -> adjustment::CustomCoerceUnsized {
         memoized(&self.custom_coerce_unsized_kinds, did, |did: DefId| {
             let (kind, src) = if did.krate != LOCAL_CRATE {
                 (csearch::get_custom_coerce_unsized_kind(self, did), "external")
@@ -3071,35 +2295,6 @@ impl<'tcx> ctxt<'tcx> {
         }
     }
 
-    /// Returns `(normalized_type, ty)`, where `normalized_type` is the
-    /// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8},
-    /// and `ty` is the original type (i.e. may include `isize` or
-    /// `usize`).
-    pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>)
-                          -> (attr::IntType, Ty<'tcx>) {
-        let repr_type = match opt_hint {
-            // Feed in the given type
-            Some(&attr::ReprInt(_, int_t)) => int_t,
-            // ... but provide sensible default if none provided
-            //
-            // NB. Historically `fn enum_variants` generate i64 here, while
-            // rustc_typeck::check would generate isize.
-            _ => SignedInt(hir::TyIs),
-        };
-
-        let repr_type_ty = repr_type.to_ty(self);
-        let repr_type = match repr_type {
-            SignedInt(hir::TyIs) =>
-                SignedInt(self.sess.target.int_type),
-            UnsignedInt(hir::TyUs) =>
-                UnsignedInt(self.sess.target.uint_type),
-            other => other
-        };
-
-        (repr_type, repr_type_ty)
-    }
-
-
     // Register a given item type
     pub fn register_item_type(&self, did: DefId, ty: TypeScheme<'tcx>) {
         self.tcache.borrow_mut().insert(did, ty);
@@ -3195,155 +2390,6 @@ impl<'tcx> ctxt<'tcx> {
         })
     }
 
-
-    /// Returns the deeply last field of nested structures, or the same type,
-    /// if not a structure at all. Corresponds to the only possible unsized
-    /// field, and its type can be used to determine unsizing strategy.
-    pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        while let TyStruct(def, substs) = ty.sty {
-            match def.struct_variant().fields.last() {
-                Some(f) => ty = f.ty(self, substs),
-                None => break
-            }
-        }
-        ty
-    }
-
-    /// Same as applying struct_tail on `source` and `target`, but only
-    /// keeps going as long as the two types are instances of the same
-    /// structure definitions.
-    /// For `(Foo<Foo<T>>, Foo<Trait>)`, the result will be `(Foo<T>, Trait)`,
-    /// whereas struct_tail produces `T`, and `Trait`, respectively.
-    pub fn struct_lockstep_tails(&self,
-                                 source: Ty<'tcx>,
-                                 target: Ty<'tcx>)
-                                 -> (Ty<'tcx>, Ty<'tcx>) {
-        let (mut a, mut b) = (source, target);
-        while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) {
-            if a_def != b_def {
-                break;
-            }
-            if let Some(f) = a_def.struct_variant().fields.last() {
-                a = f.ty(self, a_substs);
-                b = f.ty(self, b_substs);
-            } else {
-                break;
-            }
-        }
-        (a, b)
-    }
-
-    // Returns the repeat count for a repeating vector expression.
-    pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
-        let hint = UncheckedExprHint(self.types.usize);
-        match const_eval::eval_const_expr_partial(self, count_expr, hint) {
-            Ok(val) => {
-                let found = match val {
-                    ConstVal::Uint(count) => return count as usize,
-                    ConstVal::Int(count) if count >= 0 => return count as usize,
-                    const_val => const_val.description(),
-                };
-                span_err!(self.sess, count_expr.span, E0306,
-                    "expected positive integer for repeat count, found {}",
-                    found);
-            }
-            Err(err) => {
-                let err_msg = match count_expr.node {
-                    hir::ExprPath(None, hir::Path {
-                        global: false,
-                        ref segments,
-                        ..
-                    }) if segments.len() == 1 =>
-                        format!("found variable"),
-                    _ => match err.kind {
-                        ErrKind::MiscCatchAll => format!("but found {}", err.description()),
-                        _ => format!("but {}", err.description())
-                    }
-                };
-                span_err!(self.sess, count_expr.span, E0307,
-                    "expected constant integer for repeat count, {}", err_msg);
-            }
-        }
-        0
-    }
-
-    // Iterate over a type parameter's bounded traits and any supertraits
-    // of those traits, ignoring kinds.
-    // Here, the supertraits are the transitive closure of the supertrait
-    // relation on the supertraits from each bounded trait's constraint
-    // list.
-    pub fn each_bound_trait_and_supertraits<F>(&self,
-                                               bounds: &[PolyTraitRef<'tcx>],
-                                               mut f: F)
-                                               -> bool where
-        F: FnMut(PolyTraitRef<'tcx>) -> bool,
-    {
-        for bound_trait_ref in traits::transitive_bounds(self, bounds) {
-            if !f(bound_trait_ref) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /// Given a set of predicates that apply to an object type, returns
-    /// the region bounds that the (erased) `Self` type must
-    /// outlive. Precisely *because* the `Self` type is erased, the
-    /// parameter `erased_self_ty` must be supplied to indicate what type
-    /// has been used to represent `Self` in the predicates
-    /// themselves. This should really be a unique type; `FreshTy(0)` is a
-    /// popular choice.
-    ///
-    /// NB: in some cases, particularly around higher-ranked bounds,
-    /// this function returns a kind of conservative approximation.
-    /// That is, all regions returned by this function are definitely
-    /// required, but there may be other region bounds that are not
-    /// returned, as well as requirements like `for<'a> T: 'a`.
-    ///
-    /// Requires that trait definitions have been processed so that we can
-    /// elaborate predicates and walk supertraits.
-    pub fn required_region_bounds(&self,
-                                  erased_self_ty: Ty<'tcx>,
-                                  predicates: Vec<ty::Predicate<'tcx>>)
-                                  -> Vec<ty::Region>    {
-        debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})",
-               erased_self_ty,
-               predicates);
-
-        assert!(!erased_self_ty.has_escaping_regions());
-
-        traits::elaborate_predicates(self, predicates)
-            .filter_map(|predicate| {
-                match predicate {
-                    ty::Predicate::Projection(..) |
-                    ty::Predicate::Trait(..) |
-                    ty::Predicate::Equate(..) |
-                    ty::Predicate::WellFormed(..) |
-                    ty::Predicate::ObjectSafe(..) |
-                    ty::Predicate::RegionOutlives(..) => {
-                        None
-                    }
-                    ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => {
-                        // Search for a bound of the form `erased_self_ty
-                        // : 'a`, but be wary of something like `for<'a>
-                        // erased_self_ty : 'a` (we interpret a
-                        // higher-ranked bound like that as 'static,
-                        // though at present the code in `fulfill.rs`
-                        // considers such bounds to be unsatisfiable, so
-                        // it's kind of a moot point since you could never
-                        // construct such an object, but this seems
-                        // correct even if that code changes).
-                        if t == erased_self_ty && !r.has_escaping_regions() {
-                            Some(r)
-                        } else {
-                            None
-                        }
-                    }
-                }
-            })
-            .collect()
-    }
-
     pub fn item_variances(&self, item_id: DefId) -> Rc<ItemVariances> {
         lookup_locally_or_in_crate_store(
             "item_variance_map", item_id, &self.item_variance_map,
@@ -3527,148 +2573,6 @@ impl<'tcx> ctxt<'tcx> {
         }
     }
 
-    /// Creates a hash of the type `Ty` which will be the same no matter what crate
-    /// context it's calculated within. This is used by the `type_id` intrinsic.
-    pub fn hash_crate_independent(&self, ty: Ty<'tcx>, svh: &Svh) -> u64 {
-        let mut state = SipHasher::new();
-        helper(self, ty, svh, &mut state);
-        return state.finish();
-
-        fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh,
-                        state: &mut SipHasher) {
-            macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } }
-            macro_rules! hash { ($e:expr) => { $e.hash(state) }  }
-
-            let region = |state: &mut SipHasher, r: Region| {
-                match r {
-                    ReStatic => {}
-                    ReLateBound(db, BrAnon(i)) => {
-                        db.hash(state);
-                        i.hash(state);
-                    }
-                    ReEmpty |
-                    ReEarlyBound(..) |
-                    ReLateBound(..) |
-                    ReFree(..) |
-                    ReScope(..) |
-                    ReVar(..) |
-                    ReSkolemized(..) => {
-                        tcx.sess.bug("unexpected region found when hashing a type")
-                    }
-                }
-            };
-            let did = |state: &mut SipHasher, did: DefId| {
-                let h = if did.is_local() {
-                    svh.clone()
-                } else {
-                    tcx.sess.cstore.get_crate_hash(did.krate)
-                };
-                h.as_str().hash(state);
-                did.node.hash(state);
-            };
-            let mt = |state: &mut SipHasher, mt: TypeAndMut| {
-                mt.mutbl.hash(state);
-            };
-            let fn_sig = |state: &mut SipHasher, sig: &Binder<FnSig<'tcx>>| {
-                let sig = tcx.anonymize_late_bound_regions(sig).0;
-                for a in &sig.inputs { helper(tcx, *a, svh, state); }
-                if let ty::FnConverging(output) = sig.output {
-                    helper(tcx, output, svh, state);
-                }
-            };
-            ty.maybe_walk(|ty| {
-                match ty.sty {
-                    TyBool => byte!(2),
-                    TyChar => byte!(3),
-                    TyInt(i) => {
-                        byte!(4);
-                        hash!(i);
-                    }
-                    TyUint(u) => {
-                        byte!(5);
-                        hash!(u);
-                    }
-                    TyFloat(f) => {
-                        byte!(6);
-                        hash!(f);
-                    }
-                    TyStr => {
-                        byte!(7);
-                    }
-                    TyEnum(d, _) => {
-                        byte!(8);
-                        did(state, d.did);
-                    }
-                    TyBox(_) => {
-                        byte!(9);
-                    }
-                    TyArray(_, n) => {
-                        byte!(10);
-                        n.hash(state);
-                    }
-                    TySlice(_) => {
-                        byte!(11);
-                    }
-                    TyRawPtr(m) => {
-                        byte!(12);
-                        mt(state, m);
-                    }
-                    TyRef(r, m) => {
-                        byte!(13);
-                        region(state, *r);
-                        mt(state, m);
-                    }
-                    TyBareFn(opt_def_id, ref b) => {
-                        byte!(14);
-                        hash!(opt_def_id);
-                        hash!(b.unsafety);
-                        hash!(b.abi);
-                        fn_sig(state, &b.sig);
-                        return false;
-                    }
-                    TyTrait(ref data) => {
-                        byte!(17);
-                        did(state, data.principal_def_id());
-                        hash!(data.bounds);
-
-                        let principal = tcx.anonymize_late_bound_regions(&data.principal).0;
-                        for subty in &principal.substs.types {
-                            helper(tcx, subty, svh, state);
-                        }
-
-                        return false;
-                    }
-                    TyStruct(d, _) => {
-                        byte!(18);
-                        did(state, d.did);
-                    }
-                    TyTuple(ref inner) => {
-                        byte!(19);
-                        hash!(inner.len());
-                    }
-                    TyParam(p) => {
-                        byte!(20);
-                        hash!(p.space);
-                        hash!(p.idx);
-                        hash!(p.name.as_str());
-                    }
-                    TyInfer(_) => unreachable!(),
-                    TyError => byte!(21),
-                    TyClosure(d, _) => {
-                        byte!(22);
-                        did(state, d);
-                    }
-                    TyProjection(ref data) => {
-                        byte!(23);
-                        did(state, data.trait_ref.def_id);
-                        hash!(data.item_name.as_str());
-                    }
-                }
-                true
-            });
-        }
-    }
-
     /// Construct a parameter environment suitable for static contexts or other contexts where there
     /// are no free type/lifetime parameters in scope.
     pub fn empty_parameter_environment<'a>(&'a self)
@@ -3786,87 +2690,6 @@ impl<'tcx> ctxt<'tcx> {
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
         Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone())
     }
-
-
-    /// Returns true if this ADT is a dtorck type, i.e. whether it being
-    /// safe for destruction requires it to be alive
-    fn is_adt_dtorck(&self, adt: AdtDef<'tcx>) -> bool {
-        let dtor_method = match adt.destructor() {
-            Some(dtor) => dtor,
-            None => return false
-        };
-        let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| {
-            self.sess.bug(&format!("no Drop impl for the dtor of `{:?}`", adt))
-        });
-        let generics = adt.type_scheme(self).generics;
-
-        // In `impl<'a> Drop ...`, we automatically assume
-        // `'a` is meaningful and thus represents a bound
-        // through which we could reach borrowed data.
-        //
-        // FIXME (pnkfelix): In the future it would be good to
-        // extend the language to allow the user to express,
-        // in the impl signature, that a lifetime is not
-        // actually used (something like `where 'a: ?Live`).
-        if generics.has_region_params(subst::TypeSpace) {
-            debug!("typ: {:?} has interesting dtor due to region params",
-                   adt);
-            return true;
-        }
-
-        let mut seen_items = Vec::new();
-        let mut items_to_inspect = vec![impl_did];
-        while let Some(item_def_id) = items_to_inspect.pop() {
-            if seen_items.contains(&item_def_id) {
-                continue;
-            }
-
-            for pred in self.lookup_predicates(item_def_id).predicates {
-                let result = match pred {
-                    ty::Predicate::Equate(..) |
-                    ty::Predicate::RegionOutlives(..) |
-                    ty::Predicate::TypeOutlives(..) |
-                    ty::Predicate::WellFormed(..) |
-                    ty::Predicate::ObjectSafe(..) |
-                    ty::Predicate::Projection(..) => {
-                        // For now, assume all these where-clauses
-                        // may give drop implementation capabilty
-                        // to access borrowed data.
-                        true
-                    }
-
-                    ty::Predicate::Trait(ty::Binder(ref t_pred)) => {
-                        let def_id = t_pred.trait_ref.def_id;
-                        if self.trait_items(def_id).len() != 0 {
-                            // If trait has items, assume it adds
-                            // capability to access borrowed data.
-                            true
-                        } else {
-                            // Trait without items is itself
-                            // uninteresting from POV of dropck.
-                            //
-                            // However, may have parent w/ items;
-                            // so schedule checking of predicates,
-                            items_to_inspect.push(def_id);
-                            // and say "no capability found" for now.
-                            false
-                        }
-                    }
-                };
-
-                if result {
-                    debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}",
-                           adt, pred);
-                    return true;
-                }
-            }
-
-            seen_items.push(item_def_id);
-        }
-
-        debug!("typ: {:?} is dtorck-safe", adt);
-        false
-    }
 }
 
 /// The category of explicit self.
@@ -3899,22 +2722,6 @@ pub type TraitMap = NodeMap<Vec<DefId>>;
 // imported.
 pub type GlobMap = HashMap<NodeId, HashSet<Name>>;
 
-impl<'tcx> AutoAdjustment<'tcx> {
-    pub fn is_identity(&self) -> bool {
-        match *self {
-            AdjustReifyFnPointer |
-            AdjustUnsafeFnPointer => false,
-            AdjustDerefRef(ref r) => r.is_identity(),
-        }
-    }
-}
-
-impl<'tcx> AutoDerefRef<'tcx> {
-    pub fn is_identity(&self) -> bool {
-        self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none()
-    }
-}
-
 impl<'tcx> ctxt<'tcx> {
     pub fn with_freevars<T, F>(&self, fid: NodeId, f: F) -> T where
         F: FnOnce(&[Freevar]) -> T,
diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs
index 94e4672ea9710..0058ccbce3b19 100644
--- a/src/librustc/middle/ty/structural_impls.rs
+++ b/src/librustc/middle/ty/structural_impls.rs
@@ -641,8 +641,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::AutoRef<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::AutoRef<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::adjustment::AutoRef<'tcx> {
         folder.fold_autoref(self)
     }
 }
diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs
index a04cc89ee18a0..3969738a22e86 100644
--- a/src/librustc/middle/ty/sty.rs
+++ b/src/librustc/middle/ty/sty.rs
@@ -24,6 +24,7 @@ use std::ops;
 use std::mem;
 use syntax::abi;
 use syntax::ast::{Name, NodeId};
+use syntax::parse::token::special_idents;
 
 use rustc_front::hir;
 
@@ -504,6 +505,31 @@ pub struct ParamTy {
     pub name: Name,
 }
 
+impl ParamTy {
+    pub fn new(space: subst::ParamSpace,
+               index: u32,
+               name: Name)
+               -> ParamTy {
+        ParamTy { space: space, idx: index, name: name }
+    }
+
+    pub fn for_self() -> ParamTy {
+        ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name)
+    }
+
+    pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy {
+        ParamTy::new(def.space, def.index, def.name)
+    }
+
+    pub fn to_ty<'tcx>(self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
+        tcx.mk_param(self.space, self.idx, self.name)
+    }
+
+    pub fn is_self(&self) -> bool {
+        self.space == subst::SelfSpace && self.idx == 0
+    }
+}
+
 /// A [De Bruijn index][dbi] is a standard means of representing
 /// regions (and perhaps later types) in a higher-ranked setting. In
 /// particular, imagine a type like this:
@@ -844,6 +870,13 @@ impl Region {
 
 // Type utilities
 impl<'tcx> TyS<'tcx> {
+    pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
+        match self.sty {
+            ty::TyParam(ref d) => Some(d.clone()),
+            _ => None,
+        }
+    }
+
     pub fn is_nil(&self) -> bool {
         match self.sty {
             TyTuple(ref tys) => tys.is_empty(),
@@ -868,6 +901,13 @@ impl<'tcx> TyS<'tcx> {
 
     pub fn is_bool(&self) -> bool { self.sty == TyBool }
 
+    pub fn is_param(&self, space: subst::ParamSpace, index: u32) -> bool {
+        match self.sty {
+            ty::TyParam(ref data) => data.space == space && data.idx == index,
+            _ => false,
+        }
+    }
+
     pub fn is_self(&self) -> bool {
         match self.sty {
             TyParam(ref p) => p.space == subst::SelfSpace,
@@ -1126,4 +1166,47 @@ impl<'tcx> TyS<'tcx> {
             _ => None
         }
     }
+
+    /// Returns the regions directly referenced from this type (but
+    /// not types reachable from this type via `walk_tys`). This
+    /// ignores late-bound regions binders.
+    pub fn regions(&self) -> Vec<ty::Region> {
+        match self.sty {
+            TyRef(region, _) => {
+                vec![*region]
+            }
+            TyTrait(ref obj) => {
+                let mut v = vec![obj.bounds.region_bound];
+                v.push_all(obj.principal.skip_binder().substs.regions().as_slice());
+                v
+            }
+            TyEnum(_, substs) |
+            TyStruct(_, substs) => {
+                substs.regions().as_slice().to_vec()
+            }
+            TyClosure(_, ref substs) => {
+                substs.func_substs.regions().as_slice().to_vec()
+            }
+            TyProjection(ref data) => {
+                data.trait_ref.substs.regions().as_slice().to_vec()
+            }
+            TyBareFn(..) |
+            TyBool |
+            TyChar |
+            TyInt(_) |
+            TyUint(_) |
+            TyFloat(_) |
+            TyBox(_) |
+            TyStr |
+            TyArray(_, _) |
+            TySlice(_) |
+            TyRawPtr(_) |
+            TyTuple(_) |
+            TyParam(_) |
+            TyInfer(_) |
+            TyError => {
+                vec![]
+            }
+        }
+    }
 }
diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs
new file mode 100644
index 0000000000000..8831461853576
--- /dev/null
+++ b/src/librustc/middle/ty/util.rs
@@ -0,0 +1,891 @@
+// Copyright 2012-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.
+
+//! misc. type-system utilities too small to deserve their own file
+
+use back::svh::Svh;
+use middle::const_eval::{self, ConstVal, ErrKind};
+use middle::const_eval::EvalHint::UncheckedExprHint;
+use middle::def_id::DefId;
+use middle::subst;
+use middle::infer;
+use middle::pat_util;
+use middle::traits;
+use middle::ty::{self, Ty, TypeAndMut, TypeFlags};
+use middle::ty::{Disr, ParameterEnvironment};
+use middle::ty::{HasTypeFlags, RegionEscape};
+use middle::ty::TypeVariants::*;
+use util::num::ToPrimitive;
+
+use std::cmp;
+use std::hash::{Hash, SipHasher, Hasher};
+use syntax::ast::Name;
+use syntax::codemap::Span;
+
+use rustc_front::hir;
+use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
+
+pub trait IntTypeExt {
+    fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
+    fn i64_to_disr(&self, val: i64) -> Option<Disr>;
+    fn u64_to_disr(&self, val: u64) -> Option<Disr>;
+    fn disr_incr(&self, val: Disr) -> Option<Disr>;
+    fn disr_string(&self, val: Disr) -> String;
+    fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr;
+}
+
+impl IntTypeExt for attr::IntType {
+    fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
+        match *self {
+            SignedInt(hir::TyI8)      => cx.types.i8,
+            SignedInt(hir::TyI16)     => cx.types.i16,
+            SignedInt(hir::TyI32)     => cx.types.i32,
+            SignedInt(hir::TyI64)     => cx.types.i64,
+            SignedInt(hir::TyIs)   => cx.types.isize,
+            UnsignedInt(hir::TyU8)    => cx.types.u8,
+            UnsignedInt(hir::TyU16)   => cx.types.u16,
+            UnsignedInt(hir::TyU32)   => cx.types.u32,
+            UnsignedInt(hir::TyU64)   => cx.types.u64,
+            UnsignedInt(hir::TyUs) => cx.types.usize,
+        }
+    }
+
+    fn i64_to_disr(&self, val: i64) -> Option<Disr> {
+        match *self {
+            SignedInt(hir::TyI8)    => val.to_i8()  .map(|v| v as Disr),
+            SignedInt(hir::TyI16)   => val.to_i16() .map(|v| v as Disr),
+            SignedInt(hir::TyI32)   => val.to_i32() .map(|v| v as Disr),
+            SignedInt(hir::TyI64)   => val.to_i64() .map(|v| v as Disr),
+            UnsignedInt(hir::TyU8)  => val.to_u8()  .map(|v| v as Disr),
+            UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr),
+            UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr),
+            UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr),
+
+            UnsignedInt(hir::TyUs) |
+            SignedInt(hir::TyIs) => unreachable!(),
+        }
+    }
+
+    fn u64_to_disr(&self, val: u64) -> Option<Disr> {
+        match *self {
+            SignedInt(hir::TyI8)    => val.to_i8()  .map(|v| v as Disr),
+            SignedInt(hir::TyI16)   => val.to_i16() .map(|v| v as Disr),
+            SignedInt(hir::TyI32)   => val.to_i32() .map(|v| v as Disr),
+            SignedInt(hir::TyI64)   => val.to_i64() .map(|v| v as Disr),
+            UnsignedInt(hir::TyU8)  => val.to_u8()  .map(|v| v as Disr),
+            UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr),
+            UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr),
+            UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr),
+
+            UnsignedInt(hir::TyUs) |
+            SignedInt(hir::TyIs) => unreachable!(),
+        }
+    }
+
+    fn disr_incr(&self, val: Disr) -> Option<Disr> {
+        macro_rules! add1 {
+            ($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) }
+        }
+        match *self {
+            // SignedInt repr means we *want* to reinterpret the bits
+            // treating the highest bit of Disr as a sign-bit, so
+            // cast to i64 before range-checking.
+            SignedInt(hir::TyI8)    => add1!((val as i64).to_i8()),
+            SignedInt(hir::TyI16)   => add1!((val as i64).to_i16()),
+            SignedInt(hir::TyI32)   => add1!((val as i64).to_i32()),
+            SignedInt(hir::TyI64)   => add1!(Some(val as i64)),
+
+            UnsignedInt(hir::TyU8)  => add1!(val.to_u8()),
+            UnsignedInt(hir::TyU16) => add1!(val.to_u16()),
+            UnsignedInt(hir::TyU32) => add1!(val.to_u32()),
+            UnsignedInt(hir::TyU64) => add1!(Some(val)),
+
+            UnsignedInt(hir::TyUs) |
+            SignedInt(hir::TyIs) => unreachable!(),
+        }
+    }
+
+    // This returns a String because (1.) it is only used for
+    // rendering an error message and (2.) a string can represent the
+    // full range from `i64::MIN` through `u64::MAX`.
+    fn disr_string(&self, val: Disr) -> String {
+        match *self {
+            SignedInt(hir::TyI8)    => format!("{}", val as i8 ),
+            SignedInt(hir::TyI16)   => format!("{}", val as i16),
+            SignedInt(hir::TyI32)   => format!("{}", val as i32),
+            SignedInt(hir::TyI64)   => format!("{}", val as i64),
+            UnsignedInt(hir::TyU8)  => format!("{}", val as u8 ),
+            UnsignedInt(hir::TyU16) => format!("{}", val as u16),
+            UnsignedInt(hir::TyU32) => format!("{}", val as u32),
+            UnsignedInt(hir::TyU64) => format!("{}", val as u64),
+
+            UnsignedInt(hir::TyUs) |
+            SignedInt(hir::TyIs) => unreachable!(),
+        }
+    }
+
+    fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr {
+        macro_rules! add1 {
+            ($e:expr) => { ($e).wrapping_add(1) as Disr }
+        }
+        let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE);
+        match *self {
+            SignedInt(hir::TyI8)    => add1!(val as i8 ),
+            SignedInt(hir::TyI16)   => add1!(val as i16),
+            SignedInt(hir::TyI32)   => add1!(val as i32),
+            SignedInt(hir::TyI64)   => add1!(val as i64),
+            UnsignedInt(hir::TyU8)  => add1!(val as u8 ),
+            UnsignedInt(hir::TyU16) => add1!(val as u16),
+            UnsignedInt(hir::TyU32) => add1!(val as u32),
+            UnsignedInt(hir::TyU64) => add1!(val as u64),
+
+            UnsignedInt(hir::TyUs) |
+            SignedInt(hir::TyIs) => unreachable!(),
+        }
+    }
+}
+
+
+#[derive(Copy, Clone)]
+pub enum CopyImplementationError {
+    InfrigingField(Name),
+    InfrigingVariant(Name),
+    NotAnAdt,
+    HasDestructor
+}
+
+/// Describes whether a type is representable. For types that are not
+/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
+/// distinguish between types that are recursive with themselves and types that
+/// contain a different recursive type. These cases can therefore be treated
+/// differently when reporting errors.
+///
+/// The ordering of the cases is significant. They are sorted so that cmp::max
+/// will keep the "more erroneous" of two values.
+#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
+pub enum Representability {
+    Representable,
+    ContainsRecursive,
+    SelfRecursive,
+}
+
+impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
+    pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span)
+                                   -> Result<(),CopyImplementationError> {
+        let tcx = self.tcx;
+
+        // FIXME: (@jroesch) float this code up
+        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()), false);
+
+        let adt = match self_type.sty {
+            ty::TyStruct(struct_def, substs) => {
+                for field in struct_def.all_fields() {
+                    let field_ty = field.ty(tcx, substs);
+                    if infcx.type_moves_by_default(field_ty, span) {
+                        return Err(CopyImplementationError::InfrigingField(
+                            field.name))
+                    }
+                }
+                struct_def
+            }
+            ty::TyEnum(enum_def, substs) => {
+                for variant in &enum_def.variants {
+                    for field in &variant.fields {
+                        let field_ty = field.ty(tcx, substs);
+                        if infcx.type_moves_by_default(field_ty, span) {
+                            return Err(CopyImplementationError::InfrigingVariant(
+                                variant.name))
+                        }
+                    }
+                }
+                enum_def
+            }
+            _ => return Err(CopyImplementationError::NotAnAdt),
+        };
+
+        if adt.has_dtor() {
+            return Err(CopyImplementationError::HasDestructor)
+        }
+
+        Ok(())
+    }
+}
+
+impl<'tcx> ty::ctxt<'tcx> {
+    pub fn pat_contains_ref_binding(&self, pat: &hir::Pat) -> Option<hir::Mutability> {
+        pat_util::pat_contains_ref_binding(&self.def_map, pat)
+    }
+
+    pub fn arm_contains_ref_binding(&self, arm: &hir::Arm) -> Option<hir::Mutability> {
+        pat_util::arm_contains_ref_binding(&self.def_map, arm)
+    }
+
+    /// Returns the type of element at index `i` in tuple or tuple-like type `t`.
+    /// For an enum `t`, `variant` is None only if `t` is a univariant enum.
+    pub fn positional_element_ty(&self,
+                                 ty: Ty<'tcx>,
+                                 i: usize,
+                                 variant: Option<DefId>) -> Option<Ty<'tcx>> {
+        match (&ty.sty, variant) {
+            (&TyStruct(def, substs), None) => {
+                def.struct_variant().fields.get(i).map(|f| f.ty(self, substs))
+            }
+            (&TyEnum(def, substs), Some(vid)) => {
+                def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs))
+            }
+            (&TyEnum(def, substs), None) => {
+                assert!(def.is_univariant());
+                def.variants[0].fields.get(i).map(|f| f.ty(self, substs))
+            }
+            (&TyTuple(ref v), None) => v.get(i).cloned(),
+            _ => None
+        }
+    }
+
+    /// Returns the type of element at field `n` in struct or struct-like type `t`.
+    /// For an enum `t`, `variant` must be some def id.
+    pub fn named_element_ty(&self,
+                            ty: Ty<'tcx>,
+                            n: Name,
+                            variant: Option<DefId>) -> Option<Ty<'tcx>> {
+        match (&ty.sty, variant) {
+            (&TyStruct(def, substs), None) => {
+                def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs))
+            }
+            (&TyEnum(def, substs), Some(vid)) => {
+                def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs))
+            }
+            _ => return None
+        }
+    }
+
+    /// Returns `(normalized_type, ty)`, where `normalized_type` is the
+    /// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8},
+    /// and `ty` is the original type (i.e. may include `isize` or
+    /// `usize`).
+    pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>)
+                          -> (attr::IntType, Ty<'tcx>) {
+        let repr_type = match opt_hint {
+            // Feed in the given type
+            Some(&attr::ReprInt(_, int_t)) => int_t,
+            // ... but provide sensible default if none provided
+            //
+            // NB. Historically `fn enum_variants` generate i64 here, while
+            // rustc_typeck::check would generate isize.
+            _ => SignedInt(hir::TyIs),
+        };
+
+        let repr_type_ty = repr_type.to_ty(self);
+        let repr_type = match repr_type {
+            SignedInt(hir::TyIs) =>
+                SignedInt(self.sess.target.int_type),
+            UnsignedInt(hir::TyUs) =>
+                UnsignedInt(self.sess.target.uint_type),
+            other => other
+        };
+
+        (repr_type, repr_type_ty)
+    }
+
+    /// Returns the deeply last field of nested structures, or the same type,
+    /// if not a structure at all. Corresponds to the only possible unsized
+    /// field, and its type can be used to determine unsizing strategy.
+    pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
+        while let TyStruct(def, substs) = ty.sty {
+            match def.struct_variant().fields.last() {
+                Some(f) => ty = f.ty(self, substs),
+                None => break
+            }
+        }
+        ty
+    }
+
+    /// Same as applying struct_tail on `source` and `target`, but only
+    /// keeps going as long as the two types are instances of the same
+    /// structure definitions.
+    /// For `(Foo<Foo<T>>, Foo<Trait>)`, the result will be `(Foo<T>, Trait)`,
+    /// whereas struct_tail produces `T`, and `Trait`, respectively.
+    pub fn struct_lockstep_tails(&self,
+                                 source: Ty<'tcx>,
+                                 target: Ty<'tcx>)
+                                 -> (Ty<'tcx>, Ty<'tcx>) {
+        let (mut a, mut b) = (source, target);
+        while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) {
+            if a_def != b_def {
+                break;
+            }
+            if let Some(f) = a_def.struct_variant().fields.last() {
+                a = f.ty(self, a_substs);
+                b = f.ty(self, b_substs);
+            } else {
+                break;
+            }
+        }
+        (a, b)
+    }
+
+    /// Returns the repeat count for a repeating vector expression.
+    pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
+        let hint = UncheckedExprHint(self.types.usize);
+        match const_eval::eval_const_expr_partial(self, count_expr, hint) {
+            Ok(val) => {
+                let found = match val {
+                    ConstVal::Uint(count) => return count as usize,
+                    ConstVal::Int(count) if count >= 0 => return count as usize,
+                    const_val => const_val.description(),
+                };
+                span_err!(self.sess, count_expr.span, E0306,
+                    "expected positive integer for repeat count, found {}",
+                    found);
+            }
+            Err(err) => {
+                let err_msg = match count_expr.node {
+                    hir::ExprPath(None, hir::Path {
+                        global: false,
+                        ref segments,
+                        ..
+                    }) if segments.len() == 1 =>
+                        format!("found variable"),
+                    _ => match err.kind {
+                        ErrKind::MiscCatchAll => format!("but found {}", err.description()),
+                        _ => format!("but {}", err.description())
+                    }
+                };
+                span_err!(self.sess, count_expr.span, E0307,
+                    "expected constant integer for repeat count, {}", err_msg);
+            }
+        }
+        0
+    }
+
+    /// Given a set of predicates that apply to an object type, returns
+    /// the region bounds that the (erased) `Self` type must
+    /// outlive. Precisely *because* the `Self` type is erased, the
+    /// parameter `erased_self_ty` must be supplied to indicate what type
+    /// has been used to represent `Self` in the predicates
+    /// themselves. This should really be a unique type; `FreshTy(0)` is a
+    /// popular choice.
+    ///
+    /// NB: in some cases, particularly around higher-ranked bounds,
+    /// this function returns a kind of conservative approximation.
+    /// That is, all regions returned by this function are definitely
+    /// required, but there may be other region bounds that are not
+    /// returned, as well as requirements like `for<'a> T: 'a`.
+    ///
+    /// Requires that trait definitions have been processed so that we can
+    /// elaborate predicates and walk supertraits.
+    pub fn required_region_bounds(&self,
+                                  erased_self_ty: Ty<'tcx>,
+                                  predicates: Vec<ty::Predicate<'tcx>>)
+                                  -> Vec<ty::Region>    {
+        debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})",
+               erased_self_ty,
+               predicates);
+
+        assert!(!erased_self_ty.has_escaping_regions());
+
+        traits::elaborate_predicates(self, predicates)
+            .filter_map(|predicate| {
+                match predicate {
+                    ty::Predicate::Projection(..) |
+                    ty::Predicate::Trait(..) |
+                    ty::Predicate::Equate(..) |
+                    ty::Predicate::WellFormed(..) |
+                    ty::Predicate::ObjectSafe(..) |
+                    ty::Predicate::RegionOutlives(..) => {
+                        None
+                    }
+                    ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => {
+                        // Search for a bound of the form `erased_self_ty
+                        // : 'a`, but be wary of something like `for<'a>
+                        // erased_self_ty : 'a` (we interpret a
+                        // higher-ranked bound like that as 'static,
+                        // though at present the code in `fulfill.rs`
+                        // considers such bounds to be unsatisfiable, so
+                        // it's kind of a moot point since you could never
+                        // construct such an object, but this seems
+                        // correct even if that code changes).
+                        if t == erased_self_ty && !r.has_escaping_regions() {
+                            Some(r)
+                        } else {
+                            None
+                        }
+                    }
+                }
+            })
+            .collect()
+    }
+
+    /// Creates a hash of the type `Ty` which will be the same no matter what crate
+    /// context it's calculated within. This is used by the `type_id` intrinsic.
+    pub fn hash_crate_independent(&self, ty: Ty<'tcx>, svh: &Svh) -> u64 {
+        let mut state = SipHasher::new();
+        helper(self, ty, svh, &mut state);
+        return state.finish();
+
+        fn helper<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh,
+                        state: &mut SipHasher) {
+            macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } }
+            macro_rules! hash { ($e:expr) => { $e.hash(state) }  }
+
+            let region = |state: &mut SipHasher, r: ty::Region| {
+                match r {
+                    ty::ReStatic => {}
+                    ty::ReLateBound(db, ty::BrAnon(i)) => {
+                        db.hash(state);
+                        i.hash(state);
+                    }
+                    ty::ReEmpty |
+                    ty::ReEarlyBound(..) |
+                    ty::ReLateBound(..) |
+                    ty::ReFree(..) |
+                    ty::ReScope(..) |
+                    ty::ReVar(..) |
+                    ty::ReSkolemized(..) => {
+                        tcx.sess.bug("unexpected region found when hashing a type")
+                    }
+                }
+            };
+            let did = |state: &mut SipHasher, did: DefId| {
+                let h = if did.is_local() {
+                    svh.clone()
+                } else {
+                    tcx.sess.cstore.get_crate_hash(did.krate)
+                };
+                h.as_str().hash(state);
+                did.node.hash(state);
+            };
+            let mt = |state: &mut SipHasher, mt: TypeAndMut| {
+                mt.mutbl.hash(state);
+            };
+            let fn_sig = |state: &mut SipHasher, sig: &ty::Binder<ty::FnSig<'tcx>>| {
+                let sig = tcx.anonymize_late_bound_regions(sig).0;
+                for a in &sig.inputs { helper(tcx, *a, svh, state); }
+                if let ty::FnConverging(output) = sig.output {
+                    helper(tcx, output, svh, state);
+                }
+            };
+            ty.maybe_walk(|ty| {
+                match ty.sty {
+                    TyBool => byte!(2),
+                    TyChar => byte!(3),
+                    TyInt(i) => {
+                        byte!(4);
+                        hash!(i);
+                    }
+                    TyUint(u) => {
+                        byte!(5);
+                        hash!(u);
+                    }
+                    TyFloat(f) => {
+                        byte!(6);
+                        hash!(f);
+                    }
+                    TyStr => {
+                        byte!(7);
+                    }
+                    TyEnum(d, _) => {
+                        byte!(8);
+                        did(state, d.did);
+                    }
+                    TyBox(_) => {
+                        byte!(9);
+                    }
+                    TyArray(_, n) => {
+                        byte!(10);
+                        n.hash(state);
+                    }
+                    TySlice(_) => {
+                        byte!(11);
+                    }
+                    TyRawPtr(m) => {
+                        byte!(12);
+                        mt(state, m);
+                    }
+                    TyRef(r, m) => {
+                        byte!(13);
+                        region(state, *r);
+                        mt(state, m);
+                    }
+                    TyBareFn(opt_def_id, ref b) => {
+                        byte!(14);
+                        hash!(opt_def_id);
+                        hash!(b.unsafety);
+                        hash!(b.abi);
+                        fn_sig(state, &b.sig);
+                        return false;
+                    }
+                    TyTrait(ref data) => {
+                        byte!(17);
+                        did(state, data.principal_def_id());
+                        hash!(data.bounds);
+
+                        let principal = tcx.anonymize_late_bound_regions(&data.principal).0;
+                        for subty in &principal.substs.types {
+                            helper(tcx, subty, svh, state);
+                        }
+
+                        return false;
+                    }
+                    TyStruct(d, _) => {
+                        byte!(18);
+                        did(state, d.did);
+                    }
+                    TyTuple(ref inner) => {
+                        byte!(19);
+                        hash!(inner.len());
+                    }
+                    TyParam(p) => {
+                        byte!(20);
+                        hash!(p.space);
+                        hash!(p.idx);
+                        hash!(p.name.as_str());
+                    }
+                    TyInfer(_) => unreachable!(),
+                    TyError => byte!(21),
+                    TyClosure(d, _) => {
+                        byte!(22);
+                        did(state, d);
+                    }
+                    TyProjection(ref data) => {
+                        byte!(23);
+                        did(state, data.trait_ref.def_id);
+                        hash!(data.item_name.as_str());
+                    }
+                }
+                true
+            });
+        }
+    }
+
+    /// Returns true if this ADT is a dtorck type, i.e. whether it being
+    /// safe for destruction requires it to be alive
+    pub fn is_adt_dtorck(&self, adt: ty::AdtDef<'tcx>) -> bool {
+        let dtor_method = match adt.destructor() {
+            Some(dtor) => dtor,
+            None => return false
+        };
+        let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| {
+            self.sess.bug(&format!("no Drop impl for the dtor of `{:?}`", adt))
+        });
+        let generics = adt.type_scheme(self).generics;
+
+        // In `impl<'a> Drop ...`, we automatically assume
+        // `'a` is meaningful and thus represents a bound
+        // through which we could reach borrowed data.
+        //
+        // FIXME (pnkfelix): In the future it would be good to
+        // extend the language to allow the user to express,
+        // in the impl signature, that a lifetime is not
+        // actually used (something like `where 'a: ?Live`).
+        if generics.has_region_params(subst::TypeSpace) {
+            debug!("typ: {:?} has interesting dtor due to region params",
+                   adt);
+            return true;
+        }
+
+        let mut seen_items = Vec::new();
+        let mut items_to_inspect = vec![impl_did];
+        while let Some(item_def_id) = items_to_inspect.pop() {
+            if seen_items.contains(&item_def_id) {
+                continue;
+            }
+
+            for pred in self.lookup_predicates(item_def_id).predicates {
+                let result = match pred {
+                    ty::Predicate::Equate(..) |
+                    ty::Predicate::RegionOutlives(..) |
+                    ty::Predicate::TypeOutlives(..) |
+                    ty::Predicate::WellFormed(..) |
+                    ty::Predicate::ObjectSafe(..) |
+                    ty::Predicate::Projection(..) => {
+                        // For now, assume all these where-clauses
+                        // may give drop implementation capabilty
+                        // to access borrowed data.
+                        true
+                    }
+
+                    ty::Predicate::Trait(ty::Binder(ref t_pred)) => {
+                        let def_id = t_pred.trait_ref.def_id;
+                        if self.trait_items(def_id).len() != 0 {
+                            // If trait has items, assume it adds
+                            // capability to access borrowed data.
+                            true
+                        } else {
+                            // Trait without items is itself
+                            // uninteresting from POV of dropck.
+                            //
+                            // However, may have parent w/ items;
+                            // so schedule checking of predicates,
+                            items_to_inspect.push(def_id);
+                            // and say "no capability found" for now.
+                            false
+                        }
+                    }
+                };
+
+                if result {
+                    debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}",
+                           adt, pred);
+                    return true;
+                }
+            }
+
+            seen_items.push(item_def_id);
+        }
+
+        debug!("typ: {:?} is dtorck-safe", adt);
+        false
+    }
+}
+
+impl<'tcx> ty::TyS<'tcx> {
+    fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
+                       bound: ty::BuiltinBound,
+                       span: Span)
+                       -> bool
+    {
+        let tcx = param_env.tcx;
+        let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()), false);
+
+        let is_impld = traits::type_known_to_meet_builtin_bound(&infcx,
+                                                                self, bound, span);
+
+        debug!("Ty::impls_bound({:?}, {:?}) = {:?}",
+               self, bound, is_impld);
+
+        is_impld
+    }
+
+    // FIXME (@jroesch): I made this public to use it, not sure if should be private
+    pub fn moves_by_default<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
+                           span: Span) -> bool {
+        if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) {
+            return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT);
+        }
+
+        assert!(!self.needs_infer());
+
+        // Fast-path for primitive types
+        let result = match self.sty {
+            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+            TyRawPtr(..) | TyBareFn(..) | TyRef(_, TypeAndMut {
+                mutbl: hir::MutImmutable, ..
+            }) => Some(false),
+
+            TyStr | TyBox(..) | TyRef(_, TypeAndMut {
+                mutbl: hir::MutMutable, ..
+            }) => Some(true),
+
+            TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) |
+            TyClosure(..) | TyEnum(..) | TyStruct(..) |
+            TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
+        }.unwrap_or_else(|| !self.impls_bound(param_env, ty::BoundCopy, span));
+
+        if !self.has_param_types() && !self.has_self_ty() {
+            self.flags.set(self.flags.get() | if result {
+                TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT
+            } else {
+                TypeFlags::MOVENESS_CACHED
+            });
+        }
+
+        result
+    }
+
+    #[inline]
+    pub fn is_sized<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
+                        span: Span) -> bool
+    {
+        if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) {
+            return self.flags.get().intersects(TypeFlags::IS_SIZED);
+        }
+
+        self.is_sized_uncached(param_env, span)
+    }
+
+    fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
+                             span: Span) -> bool {
+        assert!(!self.needs_infer());
+
+        // Fast-path for primitive types
+        let result = match self.sty {
+            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+            TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) |
+            TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true),
+
+            TyStr | TyTrait(..) | TySlice(_) => Some(false),
+
+            TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) |
+            TyInfer(..) | TyError => None
+        }.unwrap_or_else(|| self.impls_bound(param_env, ty::BoundSized, span));
+
+        if !self.has_param_types() && !self.has_self_ty() {
+            self.flags.set(self.flags.get() | if result {
+                TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED
+            } else {
+                TypeFlags::SIZEDNESS_CACHED
+            });
+        }
+
+        result
+    }
+
+
+    /// Check whether a type is representable. This means it cannot contain unboxed
+    /// structural recursion. This check is needed for structs and enums.
+    pub fn is_representable(&'tcx self, cx: &ty::ctxt<'tcx>, sp: Span) -> Representability {
+
+        // Iterate until something non-representable is found
+        fn find_nonrepresentable<'tcx, It: Iterator<Item=Ty<'tcx>>>(cx: &ty::ctxt<'tcx>,
+                                                                    sp: Span,
+                                                                    seen: &mut Vec<Ty<'tcx>>,
+                                                                    iter: It)
+                                                                    -> Representability {
+            iter.fold(Representability::Representable,
+                      |r, ty| cmp::max(r, is_type_structurally_recursive(cx, sp, seen, ty)))
+        }
+
+        fn are_inner_types_recursive<'tcx>(cx: &ty::ctxt<'tcx>, sp: Span,
+                                           seen: &mut Vec<Ty<'tcx>>, ty: Ty<'tcx>)
+                                           -> Representability {
+            match ty.sty {
+                TyTuple(ref ts) => {
+                    find_nonrepresentable(cx, sp, seen, ts.iter().cloned())
+                }
+                // Fixed-length vectors.
+                // FIXME(#11924) Behavior undecided for zero-length vectors.
+                TyArray(ty, _) => {
+                    is_type_structurally_recursive(cx, sp, seen, ty)
+                }
+                TyStruct(def, substs) | TyEnum(def, substs) => {
+                    find_nonrepresentable(cx,
+                                          sp,
+                                          seen,
+                                          def.all_fields().map(|f| f.ty(cx, substs)))
+                }
+                TyClosure(..) => {
+                    // this check is run on type definitions, so we don't expect
+                    // to see closure types
+                    cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty))
+                }
+                _ => Representability::Representable,
+            }
+        }
+
+        fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
+            match ty.sty {
+                TyStruct(ty_def, _) | TyEnum(ty_def, _) => {
+                     ty_def == def
+                }
+                _ => false
+            }
+        }
+
+        fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+            match (&a.sty, &b.sty) {
+                (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) |
+                (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => {
+                    if did_a != did_b {
+                        return false;
+                    }
+
+                    let types_a = substs_a.types.get_slice(subst::TypeSpace);
+                    let types_b = substs_b.types.get_slice(subst::TypeSpace);
+
+                    let mut pairs = types_a.iter().zip(types_b);
+
+                    pairs.all(|(&a, &b)| same_type(a, b))
+                }
+                _ => {
+                    a == b
+                }
+            }
+        }
+
+        // Does the type `ty` directly (without indirection through a pointer)
+        // contain any types on stack `seen`?
+        fn is_type_structurally_recursive<'tcx>(cx: &ty::ctxt<'tcx>,
+                                                sp: Span,
+                                                seen: &mut Vec<Ty<'tcx>>,
+                                                ty: Ty<'tcx>) -> Representability {
+            debug!("is_type_structurally_recursive: {:?}", ty);
+
+            match ty.sty {
+                TyStruct(def, _) | TyEnum(def, _) => {
+                    {
+                        // Iterate through stack of previously seen types.
+                        let mut iter = seen.iter();
+
+                        // The first item in `seen` is the type we are actually curious about.
+                        // We want to return SelfRecursive if this type contains itself.
+                        // It is important that we DON'T take generic parameters into account
+                        // for this check, so that Bar<T> in this example counts as SelfRecursive:
+                        //
+                        // struct Foo;
+                        // struct Bar<T> { x: Bar<Foo> }
+
+                        match iter.next() {
+                            Some(&seen_type) => {
+                                if same_struct_or_enum(seen_type, def) {
+                                    debug!("SelfRecursive: {:?} contains {:?}",
+                                           seen_type,
+                                           ty);
+                                    return Representability::SelfRecursive;
+                                }
+                            }
+                            None => {}
+                        }
+
+                        // We also need to know whether the first item contains other types
+                        // that are structurally recursive. If we don't catch this case, we
+                        // will recurse infinitely for some inputs.
+                        //
+                        // It is important that we DO take generic parameters into account
+                        // here, so that code like this is considered SelfRecursive, not
+                        // ContainsRecursive:
+                        //
+                        // struct Foo { Option<Option<Foo>> }
+
+                        for &seen_type in iter {
+                            if same_type(ty, seen_type) {
+                                debug!("ContainsRecursive: {:?} contains {:?}",
+                                       seen_type,
+                                       ty);
+                                return Representability::ContainsRecursive;
+                            }
+                        }
+                    }
+
+                    // For structs and enums, track all previously seen types by pushing them
+                    // onto the 'seen' stack.
+                    seen.push(ty);
+                    let out = are_inner_types_recursive(cx, sp, seen, ty);
+                    seen.pop();
+                    out
+                }
+                _ => {
+                    // No need to push in other cases.
+                    are_inner_types_recursive(cx, sp, seen, ty)
+                }
+            }
+        }
+
+        debug!("is_type_representable: {:?}", self);
+
+        // To avoid a stack overflow when checking an enum variant or struct that
+        // contains a different, structurally recursive type, maintain a stack
+        // of seen types and check recursion for each of them (issues #3008, #3779).
+        let mut seen: Vec<Ty> = Vec::new();
+        let r = is_type_structurally_recursive(cx, sp, &mut seen, self);
+        debug!("is_type_representable: {:?} is {:?}", self, r);
+        r
+    }
+}
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 99e41bd22b8bb..fee60d46dc001 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -388,23 +388,23 @@ impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::AutoAdjustment<'tcx> {
+impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            ty::AdjustReifyFnPointer => {
+            ty::adjustment::AdjustReifyFnPointer => {
                 write!(f, "AdjustReifyFnPointer")
             }
-            ty::AdjustUnsafeFnPointer => {
+            ty::adjustment::AdjustUnsafeFnPointer => {
                 write!(f, "AdjustUnsafeFnPointer")
             }
-            ty::AdjustDerefRef(ref data) => {
+            ty::adjustment::AdjustDerefRef(ref data) => {
                 write!(f, "{:?}", data)
             }
         }
     }
 }
 
-impl<'tcx> fmt::Debug for ty::AutoDerefRef<'tcx> {
+impl<'tcx> fmt::Debug for ty::adjustment::AutoDerefRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
                self.autoderefs, self.unsize, self.autoref)
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index c8ffe07660611..4084f13e818f2 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -33,6 +33,7 @@ use middle::{cfg, def, infer, pat_util, stability, traits};
 use middle::def_id::DefId;
 use middle::subst::Substs;
 use middle::ty::{self, Ty};
+use middle::ty::adjustment;
 use middle::const_eval::{eval_const_expr_partial, ConstVal};
 use middle::const_eval::EvalHint::ExprTypeChecked;
 use rustc::front::map as hir_map;
@@ -1722,13 +1723,15 @@ impl LintPass for UnusedAllocation {
         }
 
         if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
-            if let ty::AdjustDerefRef(ty::AutoDerefRef { ref autoref, .. }) = *adjustment {
+            if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
+                ref autoref, ..
+            }) = *adjustment {
                 match autoref {
-                    &Some(ty::AutoPtr(_, hir::MutImmutable)) => {
+                    &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
                         cx.span_lint(UNUSED_ALLOCATION, e.span,
                                      "unnecessary allocation, use & instead");
                     }
-                    &Some(ty::AutoPtr(_, hir::MutMutable)) => {
+                    &Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
                         cx.span_lint(UNUSED_ALLOCATION, e.span,
                                      "unnecessary allocation, use &mut instead");
                     }
@@ -2297,7 +2300,7 @@ impl LintPass for UnconditionalRecursion {
             }
 
             // Check for overloaded autoderef method calls.
-            if let Some(&ty::AdjustDerefRef(ref adj)) = tables.adjustments.get(&id) {
+            if let Some(&adjustment::AdjustDerefRef(ref adj)) = tables.adjustments.get(&id) {
                 for i in 0..adj.autoderefs {
                     let method_call = ty::MethodCall::autoderef(id, i as u32);
                     if let Some(m) = tables.method_map.get(&method_call) {
diff --git a/src/librustc_mir/tcx/expr.rs b/src/librustc_mir/tcx/expr.rs
index 6352af39f1489..f15470e7851d4 100644
--- a/src/librustc_mir/tcx/expr.rs
+++ b/src/librustc_mir/tcx/expr.rs
@@ -320,7 +320,7 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
         // Now apply adjustments, if any.
         match cx.tcx.tables.borrow().adjustments.get(&self.id) {
             None => { }
-            Some(&ty::AdjustReifyFnPointer) => {
+            Some(&ty::adjustment::AdjustReifyFnPointer) => {
                 let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
                 expr = Expr {
                     temp_lifetime: temp_lifetime,
@@ -329,7 +329,7 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
                     kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
                 };
             }
-            Some(&ty::AdjustUnsafeFnPointer) => {
+            Some(&ty::adjustment::AdjustUnsafeFnPointer) => {
                 let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
                 expr = Expr {
                     temp_lifetime: temp_lifetime,
@@ -338,7 +338,7 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
                     kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
                 };
             }
-            Some(&ty::AdjustDerefRef(ref adj)) => {
+            Some(&ty::adjustment::AdjustDerefRef(ref adj)) => {
                 for i in 0..adj.autoderefs {
                     let i = i as u32;
                     let adjusted_ty =
@@ -372,7 +372,7 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
                 } else if let Some(autoref) = adj.autoref {
                     let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
                     match autoref {
-                        ty::AutoPtr(r, m) => {
+                        ty::adjustment::AutoPtr(r, m) => {
                             expr = Expr {
                                 temp_lifetime: temp_lifetime,
                                 ty: adjusted_ty,
@@ -382,7 +382,7 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
                                                          arg: expr.to_ref() }
                             };
                         }
-                        ty::AutoUnsafe(m) => {
+                        ty::adjustment::AutoUnsafe(m) => {
                             // Convert this to a suitable `&foo` and
                             // then an unsafe coercion. Limit the region to be just this
                             // expression.
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index c98760ce02a26..a2d74635b5e1c 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -34,6 +34,8 @@ use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of;
 use middle::subst::Substs;
+use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
+use middle::ty::adjustment::AdjustUnsafeFnPointer;
 use middle::ty::{self, Ty};
 use middle::ty::cast::{CastTy,IntTy};
 use util::nodemap::NodeMap;
@@ -289,14 +291,14 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                             &cx.tcx().expr_ty_adjusted(e));
     let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned();
     match opt_adj {
-        Some(ty::AdjustReifyFnPointer) => {
+        Some(AdjustReifyFnPointer) => {
             // FIXME(#19925) once fn item types are
             // zero-sized, we'll need to do something here
         }
-        Some(ty::AdjustUnsafeFnPointer) => {
+        Some(AdjustUnsafeFnPointer) => {
             // purely a type-level thing
         }
-        Some(ty::AdjustDerefRef(adj)) => {
+        Some(AdjustDerefRef(adj)) => {
             let mut ty = ety;
             // Save the last autoderef in case we can avoid it.
             if adj.autoderefs > 0 {
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 59040b9cafef5..7d8996867c016 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -71,7 +71,8 @@ use trans::machine;
 use trans::meth;
 use trans::tvec;
 use trans::type_of;
-use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
+use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
+use middle::ty::adjustment::{AdjustUnsafeFnPointer, CustomCoerceUnsized};
 use middle::ty::{self, Ty};
 use middle::ty::MethodCall;
 use middle::ty::cast::{CastKind, CastTy};
@@ -514,7 +515,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             };
 
             let coerce_index = match kind {
-                ty::CustomCoerceUnsized::Struct(i) => i
+                CustomCoerceUnsized::Struct(i) => i
             };
             assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len());
 
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index cde188fa41e48..69efaa792fe05 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -65,7 +65,9 @@ use check::{autoderef, FnCtxt, UnresolvedTypeAction};
 use middle::infer::{self, Coercion};
 use middle::traits::{self, ObligationCause};
 use middle::traits::{predicate_for_trait_def, report_selection_error};
-use middle::ty::{AutoDerefRef, AdjustDerefRef};
+use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
+use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
+use middle::ty::adjustment::{AdjustUnsafeFnPointer};
 use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
 use middle::ty::error::TypeError;
 use middle::ty::relate::RelateResult;
@@ -81,7 +83,7 @@ struct Coerce<'a, 'tcx: 'a> {
     unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
 }
 
-type CoerceResult<'tcx> = RelateResult<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
+type CoerceResult<'tcx> = RelateResult<'tcx, Option<AutoAdjustment<'tcx>>>;
 
 impl<'f, 'tcx> Coerce<'f, 'tcx> {
     fn tcx(&self) -> &ty::ctxt<'tcx> {
@@ -186,7 +188,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let coercion = Coercion(self.origin.span());
         let r_borrow = self.fcx.infcx().next_region_var(coercion);
         let r_borrow = self.tcx().mk_region(r_borrow);
-        let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b));
+        let autoref = Some(AutoPtr(r_borrow, mutbl_b));
 
         let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b);
         let mut first_error = None;
@@ -264,11 +266,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 let coercion = Coercion(self.origin.span());
                 let r_borrow = self.fcx.infcx().next_region_var(coercion);
                 let region = self.tcx().mk_region(r_borrow);
-                (mt_a.ty, Some(ty::AutoPtr(region, mt_b.mutbl)))
+                (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl)))
             }
             (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
                 try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
-                (mt_a.ty, Some(ty::AutoUnsafe(mt_b.mutbl)))
+                (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
             }
             _ => (source, None)
         };
@@ -360,7 +362,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
                         let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
                         try!(self.subtype(unsafe_a, b));
-                        return Ok(Some(ty::AdjustUnsafeFnPointer));
+                        return Ok(Some(AdjustUnsafeFnPointer));
                     }
                     _ => {}
                 }
@@ -387,7 +389,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 ty::TyBareFn(None, _) => {
                     let a_fn_pointer = self.tcx().mk_fn(None, fn_ty_a);
                     try!(self.subtype(a_fn_pointer, b));
-                    Ok(Some(ty::AdjustReifyFnPointer))
+                    Ok(Some(AdjustReifyFnPointer))
                 }
                 _ => self.subtype(a, b)
             }
@@ -422,7 +424,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         if is_ref {
             Ok(Some(AdjustDerefRef(AutoDerefRef {
                 autoderefs: 1,
-                autoref: Some(ty::AutoUnsafe(mutbl_b)),
+                autoref: Some(AutoUnsafe(mutbl_b)),
                 unsize: None
             })))
         } else {
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 048a2b62bcaa3..572ba7a848713 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -16,6 +16,7 @@ use middle::def_id::DefId;
 use middle::subst::{self};
 use middle::traits;
 use middle::ty::{self, NoPreference, PreferMutLvalue, Ty};
+use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
 use middle::ty::fold::TypeFoldable;
 use middle::infer;
 use middle::infer::InferCtxt;
@@ -136,7 +137,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
     {
         let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
             let region = self.infcx().next_region_var(infer::Autoref(self.span));
-            let autoref = ty::AutoPtr(self.tcx().mk_region(region), mutbl);
+            let autoref = AutoPtr(self.tcx().mk_region(region), mutbl);
             (Some(autoref), pick.unsize.map(|target| {
                 target.adjust_for_autoref(self.tcx(), Some(autoref))
             }))
@@ -169,7 +170,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
 
         // Write out the final adjustment.
         self.fcx.write_adjustment(self.self_expr.id,
-                                  ty::AdjustDerefRef(ty::AutoDerefRef {
+                                  AdjustDerefRef(AutoDerefRef {
             autoderefs: pick.autoderefs,
             autoref: autoref,
             unsize: unsize
@@ -488,7 +489,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                                             .borrow()
                                             .adjustments
                                             .get(&expr.id) {
-                Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs,
+                Some(&AdjustDerefRef(ref adj)) => adj.autoderefs,
                 Some(_) | None => 0,
             };
 
@@ -527,12 +528,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                         let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id)
                                                                           .cloned();
                         let (autoderefs, unsize) = match adj {
-                            Some(ty::AdjustDerefRef(adr)) => match adr.autoref {
+                            Some(AdjustDerefRef(adr)) => match adr.autoref {
                                 None => {
                                     assert!(adr.unsize.is_none());
                                     (adr.autoderefs, None)
                                 }
-                                Some(ty::AutoPtr(_, _)) => {
+                                Some(AutoPtr(_, _)) => {
                                     (adr.autoderefs, adr.unsize.map(|target| {
                                         target.builtin_deref(false, NoPreference)
                                               .expect("fixup: AutoPtr is not &T").ty
@@ -557,7 +558,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                             (target, true)
                         } else {
                             (self.fcx.adjust_expr_ty(base_expr,
-                                Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
+                                Some(&AdjustDerefRef(AutoDerefRef {
                                     autoderefs: autoderefs,
                                     autoref: None,
                                     unsize: None
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index e319e37fa3098..1cfb495b36ed7 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -18,6 +18,7 @@ use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod};
 use middle::subst;
 use middle::traits;
 use middle::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef};
+use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
 use middle::infer;
 
 use syntax::ast;
@@ -282,9 +283,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     match transformed_self_ty.sty {
                         ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
                             fcx.write_adjustment(self_expr.id,
-                                ty::AdjustDerefRef(ty::AutoDerefRef {
+                                AdjustDerefRef(AutoDerefRef {
                                     autoderefs: autoderefs,
-                                    autoref: Some(ty::AutoPtr(region, mutbl)),
+                                    autoref: Some(AutoPtr(region, mutbl)),
                                     unsize: if unsize {
                                         Some(transformed_self_ty)
                                     } else {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3160ed3502578..656a740e9840e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -97,8 +97,10 @@ use middle::ty::{Disr, ParamTy, ParameterEnvironment};
 use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
 use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
 use middle::ty::{MethodCall, MethodCallee};
+use middle::ty::adjustment;
 use middle::ty::error::TypeError;
 use middle::ty::fold::{TypeFolder, TypeFoldable};
+use middle::ty::util::Representability;
 use require_c_abi_if_variadic;
 use rscope::{ElisionFailureInfo, RegionScope};
 use session::Session;
@@ -1337,7 +1339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                       derefs: usize) {
         self.write_adjustment(
             node_id,
-            ty::AdjustDerefRef(ty::AutoDerefRef {
+            adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
                 autoderefs: derefs,
                 autoref: None,
                 unsize: None
@@ -1347,7 +1349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub fn write_adjustment(&self,
                             node_id: ast::NodeId,
-                            adj: ty::AutoAdjustment<'tcx>) {
+                            adj: adjustment::AutoAdjustment<'tcx>) {
         debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj);
 
         if adj.is_identity() {
@@ -1576,7 +1578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Apply `adjustment` to the type of `expr`
     pub fn adjust_expr_ty(&self,
                           expr: &hir::Expr,
-                          adjustment: Option<&ty::AutoAdjustment<'tcx>>)
+                          adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
                           -> Ty<'tcx>
     {
         let raw_ty = self.expr_ty(expr);
@@ -4170,12 +4172,13 @@ pub fn check_representable(tcx: &ty::ctxt,
     // contain themselves. For case 2, there must be an inner type that will be
     // caught by case 1.
     match rty.is_representable(tcx, sp) {
-      ty::SelfRecursive => {
-        span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation);
-        tcx.sess.fileline_help(sp, "wrap the inner value in a box to make it representable");
-        return false
-      }
-      ty::Representable | ty::ContainsRecursive => (),
+        Representability::SelfRecursive => {
+            span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation);
+            tcx.sess.fileline_help(
+                sp, "wrap the inner value in a box to make it representable");
+            return false
+        }
+        Representability::Representable | Representability::ContainsRecursive => (),
     }
     return true
 }
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index b6ff7b529c556..155caaa8cb0fe 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -94,6 +94,7 @@ use middle::traits;
 use middle::ty::{self, RegionEscape, ReScope, Ty, MethodCall, HasTypeFlags};
 use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, VerifyBound};
 use middle::pat_util;
+use middle::ty::adjustment;
 use middle::ty::wf::ImpliedBound;
 
 use std::mem;
@@ -598,7 +599,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
     if let Some(adjustment) = adjustment {
         debug!("adjustment={:?}", adjustment);
         match adjustment {
-            ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => {
+            adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
+                autoderefs, ref autoref, ..
+            }) => {
                 let expr_ty = rcx.resolve_node_type(expr.id);
                 constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
                 if let Some(ref autoref) = *autoref {
@@ -614,7 +617,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
                 }
             }
             /*
-            ty::AutoObject(_, ref bounds, _, _) => {
+            adjustment::AutoObject(_, ref bounds, _, _) => {
                 // Determine if we are casting `expr` to a trait
                 // instance. If so, we have to be sure that the type
                 // of the source obeys the new region bound.
@@ -1221,7 +1224,7 @@ fn link_pattern<'t, 'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
 fn link_autoref(rcx: &Rcx,
                 expr: &hir::Expr,
                 autoderefs: usize,
-                autoref: &ty::AutoRef)
+                autoref: &adjustment::AutoRef)
 {
     debug!("link_autoref(autoref={:?})", autoref);
     let mc = mc::MemCategorizationContext::new(rcx.fcx.infcx());
@@ -1229,12 +1232,12 @@ fn link_autoref(rcx: &Rcx,
     debug!("expr_cmt={:?}", expr_cmt);
 
     match *autoref {
-        ty::AutoPtr(r, m) => {
+        adjustment::AutoPtr(r, m) => {
             link_region(rcx, expr.span, r,
                 ty::BorrowKind::from_mutbl(m), expr_cmt);
         }
 
-        ty::AutoUnsafe(m) => {
+        adjustment::AutoUnsafe(m) => {
             let r = ty::ReScope(rcx.tcx().region_maps.node_extent(expr.id));
             link_region(rcx, expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt);
         }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index de841a0cc0022..6f8e064c9d819 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -18,6 +18,7 @@ use check::FnCtxt;
 use middle::def_id::DefId;
 use middle::pat_util;
 use middle::ty::{self, Ty, MethodCall, MethodCallee};
+use middle::ty::adjustment;
 use middle::ty::fold::{TypeFolder,TypeFoldable};
 use middle::infer;
 use write_substs_to_tcx;
@@ -268,19 +269,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
             Some(adjustment) => {
                 let resolved_adjustment = match adjustment {
-                    ty::AdjustReifyFnPointer => ty::AdjustReifyFnPointer,
+                    adjustment::AdjustReifyFnPointer => {
+                        adjustment::AdjustReifyFnPointer
+                    }
 
-                    ty::AdjustUnsafeFnPointer => {
-                        ty::AdjustUnsafeFnPointer
+                    adjustment::AdjustUnsafeFnPointer => {
+                        adjustment::AdjustUnsafeFnPointer
                     }
 
-                    ty::AdjustDerefRef(adj) => {
+                    adjustment::AdjustDerefRef(adj) => {
                         for autoderef in 0..adj.autoderefs {
                             let method_call = MethodCall::autoderef(id, autoderef as u32);
                             self.visit_method_map_entry(reason, method_call);
                         }
 
-                        ty::AdjustDerefRef(ty::AutoDerefRef {
+                        adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
                             autoderefs: adj.autoderefs,
                             autoref: self.resolve(&adj.autoref, reason),
                             unsize: self.resolve(&adj.unsize, reason),
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 8048c302f2c78..9ba6f1398e471 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -20,6 +20,7 @@ use middle::def_id::{DefId, LOCAL_CRATE};
 use middle::lang_items::UnsizeTraitLangItem;
 use middle::subst::{self, Subst};
 use middle::traits;
+use middle::ty;
 use middle::ty::RegionEscape;
 use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId};
 use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
@@ -29,7 +30,7 @@ use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple};
 use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
 use middle::ty::{TyUint, TyClosure, TyBox, TyBareFn};
 use middle::ty::TyProjection;
-use middle::ty;
+use middle::ty::util::CopyImplementationError;
 use middle::free_region::FreeRegionMap;
 use CrateCtxt;
 use middle::infer::{self, InferCtxt, new_infer_ctxt};
@@ -370,27 +371,27 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
 
             match param_env.can_type_implement_copy(self_type, span) {
                 Ok(()) => {}
-                Err(ty::FieldDoesNotImplementCopy(name)) => {
+                Err(CopyImplementationError::InfrigingField(name)) => {
                        span_err!(tcx.sess, span, E0204,
                                  "the trait `Copy` may not be \
                                           implemented for this type; field \
                                           `{}` does not implement `Copy`",
                                          name)
                 }
-                Err(ty::VariantDoesNotImplementCopy(name)) => {
+                Err(CopyImplementationError::InfrigingVariant(name)) => {
                        span_err!(tcx.sess, span, E0205,
                                  "the trait `Copy` may not be \
                                           implemented for this type; variant \
                                           `{}` does not implement `Copy`",
                                          name)
                 }
-                Err(ty::TypeIsStructural) => {
+                Err(CopyImplementationError::NotAnAdt) => {
                        span_err!(tcx.sess, span, E0206,
                                  "the trait `Copy` may not be implemented \
                                   for this type; type is not a structure or \
                                   enumeration")
                 }
-                Err(ty::TypeHasDestructor) => {
+                Err(CopyImplementationError::HasDestructor) => {
                     span_err!(tcx.sess, span, E0184,
                               "the trait `Copy` may not be implemented for this type; \
                                the type has a destructor");
@@ -510,7 +511,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
                     }
 
                     let (i, a, b) = diff_fields[0];
-                    let kind = ty::CustomCoerceUnsized::Struct(i);
+                    let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
                     (a, b, coerce_unsized_trait, Some(kind))
                 }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 0f71c4d8ceb56..f7520ed54b77e 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -76,9 +76,10 @@ use middle::const_eval::{self, ConstVal};
 use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
 use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
-use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme, IntTypeExt};
+use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme};
 use middle::ty::{VariantKind};
 use middle::ty::fold::{TypeFolder, TypeFoldable};
+use middle::ty::util::IntTypeExt;
 use middle::infer;
 use rscope::*;
 use rustc::front::map as hir_map;