about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/implicator.rs4
-rw-r--r--src/librustc/middle/infer/combine.rs2
-rw-r--r--src/librustc/middle/infer/error_reporting.rs6
-rw-r--r--src/librustc/middle/infer/freshen.rs5
-rw-r--r--src/librustc/middle/infer/higher_ranked/mod.rs5
-rw-r--r--src/librustc/middle/infer/mod.rs12
-rw-r--r--src/librustc/middle/infer/resolve.rs9
-rw-r--r--src/librustc/middle/intrinsicck.rs2
-rw-r--r--src/librustc/middle/subst.rs4
-rw-r--r--src/librustc/middle/traits/error_reporting.rs5
-rw-r--r--src/librustc/middle/traits/fulfill.rs2
-rw-r--r--src/librustc/middle/traits/mod.rs5
-rw-r--r--src/librustc/middle/traits/object_safety.rs2
-rw-r--r--src/librustc/middle/traits/project.rs10
-rw-r--r--src/librustc/middle/traits/select.rs5
-rw-r--r--src/librustc/middle/traits/structural_impls.rs124
-rw-r--r--src/librustc/middle/ty/adjustment.rs3
-rw-r--r--src/librustc/middle/ty/flags.rs2
-rw-r--r--src/librustc/middle/ty/fold.rs376
-rw-r--r--src/librustc/middle/ty/mod.rs71
-rw-r--r--src/librustc/middle/ty/outlives.rs2
-rw-r--r--src/librustc/middle/ty/relate.rs5
-rw-r--r--src/librustc/middle/ty/structural_impls.rs813
-rw-r--r--src/librustc/middle/ty/sty.rs3
-rw-r--r--src/librustc/middle/ty/util.rs3
-rw-r--r--src/librustc/middle/ty/wf.rs2
-rw-r--r--src/librustc/util/ppaux.rs10
-rw-r--r--src/librustc_driver/test.rs2
-rw-r--r--src/librustc_metadata/decoder.rs2
-rw-r--r--src/librustc_metadata/tydecode.rs2
-rw-r--r--src/librustc_trans/trans/base.rs2
-rw-r--r--src/librustc_trans/trans/callee.rs2
-rw-r--r--src/librustc_trans/trans/common.rs6
-rw-r--r--src/librustc_trans/trans/intrinsic.rs2
-rw-r--r--src/librustc_trans/trans/meth.rs2
-rw-r--r--src/librustc_trans/trans/mir/constant.rs2
-rw-r--r--src/librustc_trans/trans/mir/did.rs2
-rw-r--r--src/librustc_trans/trans/mir/lvalue.rs2
-rw-r--r--src/librustc_trans/trans/mir/operand.rs2
-rw-r--r--src/librustc_trans/trans/monomorphize.rs4
-rw-r--r--src/librustc_trans/trans/type_of.rs2
-rw-r--r--src/librustc_typeck/astconv.rs2
-rw-r--r--src/librustc_typeck/check/_match.rs2
-rw-r--r--src/librustc_typeck/check/assoc.rs3
-rw-r--r--src/librustc_typeck/check/cast.rs2
-rw-r--r--src/librustc_typeck/check/method/mod.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs4
-rw-r--r--src/librustc_typeck/check/method/suggest.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs8
-rw-r--r--src/librustc_typeck/check/op.rs2
-rw-r--r--src/librustc_typeck/check/regionck.rs2
-rw-r--r--src/librustc_typeck/check/writeback.rs2
-rw-r--r--src/librustc_typeck/coherence/mod.rs3
-rw-r--r--src/librustc_typeck/lib.rs2
54 files changed, 689 insertions, 873 deletions
diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs
index 9f33c4df03d..d25084bbdff 100644
--- a/src/librustc/middle/implicator.rs
+++ b/src/librustc/middle/implicator.rs
@@ -14,7 +14,7 @@ use middle::def_id::DefId;
 use middle::infer::{InferCtxt, GenericKind};
 use middle::subst::Substs;
 use middle::traits;
-use middle::ty::{self, RegionEscape, ToPredicate, Ty};
+use middle::ty::{self, ToPredicate, Ty};
 use middle::ty::fold::{TypeFoldable, TypeFolder};
 
 use syntax::ast;
@@ -404,7 +404,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
     }
 
     fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
-        where T : TypeFoldable<'tcx> + ty::HasTypeFlags
+        where T : TypeFoldable<'tcx>
     {
         let value =
             traits::fully_normalize(self.infcx,
diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs
index 2a25ed2c6e1..faf1bdb0ce5 100644
--- a/src/librustc/middle/infer/combine.rs
+++ b/src/librustc/middle/infer/combine.rs
@@ -318,7 +318,7 @@ impl<'cx, 'tcx> ty::fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
                 }
             }
             _ => {
-                ty::fold::super_fold_ty(self, t)
+                t.super_fold_with(self)
             }
         }
     }
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index d628227d5e6..f390d85a28d 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -82,7 +82,7 @@ use middle::def_id::DefId;
 use middle::infer::{self, TypeOrigin};
 use middle::region;
 use middle::subst;
-use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::{self, Ty, TypeFoldable};
 use middle::ty::{Region, ReFree};
 use middle::ty::error::TypeError;
 
@@ -250,7 +250,7 @@ pub trait ErrorReporting<'tcx> {
 
     fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
 
-    fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + HasTypeFlags>(
+    fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>(
         &self,
         exp_found: &ty::error::ExpectedFound<T>)
         -> Option<String>;
@@ -575,7 +575,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
         }
     }
 
-    fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + HasTypeFlags>(
+    fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>(
         &self,
         exp_found: &ty::error::ExpectedFound<T>)
         -> Option<String>
diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs
index 0bae3cd2d86..76dd62383f1 100644
--- a/src/librustc/middle/infer/freshen.rs
+++ b/src/librustc/middle/infer/freshen.rs
@@ -30,8 +30,7 @@
 //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
 //! inferencer knows "so far".
 
-use middle::ty::{self, Ty, HasTypeFlags};
-use middle::ty::fold::TypeFoldable;
+use middle::ty::{self, Ty, TypeFoldable};
 use middle::ty::fold::TypeFolder;
 use std::collections::hash_map::{self, Entry};
 
@@ -169,7 +168,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
             ty::TyTuple(..) |
             ty::TyProjection(..) |
             ty::TyParam(..) => {
-                ty::fold::super_fold_ty(self, t)
+                t.super_fold_with(self)
             }
         }
     }
diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs
index ef6d9ae4191..e8f542db933 100644
--- a/src/librustc/middle/infer/higher_ranked/mod.rs
+++ b/src/librustc/middle/infer/higher_ranked/mod.rs
@@ -14,9 +14,8 @@
 use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
 use super::combine::CombineFields;
 
-use middle::ty::{self, Binder};
+use middle::ty::{self, Binder, TypeFoldable};
 use middle::ty::error::TypeError;
-use middle::ty::fold::TypeFoldable;
 use middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use syntax::codemap::Span;
 use util::nodemap::{FnvHashMap, FnvHashSet};
@@ -557,7 +556,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                              snapshot: &CombinedSnapshot,
                              value: &T)
                              -> T
-    where T : TypeFoldable<'tcx> + ty::HasTypeFlags
+    where T : TypeFoldable<'tcx>
 {
     debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok());
 
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 21a1ee37b7f..922d4c251bb 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -30,7 +30,7 @@ use middle::subst::Subst;
 use middle::traits;
 use middle::ty::adjustment;
 use middle::ty::{TyVid, IntVid, FloatVid};
-use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::{self, Ty};
 use middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use middle::ty::fold::{TypeFolder, TypeFoldable};
 use middle::ty::relate::{Relate, RelateResult, TypeRelation};
@@ -512,7 +512,7 @@ pub struct CombinedSnapshot {
 }
 
 pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
-    where T : TypeFoldable<'tcx> + HasTypeFlags
+    where T : TypeFoldable<'tcx>
 {
     debug!("normalize_associated_type(t={:?})", value);
 
@@ -546,7 +546,7 @@ pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
                                                 fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
                                                 result: &T)
                                                 -> T
-    where T : TypeFoldable<'tcx> + HasTypeFlags
+    where T : TypeFoldable<'tcx>
 {
     match drain_fulfillment_cx(infcx, fulfill_cx, result) {
         Ok(v) => v,
@@ -570,7 +570,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                        fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
                                        result: &T)
                                        -> Result<T,Vec<traits::FulfillmentError<'tcx>>>
-    where T : TypeFoldable<'tcx> + HasTypeFlags
+    where T : TypeFoldable<'tcx>
 {
     debug!("drain_fulfillment_cx(result={:?})",
            result);
@@ -929,7 +929,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                          snapshot: &CombinedSnapshot,
                          value: &T)
                          -> T
-        where T : TypeFoldable<'tcx> + HasTypeFlags
+        where T : TypeFoldable<'tcx>
     {
         /*! See `higher_ranked::plug_leaks` */
 
@@ -1201,7 +1201,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
-        where T: TypeFoldable<'tcx> + HasTypeFlags
+        where T: TypeFoldable<'tcx>
     {
         /*!
          * Where possible, replaces type/int/float variables in
diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs
index 5190c658194..c68d0a9fa56 100644
--- a/src/librustc/middle/infer/resolve.rs
+++ b/src/librustc/middle/infer/resolve.rs
@@ -9,8 +9,7 @@
 // except according to those terms.
 
 use super::{InferCtxt, FixupError, FixupResult};
-use middle::ty::{self, Ty, HasTypeFlags};
-use middle::ty::fold::{TypeFoldable};
+use middle::ty::{self, Ty, TypeFoldable};
 
 ///////////////////////////////////////////////////////////////////////////
 // OPPORTUNISTIC TYPE RESOLVER
@@ -40,7 +39,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)
+            t0.super_fold_with(self)
         }
     }
 }
@@ -68,7 +67,7 @@ impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver
             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)
+            t0.super_fold_with(self)
         }
     }
 
@@ -133,7 +132,7 @@ impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
                                 t));
                 }
                 _ => {
-                    ty::fold::super_fold_ty(self, t)
+                    t.super_fold_with(self)
                 }
             }
         }
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index f1eed256dd1..69b952ca1f3 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -13,7 +13,7 @@ use middle::def::DefFn;
 use middle::def_id::DefId;
 use middle::subst::{Subst, Substs, EnumeratedItems};
 use middle::ty::{TransmuteRestriction, ctxt, TyBareFn};
-use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::{self, Ty, TypeFoldable};
 
 use std::fmt;
 
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index aa47b32dc3e..61f7b2db4c4 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::cstore;
-use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
+use middle::ty::{self, Ty};
 use middle::ty::fold::{TypeFoldable, TypeFolder};
 
 use serialize::{Encodable, Encoder, Decodable, Decoder};
@@ -674,7 +674,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
                 self.ty_for_param(p, t)
             }
             _ => {
-                ty::fold::super_fold_ty(self, t)
+                t.super_fold_with(self)
             }
         };
 
diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
index 038c414662a..883c5e7bb40 100644
--- a/src/librustc/middle/traits/error_reporting.rs
+++ b/src/librustc/middle/traits/error_reporting.rs
@@ -26,9 +26,8 @@ use super::{
 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::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TypeFoldable};
 use middle::ty::fast_reject;
-use middle::ty::fold::TypeFoldable;
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
 use std::cmp;
@@ -185,7 +184,7 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
                                           obligation: &Obligation<'tcx, T>)
                                           -> !
-    where T: fmt::Display + TypeFoldable<'tcx> + HasTypeFlags
+    where T: fmt::Display + TypeFoldable<'tcx>
 {
     let predicate =
         infcx.resolve_type_vars_if_possible(&obligation.predicate);
diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index b93961f1aa9..4f8f6b846a6 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use middle::infer::InferCtxt;
-use middle::ty::{self, RegionEscape, Ty, HasTypeFlags};
+use middle::ty::{self, Ty, TypeFoldable};
 
 use syntax::ast;
 use util::common::ErrorReported;
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index dddd6f8bc85..6cf841cc477 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -19,9 +19,8 @@ use dep_graph::DepNode;
 use middle::def_id::DefId;
 use middle::free_region::FreeRegionMap;
 use middle::subst;
-use middle::ty::{self, HasTypeFlags, Ty};
+use middle::ty::{self, Ty, TypeFoldable};
 use middle::ty::fast_reject;
-use middle::ty::fold::TypeFoldable;
 use middle::infer::{self, fixup_err_to_string, InferCtxt};
 
 use std::rc::Rc;
@@ -470,7 +469,7 @@ pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                   cause: ObligationCause<'tcx>,
                                   value: &T)
                                   -> Result<T, Vec<FulfillmentError<'tcx>>>
-    where T : TypeFoldable<'tcx> + HasTypeFlags
+    where T : TypeFoldable<'tcx>
 {
     debug!("normalize_param_env(value={:?})", value);
 
diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs
index c8e34165b90..0e4a42bd151 100644
--- a/src/librustc/middle/traits/object_safety.rs
+++ b/src/librustc/middle/traits/object_safety.rs
@@ -23,7 +23,7 @@ use super::elaborate_predicates;
 use middle::def_id::DefId;
 use middle::subst::{self, SelfSpace, TypeSpace};
 use middle::traits;
-use middle::ty::{self, HasTypeFlags, ToPolyTraitRef, Ty};
+use middle::ty::{self, ToPolyTraitRef, Ty, TypeFoldable};
 use std::rc::Rc;
 use syntax::ast;
 
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index 8fbfd513c78..ad3524661d3 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -23,7 +23,7 @@ use super::util;
 
 use middle::infer::{self, TypeOrigin};
 use middle::subst::Subst;
-use middle::ty::{self, ToPredicate, RegionEscape, HasTypeFlags, ToPolyTraitRef, Ty};
+use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty};
 use middle::ty::fold::{TypeFoldable, TypeFolder};
 use syntax::parse::token;
 use util::common::FN_OUTPUT_NAME;
@@ -202,7 +202,7 @@ pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
                                cause: ObligationCause<'tcx>,
                                value: &T)
                                -> Normalized<'tcx, T>
-    where T : TypeFoldable<'tcx> + HasTypeFlags
+    where T : TypeFoldable<'tcx>
 {
     normalize_with_depth(selcx, cause, 0, value)
 }
@@ -213,7 +213,7 @@ pub fn normalize_with_depth<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tc
                                           depth: usize,
                                           value: &T)
                                           -> Normalized<'tcx, T>
-    where T : TypeFoldable<'tcx> + HasTypeFlags
+    where T : TypeFoldable<'tcx>
 {
     let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
     let result = normalizer.fold(value);
@@ -245,7 +245,7 @@ impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> {
         }
     }
 
-    fn fold<T:TypeFoldable<'tcx> + HasTypeFlags>(&mut self, value: &T) -> T {
+    fn fold<T:TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
         let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
 
         if !value.has_projection_types() {
@@ -273,7 +273,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.super_fold_with(self);
         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 bd92f974866..f544f8ce362 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -39,9 +39,8 @@ use middle::def_id::DefId;
 use middle::infer;
 use middle::infer::{InferCtxt, TypeFreshener, TypeOrigin};
 use middle::subst::{Subst, Substs, TypeSpace};
-use middle::ty::{self, ToPredicate, RegionEscape, ToPolyTraitRef, Ty, HasTypeFlags};
+use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TypeFoldable};
 use middle::ty::fast_reject;
-use middle::ty::fold::TypeFoldable;
 use middle::ty::relate::TypeRelation;
 
 use std::cell::RefCell;
@@ -965,7 +964,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         match *candidate {
             Ok(Some(_)) | Err(_) => true,
             Ok(None) => {
-                cache_fresh_trait_pred.0.input_types().has_infer_types()
+                cache_fresh_trait_pred.0.trait_ref.substs.types.has_infer_types()
             }
         }
     }
diff --git a/src/librustc/middle/traits/structural_impls.rs b/src/librustc/middle/traits/structural_impls.rs
index 8ce21112001..453420e2a54 100644
--- a/src/librustc/middle/traits/structural_impls.rs
+++ b/src/librustc/middle/traits/structural_impls.rs
@@ -10,8 +10,7 @@
 
 use middle::traits;
 use middle::traits::project::Normalized;
-use middle::ty::{HasTypeFlags, TypeFlags, RegionEscape};
-use middle::ty::fold::{TypeFoldable, TypeFolder};
+use middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use std::fmt;
 
@@ -131,130 +130,89 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'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, 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, N: HasTypeFlags> HasTypeFlags for traits::VtableImplData<'tcx, N> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.substs.has_type_flags(flags) ||
-            self.nested.has_type_flags(flags)
-    }
-}
-
-impl<'tcx, N: HasTypeFlags> HasTypeFlags for traits::VtableClosureData<'tcx, N> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.substs.has_type_flags(flags) ||
-            self.nested.has_type_flags(flags)
-    }
-}
-
-impl<'tcx, N: HasTypeFlags> HasTypeFlags for traits::VtableDefaultImplData<N> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.nested.has_type_flags(flags)
-    }
-}
-
-impl<'tcx, N: HasTypeFlags> HasTypeFlags for traits::VtableBuiltinData<N> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.nested.has_type_flags(flags)
-    }
-}
-
-impl<'tcx> HasTypeFlags for traits::VtableObjectData<'tcx> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.upcast_trait_ref.has_type_flags(flags)
-    }
-}
-
-impl<'tcx, N: HasTypeFlags> HasTypeFlags for traits::Vtable<'tcx, N> {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        match *self {
-            traits::VtableImpl(ref v) => v.has_type_flags(flags),
-            traits::VtableDefaultImpl(ref t) => t.has_type_flags(flags),
-            traits::VtableClosure(ref d) => d.has_type_flags(flags),
-            traits::VtableFnPointer(ref d) => d.has_type_flags(flags),
-            traits::VtableParam(ref n) => n.has_type_flags(flags),
-            traits::VtableBuiltin(ref d) => d.has_type_flags(flags),
-            traits::VtableObject(ref d) => d.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> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         traits::Obligation {
             cause: self.cause.clone(),
             recursion_depth: self.recursion_depth,
             predicate: self.predicate.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.predicate.visit_with(visitor)
+    }
 }
 
 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> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         traits::VtableImplData {
             impl_def_id: self.impl_def_id,
             substs: self.substs.fold_with(folder),
             nested: self.nested.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.substs.visit_with(visitor) || self.nested.visit_with(visitor)
+    }
 }
 
 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> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         traits::VtableClosureData {
             closure_def_id: self.closure_def_id,
             substs: self.substs.fold_with(folder),
             nested: self.nested.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.substs.visit_with(visitor) || self.nested.visit_with(visitor)
+    }
 }
 
 impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         traits::VtableDefaultImplData {
             trait_def_id: self.trait_def_id,
             nested: self.nested.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.nested.visit_with(visitor)
+    }
 }
 
 impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         traits::VtableBuiltinData {
             nested: self.nested.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.nested.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         traits::VtableObjectData {
             upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
             vtable_base: self.vtable_base
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.upcast_trait_ref.visit_with(visitor)
+    }
 }
 
 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> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
             traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
             traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
@@ -269,13 +227,29 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
             traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            traits::VtableImpl(ref v) => v.visit_with(visitor),
+            traits::VtableDefaultImpl(ref t) => t.visit_with(visitor),
+            traits::VtableClosure(ref d) => d.visit_with(visitor),
+            traits::VtableFnPointer(ref d) => d.visit_with(visitor),
+            traits::VtableParam(ref n) => n.visit_with(visitor),
+            traits::VtableBuiltin(ref d) => d.visit_with(visitor),
+            traits::VtableObject(ref d) => d.visit_with(visitor),
+        }
+    }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Normalized<'tcx, T> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         Normalized {
             value: self.value.fold_with(folder),
             obligations: self.obligations.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.value.visit_with(visitor) || self.obligations.visit_with(visitor)
+    }
 }
diff --git a/src/librustc/middle/ty/adjustment.rs b/src/librustc/middle/ty/adjustment.rs
index c44ebcfdb69..6cab0baa553 100644
--- a/src/librustc/middle/ty/adjustment.rs
+++ b/src/librustc/middle/ty/adjustment.rs
@@ -11,8 +11,7 @@
 pub use self::AutoAdjustment::*;
 pub use self::AutoRef::*;
 
-use middle::ty::{self, Ty, TypeAndMut};
-use middle::ty::HasTypeFlags;
+use middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
 use middle::ty::LvaluePreference::{NoPreference};
 
 use syntax::ast;
diff --git a/src/librustc/middle/ty/flags.rs b/src/librustc/middle/ty/flags.rs
index 94a50e3cac7..a0b03fe8126 100644
--- a/src/librustc/middle/ty/flags.rs
+++ b/src/librustc/middle/ty/flags.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use middle::subst;
-use middle::ty::{self, HasTypeFlags, Ty, TypeFlags};
+use middle::ty::{self, Ty, TypeFlags, TypeFoldable};
 
 pub struct FlagComputation {
     pub flags: TypeFlags,
diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs
index 605e78e9281..da0245a8d25 100644
--- a/src/librustc/middle/ty/fold.rs
+++ b/src/librustc/middle/ty/fold.rs
@@ -14,41 +14,98 @@
 //! instance of a "folder" (a type which implements `TypeFolder`). Then
 //! the setup is intended to be:
 //!
-//!     T.fold_with(F) --calls--> F.fold_T(T) --calls--> super_fold_T(F, T)
+//!   T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F)
 //!
 //! This way, when you define a new folder F, you can override
-//! `fold_T()` to customize the behavior, and invoke `super_fold_T()`
+//! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()`
 //! to get the original behavior. Meanwhile, to actually fold
 //! something, you can just write `T.fold_with(F)`, which is
 //! convenient. (Note that `fold_with` will also transparently handle
 //! things like a `Vec<T>` where T is foldable and so on.)
 //!
 //! In this ideal setup, the only function that actually *does*
-//! anything is `super_fold_T`, which traverses the type `T`. Moreover,
-//! `super_fold_T` should only ever call `T.fold_with()`.
+//! anything is `T.super_fold_with()`, which traverses the type `T`.
+//! Moreover, `T.super_fold_with()` should only ever call `T.fold_with()`.
 //!
 //! In some cases, we follow a degenerate pattern where we do not have
-//! a `fold_T` nor `super_fold_T` method. Instead, `T.fold_with`
-//! traverses the structure directly. This is suboptimal because the
-//! behavior cannot be overridden, but it's much less work to implement.
-//! If you ever *do* need an override that doesn't exist, it's not hard
-//! to convert the degenerate pattern into the proper thing.
+//! a `fold_T` method. Instead, `T.fold_with` traverses the structure directly.
+//! This is suboptimal because the behavior cannot be overridden, but it's
+//! much less work to implement. If you ever *do* need an override that
+//! doesn't exist, it's not hard to convert the degenerate pattern into the
+//! proper thing.
+//!
+//! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup:
+//!   T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V).
+//! These methods return true to indicate that the visitor has found what it is looking for
+//! and does not need to visit anything else.
 
 use middle::region;
 use middle::subst;
 use middle::ty::adjustment;
-use middle::ty::{self, Binder, Ty, RegionEscape};
+use middle::ty::{self, Binder, Ty, TypeFlags};
 
 use std::fmt;
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
-///////////////////////////////////////////////////////////////////////////
-// Two generic traits
-
 /// The TypeFoldable trait is implemented for every type that can be folded.
 /// Basically, every type that has a corresponding method in TypeFolder.
 pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        self.super_fold_with(folder)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool;
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.super_visit_with(visitor)
+    }
+
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.visit_with(&mut HasEscapingRegionsVisitor { depth: depth })
+    }
+    fn has_escaping_regions(&self) -> bool {
+        self.has_regions_escaping_depth(0)
+    }
+
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.visit_with(&mut HasTypeFlagsVisitor { flags: flags })
+    }
+    fn has_projection_types(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_PROJECTION)
+    }
+    fn references_error(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_ERR)
+    }
+    fn has_param_types(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_PARAMS)
+    }
+    fn has_self_ty(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_SELF)
+    }
+    fn has_infer_types(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_INFER)
+    }
+    fn needs_infer(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
+    }
+    fn needs_subst(&self) -> bool {
+        self.has_type_flags(TypeFlags::NEEDS_SUBST)
+    }
+    fn has_closure_types(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_CLOSURE)
+    }
+    fn has_erasable_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND |
+                            TypeFlags::HAS_RE_INFER |
+                            TypeFlags::HAS_FREE_REGIONS)
+    }
+    /// Indicates whether this value references only 'global'
+    /// types/lifetimes that are the same regardless of what fn we are
+    /// in. This is used for caching. Errs on the side of returning
+    /// false.
+    fn is_global(&self) -> bool {
+        !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES)
+    }
 }
 
 /// The TypeFolder trait defines the actual *folding*. There is a
@@ -74,248 +131,77 @@ pub trait TypeFolder<'tcx> : Sized {
         where T : TypeFoldable<'tcx>
     {
         // FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`.
-        super_fold_binder(self, t)
+        t.super_fold_with(self)
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        super_fold_ty(self, t)
+        t.super_fold_with(self)
     }
 
     fn fold_mt(&mut self, t: &ty::TypeAndMut<'tcx>) -> ty::TypeAndMut<'tcx> {
-        super_fold_mt(self, t)
+        t.super_fold_with(self)
     }
 
     fn fold_trait_ref(&mut self, t: &ty::TraitRef<'tcx>) -> ty::TraitRef<'tcx> {
-        super_fold_trait_ref(self, t)
+        t.super_fold_with(self)
     }
 
     fn fold_substs(&mut self,
                    substs: &subst::Substs<'tcx>)
                    -> subst::Substs<'tcx> {
-        super_fold_substs(self, substs)
+        substs.super_fold_with(self)
     }
 
     fn fold_fn_sig(&mut self,
                    sig: &ty::FnSig<'tcx>)
                    -> ty::FnSig<'tcx> {
-        super_fold_fn_sig(self, sig)
+        sig.super_fold_with(self)
     }
 
     fn fold_output(&mut self,
                       output: &ty::FnOutput<'tcx>)
                       -> ty::FnOutput<'tcx> {
-        super_fold_output(self, output)
+        output.super_fold_with(self)
     }
 
     fn fold_bare_fn_ty(&mut self,
                        fty: &ty::BareFnTy<'tcx>)
                        -> ty::BareFnTy<'tcx>
     {
-        super_fold_bare_fn_ty(self, fty)
+        fty.super_fold_with(self)
     }
 
     fn fold_closure_ty(&mut self,
                        fty: &ty::ClosureTy<'tcx>)
                        -> ty::ClosureTy<'tcx> {
-        super_fold_closure_ty(self, fty)
+        fty.super_fold_with(self)
     }
 
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        r
+        r.super_fold_with(self)
     }
 
     fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>)
                                -> ty::ExistentialBounds<'tcx> {
-        super_fold_existential_bounds(self, s)
+        s.super_fold_with(self)
     }
 
     fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>)
                     -> adjustment::AutoRef<'tcx> {
-        super_fold_autoref(self, ar)
+        ar.super_fold_with(self)
     }
-
-    fn fold_item_substs(&mut self, i: ty::ItemSubsts<'tcx>) -> ty::ItemSubsts<'tcx> {
-        super_fold_item_substs(self, i)
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// "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: &Binder<U>)
-                                     -> Binder<U>
-    where T : TypeFolder<'tcx>, U : TypeFoldable<'tcx>
-{
-    this.enter_region_binder();
-    let result = Binder(binder.0.fold_with(this));
-    this.exit_region_binder();
-    result
 }
 
-pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                ty: Ty<'tcx>)
-                                                -> Ty<'tcx> {
-    let sty = match ty.sty {
-        ty::TyBox(typ) => {
-            ty::TyBox(typ.fold_with(this))
-        }
-        ty::TyRawPtr(ref tm) => {
-            ty::TyRawPtr(tm.fold_with(this))
-        }
-        ty::TyArray(typ, sz) => {
-            ty::TyArray(typ.fold_with(this), sz)
-        }
-        ty::TySlice(typ) => {
-            ty::TySlice(typ.fold_with(this))
-        }
-        ty::TyEnum(tid, ref substs) => {
-            let substs = substs.fold_with(this);
-            ty::TyEnum(tid, this.tcx().mk_substs(substs))
-        }
-        ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => {
-            ty::TyTrait(box ty::TraitTy {
-                principal: principal.fold_with(this),
-                bounds: bounds.fold_with(this),
-            })
-        }
-        ty::TyTuple(ref ts) => {
-            ty::TyTuple(ts.fold_with(this))
-        }
-        ty::TyBareFn(opt_def_id, ref f) => {
-            let bfn = f.fold_with(this);
-            ty::TyBareFn(opt_def_id, this.tcx().mk_bare_fn(bfn))
-        }
-        ty::TyRef(r, ref tm) => {
-            let r = r.fold_with(this);
-            ty::TyRef(this.tcx().mk_region(r), tm.fold_with(this))
-        }
-        ty::TyStruct(did, ref substs) => {
-            let substs = substs.fold_with(this);
-            ty::TyStruct(did, this.tcx().mk_substs(substs))
-        }
-        ty::TyClosure(did, ref substs) => {
-            let s = substs.fold_with(this);
-            ty::TyClosure(did, s)
-        }
-        ty::TyProjection(ref data) => {
-            ty::TyProjection(data.fold_with(this))
-        }
-        ty::TyBool | ty::TyChar | ty::TyStr |
-        ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
-        ty::TyError | ty::TyInfer(_) |
-        ty::TyParam(..) => {
-            ty.sty.clone()
-        }
-    };
-    this.tcx().mk_ty(sty)
-}
-
-pub fn super_fold_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                    substs: &subst::Substs<'tcx>)
-                                                    -> subst::Substs<'tcx> {
-    let regions = match substs.regions {
-        subst::ErasedRegions => {
-            subst::ErasedRegions
-        }
-        subst::NonerasedRegions(ref regions) => {
-            subst::NonerasedRegions(regions.fold_with(this))
-        }
-    };
-
-    subst::Substs { regions: regions,
-                    types: substs.types.fold_with(this) }
-}
-
-pub fn super_fold_fn_sig<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                    sig: &ty::FnSig<'tcx>)
-                                                    -> ty::FnSig<'tcx>
-{
-    ty::FnSig { inputs: sig.inputs.fold_with(this),
-                output: sig.output.fold_with(this),
-                variadic: sig.variadic }
-}
-
-pub fn super_fold_output<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                    output: &ty::FnOutput<'tcx>)
-                                                    -> ty::FnOutput<'tcx> {
-    match *output {
-        ty::FnConverging(ref ty) => ty::FnConverging(ty.fold_with(this)),
-        ty::FnDiverging => ty::FnDiverging
-    }
-}
-
-pub fn super_fold_bare_fn_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                        fty: &ty::BareFnTy<'tcx>)
-                                                        -> ty::BareFnTy<'tcx>
-{
-    ty::BareFnTy { sig: fty.sig.fold_with(this),
-                   abi: fty.abi,
-                   unsafety: fty.unsafety }
-}
-
-pub fn super_fold_closure_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                        fty: &ty::ClosureTy<'tcx>)
-                                                        -> ty::ClosureTy<'tcx>
-{
-    ty::ClosureTy {
-        sig: fty.sig.fold_with(this),
-        unsafety: fty.unsafety,
-        abi: fty.abi,
-    }
-}
-
-pub fn super_fold_trait_ref<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                       t: &ty::TraitRef<'tcx>)
-                                                       -> ty::TraitRef<'tcx>
-{
-    let substs = t.substs.fold_with(this);
-    ty::TraitRef {
-        def_id: t.def_id,
-        substs: this.tcx().mk_substs(substs),
-    }
-}
-
-pub fn super_fold_mt<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                mt: &ty::TypeAndMut<'tcx>)
-                                                -> ty::TypeAndMut<'tcx> {
-    ty::TypeAndMut {ty: mt.ty.fold_with(this),
-            mutbl: mt.mutbl}
-}
-
-pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>(
-    this: &mut T,
-    bounds: &ty::ExistentialBounds<'tcx>)
-    -> ty::ExistentialBounds<'tcx>
-{
-    ty::ExistentialBounds {
-        region_bound: bounds.region_bound.fold_with(this),
-        builtin_bounds: bounds.builtin_bounds,
-        projection_bounds: bounds.projection_bounds.fold_with(this),
-    }
-}
+pub trait TypeVisitor<'tcx> : Sized {
+    fn enter_region_binder(&mut self) { }
+    fn exit_region_binder(&mut self) { }
 
-pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                     autoref: &adjustment::AutoRef<'tcx>)
-                                                     -> adjustment::AutoRef<'tcx>
-{
-    match *autoref {
-        adjustment::AutoPtr(r, m) => {
-            let r = r.fold_with(this);
-            adjustment::AutoPtr(this.tcx().mk_region(r), m)
-        }
-        adjustment::AutoUnsafe(m) => adjustment::AutoUnsafe(m)
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+        t.super_visit_with(self)
     }
-}
 
-pub fn super_fold_item_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                         substs: ty::ItemSubsts<'tcx>)
-                                                         -> ty::ItemSubsts<'tcx>
-{
-    ty::ItemSubsts {
-        substs: substs.substs.fold_with(this),
+    fn visit_region(&mut self, r: ty::Region) -> bool {
+        r.super_visit_with(self)
     }
 }
 
@@ -333,7 +219,7 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where
     fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let t1 = super_fold_ty(self, ty);
+        let t1 = ty.super_fold_with(self);
         (self.fldop)(t1)
     }
 }
@@ -495,7 +381,7 @@ impl<'tcx> ty::ctxt<'tcx> {
     }
 
     pub fn no_late_bound_regions<T>(&self, value: &Binder<T>) -> Option<T>
-        where T : TypeFoldable<'tcx> + RegionEscape
+        where T : TypeFoldable<'tcx>
     {
         if value.0.has_escaping_regions() {
             None
@@ -561,7 +447,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx>
             return t;
         }
 
-        super_fold_ty(self, t)
+        t.super_fold_with(self)
     }
 
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
@@ -612,7 +498,7 @@ impl<'tcx> ty::ctxt<'tcx> {
                     Some(u) => return u
                 }
 
-                let t_norm = ty::fold::super_fold_ty(self, ty);
+                let t_norm = ty.super_fold_with(self);
                 self.tcx().normalized_cache.borrow_mut().insert(ty, t_norm);
                 return t_norm;
             }
@@ -621,7 +507,7 @@ impl<'tcx> ty::ctxt<'tcx> {
                 where T : TypeFoldable<'tcx>
             {
                 let u = self.tcx().anonymize_late_bound_regions(t);
-                ty::fold::super_fold_binder(self, &u)
+                u.super_fold_with(self)
             }
 
             fn fold_region(&mut self, r: ty::Region) -> ty::Region {
@@ -678,3 +564,75 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>,
         shift_region(region, amount)
     }))
 }
+
+/// 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:
+///
+///    for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
+///    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
+///                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
+///
+/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
+/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
+/// fn type*, that type has an escaping region: `'a`.
+///
+/// Note that what I'm calling an "escaping region" is often just called a "free region". However,
+/// we already use the term "free region". It refers to the regions that we use to represent bound
+/// regions on a fn definition while we are typechecking its body.
+///
+/// To clarify, conceptually there is no particular difference between an "escaping" region and a
+/// "free" region. However, there is a big difference in practice. Basically, when "entering" a
+/// binding level, one is generally required to do some sort of processing to a bound region, such
+/// as replacing it with a fresh/skolemized region, or making an entry in the environment to
+/// represent the scope to which it is attached, etc. An escaping region represents a bound region
+/// for which this processing has not yet been done.
+struct HasEscapingRegionsVisitor {
+    depth: u32,
+}
+
+impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor {
+    fn enter_region_binder(&mut self) {
+        self.depth += 1;
+    }
+
+    fn exit_region_binder(&mut self) {
+        self.depth -= 1;
+    }
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+        t.region_depth > self.depth
+    }
+
+    fn visit_region(&mut self, r: ty::Region) -> bool {
+        r.escapes_depth(self.depth)
+    }
+}
+
+struct HasTypeFlagsVisitor {
+    flags: ty::TypeFlags,
+}
+
+impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
+    fn visit_ty(&mut self, t: Ty) -> bool {
+        t.flags.get().intersects(self.flags)
+    }
+
+    fn visit_region(&mut self, r: ty::Region) -> bool {
+        if self.flags.intersects(ty::TypeFlags::HAS_LOCAL_NAMES) {
+            // does this represent a region that cannot be named
+            // in a global way? used in fulfillment caching.
+            match r {
+                ty::ReStatic | ty::ReEmpty => {}
+                _ => return true,
+            }
+        }
+        if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER) {
+            match r {
+                ty::ReVar(_) | ty::ReSkolemized(..) => { return true }
+                _ => {}
+            }
+        }
+        false
+    }
+}
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index 2baf5c5145f..852d9d80a91 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -17,6 +17,7 @@ pub use self::BorrowKind::*;
 pub use self::ImplOrTraitItem::*;
 pub use self::IntVarValue::*;
 pub use self::LvaluePreference::*;
+pub use self::fold::TypeFoldable;
 
 use dep_graph::{self, DepNode};
 use front::map as ast_map;
@@ -2667,73 +2668,3 @@ impl<'tcx> ctxt<'tcx> {
         trait_ref.substs.clone().with_method(meth_tps, meth_regions)
     }
 }
-
-/// 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:
-///
-///    for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
-///    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
-///                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
-///
-/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
-/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
-/// fn type*, that type has an escaping region: `'a`.
-///
-/// Note that what I'm calling an "escaping region" is often just called a "free region". However,
-/// we already use the term "free region". It refers to the regions that we use to represent bound
-/// regions on a fn definition while we are typechecking its body.
-///
-/// To clarify, conceptually there is no particular difference between an "escaping" region and a
-/// "free" region. However, there is a big difference in practice. Basically, when "entering" a
-/// binding level, one is generally required to do some sort of processing to a bound region, such
-/// as replacing it with a fresh/skolemized region, or making an entry in the environment to
-/// represent the scope to which it is attached, etc. An escaping region represents a bound region
-/// for which this processing has not yet been done.
-pub trait RegionEscape {
-    fn has_escaping_regions(&self) -> bool {
-        self.has_regions_escaping_depth(0)
-    }
-
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool;
-}
-
-pub trait HasTypeFlags {
-    fn has_type_flags(&self, flags: TypeFlags) -> bool;
-    fn has_projection_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PROJECTION)
-    }
-    fn references_error(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_ERR)
-    }
-    fn has_param_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PARAMS)
-    }
-    fn has_self_ty(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_SELF)
-    }
-    fn has_infer_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_INFER)
-    }
-    fn needs_infer(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
-    }
-    fn needs_subst(&self) -> bool {
-        self.has_type_flags(TypeFlags::NEEDS_SUBST)
-    }
-    fn has_closure_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_CLOSURE)
-    }
-    fn has_erasable_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND |
-                            TypeFlags::HAS_RE_INFER |
-                            TypeFlags::HAS_FREE_REGIONS)
-    }
-    /// Indicates whether this value references only 'global'
-    /// types/lifetimes that are the same regardless of what fn we are
-    /// in. This is used for caching. Errs on the side of returning
-    /// false.
-    fn is_global(&self) -> bool {
-        !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES)
-    }
-}
diff --git a/src/librustc/middle/ty/outlives.rs b/src/librustc/middle/ty/outlives.rs
index 7752367febb..fc20c1bcb85 100644
--- a/src/librustc/middle/ty/outlives.rs
+++ b/src/librustc/middle/ty/outlives.rs
@@ -13,7 +13,7 @@
 // RFC for reference.
 
 use middle::infer::InferCtxt;
-use middle::ty::{self, RegionEscape, Ty};
+use middle::ty::{self, Ty, TypeFoldable};
 
 #[derive(Debug)]
 pub enum Component<'tcx> {
diff --git a/src/librustc/middle/ty/relate.rs b/src/librustc/middle/ty/relate.rs
index ff0a9789cf1..46bc13bd598 100644
--- a/src/librustc/middle/ty/relate.rs
+++ b/src/librustc/middle/ty/relate.rs
@@ -15,9 +15,8 @@
 
 use middle::def_id::DefId;
 use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
-use middle::ty::{self, HasTypeFlags, Ty};
+use middle::ty::{self, Ty, TypeFoldable};
 use middle::ty::error::{ExpectedFound, TypeError};
-use middle::ty::fold::TypeFoldable;
 use std::rc::Rc;
 use syntax::abi;
 use rustc_front::hir as ast;
@@ -80,7 +79,7 @@ pub trait TypeRelation<'a,'tcx> : Sized {
         where T: Relate<'a,'tcx>;
 }
 
-pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> + HasTypeFlags {
+pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> {
     fn relate<R:TypeRelation<'a,'tcx>>(relation: &mut R,
                                        a: &Self,
                                        b: &Self)
diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs
index ecb2b85fd77..01b2bd36b4f 100644
--- a/src/librustc/middle/ty/structural_impls.rs
+++ b/src/librustc/middle/ty/structural_impls.rs
@@ -10,9 +10,8 @@
 
 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 middle::ty::{self, Lift, TraitRef, Ty};
+use middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use std::rc::Rc;
 use syntax::abi;
@@ -20,390 +19,6 @@ use syntax::ptr::P;
 
 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 ty::InstantiatedPredicates<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.predicates.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> 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 HasTypeFlags for () {
-    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
-        false
-    }
-}
-
-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
 
@@ -508,9 +123,13 @@ macro_rules! CopyImpls {
     ($($ty:ty),+) => {
         $(
             impl<'tcx> TypeFoldable<'tcx> for $ty {
-                fn fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> $ty {
+                fn super_fold_with<F:TypeFolder<'tcx>>(&self, _: &mut F) -> $ty {
                     *self
                 }
+
+                fn super_visit_with<F: TypeVisitor<'tcx>>(&self, _: &mut F) -> bool {
+                    false
+                }
             }
         )+
     }
@@ -519,50 +138,88 @@ macro_rules! CopyImpls {
 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) {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
         (self.0.fold_with(folder), self.1.fold_with(folder))
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.0.visit_with(visitor) || self.1.visit_with(visitor)
+    }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Option<T> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         self.as_ref().map(|t| t.fold_with(folder))
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|t| t.visit_with(visitor))
+    }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Rc<T> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         Rc::new((**self).fold_with(folder))
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        (**self).visit_with(visitor)
+    }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Box<T> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         let content: T = (**self).fold_with(folder);
         box content
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        (**self).visit_with(visitor)
+    }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Vec<T> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         self.iter().map(|t| t.fold_with(folder)).collect()
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|t| t.visit_with(visitor))
+    }
 }
 
 impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        folder.enter_region_binder();
+        let result = ty::Binder(self.0.fold_with(folder));
+        folder.exit_region_binder();
+        result
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_binder(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        visitor.enter_region_binder();
+        if self.0.visit_with(visitor) { return true }
+        visitor.exit_region_binder();
+        false
+    }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for P<[T]> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> P<[T]> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         self.iter().map(|t| t.fold_with(folder)).collect()
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|t| t.visit_with(visitor))
+    }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace<T> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> VecPerParamSpace<T> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
 
         // Things in the Fn space take place under an additional level
         // of region binding relative to the other spaces. This is
@@ -582,100 +239,325 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for VecPerParamSpace<T> {
         }
         result
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        let mut entered_region_binder = false;
+        let result = self.iter_enumerated().any(|(space, index, t)| {
+            if space == subst::FnSpace && index == 0 {
+                visitor.enter_region_binder();
+                entered_region_binder = true;
+            }
+            t.visit_with(visitor)
+        });
+        if entered_region_binder {
+            visitor.exit_region_binder();
+        }
+        result
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TraitTy<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        ty::TraitTy {
+            principal: self.principal.fold_with(folder),
+            bounds: self.bounds.fold_with(folder),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.principal.visit_with(visitor) || self.bounds.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Ty<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let sty = match self.sty {
+            ty::TyBox(typ) => ty::TyBox(typ.fold_with(folder)),
+            ty::TyRawPtr(ref tm) => ty::TyRawPtr(tm.fold_with(folder)),
+            ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz),
+            ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)),
+            ty::TyEnum(tid, ref substs) => {
+                let substs = substs.fold_with(folder);
+                ty::TyEnum(tid, folder.tcx().mk_substs(substs))
+            }
+            ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)),
+            ty::TyTuple(ref ts) => ty::TyTuple(ts.fold_with(folder)),
+            ty::TyBareFn(opt_def_id, ref f) => {
+                let bfn = f.fold_with(folder);
+                ty::TyBareFn(opt_def_id, folder.tcx().mk_bare_fn(bfn))
+            }
+            ty::TyRef(r, ref tm) => {
+                let r = r.fold_with(folder);
+                ty::TyRef(folder.tcx().mk_region(r), tm.fold_with(folder))
+            }
+            ty::TyStruct(did, ref substs) => {
+                let substs = substs.fold_with(folder);
+                ty::TyStruct(did, folder.tcx().mk_substs(substs))
+            }
+            ty::TyClosure(did, ref substs) => {
+                ty::TyClosure(did, substs.fold_with(folder))
+            }
+            ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)),
+            ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
+            ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
+            ty::TyParam(..) => self.sty.clone(),
+        };
+        folder.tcx().mk_ty(sty)
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_ty(*self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match self.sty {
+            ty::TyBox(typ) => typ.visit_with(visitor),
+            ty::TyRawPtr(ref tm) => tm.visit_with(visitor),
+            ty::TyArray(typ, _sz) => typ.visit_with(visitor),
+            ty::TySlice(typ) => typ.visit_with(visitor),
+            ty::TyEnum(_tid, ref substs) => substs.visit_with(visitor),
+            ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor),
+            ty::TyTuple(ref ts) => ts.visit_with(visitor),
+            ty::TyBareFn(_opt_def_id, ref f) => f.visit_with(visitor),
+            ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor),
+            ty::TyStruct(_did, ref substs) => substs.visit_with(visitor),
+            ty::TyClosure(_did, ref substs) => substs.visit_with(visitor),
+            ty::TyProjection(ref data) => data.visit_with(visitor),
+            ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
+            ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
+            ty::TyParam(..) => false,
+        }
+    }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        visitor.visit_ty(self)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::BareFnTy<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        ty::BareFnTy { sig: self.sig.fold_with(folder),
+                       abi: self.abi,
+                       unsafety: self.unsafety }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_bare_fn_ty(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.sig.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureTy<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+       ty::ClosureTy {
+            sig: self.sig.fold_with(folder),
+            unsafety: self.unsafety,
+            abi: self.abi,
+        }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_closure_ty(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.sig.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeAndMut<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_mt(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.ty.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnOutput<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            ty::FnConverging(ref ty) => ty::FnConverging(ty.fold_with(folder)),
+            ty::FnDiverging => ty::FnDiverging
+        }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_output(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            ty::FnConverging(ref ty) => ty.visit_with(visitor),
+            ty::FnDiverging => false,
+        }
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnSig<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        ty::FnSig { inputs: self.inputs.fold_with(folder),
+                    output: self.output.fold_with(folder),
+                    variadic: self.variadic }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_fn_sig(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.inputs.visit_with(visitor) || self.output.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitRef<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let substs = self.substs.fold_with(folder);
+        ty::TraitRef {
+            def_id: self.def_id,
+            substs: folder.tcx().mk_substs(substs),
+        }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_trait_ref(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.substs.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Region {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Region {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self {
+        *self
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_region(*self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
+        false
+    }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        visitor.visit_region(*self)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> subst::Substs<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let regions = match self.regions {
+            subst::ErasedRegions => subst::ErasedRegions,
+            subst::NonerasedRegions(ref regions) => {
+                subst::NonerasedRegions(regions.fold_with(folder))
+            }
+        };
+
+        subst::Substs { regions: regions,
+                        types: self.types.fold_with(folder) }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_substs(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.types.visit_with(visitor) || match self.regions {
+            subst::ErasedRegions => false,
+            subst::NonerasedRegions(ref regions) => regions.visit_with(visitor),
+        }
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureSubsts<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         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),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.func_substs.visit_with(visitor) || self.upvar_tys.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ItemSubsts<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::ItemSubsts {
             substs: self.substs.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.substs.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::adjustment::AutoRef<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            ty::adjustment::AutoPtr(r, m) => {
+                let r = r.fold_with(folder);
+                ty::adjustment::AutoPtr(folder.tcx().mk_region(r), m)
+            }
+            ty::adjustment::AutoUnsafe(m) => ty::adjustment::AutoUnsafe(m)
+        }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_autoref(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            ty::adjustment::AutoPtr(r, _m) => r.visit_with(visitor),
+            ty::adjustment::AutoUnsafe(_m) => false,
+        }
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> ty::BuiltinBounds {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self {
         *self
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
+        false
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ExistentialBounds<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        ty::ExistentialBounds {
+            region_bound: self.region_bound.fold_with(folder),
+            builtin_bounds: self.builtin_bounds,
+            projection_bounds: self.projection_bounds.fold_with(folder),
+        }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         folder.fold_existential_bounds(self)
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.region_bound.visit_with(visitor) || self.projection_bounds.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeParameterDef<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::TypeParameterDef {
             name: self.name,
             def_id: self.def_id,
@@ -686,10 +568,15 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
             object_lifetime_default: self.object_lifetime_default.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.default.visit_with(visitor) ||
+            self.object_lifetime_default.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ObjectLifetimeDefault {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
             ty::ObjectLifetimeDefault::Ambiguous =>
                 ty::ObjectLifetimeDefault::Ambiguous,
@@ -701,10 +588,17 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
                 ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            ty::ObjectLifetimeDefault::Specific(r) => r.visit_with(visitor),
+            _ => false,
+        }
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::RegionParameterDef {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::RegionParameterDef {
             name: self.name,
             def_id: self.def_id,
@@ -713,27 +607,39 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
             bounds: self.bounds.fold_with(folder)
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.bounds.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Generics<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::Generics {
             types: self.types.fold_with(folder),
             regions: self.regions.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.types.visit_with(visitor) || self.regions.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::GenericPredicates<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::GenericPredicates {
             predicates: self.predicates.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.predicates.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Predicate<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
             ty::Predicate::Trait(ref a) =>
                 ty::Predicate::Trait(a.fold_with(folder)),
@@ -751,71 +657,111 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
                 ty::Predicate::ObjectSafe(trait_def_id),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        match *self {
+            ty::Predicate::Trait(ref a) => a.visit_with(visitor),
+            ty::Predicate::Equate(ref binder) => binder.visit_with(visitor),
+            ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor),
+            ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor),
+            ty::Predicate::Projection(ref binder) => binder.visit_with(visitor),
+            ty::Predicate::WellFormed(data) => data.visit_with(visitor),
+            ty::Predicate::ObjectSafe(_trait_def_id) => false,
+        }
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionPredicate<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::ProjectionPredicate {
             projection_ty: self.projection_ty.fold_with(folder),
             ty: self.ty.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.projection_ty.visit_with(visitor) || self.ty.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionTy<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::ProjectionTy {
             trait_ref: self.trait_ref.fold_with(folder),
             item_name: self.item_name,
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.trait_ref.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::InstantiatedPredicates<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::InstantiatedPredicates {
             predicates: self.predicates.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.predicates.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::EquatePredicate(self.0.fold_with(folder),
                             self.1.fold_with(folder))
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.0.visit_with(visitor) || self.1.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitPredicate<'tcx> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::TraitPredicate {
             trait_ref: self.trait_ref.fold_with(folder)
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.trait_ref.visit_with(visitor)
+    }
 }
 
 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> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::OutlivesPredicate(self.0.fold_with(folder),
                               self.1.fold_with(folder))
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.0.visit_with(visitor) || self.1.visit_with(visitor)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ClosureUpvar<'tcx> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::ClosureUpvar {
             def: self.def,
             span: self.span,
             ty: self.ty.fold_with(folder),
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.ty.visit_with(visitor)
+    }
 }
 
 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> {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         ty::ParameterEnvironment {
             tcx: self.tcx,
             free_substs: self.free_substs.fold_with(folder),
@@ -826,4 +772,23 @@ impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where '
             free_id_outlive: self.free_id_outlive,
         }
     }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.free_substs.visit_with(visitor) ||
+            self.implicit_region_bound.visit_with(visitor) ||
+            self.caller_bounds.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx>  {
+    fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        ty::TypeScheme {
+            generics: self.generics.fold_with(folder),
+            ty: self.ty.fold_with(folder),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.generics.visit_with(visitor) || self.ty.visit_with(visitor)
+    }
 }
diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs
index 6f72d3df07e..7e8d38ae8e7 100644
--- a/src/librustc/middle/ty/sty.rs
+++ b/src/librustc/middle/ty/sty.rs
@@ -15,8 +15,7 @@ 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 middle::ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyS, TypeFoldable};
 use util::common::ErrorReported;
 
 use collections::enum_set::{self, EnumSet, CLike};
diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs
index 0517769356f..af23efe2bf4 100644
--- a/src/librustc/middle/ty/util.rs
+++ b/src/librustc/middle/ty/util.rs
@@ -18,9 +18,8 @@ use middle::subst::{self, Subst, Substs};
 use middle::infer;
 use middle::pat_util;
 use middle::traits;
-use middle::ty::{self, Ty, TypeAndMut, TypeFlags};
+use middle::ty::{self, Ty, TypeAndMut, TypeFlags, TypeFoldable};
 use middle::ty::{Disr, ParameterEnvironment};
-use middle::ty::{HasTypeFlags, RegionEscape};
 use middle::ty::TypeVariants::*;
 use util::num::ToPrimitive;
 
diff --git a/src/librustc/middle/ty/wf.rs b/src/librustc/middle/ty/wf.rs
index d015711fa64..5f0fc306c24 100644
--- a/src/librustc/middle/ty/wf.rs
+++ b/src/librustc/middle/ty/wf.rs
@@ -13,7 +13,7 @@ use middle::infer::InferCtxt;
 use middle::ty::outlives::{self, Component};
 use middle::subst::Substs;
 use middle::traits;
-use middle::ty::{self, RegionEscape, ToPredicate, Ty};
+use middle::ty::{self, ToPredicate, Ty, TypeFoldable};
 use std::iter::once;
 use syntax::ast;
 use syntax::codemap::Span;
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 11d3068f065..77e39bba54a 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -17,8 +17,7 @@ use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyBareFn};
 use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple};
 use middle::ty::TyClosure;
 use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
-use middle::ty::{self, Ty, HasTypeFlags};
-use middle::ty::fold::TypeFoldable;
+use middle::ty::{self, Ty, TypeFoldable};
 
 use std::fmt;
 use syntax::{abi};
@@ -252,10 +251,13 @@ 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)
-                                              -> TraitAndProjections<'tcx> {
+    fn super_fold_with<F:ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder))
     }
+
+    fn super_visit_with<V: ty::fold::TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.0.visit_with(visitor) || self.1.visit_with(visitor)
+    }
 }
 
 impl<'tcx> fmt::Display for TraitAndProjections<'tcx> {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 7bcf3276da7..8f3366eacb3 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -21,7 +21,7 @@ use rustc_typeck::middle::resolve_lifetime;
 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::{self, Ty, TypeFoldable};
 use rustc_typeck::middle::ty::relate::TypeRelation;
 use rustc_typeck::middle::infer::{self, TypeOrigin};
 use rustc_typeck::middle::infer::lub::Lub;
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 0b48cad36ba..b8dfb9f74c6 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -33,7 +33,7 @@ use middle::def_id::{DefId, DefIndex};
 use middle::lang_items;
 use middle::subst;
 use middle::ty::{ImplContainer, TraitContainer};
-use middle::ty::{self, RegionEscape, Ty};
+use middle::ty::{self, Ty, TypeFoldable};
 
 use rustc::mir;
 use rustc::mir::visit::MutVisitor;
diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs
index c7a5faed35c..5a48d6019d6 100644
--- a/src/librustc_metadata/tydecode.rs
+++ b/src/librustc_metadata/tydecode.rs
@@ -22,7 +22,7 @@ use middle::def_id::{DefId, DefIndex};
 use middle::region;
 use middle::subst;
 use middle::subst::VecPerParamSpace;
-use middle::ty::{self, ToPredicate, Ty, HasTypeFlags};
+use middle::ty::{self, ToPredicate, Ty, TypeFoldable};
 
 use rbml;
 use rbml::leb128;
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 1c3732d3ce4..d694374acc9 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -42,7 +42,7 @@ use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
 use middle::weak_lang_items;
 use middle::pat_util::simple_name;
 use middle::subst::Substs;
-use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::{self, Ty, TypeFoldable};
 use rustc::dep_graph::DepNode;
 use rustc::front::map as hir_map;
 use rustc::util::common::time;
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index d33beab9313..e3b7502b69c 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -50,7 +50,7 @@ use trans::meth;
 use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of;
-use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
+use middle::ty::{self, Ty, TypeFoldable};
 use middle::ty::MethodCall;
 use rustc_front::hir;
 
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 964e981aec0..5046c2e2920 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -37,7 +37,7 @@ use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of;
 use middle::traits;
-use middle::ty::{self, HasTypeFlags, Ty};
+use middle::ty::{self, Ty};
 use middle::ty::fold::{TypeFolder, TypeFoldable};
 use rustc_front::hir;
 use rustc::mir::repr::Mir;
@@ -469,7 +469,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
     }
 
     pub fn monomorphize<T>(&self, value: &T) -> T
-        where T : TypeFoldable<'tcx> + HasTypeFlags
+        where T : TypeFoldable<'tcx>
     {
         monomorphize::apply_param_substs(self.ccx.tcx(),
                                          self.param_substs,
@@ -650,7 +650,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
     }
 
     pub fn monomorphize<T>(&self, value: &T) -> T
-        where T : TypeFoldable<'tcx> + HasTypeFlags
+        where T : TypeFoldable<'tcx>
     {
         monomorphize::apply_param_substs(self.tcx(),
                                          self.fcx.param_substs,
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index d8a3cc50ff4..07cc6ec8fbd 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -35,7 +35,7 @@ use trans::glue;
 use trans::type_of;
 use trans::machine;
 use trans::type_::Type;
-use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::{self, Ty, TypeFoldable};
 use middle::subst::Substs;
 use rustc::dep_graph::DepNode;
 use rustc_front::hir;
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 7a1cbf20607..bd12dd8c3ef 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -34,7 +34,7 @@ use trans::machine;
 use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of::*;
-use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::{self, Ty, TypeFoldable};
 use middle::ty::MethodCall;
 
 use syntax::ast;
diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs
index 0f4a0407298..e461a1c05bc 100644
--- a/src/librustc_trans/trans/mir/constant.rs
+++ b/src/librustc_trans/trans/mir/constant.rs
@@ -11,7 +11,7 @@
 use back::abi;
 use llvm::ValueRef;
 use middle::subst::Substs;
-use middle::ty::{Ty, HasTypeFlags};
+use middle::ty::{Ty, TypeFoldable};
 use rustc::middle::const_eval::ConstVal;
 use rustc::mir::repr as mir;
 use trans::common::{self, Block, C_bool, C_bytes, C_floating_f64, C_integral, C_str_slice};
diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs
index 737c3dace2e..0e2387e3e34 100644
--- a/src/librustc_trans/trans/mir/did.rs
+++ b/src/librustc_trans/trans/mir/did.rs
@@ -12,7 +12,7 @@
 
 use syntax::codemap::DUMMY_SP;
 use rustc::front::map;
-use rustc::middle::ty::{self, Ty, HasTypeFlags};
+use rustc::middle::ty::{self, Ty, TypeFoldable};
 use rustc::middle::subst::Substs;
 use rustc::middle::const_eval;
 use rustc::middle::def_id::DefId;
diff --git a/src/librustc_trans/trans/mir/lvalue.rs b/src/librustc_trans/trans/mir/lvalue.rs
index f7245879e2d..ba0427ec3d6 100644
--- a/src/librustc_trans/trans/mir/lvalue.rs
+++ b/src/librustc_trans/trans/mir/lvalue.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::middle::ty::{self, Ty, HasTypeFlags};
+use rustc::middle::ty::{self, Ty, TypeFoldable};
 use rustc::mir::repr as mir;
 use rustc::mir::tcx::LvalueTy;
 use trans::adt;
diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs
index 3a3087b4788..6240473b78e 100644
--- a/src/librustc_trans/trans/mir/operand.rs
+++ b/src/librustc_trans/trans/mir/operand.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::middle::ty::{Ty, HasTypeFlags};
+use rustc::middle::ty::{Ty, TypeFoldable};
 use rustc::mir::repr as mir;
 use trans::base;
 use trans::common::{self, Block};
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 80a86bac26b..416c1908c97 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -23,7 +23,7 @@ use trans::base;
 use trans::common::*;
 use trans::declare;
 use trans::foreign;
-use middle::ty::{self, HasTypeFlags, Ty};
+use middle::ty::{self, Ty};
 use rustc::front::map as hir_map;
 
 use rustc_front::hir;
@@ -299,7 +299,7 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
                                   param_substs: &Substs<'tcx>,
                                   value: &T)
                                   -> T
-    where T : TypeFoldable<'tcx> + HasTypeFlags
+    where T : TypeFoldable<'tcx>
 {
     let substituted = value.subst(tcx, param_substs);
     normalize_associated_type(tcx, &substituted)
diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs
index e65a212e41b..8696bdd60e2 100644
--- a/src/librustc_trans/trans/type_of.rs
+++ b/src/librustc_trans/trans/type_of.rs
@@ -17,7 +17,7 @@ use trans::adt;
 use trans::common::*;
 use trans::foreign;
 use trans::machine;
-use middle::ty::{self, RegionEscape, Ty};
+use middle::ty::{self, Ty, TypeFoldable};
 
 use trans::type_::Type;
 
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 607daa82374..98effeefad2 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -57,7 +57,7 @@ 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, Ty, ToPredicate, HasTypeFlags};
+use middle::ty::{self, Ty, ToPredicate, TypeFoldable};
 use middle::ty::wf::object_region_bounds;
 use require_c_abi_if_variadic;
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 588dee57c52..926d7fd6e25 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -14,7 +14,7 @@ use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
 use middle::pat_util::pat_is_resolved_const;
 use middle::privacy::{AllPublic, LastMod};
 use middle::subst::Substs;
-use middle::ty::{self, Ty, HasTypeFlags, LvaluePreference};
+use middle::ty::{self, Ty, TypeFoldable, LvaluePreference};
 use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
 use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
 use check::{check_expr_with_lvalue_pref};
diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs
index 8dc95562e44..91916efa882 100644
--- a/src/librustc_typeck/check/assoc.rs
+++ b/src/librustc_typeck/check/assoc.rs
@@ -11,7 +11,6 @@
 use middle::infer::InferCtxt;
 use middle::traits::{self, FulfillmentContext, Normalized, MiscObligation,
                      SelectionContext, ObligationCause};
-use middle::ty::HasTypeFlags;
 use middle::ty::fold::TypeFoldable;
 use syntax::ast;
 use syntax::codemap::Span;
@@ -23,7 +22,7 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                                 body_id: ast::NodeId,
                                                 value: &T)
                                                 -> T
-    where T : TypeFoldable<'tcx> + HasTypeFlags
+    where T : TypeFoldable<'tcx>
 {
     debug!("normalize_associated_types_in(value={:?})", value);
     let mut selcx = SelectionContext::new(infcx);
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 90e67944ef9..fd6c4f44ba4 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -45,7 +45,7 @@ use super::structurally_resolved_type;
 
 use lint;
 use middle::def_id::DefId;
-use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::{self, Ty, TypeFoldable};
 use middle::ty::cast::{CastKind, CastTy};
 use syntax::codemap::Span;
 use rustc_front::hir;
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index a961268c6c4..44b36294cb4 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -17,7 +17,7 @@ use middle::def_id::DefId;
 use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod};
 use middle::subst;
 use middle::traits;
-use middle::ty::{self, RegionEscape, ToPredicate, ToPolyTraitRef, TraitRef};
+use middle::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
 use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
 use middle::infer;
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 3bf24aba624..44dd0ef7b17 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -19,9 +19,7 @@ use middle::def_id::DefId;
 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::{self, NoPreference, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
 use middle::infer;
 use middle::infer::{InferCtxt, TypeOrigin};
 use syntax::ast;
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 65b0d589275..560e84b52d1 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -16,7 +16,7 @@ use CrateCtxt;
 use astconv::AstConv;
 use check::{self, FnCtxt};
 use front::map as hir_map;
-use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, HasTypeFlags};
+use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
 use middle::cstore::{self, CrateStore, DefLike};
 use middle::def;
 use middle::def_id::DefId;
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 14adc84f701..3cf75483fea 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -97,7 +97,7 @@ use middle::traits::{self, report_fulfillment_errors};
 use middle::ty::{GenericPredicates, TypeScheme};
 use middle::ty::{Disr, ParamTy, ParameterEnvironment};
 use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
-use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
+use middle::ty::{self, ToPolyTraitRef, Ty};
 use middle::ty::{MethodCall, MethodCallee};
 use middle::ty::adjustment;
 use middle::ty::error::TypeError;
@@ -318,7 +318,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
                                         body_id: ast::NodeId,
                                         value: &T)
                                         -> T
-        where T : TypeFoldable<'tcx> + HasTypeFlags
+        where T : TypeFoldable<'tcx>
     {
         let mut fulfillment_cx = self.infcx.fulfillment_cx.borrow_mut();
         assoc::normalize_associated_types_in(&self.infcx,
@@ -1334,7 +1334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                   substs: &Substs<'tcx>,
                                   value: &T)
                                   -> T
-        where T : TypeFoldable<'tcx> + HasTypeFlags
+        where T : TypeFoldable<'tcx>
     {
         let value = value.subst(self.tcx(), substs);
         let result = self.normalize_associated_types_in(span, &value);
@@ -1360,7 +1360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
 
     fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
-        where T : TypeFoldable<'tcx> + HasTypeFlags
+        where T : TypeFoldable<'tcx>
     {
         self.inh.normalize_associated_types_in(span, self.body_id, value)
     }
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index c5a36fb4ada..f4841b75d13 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -19,7 +19,7 @@ use super::{
     FnCtxt,
 };
 use middle::def_id::DefId;
-use middle::ty::{Ty, HasTypeFlags, PreferMutLvalue};
+use middle::ty::{Ty, TypeFoldable, PreferMutLvalue};
 use syntax::ast;
 use syntax::parse::token;
 use rustc_front::hir;
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 801700ba673..47cd31d9898 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -92,7 +92,7 @@ use middle::mem_categorization::Categorization;
 use middle::region::{self, CodeExtent};
 use middle::subst::Substs;
 use middle::traits;
-use middle::ty::{self, RegionEscape, Ty, MethodCall, HasTypeFlags};
+use middle::ty::{self, Ty, MethodCall, TypeFoldable};
 use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, TypeOrigin, VerifyBound};
 use middle::pat_util;
 use middle::ty::adjustment;
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 1536f13a1d5..c2abb074efa 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -17,7 +17,7 @@ use astconv::AstConv;
 use check::FnCtxt;
 use middle::def_id::DefId;
 use middle::pat_util;
-use middle::ty::{self, Ty, MethodCall, MethodCallee, HasTypeFlags};
+use middle::ty::{self, Ty, MethodCall, MethodCallee};
 use middle::ty::adjustment;
 use middle::ty::fold::{TypeFolder,TypeFoldable};
 use middle::infer;
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 07c920829d9..2c8fedb46a7 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -20,8 +20,7 @@ use middle::def_id::DefId;
 use middle::lang_items::UnsizeTraitLangItem;
 use middle::subst::{self, Subst};
 use middle::traits;
-use middle::ty;
-use middle::ty::RegionEscape;
+use middle::ty::{self, TypeFoldable};
 use middle::ty::{ImplOrTraitItemId, ConstTraitItemId};
 use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
 use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 580d200eb73..867d12a1def 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -103,7 +103,7 @@ use front::map as hir_map;
 use middle::def;
 use middle::infer::{self, TypeOrigin};
 use middle::subst;
-use middle::ty::{self, Ty, HasTypeFlags};
+use middle::ty::{self, Ty, TypeFoldable};
 use session::config;
 use util::common::time;
 use rustc_front::hir;