about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/mod.rs6
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/traits/select.rs6
-rw-r--r--src/librustc/ty/contents.rs13
-rw-r--r--src/librustc/ty/context.rs7
-rw-r--r--src/librustc/ty/flags.rs3
-rw-r--r--src/librustc/ty/layout.rs12
-rw-r--r--src/librustc/ty/mod.rs4
-rw-r--r--src/librustc/ty/outlives.rs4
-rw-r--r--src/librustc/ty/relate.rs9
-rw-r--r--src/librustc/ty/structural_impls.rs12
-rw-r--r--src/librustc/ty/sty.rs23
-rw-r--r--src/librustc/ty/subst.rs29
-rw-r--r--src/librustc/ty/util.rs11
-rw-r--r--src/librustc/ty/walk.rs3
-rw-r--r--src/librustc/util/ppaux.rs5
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs8
-rw-r--r--src/librustc_metadata/encoder.rs4
-rw-r--r--src/librustc_mir/hair/cx/expr.rs4
-rw-r--r--src/librustc_mir/transform/type_check.rs12
-rw-r--r--src/librustc_trans/adt.rs4
-rw-r--r--src/librustc_trans/base.rs63
-rw-r--r--src/librustc_trans/callee.rs177
-rw-r--r--src/librustc_trans/closure.rs319
-rw-r--r--src/librustc_trans/collector.rs32
-rw-r--r--src/librustc_trans/common.rs42
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs5
-rw-r--r--src/librustc_trans/debuginfo/mod.rs13
-rw-r--r--src/librustc_trans/declare.rs5
-rw-r--r--src/librustc_trans/glue.rs4
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/mir/constant.rs8
-rw-r--r--src/librustc_trans/mir/mod.rs4
-rw-r--r--src/librustc_trans/mir/rvalue.rs9
-rw-r--r--src/librustc_trans/trans_item.rs11
-rw-r--r--src/librustc_typeck/check/closure.rs19
-rw-r--r--src/librustc_typeck/check/dropck.rs10
-rw-r--r--src/librustc_typeck/check/upvar.rs8
-rw-r--r--src/librustc_typeck/collect.rs50
39 files changed, 455 insertions, 505 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 46074f6c1f3..2d4b36ec187 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1150,10 +1150,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.tcx.mk_var(self.next_ty_var_id(true))
     }
 
-    pub fn next_ty_vars(&self, n: usize) -> Vec<Ty<'tcx>> {
-        (0..n).map(|_i| self.next_ty_var()).collect()
-    }
-
     pub fn next_int_var_id(&self) -> IntVid {
         self.int_unification_table
             .borrow_mut()
@@ -1657,7 +1653,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     {
         if let InferTables::Local(tables) = self.tables {
             if let Some(ty) = tables.borrow().closure_tys.get(&def_id) {
-                return ty.subst(self.tcx, substs.func_substs);
+                return ty.subst(self.tcx, substs.substs);
             }
         }
 
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index fa49e5c7289..8c0d70c6d60 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -40,6 +40,7 @@
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
 #![feature(staged_api)]
+#![feature(unboxed_closures)]
 #![cfg_attr(stage0, feature(question_mark))]
 #![cfg_attr(test, feature(test))]
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 3944c7e09c0..6f6534cb206 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1912,16 +1912,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 tys.to_vec()
             }
 
-            ty::TyClosure(_, ref substs) => {
+            ty::TyClosure(def_id, ref substs) => {
                 // FIXME(#27086). We are invariant w/r/t our
-                // substs.func_substs, but we don't see them as
+                // func_substs, but we don't see them as
                 // constituent types; this seems RIGHT but also like
                 // something that a normal type couldn't simulate. Is
                 // this just a gap with the way that PhantomData and
                 // 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.to_vec()
+                substs.upvar_tys(def_id, self.tcx()).collect()
             }
 
             // for `PhantomData<T>`, we pass `T`
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
index 7ed4de38be9..9f80c2487fb 100644
--- a/src/librustc/ty/contents.rs
+++ b/src/librustc/ty/contents.rs
@@ -98,10 +98,11 @@ impl TypeContents {
         TC::OwnsOwned | (*self & TC::OwnsAll)
     }
 
-    pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
-        F: FnMut(&T) -> TypeContents,
+    pub fn union<I, T, F>(v: I, mut f: F) -> TypeContents where
+        I: IntoIterator<Item=T>,
+        F: FnMut(T) -> TypeContents,
     {
-        v.iter().fold(TC::None, |tc, ty| tc | f(ty))
+        v.into_iter().fold(TC::None, |tc, ty| tc | f(ty))
     }
 
     pub fn has_dtor(&self) -> bool {
@@ -215,8 +216,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                 }
                 ty::TyStr => TC::None,
 
-                ty::TyClosure(_, ref substs) => {
-                    TypeContents::union(&substs.upvar_tys, |ty| tc_ty(tcx, &ty, cache))
+                ty::TyClosure(def_id, ref substs) => {
+                    TypeContents::union(
+                        substs.upvar_tys(def_id, tcx),
+                        |ty| tc_ty(tcx, &ty, cache))
                 }
 
                 ty::TyTuple(ref tys) => {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index ac1c4fc6a19..45450456e8a 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1446,12 +1446,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn mk_closure(self,
                       closure_id: DefId,
-                      substs: &'tcx Substs<'tcx>,
-                      tys: &[Ty<'tcx>])
+                      substs: &'tcx Substs<'tcx>)
                       -> Ty<'tcx> {
         self.mk_closure_from_closure_substs(closure_id, ClosureSubsts {
-            func_substs: substs,
-            upvar_tys: self.intern_type_list(tys)
+            substs: substs
         })
     }
 
@@ -1574,4 +1572,3 @@ impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
         Ok(f(&iter.collect::<Result<AccumulateVec<[_; 8]>, _>>()?))
     }
 }
-
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 649d78f9d9e..2c09b89beb2 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -88,8 +88,7 @@ impl FlagComputation {
             &ty::TyClosure(_, ref substs) => {
                 self.add_flags(TypeFlags::HAS_TY_CLOSURE);
                 self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
-                self.add_substs(&substs.func_substs);
-                self.add_tys(&substs.upvar_tys);
+                self.add_substs(&substs.substs);
             }
 
             &ty::TyInfer(infer) => {
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 5ce43d905ec..5ee1c3678d6 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -631,7 +631,9 @@ impl<'a, 'gcx, 'tcx> Struct {
 
             // Perhaps one of the upvars of this closure is non-zero
             // Let's recurse and find out!
-            (_, &ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. })) |
+            (_, &ty::TyClosure(def_id, ref substs)) => {
+                Struct::non_zero_field_path(infcx, substs.upvar_tys(def_id, tcx))
+            }
             // Can we use one of the fields in this tuple?
             (_, &ty::TyTuple(tys)) => {
                 Struct::non_zero_field_path(infcx, tys.iter().cloned())
@@ -961,7 +963,13 @@ impl<'a, 'gcx, 'tcx> Layout {
             }
 
             // Tuples and closures.
-            ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) |
+            ty::TyClosure(def_id, ref substs) => {
+                let mut st = Struct::new(dl, false);
+                let tys = substs.upvar_tys(def_id, tcx);
+                st.extend(dl, tys.map(|ty| ty.layout(infcx)), ty)?;
+                Univariant { variant: st, non_zero: false }
+            }
+
             ty::TyTuple(tys) => {
                 let mut st = Struct::new(dl, false);
                 st.extend(dl, tys.iter().map(|ty| ty.layout(infcx)), ty)?;
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 3db70514041..1de54f49a55 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2544,12 +2544,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // tables by typeck; else, it will be retreived from
         // the external crate metadata.
         if let Some(ty) = self.tables.borrow().closure_tys.get(&def_id) {
-            return ty.subst(self, substs.func_substs);
+            return ty.subst(self, substs.substs);
         }
 
         let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id);
         self.tables.borrow_mut().closure_tys.insert(def_id, ty.clone());
-        ty.subst(self, substs.func_substs)
+        ty.subst(self, substs.substs)
     }
 
     /// Given the def_id of an impl, return the def_id of the trait it implements.
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index 51feab9d40c..e3d13f59395 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -72,7 +72,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // in the `subtys` iterator (e.g., when encountering a
         // projection).
         match ty.sty {
-            ty::TyClosure(_, ref substs) => {
+            ty::TyClosure(def_id, ref substs) => {
                 // FIXME(#27086). We do not accumulate from substs, since they
                 // don't represent reachable data. This means that, in
                 // practice, some of the lifetime parameters might not
@@ -110,7 +110,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '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(def_id, *self) {
                     self.compute_components(upvar_ty, out);
                 }
             }
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index cb90e6392cf..2a01bad33c5 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -534,13 +534,8 @@ 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 substs = relate_substs(relation, None, a.func_substs, b.func_substs)?;
-        assert_eq!(a.upvar_tys.len(), b.upvar_tys.len());
-        Ok(ty::ClosureSubsts {
-            func_substs: substs,
-            upvar_tys: relation.tcx().mk_type_list(
-                a.upvar_tys.iter().zip(b.upvar_tys).map(|(a, b)| relation.relate(a, b)))?
-        })
+        let substs = relate_substs(relation, None, a.substs, b.substs)?;
+        Ok(ty::ClosureSubsts { substs: substs })
     }
 }
 
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 282cb9f80f5..e73be23a42c 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -198,11 +198,8 @@ 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
-            }
+        tcx.lift(&self.substs).map(|substs| {
+            ty::ClosureSubsts { substs: substs }
         })
     }
 }
@@ -654,13 +651,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region {
 impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::ClosureSubsts {
-            func_substs: self.func_substs.fold_with(folder),
-            upvar_tys: self.upvar_tys.fold_with(folder),
+            substs: self.substs.fold_with(folder),
         }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.func_substs.visit_with(visitor) || self.upvar_tys.visit_with(visitor)
+        self.substs.visit_with(visitor)
     }
 }
 
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 7d209093ec7..56466d59682 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -11,6 +11,7 @@
 //! This module contains TypeVariants and its major components
 
 use hir::def_id::DefId;
+
 use middle::region;
 use ty::subst::Substs;
 use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TypeFoldable};
@@ -254,15 +255,23 @@ pub enum TypeVariants<'tcx> {
 /// handle). Plus it fixes an ICE. :P
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ClosureSubsts<'tcx> {
-    /// Lifetime and type parameters from the enclosing function.
+    /// Lifetime and type parameters from the enclosing function,
+    /// concatenated with the types of the upvars.
+    ///
     /// These are separated out because trans wants to pass them around
     /// when monomorphizing.
-    pub func_substs: &'tcx Substs<'tcx>,
+    pub substs: &'tcx Substs<'tcx>,
+}
 
-    /// The types of the upvars. The list parallels the freevars and
-    /// `upvar_borrows` lists. These are kept distinct so that we can
-    /// easily index into them.
-    pub upvar_tys: &'tcx Slice<Ty<'tcx>>
+impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> {
+    #[inline]
+    pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) ->
+        impl Iterator<Item=Ty<'tcx>> + 'tcx
+    {
+        let generics = tcx.item_generics(def_id);
+        self.substs[self.substs.len()-generics.own_count()..].iter().map(
+            |t| t.as_type().expect("unexpected region in upvars"))
+    }
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
@@ -1234,7 +1243,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
                 substs.regions().collect()
             }
             TyClosure(_, ref substs) => {
-                substs.func_substs.regions().collect()
+                substs.substs.regions().collect()
             }
             TyProjection(ref data) => {
                 data.trait_ref.substs.regions().collect()
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 15f4437ed0a..41fcb09fb2d 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -183,6 +183,22 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         tcx.intern_substs(&substs)
     }
 
+    pub fn extend_to<FR, FT>(&self,
+                             tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                             def_id: DefId,
+                             mut mk_region: FR,
+                             mut mk_type: FT)
+                             -> &'tcx Substs<'tcx>
+    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
+          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx>
+    {
+        let defs = tcx.item_generics(def_id);
+        let mut result = Vec::with_capacity(defs.count());
+        result.extend(self[..].iter().cloned());
+        Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type);
+        tcx.intern_substs(&result)
+    }
+
     fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
                          tcx: TyCtxt<'a, 'gcx, 'tcx>,
                          defs: &ty::Generics<'tcx>,
@@ -195,7 +211,15 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
             let parent_defs = tcx.item_generics(def_id);
             Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type);
         }
+        Substs::fill_single(substs, defs, mk_region, mk_type)
+    }
 
+    fn fill_single<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
+                           defs: &ty::Generics<'tcx>,
+                           mk_region: &mut FR,
+                           mk_type: &mut FT)
+    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
+          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
         // Handle Self first, before all regions.
         let mut types = defs.types.iter();
         if defs.parent.is_none() && defs.has_self {
@@ -274,6 +298,11 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
         let defs = tcx.item_generics(source_ancestor);
         tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned())
     }
+
+    pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics<'tcx>)
+                       -> &'tcx Substs<'tcx> {
+        tcx.mk_substs(self.iter().take(generics.count()).cloned())
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index b1aeaeb48d1..7d3e380a3b5 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -11,6 +11,7 @@
 //! misc. type-system utilities too small to deserve their own file
 
 use hir::def_id::DefId;
+use hir::map::DefPathData;
 use infer::InferCtxt;
 use hir::map as ast_map;
 use hir::pat_util;
@@ -390,6 +391,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
         return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params");
     }
+
+    pub fn closure_base_def_id(&self, def_id: DefId) -> DefId {
+        let mut def_id = def_id;
+        while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr {
+            def_id = self.parent_def_id(def_id).unwrap_or_else(|| {
+                bug!("closure {:?} has no parent", def_id);
+            });
+        }
+        def_id
+    }
 }
 
 /// When hashing a type this ends up affecting properties like symbol names. We
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index bebdebf127a..a6ecfd2fb70 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -97,8 +97,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
             stack.extend(substs.types().rev());
         }
         ty::TyClosure(_, ref substs) => {
-            stack.extend(substs.func_substs.types().rev());
-            stack.extend(substs.upvar_tys.iter().cloned().rev());
+            stack.extend(substs.substs.types().rev());
         }
         ty::TyTuple(ts) => {
             stack.extend(ts.iter().cloned().rev());
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 3ed4580336a..a63c7ba6a25 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -907,13 +907,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
             }
             TyStr => write!(f, "str"),
             TyClosure(did, substs) => ty::tls::with(|tcx| {
+                let upvar_tys = substs.upvar_tys(did, 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(upvar_tys) {
                             let def_id = freevar.def.def_id();
                             let node_id = tcx.map.as_local_node_id(def_id).unwrap();
                             write!(f,
@@ -930,7 +931,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                     // visible in trans bug reports, I imagine.
                     write!(f, "@{:?}", did)?;
                     let mut sep = " ";
-                    for (index, upvar_ty) in substs.upvar_tys.iter().enumerate() {
+                    for (index, upvar_ty) in upvar_tys.enumerate() {
                         write!(f, "{}{}:{}", sep, index, upvar_ty)?;
                         sep = ", ";
                     }
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index eced5d1eb1b..cdb19d164bf 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -709,9 +709,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             ty::TyAdt(def, substs) => {
                 self.open_drop_for_adt(c, def, substs)
             }
-            ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts {
-                upvar_tys: tys, ..
-            }) => {
+            ty::TyClosure(def_id, substs) => {
+                let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx).collect();
+                self.open_drop_for_tuple(c, &tys)
+            }
+            ty::TyTuple(tys) => {
                 self.open_drop_for_tuple(c, tys)
             }
             ty::TyBox(ty) => {
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index f169ad66480..778a9d185e1 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1056,10 +1056,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             stability: None,
             deprecation: None,
 
-            ty: None,
+            ty: Some(self.encode_item_type(def_id)),
             inherent_impls: LazySeq::empty(),
             variances: LazySeq::empty(),
-            generics: None,
+            generics: Some(self.encode_generics(def_id)),
             predicates: None,
 
             ast: None,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index ba0d3b49a6c..24c1ca574a0 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -521,8 +521,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             };
             let upvars = cx.tcx.with_freevars(expr.id, |freevars| {
                 freevars.iter()
-                    .enumerate()
-                    .map(|(i, fv)| capture_freevar(cx, expr, fv, substs.upvar_tys[i]))
+                    .zip(substs.upvar_tys(def_id, cx.tcx))
+                    .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty))
                     .collect()
             });
             ExprKind::Closure {
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index ad525d21069..79bb14b7336 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -274,9 +274,15 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                 ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => {
                         (&adt_def.variants[0], substs)
                     }
-                ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts {
-                    upvar_tys: tys, ..
-                }) => {
+                ty::TyClosure(def_id, substs) => {
+                    return match substs.upvar_tys(def_id, tcx).nth(field.index()) {
+                        Some(ty) => Ok(ty),
+                        None => Err(FieldAccessError::OutOfRange {
+                            field_count: substs.upvar_tys(def_id, tcx).count()
+                        })
+                    }
+                }
+                ty::TyTuple(tys) => {
                     return match tys.get(field.index()) {
                         Some(&ty) => Ok(ty),
                         None => Err(FieldAccessError::OutOfRange {
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index d028dd7e7b5..c3340281d07 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -108,9 +108,9 @@ fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
             }).collect::<Vec<_>>()
         },
         ty::TyTuple(fields) => fields.to_vec(),
-        ty::TyClosure(_, substs) => {
+        ty::TyClosure(def_id, substs) => {
             if variant_index > 0 { bug!("{} is a closure, which only has one variant", t);}
-            substs.upvar_tys.to_vec()
+            substs.upvar_tys(def_id, cx.tcx()).collect()
         },
         _ => bug!("{} is not a type that can have fields.", t)
     }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index a990a7c507f..c7cad6455bc 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1003,34 +1003,41 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
     }
 }
 
-/// Builds an LLVM function out of a source function.
-///
-/// If the function closes over its environment a closure will be returned.
-pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                               llfndecl: ValueRef,
-                               instance: Instance<'tcx>,
-                               sig: &ty::FnSig<'tcx>,
-                               abi: Abi) {
+pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
+    let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def));
+    // this is an info! to allow collecting monomorphization statistics
+    // and to allow finding the last function before LLVM aborts from
+    // release builds.
+    info!("trans_instance({})", instance);
+
+    let _icx = push_ctxt("trans_instance");
+
+    let fn_ty = ccx.tcx().item_type(instance.def);
+    let fn_ty = ccx.tcx().erase_regions(&fn_ty);
+    let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
+
+    let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_ty);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
+
+    let lldecl = match ccx.instances().borrow().get(&instance) {
+        Some(&val) => val,
+        None => bug!("Instance `{:?}` not already declared", instance)
+    };
+
     ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
 
-    let _icx = push_ctxt("trans_closure");
     if !ccx.sess().no_landing_pads() {
-        attributes::emit_uwtable(llfndecl, true);
+        attributes::emit_uwtable(lldecl, true);
     }
 
-    // this is an info! to allow collecting monomorphization statistics
-    // and to allow finding the last function before LLVM aborts from
-    // release builds.
-    info!("trans_closure(..., {})", instance);
-
-    let fn_ty = FnType::new(ccx, abi, sig, &[]);
+    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
     let (arena, fcx): (TypedArena<_>, FunctionContext);
     arena = TypedArena::new();
     fcx = FunctionContext::new(ccx,
-                               llfndecl,
+                               lldecl,
                                fn_ty,
-                               Some((instance, sig, abi)),
+                               Some((instance, &sig, abi)),
                                &arena);
 
     if fcx.mir.is_none() {
@@ -1040,26 +1047,6 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     mir::trans_mir(&fcx);
 }
 
-pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
-    let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def));
-    debug!("trans_instance(instance={:?})", instance);
-    let _icx = push_ctxt("trans_instance");
-
-    let fn_ty = ccx.tcx().item_type(instance.def);
-    let fn_ty = ccx.tcx().erase_regions(&fn_ty);
-    let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
-
-    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_ty.fn_sig());
-    let abi = fn_ty.fn_abi();
-
-    let lldecl = match ccx.instances().borrow().get(&instance) {
-        Some(&val) => val,
-        None => bug!("Instance `{:?}` not already declared", instance)
-    };
-
-    trans_closure(ccx, lldecl, instance, &sig, abi);
-}
-
 pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                  def_id: DefId,
                                  substs: &'tcx Substs<'tcx>,
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index f49d63b8376..faf65f3f98b 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -26,11 +26,11 @@ use attributes;
 use base;
 use base::*;
 use build::*;
-use closure;
 use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
 use consts;
 use debuginfo::DebugLoc;
 use declare;
+use value::Value;
 use meth;
 use monomorphize::{self, Instance};
 use trans_item::TransItem;
@@ -147,11 +147,12 @@ impl<'tcx> Callee<'tcx> {
                 // after passing through fulfill_obligation
                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
                 let instance = Instance::new(def_id, substs);
-                let llfn = closure::trans_closure_method(ccx,
-                                                         vtable_closure.closure_def_id,
-                                                         vtable_closure.substs,
-                                                         instance,
-                                                         trait_closure_kind);
+                let llfn = trans_closure_method(
+                    ccx,
+                    vtable_closure.closure_def_id,
+                    vtable_closure.substs,
+                    instance,
+                    trait_closure_kind);
 
                 let method_ty = def_ty(ccx.shared(), def_id, substs);
                 Callee::ptr(llfn, method_ty)
@@ -250,6 +251,170 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
     monomorphize::apply_param_substs(shared, substs, &ty)
 }
 
+
+fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
+                                  def_id: DefId,
+                                  substs: ty::ClosureSubsts<'tcx>,
+                                  method_instance: Instance<'tcx>,
+                                  trait_closure_kind: ty::ClosureKind)
+                                  -> ValueRef
+{
+    // If this is a closure, redirect to it.
+    let (llfn, _) = get_fn(ccx, def_id, substs.substs);
+
+    // If the closure is a Fn closure, but a FnOnce is needed (etc),
+    // then adapt the self type
+    let llfn_closure_kind = ccx.tcx().closure_kind(def_id);
+
+    let _icx = push_ctxt("trans_closure_adapter_shim");
+
+    debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
+           trait_closure_kind={:?}, llfn={:?})",
+           llfn_closure_kind, trait_closure_kind, Value(llfn));
+
+    match (llfn_closure_kind, trait_closure_kind) {
+        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
+        (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
+        (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
+            // No adapter needed.
+            llfn
+        }
+        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
+            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
+            // `fn(&mut self, ...)`. In fact, at trans time, these are
+            // basically the same thing, so we can just return llfn.
+            llfn
+        }
+        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
+        (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
+            // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
+            // self, ...)`.  We want a `fn(self, ...)`. We can produce
+            // this by doing something like:
+            //
+            //     fn call_once(self, ...) { call_mut(&self, ...) }
+            //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
+            //
+            // These are both the same at trans time.
+            trans_fn_once_adapter_shim(ccx, def_id, substs, method_instance, llfn)
+        }
+        _ => {
+            bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
+                 llfn_closure_kind,
+                 trait_closure_kind);
+        }
+    }
+}
+
+fn trans_fn_once_adapter_shim<'a, 'tcx>(
+    ccx: &'a CrateContext<'a, 'tcx>,
+    def_id: DefId,
+    substs: ty::ClosureSubsts<'tcx>,
+    method_instance: Instance<'tcx>,
+    llreffn: ValueRef)
+    -> ValueRef
+{
+    if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) {
+        return llfn;
+    }
+
+    debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})",
+           def_id, substs, Value(llreffn));
+
+    let tcx = ccx.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(def_id, substs);
+    let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
+
+    // Make a version with the type of by-ref closure.
+    let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(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(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);
+
+
+    // Make a version of the closure type with the same arguments, but
+    // with argument #0 being by value.
+    assert_eq!(abi, Abi::RustCall);
+    sig.0.inputs[0] = closure_ty;
+
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
+    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
+
+    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 = method_instance.symbol_name(ccx.shared());
+    let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
+    attributes::set_frame_pointer_elimination(ccx, lloncefn);
+
+    let (block_arena, fcx): (TypedArena<_>, FunctionContext);
+    block_arena = TypedArena::new();
+    fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena);
+    let mut bcx = fcx.init(false);
+
+
+    // the first argument (`self`) will be the (by value) closure env.
+
+    let mut llargs = get_params(fcx.llfn);
+    let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize;
+    let env_arg = &fcx.fn_ty.args[0];
+    let llenv = if env_arg.is_indirect() {
+        llargs[self_idx]
+    } else {
+        let scratch = alloc_ty(bcx, closure_ty, "self");
+        let mut llarg_idx = self_idx;
+        env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch);
+        scratch
+    };
+
+    debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv));
+    // Adjust llargs such that llargs[self_idx..] has the call arguments.
+    // For zero-sized closures that means sneaking in a new argument.
+    if env_arg.is_ignore() {
+        if self_idx > 0 {
+            self_idx -= 1;
+            llargs[self_idx] = llenv;
+        } else {
+            llargs.insert(0, llenv);
+        }
+    } else {
+        llargs[self_idx] = llenv;
+    }
+
+    let dest = fcx.llretslotptr.get();
+
+    let callee = Callee {
+        data: Fn(llreffn),
+        ty: llref_fn_ty
+    };
+
+    // Call the by-ref closure body with `self` in a cleanup scope,
+    // to drop `self` when the body returns, or in case it unwinds.
+    let self_scope = fcx.push_custom_cleanup_scope();
+    fcx.schedule_drop_mem(self_scope, llenv, closure_ty);
+
+    bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx;
+
+    fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
+
+    fcx.finish(bcx, DebugLoc::None);
+
+    ccx.instances().borrow_mut().insert(method_instance, lloncefn);
+
+    lloncefn
+}
+
 /// Translates an adapter that implements the `Fn` trait for a fn
 /// pointer. This is basically the equivalent of something like:
 ///
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
deleted file mode 100644
index a1d645fb993..00000000000
--- a/src/librustc_trans/closure.rs
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use arena::TypedArena;
-use llvm::{self, ValueRef, get_params};
-use rustc::hir::def_id::DefId;
-use abi::{Abi, FnType};
-use attributes;
-use base::*;
-use callee::{self, Callee};
-use common::*;
-use debuginfo::{DebugLoc};
-use declare;
-use monomorphize::{Instance};
-use value::Value;
-use rustc::ty::{self, Ty, TyCtxt};
-
-use rustc::hir;
-
-fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           closure_id: DefId,
-                           fn_ty: Ty<'tcx>)
-                           -> Ty<'tcx> {
-    match tcx.closure_kind(closure_id) {
-        ty::ClosureKind::Fn => {
-            tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), fn_ty)
-        }
-        ty::ClosureKind::FnMut => {
-            tcx.mk_mut_ref(tcx.mk_region(ty::ReErased), fn_ty)
-        }
-        ty::ClosureKind::FnOnce => fn_ty,
-    }
-}
-
-/// Returns the LLVM function declaration for a closure, creating it if
-/// 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>)
-                                               -> 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);
-
-    if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
-        debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}",
-               instance, Value(llfn));
-        return llfn;
-    }
-
-    let symbol = instance.symbol_name(ccx.shared());
-
-    // Compute the rust-call form of the closure call method.
-    let sig = &tcx.closure_type(closure_id, substs).sig;
-    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
-    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 {
-            inputs: Some(get_self_type(tcx, closure_id, closure_type))
-                        .into_iter().chain(sig.inputs).collect(),
-            output: sig.output,
-            variadic: false
-        })
-    }));
-    let llfn = declare::declare_fn(ccx, &symbol, function_type);
-
-    attributes::set_frame_pointer_elimination(ccx, llfn);
-
-    debug!("get_or_create_declaration_if_closure(): inserting new \
-            closure {:?}: {:?}",
-           instance, Value(llfn));
-
-    // NOTE: We do *not* store llfn in the ccx.instances() map here,
-    //       that is only done, when the closures body is translated.
-
-    llfn
-}
-
-pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                            closure_def_id: DefId,
-                                            closure_substs: ty::ClosureSubsts<'tcx>) {
-    // (*) Note that in the case of inlined functions, the `closure_def_id` will be the
-    // defid of the closure in its original crate, whereas `id` will be the id of the local
-    // inlined copy.
-    debug!("trans_closure_body_via_mir(closure_def_id={:?}, closure_substs={:?})",
-           closure_def_id, closure_substs);
-
-    let tcx = ccx.tcx();
-    let _icx = push_ctxt("closure::trans_closure_expr");
-
-    let param_substs = closure_substs.func_substs;
-    let instance = Instance::new(closure_def_id, param_substs);
-
-    // If we have not done so yet, translate this closure's body
-    if  !ccx.instances().borrow().contains_key(&instance) {
-        let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
-
-        unsafe {
-            if ccx.sess().target.target.options.allows_weak_linkage {
-                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::WeakODRLinkage);
-                llvm::SetUniqueComdat(ccx.llmod(), llfn);
-            } else {
-                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage);
-            }
-        }
-
-        // set an inline hint for all closures
-        attributes::inline(llfn, attributes::InlineAttr::Hint);
-
-        // Get the type of this closure. Use the current `param_substs` as
-        // the closure substitutions. This makes sense because the closure
-        // takes the same set of type arguments as the enclosing fn, and
-        // this function (`trans_closure`) is invoked at the point
-        // of the closure expression.
-
-        let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
-        let sig = tcx.erase_late_bound_regions_and_normalize(sig);
-
-        let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
-                                                              closure_substs);
-        let sig = ty::FnSig {
-            inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
-                        .into_iter().chain(sig.inputs).collect(),
-            output: sig.output,
-            variadic: false
-        };
-
-        trans_closure(ccx,
-                      llfn,
-                      Instance::new(closure_def_id, param_substs),
-                      &sig,
-                      Abi::RustCall);
-
-        ccx.instances().borrow_mut().insert(instance, llfn);
-    }
-}
-
-pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
-                                      closure_def_id: DefId,
-                                      substs: ty::ClosureSubsts<'tcx>,
-                                      method_instance: Instance<'tcx>,
-                                      trait_closure_kind: ty::ClosureKind)
-                                      -> ValueRef
-{
-    // If this is a closure, redirect to it.
-    let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs);
-
-    // If weak linkage is not allowed, we have to make sure that a local,
-    // private copy of the closure is available in this codegen unit
-    if !ccx.sess().target.target.options.allows_weak_linkage &&
-       !ccx.sess().opts.single_codegen_unit() {
-
-        trans_closure_body_via_mir(ccx, closure_def_id, substs);
-    }
-
-    // If the closure is a Fn closure, but a FnOnce is needed (etc),
-    // then adapt the self type
-    let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id);
-
-    let _icx = push_ctxt("trans_closure_adapter_shim");
-
-    debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
-           trait_closure_kind={:?}, llfn={:?})",
-           llfn_closure_kind, trait_closure_kind, Value(llfn));
-
-    match (llfn_closure_kind, trait_closure_kind) {
-        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
-        (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
-        (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
-            // No adapter needed.
-            llfn
-        }
-        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
-            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
-            // `fn(&mut self, ...)`. In fact, at trans time, these are
-            // basically the same thing, so we can just return llfn.
-            llfn
-        }
-        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
-        (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
-            // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
-            // self, ...)`.  We want a `fn(self, ...)`. We can produce
-            // this by doing something like:
-            //
-            //     fn call_once(self, ...) { call_mut(&self, ...) }
-            //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
-            //
-            // These are both the same at trans time.
-            trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn)
-        }
-        _ => {
-            bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
-                 llfn_closure_kind,
-                 trait_closure_kind);
-        }
-    }
-}
-
-fn trans_fn_once_adapter_shim<'a, 'tcx>(
-    ccx: &'a CrateContext<'a, 'tcx>,
-    closure_def_id: DefId,
-    substs: ty::ClosureSubsts<'tcx>,
-    method_instance: Instance<'tcx>,
-    llreffn: ValueRef)
-    -> ValueRef
-{
-    if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) {
-        return llfn;
-    }
-
-    debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={:?})",
-           closure_def_id, substs, Value(llreffn));
-
-    let tcx = ccx.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, substs);
-    let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
-
-    // Make a version with the type of by-ref closure.
-    let ty::ClosureTy { unsafety, abi, mut sig } =
-        tcx.closure_type(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(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);
-
-
-    // Make a version of the closure type with the same arguments, but
-    // with argument #0 being by value.
-    assert_eq!(abi, Abi::RustCall);
-    sig.0.inputs[0] = closure_ty;
-
-    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
-    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
-
-    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 = method_instance.symbol_name(ccx.shared());
-    let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
-    attributes::set_frame_pointer_elimination(ccx, lloncefn);
-
-    let (block_arena, fcx): (TypedArena<_>, FunctionContext);
-    block_arena = TypedArena::new();
-    fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena);
-    let mut bcx = fcx.init(false);
-
-
-    // the first argument (`self`) will be the (by value) closure env.
-
-    let mut llargs = get_params(fcx.llfn);
-    let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize;
-    let env_arg = &fcx.fn_ty.args[0];
-    let llenv = if env_arg.is_indirect() {
-        llargs[self_idx]
-    } else {
-        let scratch = alloc_ty(bcx, closure_ty, "self");
-        let mut llarg_idx = self_idx;
-        env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch);
-        scratch
-    };
-
-    debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv));
-    // Adjust llargs such that llargs[self_idx..] has the call arguments.
-    // For zero-sized closures that means sneaking in a new argument.
-    if env_arg.is_ignore() {
-        if self_idx > 0 {
-            self_idx -= 1;
-            llargs[self_idx] = llenv;
-        } else {
-            llargs.insert(0, llenv);
-        }
-    } else {
-        llargs[self_idx] = llenv;
-    }
-
-    let dest = fcx.llretslotptr.get();
-
-    let callee = Callee {
-        data: callee::Fn(llreffn),
-        ty: llref_fn_ty
-    };
-
-    // Call the by-ref closure body with `self` in a cleanup scope,
-    // to drop `self` when the body returns, or in case it unwinds.
-    let self_scope = fcx.push_custom_cleanup_scope();
-    fcx.schedule_drop_mem(self_scope, llenv, closure_ty);
-
-    bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx;
-
-    fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
-
-    fcx.finish(bcx, DebugLoc::None);
-
-    ccx.instances().borrow_mut().insert(method_instance, lloncefn);
-
-    lloncefn
-}
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 41071057274..2728a666556 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -446,24 +446,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         debug!("visiting rvalue {:?}", *rvalue);
 
         match *rvalue {
-            mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id,
-                                                               ref substs), _) => {
-                let mir = self.scx.tcx().item_mir(def_id);
-
-                let concrete_substs = monomorphize::apply_param_substs(self.scx,
-                                                                       self.param_substs,
-                                                                       &substs.func_substs);
-                let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs);
-
-                let visitor = MirNeighborCollector {
-                    scx: self.scx,
-                    mir: &mir,
-                    output: self.output,
-                    param_substs: concrete_substs
-                };
-
-                visit_mir_and_promoted(visitor, &mir);
-            }
             // When doing an cast from a regular pointer to a fat pointer, we
             // have to instantiate all methods of the trait being cast to, so we
             // can build the appropriate vtable.
@@ -797,8 +779,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                 }
             }
         }
-        ty::TyClosure(_, substs) => {
-            for upvar_ty in substs.upvar_tys {
+        ty::TyClosure(def_id, substs) => {
+            for upvar_ty in substs.upvar_tys(def_id, scx.tcx()) {
                 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)));
@@ -888,10 +870,12 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         traits::VtableImpl(impl_data) => {
             Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data))
         }
-        // If we have a closure or a function pointer, we will also encounter
-        // the concrete closure/function somewhere else (during closure or fn
-        // pointer construction). That's where we track those things.
-        traits::VtableClosure(..) |
+        traits::VtableClosure(closure_data) => {
+            Some((closure_data.closure_def_id, closure_data.substs.substs))
+        }
+        // Trait object and function pointer shims are always
+        // instantiated in-place, and as they are just an ABI-adjusting
+        // indirect call they do not have any dependencies.
         traits::VtableFnPointer(..) |
         traits::VtableObject(..) => {
             None
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index d238cf7bb45..a0fac9cc659 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -44,6 +44,8 @@ use rustc::hir;
 
 use arena::TypedArena;
 use libc::{c_uint, c_char};
+use std::borrow::Cow;
+use std::iter;
 use std::ops::Deref;
 use std::ffi::CString;
 use std::cell::{Cell, RefCell, Ref};
@@ -109,7 +111,16 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
             Some([monomorphize::field_ty(ccx.tcx(), substs, &fields[0]),
                   monomorphize::field_ty(ccx.tcx(), substs, &fields[1])])
         }
-        ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) |
+        ty::TyClosure(def_id, substs) => {
+            let mut tys = substs.upvar_tys(def_id, ccx.tcx());
+            tys.next().and_then(|first_ty| tys.next().and_then(|second_ty| {
+                if tys.next().is_some() {
+                    None
+                } else {
+                    Some([first_ty, second_ty])
+                }
+            }))
+        }
         ty::TyTuple(tys) => {
             if tys.len() != 2 {
                 return None;
@@ -1060,3 +1071,32 @@ pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
     }
 }
+
+pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                          ty: Ty<'tcx>)
+                          -> Cow<'tcx, ty::BareFnTy<'tcx>>
+{
+    match ty.sty {
+        ty::TyFnDef(_, _, fty) => Cow::Borrowed(fty),
+        // Shims currently have type TyFnPtr. Not sure this should remain.
+        ty::TyFnPtr(fty) => Cow::Borrowed(fty),
+        ty::TyClosure(def_id, substs) => {
+            let tcx = ccx.tcx();
+            let ty::ClosureTy { unsafety, abi, sig } = tcx.closure_type(def_id, substs);
+
+            let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
+            let env_ty = match tcx.closure_kind(def_id) {
+                ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty),
+                ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty),
+                ty::ClosureKind::FnOnce => ty,
+            };
+
+            let sig = sig.map_bound(|sig| ty::FnSig {
+                inputs: iter::once(env_ty).chain(sig.inputs).collect(),
+                ..sig
+            });
+            Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig })
+        }
+        _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
+    }
+}
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 679e308c345..5b9ef78ddc2 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -574,10 +574,11 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
 
         }
-        ty::TyClosure(_, ref substs) => {
+        ty::TyClosure(def_id, substs) => {
+            let upvar_tys : Vec<_> = substs.upvar_tys(def_id, cx.tcx()).collect();
             prepare_tuple_metadata(cx,
                                    t,
-                                   &substs.upvar_tys,
+                                   &upvar_tys,
                                    unique_type_id,
                                    usage_site_span).finalize(cx)
         }
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index 45b8ec1dc80..482275d298b 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -25,7 +25,6 @@ use llvm::{ModuleRef, ContextRef, ValueRef};
 use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
                       FlagPrototyped};
 use rustc::hir::def_id::DefId;
-use rustc::hir::map::DefPathData;
 use rustc::ty::subst::Substs;
 
 use abi::Abi;
@@ -248,21 +247,19 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     };
 
     // Find the enclosing function, in case this is a closure.
-    let mut fn_def_id = instance.def;
-    let mut def_key = cx.tcx().def_key(fn_def_id);
+    let def_key = cx.tcx().def_key(instance.def);
     let mut name = def_key.disambiguated_data.data.to_string();
     let name_len = name.len();
-    while def_key.disambiguated_data.data == DefPathData::ClosureExpr {
-        fn_def_id.index = def_key.parent.expect("closure without a parent?");
-        def_key = cx.tcx().def_key(fn_def_id);
-    }
+
+    let fn_def_id = cx.tcx().closure_base_def_id(instance.def);
 
     // Get_template_parameters() will append a `<...>` clause to the function
     // name if necessary.
     let generics = cx.tcx().item_generics(fn_def_id);
+    let substs = instance.substs.truncate_to(cx.tcx(), generics);
     let template_parameters = get_template_parameters(cx,
                                                       &generics,
-                                                      instance.substs,
+                                                      substs,
                                                       file_metadata,
                                                       &mut name);
 
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index 1ec5ca4a563..662e3bec66d 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -25,6 +25,7 @@ use rustc::ty;
 use abi::{Abi, FnType};
 use attributes;
 use context::CrateContext;
+use common;
 use type_::Type;
 use value::Value;
 
@@ -103,8 +104,8 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef {
 pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
                             fn_type: ty::Ty<'tcx>) -> ValueRef {
     debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
-    let abi = fn_type.fn_abi();
-    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_type.fn_sig());
+    let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_type);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
     debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
 
     let fty = FnType::new(ccx, abi, &sig, &[]);
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 648dd9f3e3a..d6d4d33923f 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -531,8 +531,8 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
 
     let mut cx = cx;
     match t.sty {
-        ty::TyClosure(_, ref substs) => {
-            for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() {
+        ty::TyClosure(def_id, substs) => {
+            for (i, upvar_ty) in substs.upvar_tys(def_id, cx.tcx()).enumerate() {
                 let llupvar = adt::trans_field_ptr(cx, t, value, Disr(0), i);
                 cx = drop_ty(cx, llupvar, upvar_ty, DebugLoc::None);
             }
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 8ef7f04d4ee..0757343a8af 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -109,7 +109,6 @@ mod cabi_x86_64;
 mod cabi_x86_win64;
 mod callee;
 mod cleanup;
-mod closure;
 mod collector;
 mod common;
 mod consts;
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index b8d346b11c1..bca81fa3645 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -553,14 +553,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                 }
                 failure?;
 
-                // FIXME Shouldn't need to manually trigger closure instantiations.
-                if let mir::AggregateKind::Closure(def_id, substs) = *kind {
-                    use closure;
-                    closure::trans_closure_body_via_mir(self.ccx,
-                                                        def_id,
-                                                        self.monomorphize(&substs));
-                }
-
                 match *kind {
                     mir::AggregateKind::Array => {
                         self.const_array(dest_ty, &fields)
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index d2adf88c916..12b17c26cbc 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -470,8 +470,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
             } else {
                 (arg_ty, false)
             };
-            let upvar_tys = if let ty::TyClosure(_, ref substs) = closure_ty.sty {
-                &substs.upvar_tys[..]
+            let upvar_tys = if let ty::TyClosure(def_id, substs) = closure_ty.sty {
+                substs.upvar_tys(def_id, tcx)
             } else {
                 bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty);
             };
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index f25877b1de1..bf01db0ffd3 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -133,15 +133,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         }
                     },
                     _ => {
-                        // FIXME Shouldn't need to manually trigger closure instantiations.
-                        if let mir::AggregateKind::Closure(def_id, substs) = *kind {
-                            use closure;
-
-                            closure::trans_closure_body_via_mir(bcx.ccx(),
-                                                                def_id,
-                                                                bcx.monomorphize(&substs));
-                        }
-
                         for (i, operand) in operands.iter().enumerate() {
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 93790cc27bc..c5a7dbbcf54 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -166,6 +166,11 @@ impl<'a, 'tcx> TransItem<'tcx> {
             llvm::SetUniqueComdat(ccx.llmod(), lldecl);
         }
 
+        if let ty::TyClosure(..) = mono_ty.sty {
+            // set an inline hint for all closures
+            attributes::inline(lldecl, attributes::InlineAttr::Hint);
+        }
+
         attributes::from_fn_attrs(ccx, &attrs, lldecl);
 
         ccx.instances().borrow_mut().insert(instance, lldecl);
@@ -477,12 +482,14 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 push_unique_type_name(tcx, sig.output, output);
             }
         },
-        ty::TyClosure(def_id, ref closure_substs) => {
+        ty::TyClosure(def_id, closure_substs) => {
             push_item_name(tcx, def_id, output);
             output.push_str("{");
             output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize()));
             output.push_str("}");
-            push_type_params(tcx, closure_substs.func_substs, &[], output);
+            let generics = tcx.item_generics(tcx.closure_base_def_id(def_id));
+            let substs = closure_substs.substs.truncate_to(tcx, generics);
+            push_type_params(tcx, substs, &[], output);
         }
         ty::TyError |
         ty::TyInfer(_) |
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index af834f3f84d..75287d4064a 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -47,12 +47,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                      body: &'gcx hir::Expr,
                      expected_sig: Option<ty::FnSig<'tcx>>)
                      -> Ty<'tcx> {
-        let expr_def_id = self.tcx.map.local_def_id(expr.id);
-
         debug!("check_closure opt_kind={:?} expected_sig={:?}",
                opt_kind,
                expected_sig);
 
+        let expr_def_id = self.tcx.map.local_def_id(expr.id);
         let mut fn_ty = AstConv::ty_of_closure(self,
                                                hir::Unsafety::Normal,
                                                decl,
@@ -62,16 +61,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Create type variables (for now) to represent the transformed
         // types of upvars. These will be unified during the upvar
         // inference phase (`upvar.rs`).
-        let num_upvars = self.tcx.with_freevars(expr.id, |fv| fv.len());
-        let upvar_tys = self.next_ty_vars(num_upvars);
-
-        debug!("check_closure: expr.id={:?} upvar_tys={:?}",
-               expr.id,
-               upvar_tys);
-
         let closure_type = self.tcx.mk_closure(expr_def_id,
-                                               self.parameter_environment.free_substs,
-                                               &upvar_tys);
+            self.parameter_environment.free_substs.extend_to(self.tcx, expr_def_id,
+                |_, _| span_bug!(expr.span, "closure has region param"),
+                |_, _| self.infcx.next_ty_var()
+            )
+        );
+
+        debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
 
         let fn_sig = self.tcx
             .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id),
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 8657b30bf8e..09e1f6592c1 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -482,8 +482,14 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
             Ok(())
         }
 
-        ty::TyTuple(tys) |
-        ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) => {
+        ty::TyClosure(def_id, substs) => {
+            for ty in substs.upvar_tys(def_id, tcx) {
+                iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
+            }
+            Ok(())
+        }
+
+        ty::TyTuple(tys) => {
             for ty in tys {
                 iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
             }
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 2fea86cb212..1ea47107c3b 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -183,8 +183,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         // inference algorithm will reject it).
 
         // Extract the type variables UV0...UVn.
-        let closure_substs = match self.fcx.node_ty(id).sty {
-            ty::TyClosure(_, ref substs) => substs,
+        let (def_id, closure_substs) = match self.fcx.node_ty(id).sty {
+            ty::TyClosure(def_id, substs) => (def_id, substs),
             ref t => {
                 span_bug!(
                     span,
@@ -197,7 +197,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         let final_upvar_tys = self.final_upvar_tys(id);
         debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}",
                id, closure_substs, final_upvar_tys);
-        for (&upvar_ty, final_upvar_ty) in closure_substs.upvar_tys.iter().zip(final_upvar_tys) {
+        for (upvar_ty, final_upvar_ty) in
+            closure_substs.upvar_tys(def_id, self.fcx.tcx).zip(final_upvar_tys)
+        {
             self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty);
         }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 968d5d73e7a..816243b3eab 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -80,7 +80,7 @@ use std::cell::RefCell;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 
 use syntax::{abi, ast, attr};
-use syntax::parse::token::keywords;
+use syntax::parse::token::{self, keywords};
 use syntax_pos::Span;
 
 use rustc::hir::{self, intravisit, map as hir_map, print as pprust};
@@ -134,6 +134,13 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx>
         intravisit::walk_item(self, item);
     }
 
+    fn visit_expr(&mut self, expr: &hir::Expr) {
+        if let hir::ExprClosure(..) = expr.node {
+            convert_closure(self.ccx, expr.id);
+        }
+        intravisit::walk_expr(self, expr);
+    }
+
     fn visit_ty(&mut self, ty: &hir::Ty) {
         if let hir::TyImplTrait(..) = ty.node {
             let def_id = self.ccx.tcx.map.local_def_id(ty.id);
@@ -559,6 +566,40 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone());
 }
 
+fn convert_closure<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                             node_id: ast::NodeId)
+{
+    let tcx = ccx.tcx;
+    let def_id = tcx.map.local_def_id(node_id);
+    let base_def_id = tcx.closure_base_def_id(def_id);
+    let base_generics = generics_of_def_id(ccx, base_def_id);
+
+    // provide junk type parameter defs - the only place that
+    // cares about anything but the length is instantiation,
+    // and we don't do that for closures.
+    let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| {
+        fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
+            index: (base_generics.count() as u32) + (i as u32),
+            name: token::intern("<upvar>"),
+            def_id: def_id,
+            default_def_id: base_def_id,
+            default: None,
+            object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
+            pure_wrt_drop: false,
+        }).collect()
+    });
+    tcx.generics.borrow_mut().insert(def_id, tcx.alloc_generics(ty::Generics {
+        parent: Some(base_def_id),
+        parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32),
+        parent_types: base_generics.parent_types + (base_generics.types.len() as u32),
+        regions: vec![],
+        types: upvar_decls,
+        has_self: base_generics.has_self,
+    }));
+
+    type_of_def_id(ccx, def_id);
+}
+
 fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             container: AssociatedItemContainer,
                             id: ast::NodeId,
@@ -1504,6 +1545,13 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     }
                 }
             }
+            NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+                ccx.tcx.mk_closure(def_id, Substs::for_item(
+                    ccx.tcx, def_id,
+                    |def, _| ccx.tcx.mk_region(def.to_early_bound_region()),
+                    |def, _| ccx.tcx.mk_param_from_def(def)
+                ))
+            }
             x => {
                 bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
             }