about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-04-29 08:30:54 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-05-11 04:14:58 +0300
commit20652162ca5e330cb9d637924c6d93cb43fbb6aa (patch)
treea448be3895c6865ba828471f76309e234479295c
parent8f72d8127fd91911b80b8b8b9e0f51f6e001d748 (diff)
downloadrust-20652162ca5e330cb9d637924c6d93cb43fbb6aa.tar.gz
rust-20652162ca5e330cb9d637924c6d93cb43fbb6aa.zip
rustc: More interning for data used in Ty<'tcx>.
-rw-r--r--src/librustc/infer/mod.rs6
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc/mir/repr.rs2
-rw-r--r--src/librustc/mir/tcx.rs6
-rw-r--r--src/librustc/mir/visit.rs4
-rw-r--r--src/librustc/traits/project.rs4
-rw-r--r--src/librustc/traits/select.rs32
-rw-r--r--src/librustc/traits/specialize/mod.rs4
-rw-r--r--src/librustc/traits/structural_impls.rs3
-rw-r--r--src/librustc/traits/util.rs2
-rw-r--r--src/librustc/ty/adjustment.rs4
-rw-r--r--src/librustc/ty/context.rs73
-rw-r--r--src/librustc/ty/fold.rs15
-rw-r--r--src/librustc/ty/layout.rs8
-rw-r--r--src/librustc/ty/mod.rs24
-rw-r--r--src/librustc/ty/outlives.rs2
-rw-r--r--src/librustc/ty/relate.rs66
-rw-r--r--src/librustc/ty/structural_impls.rs111
-rw-r--r--src/librustc/ty/sty.rs37
-rw-r--r--src/librustc/ty/subst.rs4
-rw-r--r--src/librustc/util/ppaux.rs4
-rw-r--r--src/librustc_const_eval/eval.rs6
-rw-r--r--src/librustc_driver/test.rs4
-rw-r--r--src/librustc_lint/builtin.rs6
-rw-r--r--src/librustc_metadata/astencode.rs2
-rw-r--r--src/librustc_metadata/decoder.rs2
-rw-r--r--src/librustc_metadata/tydecode.rs6
-rw-r--r--src/librustc_metadata/tyencode.rs8
-rw-r--r--src/librustc_mir/hair/cx/expr.rs8
-rw-r--r--src/librustc_mir/hair/mod.rs2
-rw-r--r--src/librustc_mir/transform/erase_regions.rs2
-rw-r--r--src/librustc_mir/transform/type_check.rs4
-rw-r--r--src/librustc_trans/callee.rs16
-rw-r--r--src/librustc_trans/closure.rs32
-rw-r--r--src/librustc_trans/collector.rs37
-rw-r--r--src/librustc_trans/common.rs4
-rw-r--r--src/librustc_trans/consts.rs13
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs10
-rw-r--r--src/librustc_trans/debuginfo/mod.rs2
-rw-r--r--src/librustc_trans/debuginfo/type_names.rs2
-rw-r--r--src/librustc_trans/expr.rs2
-rw-r--r--src/librustc_trans/intrinsic.rs8
-rw-r--r--src/librustc_trans/mir/constant.rs6
-rw-r--r--src/librustc_trans/mir/rvalue.rs2
-rw-r--r--src/librustc_typeck/astconv.rs15
-rw-r--r--src/librustc_typeck/check/_match.rs4
-rw-r--r--src/librustc_typeck/check/callee.rs2
-rw-r--r--src/librustc_typeck/check/cast.rs3
-rw-r--r--src/librustc_typeck/check/closure.rs2
-rw-r--r--src/librustc_typeck/check/coercion.rs8
-rw-r--r--src/librustc_typeck/check/compare_method.rs16
-rw-r--r--src/librustc_typeck/check/dropck.rs4
-rw-r--r--src/librustc_typeck/check/intrinsic.rs11
-rw-r--r--src/librustc_typeck/check/method/confirm.rs5
-rw-r--r--src/librustc_typeck/check/method/mod.rs5
-rw-r--r--src/librustc_typeck/check/mod.rs11
-rw-r--r--src/librustc_typeck/check/wfcheck.rs4
-rw-r--r--src/librustc_typeck/check/writeback.rs2
-rw-r--r--src/librustc_typeck/collect.rs26
-rw-r--r--src/librustc_typeck/lib.rs10
-rw-r--r--src/librustc_typeck/variance/constraints.rs2
-rw-r--r--src/librustdoc/clean/mod.rs2
62 files changed, 402 insertions, 327 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 28bb99b30f9..fdb4c3500c6 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1016,7 +1016,7 @@ pub fn drain_fulfillment_cx<T>(&self,
     pub fn fresh_substs_for_generics(&self,
                                      span: Span,
                                      generics: &ty::Generics<'tcx>)
-                                     -> subst::Substs<'tcx>
+                                     -> &'tcx subst::Substs<'tcx>
     {
         let type_params = subst::VecPerParamSpace::empty();
 
@@ -1034,7 +1034,7 @@ pub fn drain_fulfillment_cx<T>(&self,
                 generics.types.get_slice(*space));
         }
 
-        return substs;
+        self.tcx.mk_substs(substs)
     }
 
     /// Given a set of generics defined on a trait, returns a substitution mapping each output
@@ -1533,7 +1533,7 @@ pub fn drain_fulfillment_cx<T>(&self,
 
     pub fn closure_type(&self,
                         def_id: DefId,
-                        substs: &ty::ClosureSubsts<'tcx>)
+                        substs: ty::ClosureSubsts<'tcx>)
                         -> ty::ClosureTy<'tcx>
     {
         let closure_ty =
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index fd0ef992f42..de38c51aabe 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1462,7 +1462,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
         let fn_ty = self.ir.tcx.node_id_to_type(id);
         match fn_ty.sty {
-            ty::TyClosure(closure_def_id, ref substs) =>
+            ty::TyClosure(closure_def_id, substs) =>
                 self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
             _ => fn_ty.fn_ret()
         }
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 9f8a3dbfa8f..458cb28144a 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -816,7 +816,7 @@ pub enum AggregateKind<'tcx> {
     Vec,
     Tuple,
     Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>),
-    Closure(DefId, &'tcx ClosureSubsts<'tcx>),
+    Closure(DefId, ClosureSubsts<'tcx>),
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 6d2adef6f80..7041945a873 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -82,10 +82,9 @@ impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
         match *self {
             LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.fold_with(folder) },
             LvalueTy::Downcast { adt_def, substs, variant_index } => {
-                let substs = substs.fold_with(folder);
                 LvalueTy::Downcast {
                     adt_def: adt_def,
-                    substs: folder.tcx().mk_substs(substs),
+                    substs: substs.fold_with(folder),
                     variant_index: variant_index
                 }
             }
@@ -209,8 +208,7 @@ impl<'a, 'tcx> Mir<'tcx> {
                         Some(def.type_scheme(tcx).ty.subst(tcx, substs))
                     }
                     AggregateKind::Closure(did, substs) => {
-                        Some(tcx.mk_closure_from_closure_substs(
-                            did, Box::new(substs.clone())))
+                        Some(tcx.mk_closure_from_closure_substs(did, substs))
                     }
                 }
             }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index f6a241004b3..88460651352 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -197,7 +197,7 @@ macro_rules! make_mir_visitor {
             }
 
             fn visit_closure_substs(&mut self,
-                                    substs: & $($mutability)* &'tcx ClosureSubsts<'tcx>) {
+                                    substs: & $($mutability)* ClosureSubsts<'tcx>) {
                 self.super_closure_substs(substs);
             }
 
@@ -681,7 +681,7 @@ macro_rules! make_mir_visitor {
             }
 
             fn super_closure_substs(&mut self,
-                                    _substs: & $($mutability)* &'tcx ClosureSubsts<'tcx>) {
+                                    _substs: & $($mutability)* ClosureSubsts<'tcx>) {
             }
 
             fn super_const_val(&mut self, _substs: & $($mutability)* ConstVal) {
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index d057b2da52a..4c338219ffb 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -259,7 +259,7 @@ fn consider_unification_despite_ambiguity<'cx, 'gcx, 'tcx>(
     debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}",
            self_ty.sty);
     match self_ty.sty {
-        ty::TyClosure(closure_def_id, ref substs) => {
+        ty::TyClosure(closure_def_id, substs) => {
             let closure_typer = selcx.closure_typer();
             let closure_type = closure_typer.closure_type(closure_def_id, substs);
             let ty::Binder((_, ret_type)) =
@@ -1021,7 +1021,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
     -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
 {
     let closure_typer = selcx.closure_typer();
-    let closure_type = closure_typer.closure_type(vtable.closure_def_id, &vtable.substs);
+    let closure_type = closure_typer.closure_type(vtable.closure_def_id, vtable.substs);
     let Normalized {
         value: closure_type,
         mut obligations
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 0d8f2f7cabf..7d9a256a6e0 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -197,7 +197,7 @@ enum SelectionCandidate<'tcx> {
     /// Implementation of a `Fn`-family trait by one of the anonymous types
     /// generated for a `||` expression. The ty::ClosureKind informs the
     /// confirmation step what ClosureKind obligation to emit.
-    ClosureCandidate(/* closure */ DefId, &'tcx ty::ClosureSubsts<'tcx>, ty::ClosureKind),
+    ClosureCandidate(/* closure */ DefId, ty::ClosureSubsts<'tcx>, ty::ClosureKind),
 
     /// Implementation of a `Fn`-family trait by one of the anonymous
     /// types generated for a fn pointer type (e.g., `fn(int)->int`)
@@ -1270,7 +1270,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         // type/region parameters
         let self_ty = *obligation.self_ty().skip_binder();
         let (closure_def_id, substs) = match self_ty.sty {
-            ty::TyClosure(id, ref substs) => (id, substs),
+            ty::TyClosure(id, substs) => (id, substs),
             ty::TyInfer(ty::TyVar(_)) => {
                 debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
                 candidates.ambiguous = true;
@@ -1707,16 +1707,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
             ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never,
 
-            ty::TyTuple(ref tys) => {
+            ty::TyTuple(tys) => {
                 // FIXME(#33242) we only need to constrain the last field
-                Where(ty::Binder(tys.clone()))
+                Where(ty::Binder(tys.to_vec()))
             }
 
             ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
                 Where(ty::Binder(match sized_crit.sty {
-                    ty::TyTuple(ref tys) => tys.to_owned().subst(self.tcx(), substs),
+                    ty::TyTuple(tys) => tys.to_vec().subst(self.tcx(), substs),
                     ty::TyBool => vec![],
                     _ => vec![sized_crit.subst(self.tcx(), substs)]
                 }))
@@ -1763,9 +1763,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 Where(ty::Binder(vec![element_ty]))
             }
 
-            ty::TyTuple(ref tys) => {
+            ty::TyTuple(tys) => {
                 // (*) binder moved here
-                Where(ty::Binder(tys.clone()))
+                Where(ty::Binder(tys.to_vec()))
             }
 
             ty::TyStruct(..) | ty::TyEnum(..) | ty::TyProjection(..) | ty::TyParam(..) => {
@@ -1842,7 +1842,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
             ty::TyTuple(ref tys) => {
                 // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-                tys.clone()
+                tys.to_vec()
             }
 
             ty::TyClosure(_, ref substs) => {
@@ -1854,7 +1854,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 // OIBIT interact? That is, there is no way to say
                 // "make me invariant with respect to this TYPE, but
                 // do not act as though I can reach it"
-                substs.upvar_tys.clone()
+                substs.upvar_tys.to_vec()
             }
 
             // for `PhantomData<T>`, we pass `T`
@@ -2188,7 +2188,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
     fn vtable_impl(&mut self,
                    impl_def_id: DefId,
-                   mut substs: Normalized<'tcx, Substs<'tcx>>,
+                   mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>,
                    cause: ObligationCause<'tcx>,
                    recursion_depth: usize,
                    skol_map: infer::SkolemizationMap,
@@ -2221,7 +2221,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         impl_obligations.append(&mut substs.obligations);
 
         VtableImplData { impl_def_id: impl_def_id,
-                         substs: self.tcx().mk_substs(substs.value),
+                         substs: substs.value,
                          nested: impl_obligations }
     }
 
@@ -2311,7 +2311,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn confirm_closure_candidate(&mut self,
                                  obligation: &TraitObligation<'tcx>,
                                  closure_def_id: DefId,
-                                 substs: &ty::ClosureSubsts<'tcx>,
+                                 substs: ty::ClosureSubsts<'tcx>,
                                  kind: ty::ClosureKind)
                                  -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>,
                                            SelectionError<'tcx>>
@@ -2586,7 +2586,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     impl_def_id: DefId,
                     obligation: &TraitObligation<'tcx>,
                     snapshot: &infer::CombinedSnapshot)
-                    -> (Normalized<'tcx, Substs<'tcx>>, infer::SkolemizationMap)
+                    -> (Normalized<'tcx, &'tcx Substs<'tcx>>, infer::SkolemizationMap)
     {
         match self.match_impl(impl_def_id, obligation, snapshot) {
             Ok((substs, skol_map)) => (substs, skol_map),
@@ -2602,7 +2602,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                   impl_def_id: DefId,
                   obligation: &TraitObligation<'tcx>,
                   snapshot: &infer::CombinedSnapshot)
-                  -> Result<(Normalized<'tcx, Substs<'tcx>>,
+                  -> Result<(Normalized<'tcx, &'tcx Substs<'tcx>>,
                              infer::SkolemizationMap), ()>
     {
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
@@ -2752,7 +2752,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn closure_trait_ref_unnormalized(&mut self,
                                       obligation: &TraitObligation<'tcx>,
                                       closure_def_id: DefId,
-                                      substs: &ty::ClosureSubsts<'tcx>)
+                                      substs: ty::ClosureSubsts<'tcx>)
                                       -> ty::PolyTraitRef<'tcx>
     {
         let closure_type = self.infcx.closure_type(closure_def_id, substs);
@@ -2773,7 +2773,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn closure_trait_ref(&mut self,
                          obligation: &TraitObligation<'tcx>,
                          closure_def_id: DefId,
-                         substs: &ty::ClosureSubsts<'tcx>)
+                         substs: ty::ClosureSubsts<'tcx>)
                          -> Normalized<'tcx, ty::PolyTraitRef<'tcx>>
     {
         let trait_ref = self.closure_trait_ref_unnormalized(
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index a4c75e4307a..9212c54eb7d 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -96,7 +96,7 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                       specializaiton failed to hold")
             })
         }
-        specialization_graph::Node::Trait(..) => source_trait_ref.substs.clone(),
+        specialization_graph::Node::Trait(..) => source_trait_ref.substs,
     };
 
     // directly inherent the method generics, since those do not vary across impls
@@ -171,7 +171,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                        source_trait_ref: ty::TraitRef<'tcx>,
                                        target_impl: DefId)
-                                       -> Result<Substs<'tcx>, ()> {
+                                       -> Result<&'tcx Substs<'tcx>, ()> {
     infcx.commit_if_ok(|_| {
         let selcx = &mut SelectionContext::new(&infcx);
         let target_substs = fresh_type_vars_for_impl(&infcx, DUMMY_SP, target_impl);
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index a8ba9655abb..8d3f7fab38f 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -173,10 +173,9 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
 
 impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let substs = self.substs.fold_with(folder);
         traits::VtableImplData {
             impl_def_id: self.impl_def_id,
-            substs: folder.tcx().mk_substs(substs),
+            substs: self.substs.fold_with(folder),
             nested: self.nested.fold_with(folder),
         }
     }
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 3b90586810e..55fb8beee01 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -356,7 +356,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a,
 pub fn fresh_type_vars_for_impl<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                                 span: Span,
                                                 impl_def_id: DefId)
-                                                -> Substs<'tcx>
+                                                -> &'tcx Substs<'tcx>
 {
     let tcx = infcx.tcx;
     let impl_generics = tcx.lookup_item_type(impl_def_id).generics;
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index 58f24a5c6cb..71e49031347 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -156,9 +156,7 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
                 match *adjustment {
                     AdjustReifyFnPointer => {
                         match self.sty {
-                            ty::TyFnDef(_, _, b) => {
-                                tcx.mk_ty(ty::TyFnPtr(b))
-                            }
+                            ty::TyFnDef(_, _, f) => tcx.mk_fn_ptr(f),
                             _ => {
                                 bug!("AdjustReifyFnPointer adjustment on non-fn-item: {:?}",
                                      self);
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index c493942aa09..a42d256dbc3 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -53,6 +53,7 @@ use hir;
 pub struct CtxtArenas<'tcx> {
     // internings
     type_: TypedArena<TyS<'tcx>>,
+    type_list: TypedArena<Vec<Ty<'tcx>>>,
     substs: TypedArena<Substs<'tcx>>,
     bare_fn: TypedArena<BareFnTy<'tcx>>,
     region: TypedArena<Region>,
@@ -68,6 +69,7 @@ impl<'tcx> CtxtArenas<'tcx> {
     pub fn new() -> CtxtArenas<'tcx> {
         CtxtArenas {
             type_: TypedArena::new(),
+            type_list: TypedArena::new(),
             substs: TypedArena::new(),
             bare_fn: TypedArena::new(),
             region: TypedArena::new(),
@@ -87,6 +89,7 @@ struct CtxtInterners<'tcx> {
     /// Specifically use a speedy hash algorithm for these hash sets,
     /// they're accessed quite often.
     type_: RefCell<FnvHashSet<InternedTy<'tcx>>>,
+    type_list: RefCell<FnvHashSet<InternedTyList<'tcx>>>,
     substs: RefCell<FnvHashSet<InternedSubsts<'tcx>>>,
     bare_fn: RefCell<FnvHashSet<&'tcx BareFnTy<'tcx>>>,
     region: RefCell<FnvHashSet<&'tcx Region>>,
@@ -99,6 +102,7 @@ impl<'tcx> CtxtInterners<'tcx> {
         CtxtInterners {
             arenas: arenas,
             type_: RefCell::new(FnvHashSet()),
+            type_list: RefCell::new(FnvHashSet()),
             substs: RefCell::new(FnvHashSet()),
             bare_fn: RefCell::new(FnvHashSet()),
             region: RefCell::new(FnvHashSet()),
@@ -228,19 +232,19 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> {
     pub fn closure_type(this: &RefCell<Self>,
                         tcx: TyCtxt<'a, 'gcx, 'tcx>,
                         def_id: DefId,
-                        substs: &ClosureSubsts<'tcx>)
+                        substs: ClosureSubsts<'tcx>)
                         -> ty::ClosureTy<'tcx>
     {
         // If this is a local def-id, it should be inserted into the
         // tables by typeck; else, it will be retreived from
         // the external crate metadata.
         if let Some(ty) = this.borrow().closure_tys.get(&def_id) {
-            return ty.subst(tcx, &substs.func_substs);
+            return ty.subst(tcx, substs.func_substs);
         }
 
         let ty = tcx.sess.cstore.closure_ty(tcx.global_tcx(), def_id);
         this.borrow_mut().closure_tys.insert(def_id, ty.clone());
-        ty.subst(tcx, &substs.func_substs)
+        ty.subst(tcx, substs.func_substs)
     }
 }
 
@@ -742,6 +746,23 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for &'a [Ty<'a>] {
+    type Lifted = &'tcx [Ty<'tcx>];
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx [Ty<'tcx>]> {
+        if let Some(&InternedTyList { list }) = tcx.interners.type_list.borrow().get(*self) {
+            if *self as *const _ == list as *const _ {
+                return Some(list);
+            }
+        }
+        // Also try in the global tcx if we're not that.
+        if !tcx.is_global() {
+            self.lift_to_tcx(tcx.global_tcx())
+        } else {
+            None
+        }
+    }
+}
+
 
 pub mod tls {
     use super::{GlobalCtxt, TyCtxt};
@@ -914,6 +935,18 @@ impl<'tcx: 'lcx, 'lcx> Borrow<TypeVariants<'lcx>> for InternedTy<'tcx> {
     }
 }
 
+/// An entry in the type list interner.
+#[derive(PartialEq, Eq, Hash)]
+struct InternedTyList<'tcx> {
+    list: &'tcx [Ty<'tcx>]
+}
+
+impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for InternedTyList<'tcx> {
+    fn borrow<'a>(&'a self) -> &'a [Ty<'lcx>] {
+        self.list
+    }
+}
+
 /// An entry in the substs interner.
 #[derive(PartialEq, Eq, Hash)]
 struct InternedSubsts<'tcx> {
@@ -933,6 +966,18 @@ fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+    pub fn mk_type_list(self, list: Vec<Ty<'tcx>>) -> &'tcx [Ty<'tcx>] {
+        if let Some(interned) = self.interners.type_list.borrow().get(&list[..]) {
+            return interned.list;
+        }
+
+        let list = self.interners.arenas.type_list.alloc(list);
+        self.interners.type_list.borrow_mut().insert(InternedTyList {
+            list: list
+        });
+        list
+    }
+
     // Type constructors
     pub fn mk_substs(self, substs: Substs<'tcx>) -> &'tcx Substs<'tcx> {
         if let Some(interned) = self.interners.substs.borrow().get(&substs) {
@@ -949,11 +994,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Create an unsafe fn ty based on a safe fn ty.
     pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
         assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
-        self.mk_fn_ptr(ty::BareFnTy {
+        self.mk_fn_ptr(self.mk_bare_fn(ty::BareFnTy {
             unsafety: hir::Unsafety::Unsafe,
             abi: bare_fn.abi,
             sig: bare_fn.sig.clone()
-        })
+        }))
     }
 
     pub fn mk_bare_fn(self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
@@ -1063,7 +1108,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn mk_tup(self, ts: Vec<Ty<'tcx>>) -> Ty<'tcx> {
-        self.mk_ty(TyTuple(ts))
+        self.mk_ty(TyTuple(self.mk_type_list(ts)))
     }
 
     pub fn mk_nil(self) -> Ty<'tcx> {
@@ -1076,12 +1121,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn mk_fn_def(self, def_id: DefId,
                      substs: &'tcx Substs<'tcx>,
-                     fty: BareFnTy<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(TyFnDef(def_id, substs, self.mk_bare_fn(fty)))
+                     fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(TyFnDef(def_id, substs, fty))
     }
 
-    pub fn mk_fn_ptr(self, fty: BareFnTy<'tcx>) -> Ty<'tcx> {
-        self.mk_ty(TyFnPtr(self.mk_bare_fn(fty)))
+    pub fn mk_fn_ptr(self, fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+        self.mk_ty(TyFnPtr(fty))
     }
 
     pub fn mk_trait(self,
@@ -1117,15 +1162,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                       substs: &'tcx Substs<'tcx>,
                       tys: Vec<Ty<'tcx>>)
                       -> Ty<'tcx> {
-        self.mk_closure_from_closure_substs(closure_id, Box::new(ClosureSubsts {
+        self.mk_closure_from_closure_substs(closure_id, ClosureSubsts {
             func_substs: substs,
-            upvar_tys: tys
-        }))
+            upvar_tys: self.mk_type_list(tys)
+        })
     }
 
     pub fn mk_closure_from_closure_substs(self,
                                           closure_id: DefId,
-                                          closure_substs: Box<ClosureSubsts<'tcx>>)
+                                          closure_substs: ClosureSubsts<'tcx>)
                                           -> Ty<'tcx> {
         self.mk_ty(TyClosure(closure_id, closure_substs))
     }
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 463b0e17f61..14b369f244d 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -139,8 +139,8 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
     }
 
     fn fold_substs(&mut self,
-                   substs: &subst::Substs<'tcx>)
-                   -> subst::Substs<'tcx> {
+                   substs: &'tcx subst::Substs<'tcx>)
+                   -> &'tcx subst::Substs<'tcx> {
         substs.super_fold_with(self)
     }
 
@@ -157,8 +157,8 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
     }
 
     fn fold_bare_fn_ty(&mut self,
-                       fty: &ty::BareFnTy<'tcx>)
-                       -> ty::BareFnTy<'tcx>
+                       fty: &'tcx ty::BareFnTy<'tcx>)
+                       -> &'tcx ty::BareFnTy<'tcx>
     {
         fty.super_fold_with(self)
     }
@@ -519,13 +519,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     _ => ty::ReStatic
                 }
             }
-
-            fn fold_substs(&mut self,
-                           substs: &subst::Substs<'tcx>)
-                           -> subst::Substs<'tcx> {
-                subst::Substs { regions: substs.regions.fold_with(self),
-                                types: substs.types.fold_with(self) }
-            }
         }
     }
 }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index a7e253a45aa..35656fb0c2d 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -581,9 +581,9 @@ impl<'a, 'tcx> Struct {
 
             // Perhaps one of the upvars of this closure is non-zero
             // Let's recurse and find out!
-            (_, &ty::TyClosure(_, box ty::ClosureSubsts { upvar_tys: ref tys, .. })) |
+            (_, &ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. })) |
             // Can we use one of the fields in this tuple?
-            (_, &ty::TyTuple(ref tys)) => {
+            (_, &ty::TyTuple(tys)) => {
                 Struct::non_zero_field_path(infcx, tys.iter().cloned())
             }
 
@@ -844,8 +844,8 @@ impl<'a, 'tcx> Layout {
             }
 
             // Tuples.
-            ty::TyClosure(_, box ty::ClosureSubsts { upvar_tys: ref tys, .. }) |
-            ty::TyTuple(ref tys) => {
+            ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) |
+            ty::TyTuple(tys) => {
                 let mut st = Struct::new(dl, false);
                 st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?;
                 Univariant { variant: st, non_zero: false }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 4b79b3809a5..27f74de2470 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -350,7 +350,7 @@ pub struct Method<'tcx> {
     pub name: Name,
     pub generics: Generics<'tcx>,
     pub predicates: GenericPredicates<'tcx>,
-    pub fty: BareFnTy<'tcx>,
+    pub fty: &'tcx BareFnTy<'tcx>,
     pub explicit_self: ExplicitSelfCategory,
     pub vis: Visibility,
     pub defaultness: hir::Defaultness,
@@ -362,7 +362,7 @@ impl<'tcx> Method<'tcx> {
     pub fn new(name: Name,
                generics: ty::Generics<'tcx>,
                predicates: GenericPredicates<'tcx>,
-               fty: BareFnTy<'tcx>,
+               fty: &'tcx BareFnTy<'tcx>,
                explicit_self: ExplicitSelfCategory,
                vis: Visibility,
                defaultness: hir::Defaultness,
@@ -1213,7 +1213,7 @@ impl<'tcx> TraitRef<'tcx> {
 #[derive(Clone)]
 pub struct ParameterEnvironment<'tcx> {
     /// See `construct_free_substs` for details.
-    pub free_substs: Substs<'tcx>,
+    pub free_substs: &'tcx Substs<'tcx>,
 
     /// Each type parameter has an implicit region bound that
     /// indicates it must outlive at least the function body (the user
@@ -1242,7 +1242,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                               -> ParameterEnvironment<'tcx>
     {
         ParameterEnvironment {
-            free_substs: self.free_substs.clone(),
+            free_substs: self.free_substs,
             implicit_region_bound: self.implicit_region_bound,
             caller_bounds: caller_bounds,
             free_id_outlive: self.free_id_outlive,
@@ -1974,7 +1974,7 @@ impl<'a, 'gcx, 'tcx, 'container> FieldDefData<'tcx, 'container> {
 /// item into the monotype of an item reference.
 #[derive(Clone)]
 pub struct ItemSubsts<'tcx> {
-    pub substs: Substs<'tcx>,
+    pub substs: &'tcx Substs<'tcx>,
 }
 
 #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
@@ -2059,10 +2059,6 @@ impl<'tcx> TyS<'tcx> {
 }
 
 impl<'tcx> ItemSubsts<'tcx> {
-    pub fn empty() -> ItemSubsts<'tcx> {
-        ItemSubsts { substs: Substs::empty() }
-    }
-
     pub fn is_noop(&self) -> bool {
         self.substs.is_noop()
     }
@@ -2153,7 +2149,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn node_id_item_substs(self, id: NodeId) -> ItemSubsts<'gcx> {
         match self.tables.borrow().item_substs.get(&id) {
-            None => ItemSubsts::empty(),
+            None => ItemSubsts {
+                substs: self.global_tcx().mk_substs(Substs::empty())
+            },
             Some(ts) => ts.clone(),
         }
     }
@@ -2722,7 +2720,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn closure_type(self,
                         def_id: DefId,
-                        substs: &ClosureSubsts<'gcx>)
+                        substs: ClosureSubsts<'gcx>)
                         -> ty::ClosureTy<'gcx>
     {
         Tables::closure_type(&self.tables, self.global_tcx(), def_id, substs)
@@ -2805,7 +2803,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // regions, so it shouldn't matter what we use for the free id
         let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID);
         ty::ParameterEnvironment {
-            free_substs: Substs::empty(),
+            free_substs: self.mk_substs(Substs::empty()),
             caller_bounds: Vec::new(),
             implicit_region_bound: ty::ReEmpty,
             free_id_outlive: free_id_outlive
@@ -2882,7 +2880,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         //
 
         let unnormalized_env = ty::ParameterEnvironment {
-            free_substs: free_substs,
+            free_substs: tcx.mk_substs(free_substs),
             implicit_region_bound: ty::ReScope(free_id_outlive),
             caller_bounds: predicates,
             free_id_outlive: free_id_outlive,
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index 0fba7ed2a92..60f8f277d39 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -111,7 +111,7 @@ fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec<Component<'tcx>>) {
             // what func/type parameters are used and unused,
             // taking into consideration UFCS and so forth.
 
-            for &upvar_ty in &substs.upvar_tys {
+            for &upvar_ty in substs.upvar_tys {
                 self.compute_components(upvar_ty, out);
             }
         }
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index d1bbe5a173f..80c727f0221 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -118,9 +118,9 @@ impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
 // like traits etc.
 fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
                                          item_def_id: DefId,
-                                         a_subst: &Substs<'tcx>,
-                                         b_subst: &Substs<'tcx>)
-                                         -> RelateResult<'tcx, Substs<'tcx>>
+                                         a_subst: &'tcx Substs<'tcx>,
+                                         b_subst: &'tcx Substs<'tcx>)
+                                         -> RelateResult<'tcx, &'tcx Substs<'tcx>>
     where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
 {
     debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}",
@@ -140,9 +140,9 @@ fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
 
 pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
                                         variances: Option<&ty::ItemVariances>,
-                                        a_subst: &Substs<'tcx>,
-                                        b_subst: &Substs<'tcx>)
-                                        -> RelateResult<'tcx, Substs<'tcx>>
+                                        a_subst: &'tcx Substs<'tcx>,
+                                        b_subst: &'tcx Substs<'tcx>)
+                                        -> RelateResult<'tcx, &'tcx Substs<'tcx>>
     where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
 {
     let mut substs = Substs::empty();
@@ -166,7 +166,7 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
         substs.regions.replace(space, regions);
     }
 
-    Ok(substs)
+    Ok(relation.tcx().mk_substs(substs))
 }
 
 fn relate_type_params<'a, 'gcx, 'tcx, R>(relation: &mut R,
@@ -223,19 +223,21 @@ fn relate_region_params<'a, 'gcx, 'tcx, R>(relation: &mut R,
         .collect()
 }
 
-impl<'tcx> Relate<'tcx> for ty::BareFnTy<'tcx> {
+impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> {
     fn relate<'a, 'gcx, R>(relation: &mut R,
-                           a: &ty::BareFnTy<'tcx>,
-                           b: &ty::BareFnTy<'tcx>)
-                           -> RelateResult<'tcx, ty::BareFnTy<'tcx>>
+                           a: &&'tcx ty::BareFnTy<'tcx>,
+                           b: &&'tcx ty::BareFnTy<'tcx>)
+                           -> RelateResult<'tcx, &'tcx ty::BareFnTy<'tcx>>
         where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
     {
         let unsafety = relation.relate(&a.unsafety, &b.unsafety)?;
         let abi = relation.relate(&a.abi, &b.abi)?;
         let sig = relation.relate(&a.sig, &b.sig)?;
-        Ok(ty::BareFnTy {unsafety: unsafety,
-                         abi: abi,
-                         sig: sig})
+        Ok(relation.tcx().mk_bare_fn(ty::BareFnTy {
+            unsafety: unsafety,
+            abi: abi,
+            sig: sig
+        }))
     }
 }
 
@@ -418,7 +420,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
             Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
         } else {
             let substs = relate_item_substs(relation, a.def_id, a.substs, b.substs)?;
-            Ok(ty::TraitRef { def_id: a.def_id, substs: relation.tcx().mk_substs(substs) })
+            Ok(ty::TraitRef { def_id: a.def_id, substs: substs })
         }
     }
 }
@@ -481,7 +483,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             if a_def == b_def =>
         {
             let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?;
-            Ok(tcx.mk_enum(a_def, tcx.mk_substs(substs)))
+            Ok(tcx.mk_enum(a_def, substs))
         }
 
         (&ty::TyTrait(ref a_), &ty::TyTrait(ref b_)) =>
@@ -495,17 +497,17 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             if a_def == b_def =>
         {
             let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?;
-            Ok(tcx.mk_struct(a_def, tcx.mk_substs(substs)))
+            Ok(tcx.mk_struct(a_def, substs))
         }
 
-        (&ty::TyClosure(a_id, ref a_substs),
-         &ty::TyClosure(b_id, ref b_substs))
+        (&ty::TyClosure(a_id, a_substs),
+         &ty::TyClosure(b_id, b_substs))
             if a_id == b_id =>
         {
             // All TyClosure types with the same id represent
             // the (anonymous) type of the same closure expression. So
             // all of their regions should be equated.
-            let substs = relation.relate(a_substs, b_substs)?;
+            let substs = relation.relate(&a_substs, &b_substs)?;
             Ok(tcx.mk_closure_from_closure_substs(a_id, substs))
         }
 
@@ -544,7 +546,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             Ok(tcx.mk_slice(t))
         }
 
-        (&ty::TyTuple(ref as_), &ty::TyTuple(ref bs)) =>
+        (&ty::TyTuple(as_), &ty::TyTuple(bs)) =>
         {
             if as_.len() == bs.len() {
                 let ts = as_.iter().zip(bs)
@@ -564,13 +566,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             if a_def_id == b_def_id =>
         {
             let substs = relate_substs(relation, None, a_substs, b_substs)?;
-            let fty = relation.relate(a_fty, b_fty)?;
-            Ok(tcx.mk_fn_def(a_def_id, tcx.mk_substs(substs), fty))
+            let fty = relation.relate(&a_fty, &b_fty)?;
+            Ok(tcx.mk_fn_def(a_def_id, substs, fty))
         }
 
         (&ty::TyFnPtr(a_fty), &ty::TyFnPtr(b_fty)) =>
         {
-            let fty = relation.relate(a_fty, b_fty)?;
+            let fty = relation.relate(&a_fty, &b_fty)?;
             Ok(tcx.mk_fn_ptr(fty))
         }
 
@@ -594,18 +596,20 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> {
                            -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>>
         where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
     {
-        let func_substs = relate_substs(relation, None, a.func_substs, b.func_substs)?;
+        let substs = relate_substs(relation, None, a.func_substs, b.func_substs)?;
         let upvar_tys = relation.relate_zip(&a.upvar_tys, &b.upvar_tys)?;
-        Ok(ty::ClosureSubsts { func_substs: relation.tcx().mk_substs(func_substs),
-                               upvar_tys: upvar_tys })
+        Ok(ty::ClosureSubsts {
+            func_substs: substs,
+            upvar_tys: relation.tcx().mk_type_list(upvar_tys)
+        })
     }
 }
 
-impl<'tcx> Relate<'tcx> for Substs<'tcx> {
+impl<'tcx> Relate<'tcx> for &'tcx Substs<'tcx> {
     fn relate<'a, 'gcx, R>(relation: &mut R,
-                           a: &Substs<'tcx>,
-                           b: &Substs<'tcx>)
-                           -> RelateResult<'tcx, Substs<'tcx>>
+                           a: &&'tcx Substs<'tcx>,
+                           b: &&'tcx Substs<'tcx>)
+                           -> RelateResult<'tcx, &'tcx Substs<'tcx>>
         where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
     {
         relate_substs(relation, None, a, b)
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 4f8e172d49f..088ca15acb9 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -128,6 +128,18 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
+    type Lifted = ty::ClosureSubsts<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(&(self.func_substs, self.upvar_tys)).map(|(substs, upvar_tys)| {
+            ty::ClosureSubsts {
+                func_substs: substs,
+                upvar_tys: upvar_tys
+            }
+        })
+    }
+}
+
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> {
     type Lifted = ty::error::ExpectedFound<T::Lifted>;
     fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@@ -330,41 +342,38 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitTy<'tcx> {
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for &'tcx [Ty<'tcx>] {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        let tys = self.iter().map(|t| t.fold_with(folder)).collect();
+        folder.tcx().mk_type_list(tys)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|t| t.visit_with(visitor))
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, '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::TyRawPtr(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::TyEnum(tid, substs) => ty::TyEnum(tid, substs.fold_with(folder)),
             ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)),
-            ty::TyTuple(ref ts) => ty::TyTuple(ts.fold_with(folder)),
-            ty::TyFnDef(def_id, substs, ref f) => {
-                let substs = substs.fold_with(folder);
-                let bfn = f.fold_with(folder);
+            ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)),
+            ty::TyFnDef(def_id, substs, f) => {
                 ty::TyFnDef(def_id,
-                            folder.tcx().mk_substs(substs),
-                            folder.tcx().mk_bare_fn(bfn))
+                            substs.fold_with(folder),
+                            f.fold_with(folder))
             }
-            ty::TyFnPtr(ref f) => {
-                let bfn = f.fold_with(folder);
-                ty::TyFnPtr(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::TyFnPtr(f) => ty::TyFnPtr(f.fold_with(folder)),
+            ty::TyRef(ref r, tm) => {
+                ty::TyRef(r.fold_with(folder), tm.fold_with(folder))
             }
+            ty::TyStruct(did, substs) => ty::TyStruct(did, substs.fold_with(folder)),
+            ty::TyClosure(did, 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(_) |
@@ -385,7 +394,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             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::TyTuple(ts) => ts.visit_with(visitor),
             ty::TyFnDef(_, substs, ref f) => {
                 substs.visit_with(visitor) || f.visit_with(visitor)
             }
@@ -405,11 +414,14 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::BareFnTy<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::BareFnTy<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::BareFnTy { sig: self.sig.fold_with(folder),
-                       abi: self.abi,
-                       unsafety: self.unsafety }
+        let fty = ty::BareFnTy {
+            sig: self.sig.fold_with(folder),
+            abi: self.abi,
+            unsafety: self.unsafety
+        };
+        folder.tcx().mk_bare_fn(fty)
     }
 
     fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
@@ -491,10 +503,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
 
 impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, '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),
+            substs: self.substs.fold_with(folder),
         }
     }
 
@@ -546,10 +557,32 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
+        *self
+    }
+
+    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        let region = folder.fold_region(**self);
+        folder.tcx().mk_region(region)
+    }
+
+    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 &'tcx subst::Substs<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        subst::Substs { regions: self.regions.fold_with(folder),
-                        types: self.types.fold_with(folder) }
+        let substs = subst::Substs {
+            regions: self.regions.fold_with(folder),
+            types: self.types.fold_with(folder)
+        };
+        folder.tcx().mk_substs(substs)
     }
 
     fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
@@ -563,9 +596,8 @@ impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> {
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, '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),
+            func_substs: self.func_substs.fold_with(folder),
             upvar_tys: self.upvar_tys.fold_with(folder),
         }
     }
@@ -590,9 +622,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> {
 impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, '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::AutoPtr(ref r, m) => {
+                ty::adjustment::AutoPtr(r.fold_with(folder), m)
             }
             ty::adjustment::AutoUnsafe(m) => ty::adjustment::AutoUnsafe(m)
         }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index da1eedb6634..472b6f1f51a 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -25,7 +25,7 @@ use syntax::abi;
 use syntax::ast::{self, Name};
 use syntax::parse::token::keywords;
 
-use serialize::{Decodable, Decoder};
+use serialize::{Decodable, Decoder, Encodable, Encoder};
 
 use hir;
 
@@ -140,10 +140,10 @@ pub enum TypeVariants<'tcx> {
 
     /// The anonymous type of a closure. Used to represent the type of
     /// `|a| a`.
-    TyClosure(DefId, Box<ClosureSubsts<'tcx>>),
+    TyClosure(DefId, ClosureSubsts<'tcx>),
 
     /// A tuple type.  For example, `(i32, bool)`.
-    TyTuple(Vec<Ty<'tcx>>),
+    TyTuple(&'tcx [Ty<'tcx>]),
 
     /// The projection of an associated type.  For example,
     /// `<T as Trait<..>>::N`.
@@ -234,7 +234,7 @@ pub enum TypeVariants<'tcx> {
 /// closure C wind up influencing the decisions we ought to make for
 /// closure C (which would then require fixed point iteration to
 /// handle). Plus it fixes an ICE. :P
-#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct ClosureSubsts<'tcx> {
     /// Lifetime and type parameters from the enclosing function.
     /// These are separated out because trans wants to pass them around
@@ -244,22 +244,23 @@ pub struct ClosureSubsts<'tcx> {
     /// The types of the upvars. The list parallels the freevars and
     /// `upvar_borrows` lists. These are kept distinct so that we can
     /// easily index into them.
-    pub upvar_tys: Vec<Ty<'tcx>>
+    pub upvar_tys: &'tcx [Ty<'tcx>]
 }
 
-impl<'tcx> Decodable for &'tcx ClosureSubsts<'tcx> {
-    fn decode<S: Decoder>(s: &mut S) -> Result<&'tcx ClosureSubsts<'tcx>, S::Error> {
-        let closure_substs = Decodable::decode(s)?;
-        let dummy_def_id: DefId = unsafe { mem::zeroed() };
-
-        cstore::tls::with_decoding_context(s, |dcx, _| {
-            // Intern the value
-            let ty = dcx.tcx().mk_closure_from_closure_substs(dummy_def_id,
-                                                              Box::new(closure_substs));
-            match ty.sty {
-                TyClosure(_, ref closure_substs) => Ok(&**closure_substs),
-                _ => bug!()
-            }
+impl<'tcx> Encodable for ClosureSubsts<'tcx> {
+    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        (self.func_substs, self.upvar_tys).encode(s)
+    }
+}
+
+impl<'tcx> Decodable for ClosureSubsts<'tcx> {
+    fn decode<D: Decoder>(d: &mut D) -> Result<ClosureSubsts<'tcx>, D::Error> {
+        let (func_substs, upvar_tys) = Decodable::decode(d)?;
+        cstore::tls::with_decoding_context(d, |dcx, _| {
+            Ok(ClosureSubsts {
+                func_substs: func_substs,
+                upvar_tys: dcx.tcx().mk_type_list(upvar_tys)
+            })
         })
     }
 }
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 462e809be2a..9aec6b35997 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -114,8 +114,8 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         Substs { types: types, regions: regions }
     }
 
-    pub fn with_method_from_subst(self, other: &Substs<'tcx>) -> Substs<'tcx> {
-        let Substs { types, regions } = self;
+    pub fn with_method_from_subst(&self, other: &Substs<'tcx>) -> Substs<'tcx> {
+        let Substs { types, regions } = self.clone();
         let types = types.with_slice(FnSpace, other.types.get_slice(FnSpace));
         let regions = regions.with_slice(FnSpace, other.regions.get_slice(FnSpace));
         Substs { types: types, regions: regions }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 7464713c66d..ff22db4ccda 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -895,14 +895,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
             TyTrait(ref data) => write!(f, "{}", data),
             ty::TyProjection(ref data) => write!(f, "{}", data),
             TyStr => write!(f, "str"),
-            TyClosure(did, ref substs) => ty::tls::with(|tcx| {
+            TyClosure(did, substs) => ty::tls::with(|tcx| {
                 write!(f, "[closure")?;
 
                 if let Some(node_id) = tcx.map.as_local_node_id(did) {
                     write!(f, "@{:?}", tcx.map.span(node_id))?;
                     let mut sep = " ";
                     tcx.with_freevars(node_id, |freevars| {
-                        for (freevar, upvar_ty) in freevars.iter().zip(&substs.upvar_tys) {
+                        for (freevar, upvar_ty) in freevars.iter().zip(substs.upvar_tys) {
                             let node_id = freevar.def.var_id();
                             write!(f,
                                         "{}{}:{}",
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index c06fd475628..22ffebc081b 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -92,7 +92,7 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// This generally happens in late/trans const evaluation.
 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
-                                        substs: Option<subst::Substs<'tcx>>)
+                                        substs: Option<&'tcx subst::Substs<'tcx>>)
                                         -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)> {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         match tcx.map.find(node_id) {
@@ -1004,11 +1004,11 @@ fn infer<'a, 'tcx>(i: ConstInt,
 fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 ti: &'tcx hir::TraitItem,
                                                 trait_id: DefId,
-                                                rcvr_substs: subst::Substs<'tcx>)
+                                                rcvr_substs: &'tcx subst::Substs<'tcx>)
                                                 -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
 {
     let trait_ref = ty::Binder(
-        rcvr_substs.erase_regions().to_trait_ref(tcx, trait_id)
+        rcvr_substs.clone().erase_regions().to_trait_ref(tcx, trait_id)
     );
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 6fc10d968d0..fc44f808e4b 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -265,7 +265,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
 
     pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
         let input_args = input_tys.iter().cloned().collect();
-        self.infcx.tcx.mk_fn_ptr(ty::BareFnTy {
+        self.infcx.tcx.mk_fn_ptr(self.infcx.tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: hir::Unsafety::Normal,
             abi: Abi::Rust,
             sig: ty::Binder(ty::FnSig {
@@ -273,7 +273,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
                 output: ty::FnConverging(output_ty),
                 variadic: false,
             }),
-        })
+        }))
     }
 
     pub fn t_nil(&self) -> Ty<'tcx> {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 3b8f8a18bc7..13cfa2a604d 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -823,11 +823,7 @@ impl LateLintPass for UnconditionalRecursion {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
                     match tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()) {
                         Some(Def::Method(def_id)) => {
-                            let item_substs =
-                                tcx.tables.borrow().item_substs
-                                                   .get(&callee.id)
-                                                   .cloned()
-                                                   .unwrap_or_else(|| ty::ItemSubsts::empty());
+                            let item_substs = tcx.node_id_item_substs(callee.id);
                             method_call_refers_to_method(
                                 tcx, method, def_id, &item_substs.substs, id)
                         }
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 86e38274245..cd47d97d170 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -1149,7 +1149,7 @@ fn decode_side_tables(dcx: &DecodeContext,
                     }
                     c::tag_table_item_subst => {
                         let item_substs = ty::ItemSubsts {
-                            substs: val_dsr.read_substs(dcx)
+                            substs: dcx.tcx.mk_substs(val_dsr.read_substs(dcx))
                         };
                         dcx.tcx.tables.borrow_mut().item_substs.insert(
                             id, item_substs);
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 860b9f25023..e233dda7e91 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -987,7 +987,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(intr: Rc<IdentInterner>,
             let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
             let ity = tcx.lookup_item_type(def_id).ty;
             let fty = match ity.sty {
-                ty::TyFnDef(_, _, fty) => fty.clone(),
+                ty::TyFnDef(_, _, fty) => fty,
                 _ => bug!(
                     "the type {:?} of the method {:?} is not a function?",
                     ity, name)
diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs
index 8f33042be01..c94af9c5b3a 100644
--- a/src/librustc_metadata/tydecode.rs
+++ b/src/librustc_metadata/tydecode.rs
@@ -502,15 +502,15 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
         }
     }
 
-    pub fn parse_bare_fn_ty(&mut self) -> ty::BareFnTy<'tcx> {
+    pub fn parse_bare_fn_ty(&mut self) -> &'tcx ty::BareFnTy<'tcx> {
         let unsafety = parse_unsafety(self.next());
         let abi = self.parse_abi_set();
         let sig = self.parse_sig();
-        ty::BareFnTy {
+        self.tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: unsafety,
             abi: abi,
             sig: sig
-        }
+        })
     }
 
     fn parse_sig(&mut self) -> ty::PolyFnSig<'tcx> {
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index b663ba4f0d2..343c452f891 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -110,7 +110,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
             enc_existential_bounds(w, cx, bounds);
             write!(w, "]");
         }
-        ty::TyTuple(ref ts) => {
+        ty::TyTuple(ts) => {
             write!(w, "T[");
             for t in ts { enc_ty(w, cx, *t); }
             write!(w, "]");
@@ -156,10 +156,10 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
             enc_substs(w, cx, substs);
             write!(w, "]");
         }
-        ty::TyClosure(def, ref substs) => {
+        ty::TyClosure(def, substs) => {
             write!(w, "k[{}|", (cx.ds)(cx.tcx, def));
-            enc_substs(w, cx, &substs.func_substs);
-            for ty in &substs.upvar_tys {
+            enc_substs(w, cx, substs.func_substs);
+            for ty in substs.upvar_tys {
                 enc_ty(w, cx, ty);
             }
             write!(w, ".");
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index bc1197b449b..39e9ace5432 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -275,7 +275,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
                     })
                 } else { None };
                 if let Some((adt_def, index)) = adt_data {
-                    let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(fun.id).substs);
+                    let substs = cx.tcx.node_id_item_substs(fun.id).substs;
                     let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef {
                         name: Field::new(idx),
                         expr: e.to_ref()
@@ -506,7 +506,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
         hir::ExprClosure(..) => {
             let closure_ty = cx.tcx.expr_ty(expr);
             let (def_id, substs) = match closure_ty.sty {
-                ty::TyClosure(def_id, ref substs) => (def_id, substs),
+                ty::TyClosure(def_id, substs) => (def_id, substs),
                 _ => {
                     span_bug!(expr.span,
                               "closure expr w/o closure type: {:?}",
@@ -521,7 +521,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
             });
             ExprKind::Closure {
                 closure_id: def_id,
-                substs: &substs,
+                substs: substs,
                 upvars: upvars,
             }
         }
@@ -672,7 +672,7 @@ fn convert_arm<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
 fn convert_path_expr<'a, 'tcx>(cx: &mut Cx<'a, 'tcx, 'tcx>,
                                expr: &'tcx hir::Expr)
                                -> ExprKind<'tcx> {
-    let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
+    let substs = cx.tcx.node_id_item_substs(expr.id).substs;
     // Otherwise there may be def_map borrow conflicts
     let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
     let def_id = match def {
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index d29e931f593..1cdf077ffac 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -222,7 +222,7 @@ pub enum ExprKind<'tcx> {
     },
     Closure {
         closure_id: DefId,
-        substs: &'tcx ClosureSubsts<'tcx>,
+        substs: ClosureSubsts<'tcx>,
         upvars: Vec<ExprRef<'tcx>>,
     },
     Literal {
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 1ee1ee737aa..485ca3ea84a 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -37,7 +37,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
     }
 
     fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) {
-        *substs = self.tcx.mk_substs(self.tcx.erase_regions(*substs));
+        *substs = self.tcx.erase_regions(&{*substs});
     }
 }
 
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index c7f2babfc2d..9ad06e85c4f 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -276,8 +276,8 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx, 'tcx> {
                     if adt_def.is_univariant() => {
                         (&adt_def.variants[0], substs)
                     }
-                ty::TyTuple(ref tys) | ty::TyClosure(_, box ty::ClosureSubsts {
-                    upvar_tys: ref tys, ..
+                ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts {
+                    upvar_tys: tys, ..
                 }) => {
                     return match tys.get(field.index()) {
                         Some(&ty) => Ok(ty),
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 0d012ba6391..3fb86054120 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -100,7 +100,7 @@ impl<'tcx> Callee<'tcx> {
     /// Trait or impl method.
     pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
                         method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
-        let substs = bcx.tcx().mk_substs(bcx.fcx.monomorphize(&method.substs));
+        let substs = bcx.fcx.monomorphize(&method.substs);
         Callee::def(bcx.ccx(), method.def_id, substs)
     }
 
@@ -182,7 +182,7 @@ impl<'tcx> Callee<'tcx> {
 
                 let method_ty = def_ty(tcx, def_id, substs);
                 let fn_ptr_ty = match method_ty.sty {
-                    ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
+                    ty::TyFnDef(_, _, fty) => tcx.mk_fn_ptr(fty),
                     _ => bug!("expected fn item type, found {}",
                               method_ty)
                 };
@@ -194,7 +194,7 @@ impl<'tcx> Callee<'tcx> {
 
                 let method_ty = def_ty(tcx, def_id, substs);
                 let fn_ptr_ty = match method_ty.sty {
-                    ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
+                    ty::TyFnDef(_, _, fty) => tcx.mk_fn_ptr(fty),
                     _ => bug!("expected fn item type, found {}",
                               method_ty)
                 };
@@ -252,7 +252,7 @@ impl<'tcx> Callee<'tcx> {
     pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>)
                      -> Datum<'tcx, Rvalue> {
         let fn_ptr_ty = match self.ty.sty {
-            ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)),
+            ty::TyFnDef(_, _, f) => ccx.tcx().mk_fn_ptr(f),
             _ => self.ty
         };
         match self.data {
@@ -368,11 +368,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
         variadic: false
     };
     let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
-    let tuple_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
+    let tuple_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Normal,
         abi: Abi::RustCall,
         sig: ty::Binder(sig)
-    });
+    }));
     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
 
     //
@@ -476,7 +476,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let fn_ptr_ty = match fn_ty.sty {
             ty::TyFnDef(_, _, fty) => {
                 // Create a fn pointer with the substituted signature.
-                tcx.mk_ty(ty::TyFnPtr(fty))
+                tcx.mk_fn_ptr(fty)
             }
             _ => bug!("expected fn item type, found {}", fn_ty)
         };
@@ -487,7 +487,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // Find the actual function pointer.
     let ty = ccx.tcx().lookup_item_type(def_id).ty;
     let fn_ptr_ty = match ty.sty {
-        ty::TyFnDef(_, _, fty) => {
+        ty::TyFnDef(_, _, ref fty) => {
             // Create a fn pointer with the normalized signature.
             tcx.mk_fn_ptr(tcx.normalize_associated_type(fty))
         }
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index 25b76e1113c..04f5e71497c 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -136,13 +136,13 @@ fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// necessary. If the ID does not correspond to a closure ID, returns None.
 fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                closure_id: DefId,
-                                               substs: &ty::ClosureSubsts<'tcx>)
+                                               substs: ty::ClosureSubsts<'tcx>)
                                                -> ValueRef {
     // Normalize type so differences in regions and typedefs don't cause
     // duplicate declarations
     let tcx = ccx.tcx();
-    let substs = tcx.erase_regions(substs);
-    let instance = Instance::new(closure_id, &substs.func_substs);
+    let substs = tcx.erase_regions(&substs);
+    let instance = Instance::new(closure_id, substs.func_substs);
 
     if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
         debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}",
@@ -153,11 +153,11 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let symbol = symbol_names::exported_name(ccx, &instance);
 
     // Compute the rust-call form of the closure call method.
-    let sig = &ty::Tables::closure_type(&tcx.tables, tcx, closure_id, &substs).sig;
+    let sig = &ty::Tables::closure_type(&tcx.tables, tcx, closure_id, substs).sig;
     let sig = tcx.erase_late_bound_regions(sig);
     let sig = tcx.normalize_associated_type(&sig);
-    let closure_type = tcx.mk_closure_from_closure_substs(closure_id, Box::new(substs));
-    let function_type = tcx.mk_fn_ptr(ty::BareFnTy {
+    let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs);
+    let function_type = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Normal,
         abi: Abi::RustCall,
         sig: ty::Binder(ty::FnSig {
@@ -166,7 +166,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             output: sig.output,
             variadic: false
         })
-    });
+    }));
     let llfn = declare::define_internal_fn(ccx, &symbol, function_type);
 
     // set an inline hint for all closures
@@ -190,7 +190,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
                                     body: &hir::Block,
                                     id: ast::NodeId,
                                     closure_def_id: DefId, // (*)
-                                    closure_substs: &ty::ClosureSubsts<'tcx>)
+                                    closure_substs: ty::ClosureSubsts<'tcx>)
                                     -> Option<Block<'a, 'tcx>>
 {
     // (*) Note that in the case of inlined functions, the `closure_def_id` will be the
@@ -224,7 +224,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
     let sig = tcx.normalize_associated_type(&sig);
 
     let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
-        Box::new(closure_substs.clone()));
+                                                          closure_substs);
     let sig = ty::FnSig {
         inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
                     .into_iter().chain(sig.inputs).collect(),
@@ -285,7 +285,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
                                       -> ValueRef
 {
     // If this is a closure, redirect to it.
-    let llfn = get_or_create_closure_declaration(ccx, closure_def_id, &substs);
+    let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs);
 
     // If the closure is a Fn closure, but a FnOnce is needed (etc),
     // then adapt the self type
@@ -344,18 +344,18 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 
     // Find a version of the closure type. Substitute static for the
     // region since it doesn't really matter.
-    let closure_ty = tcx.mk_closure_from_closure_substs(closure_def_id, Box::new(substs.clone()));
+    let closure_ty = tcx.mk_closure_from_closure_substs(closure_def_id, substs);
     let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), closure_ty);
 
     // Make a version with the type of by-ref closure.
     let ty::ClosureTy { unsafety, abi, mut sig } =
-        ty::Tables::closure_type(&tcx.tables, tcx, closure_def_id, &substs);
+        ty::Tables::closure_type(&tcx.tables, tcx, closure_def_id, substs);
     sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
-    let llref_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
+    let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: unsafety,
         abi: abi,
         sig: sig.clone()
-    });
+    }));
     debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
            llref_fn_ty);
 
@@ -369,11 +369,11 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     let sig = tcx.normalize_associated_type(&sig);
     let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
-    let llonce_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
+    let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: unsafety,
         abi: abi,
         sig: ty::Binder(sig)
-    });
+    }));
 
     // Create the by-value helper.
     let function_name =
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 14b7e5803a8..05ed5abce14 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -530,7 +530,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                 let exchange_malloc_fn_trans_item =
                     create_fn_trans_item(self.scx.tcx(),
                                          exchange_malloc_fn_def_id,
-                                         &Substs::empty(),
+                                         self.ccx.tcx().mk_substs(Substs::empty()),
                                          self.param_substs);
 
                 self.output.push(exchange_malloc_fn_trans_item);
@@ -670,8 +670,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         let exchange_free_fn_trans_item =
             create_fn_trans_item(scx.tcx(),
                                  exchange_free_fn_def_id,
-                                 &Substs::empty(),
-                                 &Substs::empty());
+                                 ccx.tcx().mk_substs(Substs::empty()),
+                                 ccx.tcx().mk_substs(Substs::empty()));
 
         output.push(exchange_free_fn_trans_item);
     }
@@ -709,7 +709,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             let trans_item = create_fn_trans_item(scx.tcx(),
                                                   destructor_did,
                                                   substs,
-                                                  &Substs::empty());
+                                                  ccx.tcx().mk_substs(Substs::empty()));
             output.push(trans_item);
         }
 
@@ -747,8 +747,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                 }
             }
         }
-        ty::TyClosure(_, ref substs) => {
-            for upvar_ty in &substs.upvar_tys {
+        ty::TyClosure(_, substs) => {
+            for upvar_ty in substs.upvar_tys {
                 let upvar_ty = glue::get_drop_glue_type(scx.tcx(), upvar_ty);
                 if glue::type_needs_drop(scx.tcx(), upvar_ty) {
                     output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty)));
@@ -762,7 +762,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                 output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type)));
             }
         }
-        ty::TyTuple(ref args) => {
+        ty::TyTuple(args) => {
             for arg in args {
                 let arg = glue::get_drop_glue_type(scx.tcx(), arg);
                 if glue::type_needs_drop(scx.tcx(), arg) {
@@ -840,7 +840,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
     let rcvr_substs = monomorphize::apply_param_substs(tcx,
                                                        param_substs,
-                                                       callee_substs);
+                                                       &callee_substs);
 
     let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id));
     let vtbl = fulfill_obligation(scx, DUMMY_SP, trait_ref);
@@ -962,8 +962,8 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
 fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   def_id: DefId,
-                                  fn_substs: &Substs<'tcx>,
-                                  param_substs: &Substs<'tcx>)
+                                  fn_substs: &'tcx Substs<'tcx>,
+                                  param_substs: &'tcx Substs<'tcx>)
                                   -> TransItem<'tcx> {
     debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})",
             def_id_to_string(tcx, def_id),
@@ -975,12 +975,11 @@ fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // ignored because we don't want to generate any code for them.
     let concrete_substs = monomorphize::apply_param_substs(tcx,
                                                            param_substs,
-                                                           fn_substs);
+                                                           &fn_substs);
     let concrete_substs = tcx.erase_regions(&concrete_substs);
 
     let trans_item =
-        TransItem::Fn(Instance::new(def_id,
-                                    &tcx.mk_substs(concrete_substs)));
+        TransItem::Fn(Instance::new(def_id, concrete_substs));
     return trans_item;
 }
 
@@ -1013,9 +1012,9 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
                         .filter_map(|impl_method| {
                             if can_have_local_instance(scx.tcx(), impl_method.method.def_id) {
                                 Some(create_fn_trans_item(scx.tcx(),
-                                                          impl_method.method.def_id,
-                                                          &impl_method.substs,
-                                                          &Substs::empty()))
+                                    impl_method.method.def_id,
+                                    impl_method.substs,
+                                    ccx.tcx().mk_substs(Substs::empty())))
                             } else {
                                 None
                             }
@@ -1167,7 +1166,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
                 let default_impls = tcx.provided_trait_methods(trait_ref.def_id);
-                let callee_substs = tcx.mk_substs(tcx.erase_regions(trait_ref.substs));
+                let callee_substs = tcx.erase_regions(&trait_ref.substs);
                 let overridden_methods: FnvHashSet<_> = items.iter()
                                                              .map(|item| item.name)
                                                              .collect();
@@ -1195,7 +1194,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     }
 
                     if can_have_local_instance(tcx, default_impl.def_id) {
-                        let empty_substs = tcx.mk_substs(tcx.erase_regions(mth.substs));
+                        let empty_substs = tcx.erase_regions(&mth.substs);
                         let item = create_fn_trans_item(tcx,
                                                         default_impl.def_id,
                                                         callee_substs,
@@ -1249,7 +1248,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             push_item_name(tcx, adt_def.did, output);
             push_type_params(tcx, &substs.types, &[], output);
         },
-        ty::TyTuple(ref component_types) => {
+        ty::TyTuple(component_types) => {
             output.push('(');
             for &component_type in component_types {
                 push_unique_type_name(tcx, component_type, output);
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index d312d07d973..f46ab825736 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -496,7 +496,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
             return Callee::def(ccx, def_id, tcx.mk_substs(Substs::empty()));
         }
 
-        let ty = tcx.mk_fn_ptr(ty::BareFnTy {
+        let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: hir::Unsafety::Unsafe,
             abi: Abi::C,
             sig: ty::Binder(ty::FnSig {
@@ -504,7 +504,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
                 output: ty::FnDiverging,
                 variadic: false
             }),
-        });
+        }));
 
         let unwresume = ccx.eh_unwind_resume();
         if let Some(llfn) = unwresume.get() {
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 3fc9e89098c..7775ed3fc68 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -194,7 +194,7 @@ fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
 fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                            def_id: DefId,
-                           substs: Substs<'tcx>,
+                           substs: &'tcx Substs<'tcx>,
                            arg_vals: &[ValueRef],
                            param_substs: &'tcx Substs<'tcx>,
                            trueconst: TrueConst) -> Result<ValueRef, ConstEvalFailure> {
@@ -212,10 +212,10 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let arg_ids = args.iter().map(|arg| arg.pat.id);
     let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect();
 
+    let substs = ccx.tcx().mk_substs(substs.clone().erase_regions());
     let substs = monomorphize::apply_param_substs(ccx.tcx(),
                                                   param_substs,
-                                                  &substs.erase_regions());
-    let substs = ccx.tcx().mk_substs(substs);
+                                                  &substs);
 
     const_expr(ccx, body, substs, Some(&fn_args), trueconst).map(|(res, _)| res)
 }
@@ -226,9 +226,10 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 param_substs: &'tcx Substs<'tcx>)
                                 -> &'tcx hir::Expr {
     let substs = ccx.tcx().node_id_item_substs(ref_expr.id).substs;
+    let substs = ccx.tcx().mk_substs(substs.clone().erase_regions());
     let substs = monomorphize::apply_param_substs(ccx.tcx(),
                                                   param_substs,
-                                                  &substs.erase_regions());
+                                                  &substs);
     match lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) {
         Some((ref expr, _ty)) => expr,
         None => {
@@ -968,7 +969,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let arg_vals = map_list(args)?;
             let method_call = ty::MethodCall::expr(e.id);
             let method = cx.tcx().tables.borrow().method_map[&method_call];
-            const_fn_call(cx, method.def_id, method.substs.clone(),
+            const_fn_call(cx, method.def_id, method.substs,
                           &arg_vals, param_substs, trueconst)?
         },
         hir::ExprType(ref e, _) => const_expr(cx, &e, param_substs, fn_args, trueconst)?.0,
@@ -986,7 +987,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         },
         hir::ExprClosure(_, ref decl, ref body, _) => {
             match ety.sty {
-                ty::TyClosure(def_id, ref substs) => {
+                ty::TyClosure(def_id, substs) => {
                     closure::trans_closure_expr(closure::Dest::Ignore(cx),
                                                 decl,
                                                 body,
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 55b5bc2beb8..7826693c827 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -187,10 +187,10 @@ impl<'tcx> TypeMap<'tcx> {
                 unique_type_id.push_str("struct ");
                 from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id);
             },
-            ty::TyTuple(ref component_types) if component_types.is_empty() => {
+            ty::TyTuple(component_types) if component_types.is_empty() => {
                 push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
             },
-            ty::TyTuple(ref component_types) => {
+            ty::TyTuple(component_types) => {
                 unique_type_id.push_str("tuple ");
                 for &component_type in component_types {
                     let component_type_id =
@@ -289,12 +289,12 @@ impl<'tcx> TypeMap<'tcx> {
                     }
                 }
             },
-            ty::TyClosure(_, ref substs) if substs.upvar_tys.is_empty() => {
+            ty::TyClosure(_, substs) if substs.upvar_tys.is_empty() => {
                 push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
             },
-            ty::TyClosure(_, ref substs) => {
+            ty::TyClosure(_, substs) => {
                 unique_type_id.push_str("closure ");
-                for upvar_type in &substs.upvar_tys {
+                for upvar_type in substs.upvar_tys {
                     let upvar_type_id =
                         self.get_unique_type_id_of_type(cx, upvar_type);
                     let upvar_type_id =
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index f1ac89ebf52..db4a82c7b0b 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -343,7 +343,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         }
 
         if abi == Abi::RustCall && !sig.inputs.is_empty() {
-            if let ty::TyTuple(ref args) = sig.inputs[sig.inputs.len() - 1].sty {
+            if let ty::TyTuple(args) = sig.inputs[sig.inputs.len() - 1].sty {
                 for &argument_type in args {
                     signature.push(type_metadata(cx, argument_type, codemap::DUMMY_SP));
                 }
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 3e0fc7b3120..63f460e4693 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -48,7 +48,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             push_item_name(cx, def.did, qualified, output);
             push_type_params(cx, substs, output);
         },
-        ty::TyTuple(ref component_types) => {
+        ty::TyTuple(component_types) => {
             output.push('(');
             for &component_type in component_types {
                 push_debuginfo_type_name(cx, component_type, true, output);
diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs
index 03a3e753d82..b87456318cd 100644
--- a/src/librustc_trans/expr.rs
+++ b/src/librustc_trans/expr.rs
@@ -1134,7 +1134,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             // the key we need to find the closure-kind and
             // closure-type etc.
             let (def_id, substs) = match expr_ty(bcx, expr).sty {
-                ty::TyClosure(def_id, ref substs) => (def_id, substs),
+                ty::TyClosure(def_id, substs) => (def_id, substs),
                 ref t =>
                     span_bug!(
                         expr.span,
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 04c7e872f0e..640ac25a5e3 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -1259,11 +1259,11 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
     };
     let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
 
-    let rust_fn_ty = ccx.tcx().mk_fn_ptr(ty::BareFnTy {
+    let rust_fn_ty = ccx.tcx().mk_fn_ptr(ccx.tcx().mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
         abi: Abi::Rust,
         sig: ty::Binder(sig)
-    });
+    }));
     let llfn = declare::define_internal_fn(ccx, name, rust_fn_ty);
     let (fcx, block_arena);
     block_arena = TypedArena::new();
@@ -1289,7 +1289,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
     // Define the type up front for the signature of the rust_try function.
     let tcx = ccx.tcx();
     let i8p = tcx.mk_mut_ptr(tcx.types.i8);
-    let fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
+    let fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
         abi: Abi::Rust,
         sig: ty::Binder(ty::FnSig {
@@ -1297,7 +1297,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
             output: ty::FnOutput::FnConverging(tcx.mk_nil()),
             variadic: false,
         }),
-    });
+    }));
     let output = ty::FnOutput::FnConverging(tcx.types.i32);
     let rust_try = gen_fn(fcx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans);
     ccx.rust_try_fn().set(Some(rust_try));
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 267d9e9a23a..c1be6daefd3 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -445,7 +445,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                             return Ok(Const::new(C_null(llty), ty));
                         }
 
-                        let substs = self.ccx.tcx().mk_substs(self.monomorphize(substs));
+                        let substs = self.monomorphize(&substs);
                         let instance = Instance::new(def_id, substs);
                         MirConstContext::trans_def(self.ccx, instance, vec![])
                     }
@@ -509,7 +509,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                                                     span: DUMMY_SP
                                                 },
                                                 DUMMY_NODE_ID, def_id,
-                                                &self.monomorphize(substs));
+                                                self.monomorphize(&substs));
                 }
 
                 let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind {
@@ -821,7 +821,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     return Const::new(C_null(llty), ty);
                 }
 
-                let substs = bcx.tcx().mk_substs(bcx.monomorphize(substs));
+                let substs = bcx.monomorphize(&substs);
                 let instance = Instance::new(def_id, substs);
                 MirConstContext::trans_def(bcx.ccx(), instance, vec![])
             }
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 45b6bcd920f..3fb22c6bd55 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -156,7 +156,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                                             span: DUMMY_SP
                                                         },
                                                         DUMMY_NODE_ID, def_id,
-                                                        &bcx.monomorphize(substs));
+                                                        bcx.monomorphize(&substs));
                         }
 
                         for (i, operand) in operands.iter().enumerate() {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index dcb40b0b418..090867a4bf8 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1742,7 +1742,7 @@ struct SelfInfo<'a, 'tcx> {
 pub fn ty_of_method<'tcx>(this: &AstConv<'tcx, 'tcx>,
                           sig: &hir::MethodSig,
                           untransformed_self_ty: Ty<'tcx>)
-                          -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
+                          -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
     let self_info = Some(SelfInfo {
         untransformed_self_ty: untransformed_self_ty,
         explicit_self: &sig.explicit_self,
@@ -1756,8 +1756,10 @@ pub fn ty_of_method<'tcx>(this: &AstConv<'tcx, 'tcx>,
     (bare_fn_ty, optional_explicit_self_category.unwrap())
 }
 
-pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx, 'tcx>, unsafety: hir::Unsafety, abi: abi::Abi,
-                                              decl: &hir::FnDecl) -> ty::BareFnTy<'tcx> {
+pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx, 'tcx>,
+                           unsafety: hir::Unsafety, abi: abi::Abi,
+                           decl: &hir::FnDecl)
+                           -> &'tcx ty::BareFnTy<'tcx> {
     let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, unsafety, abi, None, decl);
     bare_fn_ty
 }
@@ -1767,7 +1769,8 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx, 'tcx>,
                                      abi: abi::Abi,
                                      opt_self_info: Option<SelfInfo<'a, 'tcx>>,
                                      decl: &hir::FnDecl)
-                                     -> (ty::BareFnTy<'tcx>, Option<ty::ExplicitSelfCategory>)
+                                     -> (&'tcx ty::BareFnTy<'tcx>,
+                                         Option<ty::ExplicitSelfCategory>)
 {
     debug!("ty_of_method_or_bare_fn");
 
@@ -1813,7 +1816,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx, 'tcx>,
         hir::NoReturn(..) => ty::FnDiverging
     };
 
-    (ty::BareFnTy {
+    (this.tcx().mk_bare_fn(ty::BareFnTy {
         unsafety: unsafety,
         abi: abi,
         sig: ty::Binder(ty::FnSig {
@@ -1821,7 +1824,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx, 'tcx>,
             output: output_ty,
             variadic: decl.variadic
         }),
-    }, explicit_self_category)
+    }), explicit_self_category)
 }
 
 fn determine_self_type<'a, 'tcx>(this: &AstConv<'tcx, 'tcx>,
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 1dab0c97b8a..394ecf5fbef 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -609,7 +609,9 @@ pub fn check_pat_struct(&self, pat: &'tcx hir::Pat,
     self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc);
 
     self.write_ty(pat.id, pat_ty);
-    self.write_substs(pat.id, ty::ItemSubsts { substs: item_substs.clone() });
+    self.write_substs(pat.id, ty::ItemSubsts {
+        substs: item_substs
+    });
 }
 
 fn check_pat_enum(&self,
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index e1d64c2253d..a0565a9870c 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -122,7 +122,7 @@ fn try_overloaded_call_step(&self,
             return Some(CallStep::Builtin);
         }
 
-        ty::TyClosure(def_id, ref substs) => {
+        ty::TyClosure(def_id, substs) => {
             assert_eq!(def_id.krate, LOCAL_CRATE);
 
             // Check whether this is a call to a closure where we
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 158867eebf6..ad92c3fb072 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -320,8 +320,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             (None, Some(t_cast)) => {
                 if let ty::TyFnDef(_, _, f) = self.expr_ty.sty {
                     // Attempt a coercion to a fn pointer type.
-                    let res = fcx.try_coerce(self.expr,
-                                             fcx.tcx.mk_ty(ty::TyFnPtr(f)));
+                    let res = fcx.try_coerce(self.expr, fcx.tcx.mk_fn_ptr(f));
                     if !res.is_ok() {
                         return Err(CastError::NonScalar);
                     }
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 7e0376c1683..c60020f51ae 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -217,7 +217,7 @@ fn deduce_sig_from_projection(&self,
     debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
 
     let input_tys = match arg_param_ty.sty {
-        ty::TyTuple(ref tys) => { (*tys).clone() }
+        ty::TyTuple(tys) => tys.to_vec(),
         _ => { return None; }
     };
     debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index d471ab3c99c..1e7a9c5b635 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -546,7 +546,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx, 'tcx> {
 
         match b.sty {
             ty::TyFnPtr(_) => {
-                let a_fn_pointer = self.tcx.mk_ty(ty::TyFnPtr(fn_ty_a));
+                let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
                 self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| {
                     (ty, AdjustReifyFnPointer)
                 })
@@ -667,7 +667,7 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
         (&ty::TyFnDef(a_def_id, a_substs, a_fty),
          &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
             // The signature must always match.
-            let fty = self.lub(true, trace.clone(), a_fty, b_fty)
+            let fty = self.lub(true, trace.clone(), &a_fty, &b_fty)
                 .map(|InferOk { value, obligations }| {
                     // FIXME(#32730) propagate obligations
                     assert!(obligations.is_empty());
@@ -677,13 +677,13 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
             if a_def_id == b_def_id {
                 // Same function, maybe the parameters match.
                 let substs = self.commit_if_ok(|_| {
-                    self.lub(true, trace.clone(), a_substs, b_substs)
+                    self.lub(true, trace.clone(), &a_substs, &b_substs)
                         .map(|InferOk { value, obligations }| {
                             // FIXME(#32730) propagate obligations
                             assert!(obligations.is_empty());
                             value
                         })
-                }).map(|s| self.tcx.mk_substs(s));
+                });
 
                 if let Ok(substs) = substs {
                     // We have a LUB of prev_ty and new_ty, just return it.
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 1a9db2e5449..fc02506b1cd 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -178,7 +178,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // Create mapping from trait to skolemized.
     let trait_to_skol_substs =
         trait_to_impl_substs
-        .subst(tcx, impl_to_skol_substs)
+        .subst(tcx, impl_to_skol_substs).clone()
         .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
                      impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec());
     debug!("compare_impl_method: trait_to_skol_substs={:?}",
@@ -279,9 +279,9 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         // type.
 
         // Compute skolemized form of impl and trait method tys.
-        let impl_fty = tcx.mk_fn_ptr(impl_m.fty.clone());
+        let impl_fty = tcx.mk_fn_ptr(impl_m.fty);
         let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
-        let trait_fty = tcx.mk_fn_ptr(trait_m.fty.clone());
+        let trait_fty = tcx.mk_fn_ptr(trait_m.fty);
         let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
 
         let err = infcx.commit_if_ok(|snapshot| {
@@ -299,11 +299,11 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                      impl_m_span,
                                                      impl_m_body_id,
                                                      &impl_sig);
-            let impl_fty = tcx.mk_fn_ptr(ty::BareFnTy {
+            let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: impl_m.fty.unsafety,
                 abi: impl_m.fty.abi,
                 sig: ty::Binder(impl_sig)
-            });
+            }));
             debug!("compare_impl_method: impl_fty={:?}",
                    impl_fty);
 
@@ -317,11 +317,11 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                      impl_m_span,
                                                      impl_m_body_id,
                                                      &trait_sig);
-            let trait_fty = tcx.mk_fn_ptr(ty::BareFnTy {
+            let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: trait_m.fty.unsafety,
                 abi: trait_m.fty.abi,
                 sig: ty::Binder(trait_sig)
-            });
+            }));
 
             debug!("compare_impl_method: trait_fty={:?}",
                    trait_fty);
@@ -442,7 +442,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         // Create mapping from trait to skolemized.
         let trait_to_skol_substs =
             trait_to_impl_substs
-            .subst(tcx, impl_to_skol_substs)
+            .subst(tcx, impl_to_skol_substs).clone()
             .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
                          impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec());
         debug!("compare_const_impl: trait_to_skol_substs={:?}",
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index ed9925ea22b..c5e7606106f 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -469,8 +469,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
             Ok(())
         }
 
-        ty::TyTuple(ref tys) |
-        ty::TyClosure(_, box ty::ClosureSubsts { upvar_tys: ref tys, .. }) => {
+        ty::TyTuple(tys) |
+        ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) => {
             for ty in tys {
                 iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
             }
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 79aa647d239..6243d191dcb 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -38,7 +38,8 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let mut substs = Substs::empty();
     substs.types = i_ty.generics.types.map(|def| tcx.mk_param_from_def(def));
 
-    let fty = tcx.mk_fn_def(def_id, tcx.mk_substs(substs), ty::BareFnTy {
+    let fty = tcx.mk_fn_def(def_id, tcx.mk_substs(substs),
+                            tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
         abi: abi,
         sig: ty::Binder(FnSig {
@@ -46,7 +47,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             output: output,
             variadic: false,
         }),
-    });
+    }));
     let i_n_tps = i_ty.generics.types.len(subst::FnSpace);
     if i_n_tps != n_tps {
         span_err!(tcx.sess, it.span, E0094,
@@ -285,7 +286,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
 
             "try" => {
                 let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
-                let fn_ty = ty::BareFnTy {
+                let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
                     unsafety: hir::Unsafety::Normal,
                     abi: Abi::Rust,
                     sig: ty::Binder(FnSig {
@@ -293,7 +294,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
                         output: ty::FnOutput::FnConverging(tcx.mk_nil()),
                         variadic: false,
                     }),
-                };
+                });
                 (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
             }
 
@@ -484,7 +485,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
         }
         Aggregate(_flatten, ref expected_contents) => {
             match t.sty {
-                ty::TyTuple(ref contents) => {
+                ty::TyTuple(contents) => {
                     if contents.len() != expected_contents.len() {
                         simple_error(&format!("tuple with length {}", contents.len()),
                                      &format!("tuple with length {}", expected_contents.len()));
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index ca17f4bd3a8..47098599df2 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -117,11 +117,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx, 'tcx> {
         // Create the method type
         let def_id = pick.item.def_id();
         let method_ty = pick.item.as_opt_method().unwrap();
-        let fty = self.tcx.mk_fn_def(def_id, all_substs, ty::BareFnTy {
+        let fty = self.tcx.mk_fn_def(def_id, all_substs,
+                                     self.tcx.mk_bare_fn(ty::BareFnTy {
             sig: ty::Binder(method_sig),
             unsafety: method_ty.fty.unsafety,
             abi: method_ty.fty.abi.clone(),
-        });
+        }));
 
         // Add any trait/regions obligations specified on the method's type parameters.
         self.add_obligations(fty, all_substs, &method_predicates);
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index f63f9870977..8d6cc217b8b 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -240,11 +240,12 @@ pub fn lookup_method_in_trait_adjusted(&self,
     let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
     let transformed_self_ty = fn_sig.inputs[0];
     let def_id = method_item.def_id();
-    let fty = tcx.mk_fn_def(def_id, trait_ref.substs, ty::BareFnTy {
+    let fty = tcx.mk_fn_def(def_id, trait_ref.substs,
+                            tcx.mk_bare_fn(ty::BareFnTy {
         sig: ty::Binder(fn_sig),
         unsafety: method_ty.fty.unsafety,
         abi: method_ty.fty.abi.clone(),
-    });
+    }));
 
     debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
            fty,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index e9af54882f4..edaac66763c 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2506,7 +2506,7 @@ fn check_argument_types(&self,
     let formal_tys = if tuple_arguments == TupleArguments {
         let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
         match tuple_type.sty {
-            ty::TyTuple(ref arg_types) => {
+            ty::TyTuple(arg_types) => {
                 if arg_types.len() != args.len() {
                     span_err!(tcx.sess, sp, E0057,
                         "this function takes {} parameter{} but {} parameter{} supplied",
@@ -2524,7 +2524,7 @@ fn check_argument_types(&self,
                         },
                         None => &[]
                     };
-                    (*arg_types).clone()
+                    arg_types.to_vec()
                 }
             }
             _ => {
@@ -2682,7 +2682,7 @@ fn check_argument_types(&self,
                     }, arg_ty, None);
                 }
                 ty::TyFnDef(_, _, f) => {
-                    let ptr_ty = self.tcx.mk_ty(ty::TyFnPtr(f));
+                    let ptr_ty = self.tcx.mk_fn_ptr(f);
                     let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty);
                     self.type_error_message(arg.span,
                                             |t| {
@@ -4326,6 +4326,7 @@ pub fn instantiate_path(&self,
 
     // The things we are substituting into the type should not contain
     // escaping late-bound regions, and nor should the base type scheme.
+    let substs = self.tcx.mk_substs(substs);
     assert!(!substs.has_regions_escaping_depth(0));
     assert!(!type_scheme.has_escaping_regions());
 
@@ -4371,7 +4372,9 @@ pub fn instantiate_path(&self,
            node_id,
            ty_substituted);
     self.write_ty(node_id, ty_substituted);
-    self.write_substs(node_id, ty::ItemSubsts { substs: substs });
+    self.write_substs(node_id, ty::ItemSubsts {
+        substs: substs
+    });
 }
 
     /// Finds the parameters that the user provided and adds them to `substs`. If too many
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 720881e7684..3069627a421 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -349,13 +349,13 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
     fn check_fn_or_method<'fcx>(&mut self,
                                 fcx: &FnCtxt<'fcx,'tcx, 'tcx>,
                                 span: Span,
-                                fty: &ty::BareFnTy<'tcx>,
+                                fty: &'tcx ty::BareFnTy<'tcx>,
                                 predicates: &ty::InstantiatedPredicates<'tcx>,
                                 free_id_outlive: CodeExtent,
                                 implied_bounds: &mut Vec<Ty<'tcx>>)
     {
         let free_substs = &fcx.parameter_environment.free_substs;
-        let fty = fcx.instantiate_type_scheme(span, free_substs, fty);
+        let fty = fcx.instantiate_type_scheme(span, free_substs, &fty);
         let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
 
         for &input_ty in &sig.inputs {
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 432cf896065..5307753613d 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -326,7 +326,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx, 'tcx> {
                 let new_method = MethodCallee {
                     def_id: method.def_id,
                     ty: self.resolve(&method.ty, reason),
-                    substs: self.tcx().mk_substs(self.resolve(method.substs, reason)),
+                    substs: self.resolve(&method.substs, reason),
                 };
 
                 Some(new_method)
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 25ae23cd531..e49df1fc745 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -563,7 +563,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                               sig, untransformed_rcvr_ty);
 
     let def_id = ccx.tcx.map.local_def_id(id);
-    let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
+    let substs = mk_item_substs(ccx, &ty_generics);
 
     let ty_method = ty::Method::new(name,
                                     ty_generics,
@@ -575,7 +575,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                     def_id,
                                     container);
 
-    let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty.clone());
+    let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty);
     debug!("method {} (id {}) has type {:?}",
             name, id, fty);
     ccx.tcx.register_item_type(def_id, TypeScheme {
@@ -953,8 +953,8 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 .map(|field| field.unsubst_ty())
                 .collect();
             let def_id = tcx.map.local_def_id(ctor_id);
-            let substs = tcx.mk_substs(mk_item_substs(ccx, &scheme.generics));
-            tcx.mk_fn_def(def_id, substs, ty::BareFnTy {
+            let substs = mk_item_substs(ccx, &scheme.generics);
+            tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: abi::Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -962,7 +962,7 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     output: ty::FnConverging(scheme.ty),
                     variadic: false
                 })
-            })
+            }))
         }
     };
     write_ty_to_tcx(ccx, ctor_id, ctor_ty);
@@ -1454,7 +1454,7 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
             let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl);
             let def_id = ccx.tcx.map.local_def_id(it.id);
-            let substs = tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
+            let substs = mk_item_substs(ccx, &ty_generics);
             let ty = tcx.mk_fn_def(def_id, substs, tofd);
             ty::TypeScheme { ty: ty, generics: ty_generics }
         }
@@ -1467,14 +1467,14 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             let def = convert_enum_def(ccx, it, ei);
             let ty_generics = ty_generics_for_type(ccx, generics);
             let substs = mk_item_substs(ccx, &ty_generics);
-            let t = tcx.mk_enum(def, tcx.mk_substs(substs));
+            let t = tcx.mk_enum(def, substs);
             ty::TypeScheme { ty: t, generics: ty_generics }
         }
         hir::ItemStruct(ref si, ref generics) => {
             let def = convert_struct_def(ccx, it, si);
             let ty_generics = ty_generics_for_type(ccx, generics);
             let substs = mk_item_substs(ccx, &ty_generics);
-            let t = tcx.mk_struct(def, tcx.mk_substs(substs));
+            let t = tcx.mk_struct(def, substs);
             ty::TypeScheme { ty: t, generics: ty_generics }
         }
         hir::ItemDefaultImpl(..) |
@@ -2191,14 +2191,14 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
         }
     }
 
-    let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
-    let t_fn = ccx.tcx.mk_fn_def(id, substs, ty::BareFnTy {
+    let substs = mk_item_substs(ccx, &ty_generics);
+    let t_fn = ccx.tcx.mk_fn_def(id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy {
         abi: abi,
         unsafety: hir::Unsafety::Unsafe,
         sig: ty::Binder(ty::FnSig {inputs: input_tys,
                                     output: output,
                                     variadic: decl.variadic}),
-    });
+    }));
 
     ty::TypeScheme {
         generics: ty_generics,
@@ -2208,7 +2208,7 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
 
 fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             ty_generics: &ty::Generics<'tcx>)
-                            -> Substs<'tcx>
+                            -> &'tcx Substs<'tcx>
 {
     let types =
         ty_generics.types.map(
@@ -2218,7 +2218,7 @@ fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         ty_generics.regions.map(
             |def| def.to_early_bound_region());
 
-    Substs::new(types, regions)
+    ccx.tcx.mk_substs(Substs::new(types, regions))
 }
 
 /// Checks that all the type parameters on an impl
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 32594a4e618..cdc3cfb7d31 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -247,7 +247,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
             }
             let main_def_id = tcx.map.local_def_id(main_id);
             let substs = tcx.mk_substs(Substs::empty());
-            let se_ty = tcx.mk_fn_def(main_def_id, substs, ty::BareFnTy {
+            let se_ty = tcx.mk_fn_def(main_def_id, substs,
+                                      tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -255,7 +256,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                     output: ty::FnConverging(tcx.mk_nil()),
                     variadic: false
                 })
-            });
+            }));
 
             require_same_types(ccx, None, main_span, main_t, se_ty,
                                "main function has wrong type");
@@ -292,7 +293,8 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
 
             let start_def_id = ccx.tcx.map.local_def_id(start_id);
             let substs = tcx.mk_substs(Substs::empty());
-            let se_ty = tcx.mk_fn_def(start_def_id, substs, ty::BareFnTy {
+            let se_ty = tcx.mk_fn_def(start_def_id, substs,
+                                      tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -303,7 +305,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                     output: ty::FnConverging(tcx.types.isize),
                     variadic: false,
                 }),
-            });
+            }));
 
             require_same_types(ccx, None, start_span, start_t, se_ty,
                                "start function has wrong type");
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index d4d16a60789..a532f9744f4 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -345,7 +345,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_mt(generics, mt, variance);
             }
 
-            ty::TyTuple(ref subtys) => {
+            ty::TyTuple(subtys) => {
                 for &subty in subtys {
                     self.add_constraints_from_ty(generics, subty, variance);
                 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7d8ab70a859..09761e368ff 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -731,7 +731,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
         // collect any late bound regions
         let mut late_bounds = vec![];
         for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace) {
-            if let ty::TyTuple(ref ts) = ty_s.sty {
+            if let ty::TyTuple(ts) = ty_s.sty {
                 for &ty_s in ts {
                     if let ty::TyRef(ref reg, _) = ty_s.sty {
                         if let &ty::Region::ReLateBound(_, _) = *reg {