about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-01-02 08:11:19 +0000
committerbors <bors@rust-lang.org>2015-01-02 08:11:19 +0000
commit1f887c8c5773307033fd821a5045cdc10b790ea5 (patch)
treeae60dd6f85a97200359bc0f697623f9287acaa36 /src
parentee3c5957eaaf577bff895ce819447f7e40558a28 (diff)
parent345e38cc0582d2ad00c05e9307bfddef19c84e64 (diff)
downloadrust-1f887c8c5773307033fd821a5045cdc10b790ea5.tar.gz
rust-1f887c8c5773307033fd821a5045cdc10b790ea5.zip
auto merge of #20412 : nikomatsakis/rust/assoc-types, r=aturon
These changes fix various problems encountered getting japaric's `at-iter` branch to work. This branch converts the `Iterator` trait to use an associated type.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/middle/liveness.rs18
-rw-r--r--src/librustc/middle/mem_categorization.rs13
-rw-r--r--src/librustc/middle/traits/fulfill.rs8
-rw-r--r--src/librustc/middle/traits/project.rs38
-rw-r--r--src/librustc/middle/traits/select.rs88
-rw-r--r--src/librustc/middle/ty.rs169
-rw-r--r--src/librustc/middle/ty_fold.rs10
-rw-r--r--src/librustc_trans/trans/adt.rs2
-rw-r--r--src/librustc_trans/trans/base.rs36
-rw-r--r--src/librustc_trans/trans/closure.rs21
-rw-r--r--src/librustc_trans/trans/common.rs86
-rw-r--r--src/librustc_trans/trans/debuginfo.rs16
-rw-r--r--src/librustc_trans/trans/monomorphize.rs3
-rw-r--r--src/librustc_typeck/check/assoc.rs3
-rw-r--r--src/librustc_typeck/check/mod.rs32
16 files changed, 381 insertions, 164 deletions
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 1ebb18f976e..d36c85342ce 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -1229,7 +1229,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             // inferred by regionbk
             let upvar_id = ty::UpvarId { var_id: id_var,
                                          closure_expr_id: closure_expr.id };
-            let upvar_borrow = self.typer.upvar_borrow(upvar_id);
+            let upvar_borrow = self.typer.upvar_borrow(upvar_id).unwrap();
 
             self.delegate.borrow(closure_expr.id,
                                  closure_expr.span,
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 5be8d03e743..0c3438abb2b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -111,7 +111,9 @@ use self::VarKind::*;
 
 use middle::def::*;
 use middle::mem_categorization::Typer;
-use middle::{pat_util, ty};
+use middle::pat_util;
+use middle::ty;
+use middle::ty::UnboxedClosureTyper;
 use lint;
 use util::nodemap::NodeMap;
 
@@ -1515,16 +1517,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn fn_ret(&self, id: NodeId) -> ty::FnOutput<'tcx> {
         let fn_ty = ty::node_id_to_type(self.ir.tcx, id);
         match fn_ty.sty {
-            ty::ty_unboxed_closure(closure_def_id, _, _) =>
-                self.ir.tcx.unboxed_closures()
-                    .borrow()
-                    .get(&closure_def_id)
-                    .unwrap()
-                    .closure_type
-                    .sig
-                    .0
-                    .output,
-            _ => ty::ty_fn_ret(fn_ty)
+            ty::ty_unboxed_closure(closure_def_id, _, substs) =>
+                self.ir.tcx.unboxed_closure_type(closure_def_id, substs).sig.0.output,
+            _ =>
+                ty::ty_fn_ret(fn_ty),
         }
     }
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 580b3a93d73..70942a950e3 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -74,7 +74,7 @@ pub use self::categorization::*;
 use middle::def;
 use middle::region;
 use middle::ty::{mod, Ty};
-use util::nodemap::{DefIdMap, NodeMap};
+use util::nodemap::{NodeMap};
 use util::ppaux::{ty_to_string, Repr};
 
 use syntax::ast::{MutImmutable, MutMutable};
@@ -280,7 +280,7 @@ impl<'t,TYPER:'t> Copy for MemCategorizationContext<'t,TYPER> {}
 /// In the borrow checker, in contrast, type checking is complete and we
 /// know that no errors have occurred, so we simply consult the tcx and we
 /// can be sure that only `Ok` results will occur.
-pub trait Typer<'tcx> {
+pub trait Typer<'tcx> : ty::UnboxedClosureTyper<'tcx> {
     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
     fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx>;
     fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx>;
@@ -290,11 +290,9 @@ pub trait Typer<'tcx> {
     fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>;
     fn is_method_call(&self, id: ast::NodeId) -> bool;
     fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>;
-    fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow;
+    fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow>;
     fn capture_mode(&self, closure_expr_id: ast::NodeId)
                     -> ast::CaptureClause;
-    fn unboxed_closures<'a>(&'a self)
-                        -> &'a RefCell<DefIdMap<ty::UnboxedClosure<'tcx>>>;
 }
 
 impl MutabilityCategory {
@@ -622,8 +620,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                       self.cat_upvar(id, span, var_id, fn_node_id, kind, mode, false)
                   }
                   ty::ty_unboxed_closure(closure_id, _, _) => {
-                      let unboxed_closures = self.typer.unboxed_closures().borrow();
-                      let kind = (*unboxed_closures)[closure_id].kind;
+                      let kind = self.typer.unboxed_closure_kind(closure_id);
                       let mode = self.typer.capture_mode(fn_node_id);
                       self.cat_upvar(id, span, var_id, fn_node_id, kind, mode, true)
                   }
@@ -800,7 +797,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
                 }
 
                 // Look up upvar borrow so we can get its region
-                let upvar_borrow = self.typer.upvar_borrow(upvar_id);
+                let upvar_borrow = self.typer.upvar_borrow(upvar_id).unwrap();
                 let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region);
 
                 Rc::new(cmt_ {
diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index c85baccd633..2dbb15b215e 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -110,7 +110,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
     pub fn normalize_projection_type<'a>(&mut self,
                                          infcx: &InferCtxt<'a,'tcx>,
                                          param_env: &ty::ParameterEnvironment<'tcx>,
-                                         typer: &Typer<'tcx>,
+                                         typer: &ty::UnboxedClosureTyper<'tcx>,
                                          projection_ty: ty::ProjectionTy<'tcx>,
                                          cause: ObligationCause<'tcx>)
                                          -> Ty<'tcx>
@@ -187,7 +187,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
     pub fn select_all_or_error<'a>(&mut self,
                                    infcx: &InferCtxt<'a,'tcx>,
                                    param_env: &ty::ParameterEnvironment<'tcx>,
-                                   typer: &Typer<'tcx>)
+                                   typer: &ty::UnboxedClosureTyper<'tcx>)
                                    -> Result<(),Vec<FulfillmentError<'tcx>>>
     {
         try!(self.select_where_possible(infcx, param_env, typer));
@@ -213,7 +213,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
     pub fn select_new_obligations<'a>(&mut self,
                                       infcx: &InferCtxt<'a,'tcx>,
                                       param_env: &ty::ParameterEnvironment<'tcx>,
-                                      typer: &Typer<'tcx>)
+                                      typer: &ty::UnboxedClosureTyper<'tcx>)
                                       -> Result<(),Vec<FulfillmentError<'tcx>>>
     {
         let mut selcx = SelectionContext::new(infcx, param_env, typer);
@@ -223,7 +223,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
     pub fn select_where_possible<'a>(&mut self,
                                      infcx: &InferCtxt<'a,'tcx>,
                                      param_env: &ty::ParameterEnvironment<'tcx>,
-                                     typer: &Typer<'tcx>)
+                                     typer: &ty::UnboxedClosureTyper<'tcx>)
                                      -> Result<(),Vec<FulfillmentError<'tcx>>>
     {
         let mut selcx = SelectionContext::new(infcx, param_env, typer);
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index 28a826b859b..c84f31bf6c3 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -102,7 +102,7 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
 
 /// Compute result of projecting an associated type and unify it with
 /// `obligation.predicate.ty` (if we can).
-pub fn project_and_unify_type<'cx,'tcx>(
+fn project_and_unify_type<'cx,'tcx>(
     selcx: &mut SelectionContext<'cx,'tcx>,
     obligation: &ProjectionObligation<'tcx>)
     -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
@@ -135,9 +135,19 @@ pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
                                cause: ObligationCause<'tcx>,
                                value: &T)
                                -> Normalized<'tcx, T>
-    where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone
+    where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
 {
-    let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, 0);
+    normalize_with_depth(selcx, cause, 0, value)
+}
+
+pub fn normalize_with_depth<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
+                                          cause: ObligationCause<'tcx>,
+                                          depth: uint,
+                                          value: &T)
+                                          -> Normalized<'tcx, T>
+    where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
+{
+    let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
     let result = normalizer.fold(value);
     Normalized {
         value: result,
@@ -278,9 +288,10 @@ fn opt_normalize_projection_type<'a,'b,'tcx>(
             // an impl, where-clause etc) and hence we must
             // re-normalize it
 
-            debug!("normalize_projection_type: projected_ty={} depth={}",
+            debug!("normalize_projection_type: projected_ty={} depth={} obligations={}",
                    projected_ty.repr(selcx.tcx()),
-                   depth);
+                   depth,
+                   obligations.repr(selcx.tcx()));
 
             if ty::type_has_projection(projected_ty) {
                 let tcx = selcx.tcx();
@@ -644,3 +655,20 @@ impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
         }
     }
 }
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Normalized<'tcx, T> {
+        Normalized {
+            value: self.value.fold_with(folder),
+            obligations: self.obligations.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Normalized<'tcx, T> {
+    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+        format!("Normalized({},{})",
+                self.value.repr(tcx),
+                self.obligations.repr(tcx))
+    }
+}
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index ce5337a58e1..f9dced088f8 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -18,6 +18,7 @@ use self::BuiltinBoundConditions::*;
 use self::EvaluationResult::*;
 
 use super::{DerivedObligationCause};
+use super::{project};
 use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause};
 use super::{ObligationCauseCode, BuiltinDerivedObligation};
 use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
@@ -29,7 +30,7 @@ use super::{util};
 
 use middle::fast_reject;
 use middle::mem_categorization::Typer;
-use middle::subst::{Subst, Substs, VecPerParamSpace};
+use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace};
 use middle::ty::{mod, AsPredicate, RegionEscape, ToPolyTraitRef, Ty};
 use middle::infer;
 use middle::infer::{InferCtxt, TypeFreshener};
@@ -44,7 +45,7 @@ use util::ppaux::Repr;
 pub struct SelectionContext<'cx, 'tcx:'cx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
     param_env: &'cx ty::ParameterEnvironment<'tcx>,
-    typer: &'cx (Typer<'tcx>+'cx),
+    closure_typer: &'cx (ty::UnboxedClosureTyper<'tcx>+'cx),
 
     /// Freshener used specifically for skolemizing entries on the
     /// obligation stack. This ensures that all entries on the stack
@@ -177,12 +178,12 @@ enum EvaluationResult<'tcx> {
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>,
                param_env: &'cx ty::ParameterEnvironment<'tcx>,
-               typer: &'cx Typer<'tcx>)
+               closure_typer: &'cx ty::UnboxedClosureTyper<'tcx>)
                -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
             infcx: infcx,
             param_env: param_env,
-            typer: typer,
+            closure_typer: closure_typer,
             freshener: infcx.freshener(),
             intercrate: false,
         }
@@ -190,12 +191,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>,
                       param_env: &'cx ty::ParameterEnvironment<'tcx>,
-                      typer: &'cx Typer<'tcx>)
+                      closure_typer: &'cx ty::UnboxedClosureTyper<'tcx>)
                       -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
             infcx: infcx,
             param_env: param_env,
-            typer: typer,
+            closure_typer: closure_typer,
             freshener: infcx.freshener(),
             intercrate: true,
         }
@@ -918,15 +919,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                kind,
                obligation.repr(self.tcx()));
 
-        let closure_kind = match self.typer.unboxed_closures().borrow().get(&closure_def_id) {
-            Some(closure) => closure.kind,
-            None => {
-                self.tcx().sess.span_bug(
-                    obligation.cause.span,
-                    format!("No entry for unboxed closure: {}",
-                            closure_def_id.repr(self.tcx()))[]);
-            }
-        };
+        let closure_kind = self.closure_typer.unboxed_closure_kind(closure_def_id);
 
         debug!("closure_kind = {}", closure_kind);
 
@@ -1398,32 +1391,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     return Ok(ParameterBuiltin);
                 }
 
-                match self.tcx().freevars.borrow().get(&def_id.node) {
-                    None => {
-                        // No upvars.
-                        Ok(If(Vec::new()))
+                match self.closure_typer.unboxed_closure_upvars(def_id, substs) {
+                    Some(upvars) => {
+                        Ok(If(upvars.iter().map(|c| c.ty).collect()))
                     }
-
-                    Some(freevars) => {
-                        let tys: Vec<Ty> =
-                            freevars
-                            .iter()
-                            .map(|freevar| {
-                                let freevar_def_id = freevar.def.def_id();
-                                self.typer.node_ty(freevar_def_id.node).subst(self.tcx(), substs)
-                            })
-                            .collect();
-                        Ok(If(tys))
+                    None => {
+                        Ok(AmbiguousBuiltin)
                     }
                 }
             }
 
             ty::ty_struct(def_id, substs) => {
                 let types: Vec<Ty> =
-                    ty::struct_fields(self.tcx(), def_id, substs)
-                    .iter()
-                    .map(|f| f.mt.ty)
-                    .collect();
+                    ty::struct_fields(self.tcx(), def_id, substs).iter()
+                                                                 .map(|f| f.mt.ty)
+                                                                 .collect();
                 nominal(self, bound, def_id, types)
             }
 
@@ -1798,27 +1780,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                closure_def_id.repr(self.tcx()),
                substs.repr(self.tcx()));
 
-        let closure_type = match self.typer.unboxed_closures().borrow().get(&closure_def_id) {
-            Some(closure) => closure.closure_type.clone(),
-            None => {
-                self.tcx().sess.span_bug(
-                    obligation.cause.span,
-                    format!("No entry for unboxed closure: {}",
-                            closure_def_id.repr(self.tcx()))[]);
-            }
-        };
+        let closure_type = self.closure_typer.unboxed_closure_type(closure_def_id, substs);
+
+        debug!("confirm_unboxed_closure_candidate: closure_def_id={} closure_type={}",
+               closure_def_id.repr(self.tcx()),
+               closure_type.repr(self.tcx()));
 
         let closure_sig = &closure_type.sig;
         let arguments_tuple = closure_sig.0.inputs[0];
-        let substs =
+        let trait_substs =
             Substs::new_trait(
-                vec![arguments_tuple.subst(self.tcx(), substs),
-                     closure_sig.0.output.unwrap().subst(self.tcx(), substs)],
+                vec![arguments_tuple, closure_sig.0.output.unwrap()],
                 vec![],
                 obligation.self_ty());
         let trait_ref = ty::Binder(Rc::new(ty::TraitRef {
             def_id: obligation.predicate.def_id(),
-            substs: self.tcx().mk_substs(substs),
+            substs: self.tcx().mk_substs(trait_substs),
         }));
 
         debug!("confirm_unboxed_closure_candidate(closure_def_id={}, trait_ref={})",
@@ -2100,7 +2077,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    fn impl_predicates(&self,
+    fn impl_predicates(&mut self,
                        cause: ObligationCause<'tcx>,
                        recursion_depth: uint,
                        impl_def_id: ast::DefId,
@@ -2111,8 +2088,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     {
         let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
         let bounds = impl_generics.to_bounds(self.tcx(), impl_substs);
-        let bounds = self.infcx().plug_leaks(skol_map, snapshot, &bounds);
-        util::predicates_for_generics(self.tcx(), cause, recursion_depth, &bounds)
+        let normalized_bounds =
+            project::normalize_with_depth(self, cause.clone(), recursion_depth, &bounds);
+        let normalized_bounds =
+            self.infcx().plug_leaks(skol_map, snapshot, &normalized_bounds);
+        let mut impl_obligations =
+            util::predicates_for_generics(self.tcx(),
+                                          cause,
+                                          recursion_depth,
+                                          &normalized_bounds.value);
+        for obligation in normalized_bounds.obligations.into_iter() {
+            impl_obligations.push(TypeSpace, obligation);
+        }
+        impl_obligations
     }
 
     fn fn_family_trait_kind(&self,
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 82a8bc3cd06..7bc5d3d0708 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -2267,6 +2267,23 @@ impl UnboxedClosureKind {
     }
 }
 
+pub trait UnboxedClosureTyper<'tcx> {
+    fn unboxed_closure_kind(&self,
+                            def_id: ast::DefId)
+                            -> ty::UnboxedClosureKind;
+
+    fn unboxed_closure_type(&self,
+                            def_id: ast::DefId,
+                            substs: &subst::Substs<'tcx>)
+                            -> ty::ClosureTy<'tcx>;
+
+    // Returns `None` if the upvar types cannot yet be definitively determined.
+    fn unboxed_closure_upvars(&self,
+                              def_id: ast::DefId,
+                              substs: &Substs<'tcx>)
+                              -> Option<Vec<UnboxedClosureUpvar<'tcx>>>;
+}
+
 impl<'tcx> CommonTypes<'tcx> {
     fn new(arena: &'tcx TypedArena<TyS<'tcx>>,
            interner: &mut FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>)
@@ -3353,7 +3370,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
             ty_unboxed_closure(did, r, substs) => {
                 // FIXME(#14449): `borrowed_contents` below assumes `&mut`
                 // unboxed closure.
-                let upvars = unboxed_closure_upvars(cx, did, substs);
+                let upvars = unboxed_closure_upvars(cx, did, substs).unwrap();
                 TypeContents::union(upvars.as_slice(),
                                     |f| tc_ty(cx, f.ty, cache))
                     | borrowed_contents(*r, MutMutable)
@@ -3633,7 +3650,7 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool {
             }
 
             ty_unboxed_closure(did, _, substs) => {
-                let upvars = unboxed_closure_upvars(cx, did, substs);
+                let upvars = unboxed_closure_upvars(cx, did, substs).unwrap();
                 upvars.iter().any(|f| type_requires(cx, seen, r_ty, f.ty))
             }
 
@@ -3725,7 +3742,7 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>)
                 find_nonrepresentable(cx, sp, seen, iter)
             }
             ty_unboxed_closure(did, _, substs) => {
-                let upvars = unboxed_closure_upvars(cx, did, substs);
+                let upvars = unboxed_closure_upvars(cx, did, substs).unwrap();
                 find_nonrepresentable(cx, sp, seen, upvars.iter().map(|f| f.ty))
             }
             _ => Representable,
@@ -5656,7 +5673,7 @@ pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec<field<'tcx>> {
     }).collect()
 }
 
-#[deriving(Copy)]
+#[deriving(Copy, Clone)]
 pub struct UnboxedClosureUpvar<'tcx> {
     pub def: def::Def,
     pub span: Span,
@@ -5664,38 +5681,67 @@ pub struct UnboxedClosureUpvar<'tcx> {
 }
 
 // Returns a list of `UnboxedClosureUpvar`s for each upvar.
-pub fn unboxed_closure_upvars<'tcx>(tcx: &ctxt<'tcx>, closure_id: ast::DefId, substs: &Substs<'tcx>)
-                                    -> Vec<UnboxedClosureUpvar<'tcx>> {
+pub fn unboxed_closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
+                                    closure_id: ast::DefId,
+                                    substs: &Substs<'tcx>)
+                                    -> Option<Vec<UnboxedClosureUpvar<'tcx>>>
+{
     // Presently an unboxed closure type cannot "escape" out of a
     // function, so we will only encounter ones that originated in the
     // local crate or were inlined into it along with some function.
     // This may change if abstract return types of some sort are
     // implemented.
     assert!(closure_id.krate == ast::LOCAL_CRATE);
+    let tcx = typer.tcx();
     let capture_mode = tcx.capture_modes.borrow()[closure_id.node].clone();
     match tcx.freevars.borrow().get(&closure_id.node) {
-        None => vec![],
+        None => Some(vec![]),
         Some(ref freevars) => {
-            freevars.iter().map(|freevar| {
-                let freevar_def_id = freevar.def.def_id();
-                let freevar_ty = node_id_to_type(tcx, freevar_def_id.node);
-                let mut freevar_ty = freevar_ty.subst(tcx, substs);
-                if capture_mode == ast::CaptureByRef {
-                    let borrow = tcx.upvar_borrow_map.borrow()[ty::UpvarId {
-                        var_id: freevar_def_id.node,
-                        closure_expr_id: closure_id.node
-                    }].clone();
-                    freevar_ty = mk_rptr(tcx, tcx.mk_region(borrow.region), ty::mt {
-                        ty: freevar_ty,
-                        mutbl: borrow.kind.to_mutbl_lossy()
-                    });
-                }
-                UnboxedClosureUpvar {
-                    def: freevar.def,
-                    span: freevar.span,
-                    ty: freevar_ty
-                }
-            }).collect()
+            freevars.iter()
+                    .map(|freevar| {
+                        let freevar_def_id = freevar.def.def_id();
+                        let freevar_ty = typer.node_ty(freevar_def_id.node);
+                        let freevar_ty = freevar_ty.subst(tcx, substs);
+
+                        match capture_mode {
+                            ast::CaptureByValue => {
+                                Some(UnboxedClosureUpvar { def: freevar.def,
+                                                           span: freevar.span,
+                                                           ty: freevar_ty })
+                            }
+
+                            ast::CaptureByRef => {
+                                let upvar_id = ty::UpvarId {
+                                    var_id: freevar_def_id.node,
+                                    closure_expr_id: closure_id.node
+                                };
+
+                                // FIXME
+                                let freevar_ref_ty = match typer.upvar_borrow(upvar_id) {
+                                    Some(borrow) => {
+                                        mk_rptr(tcx,
+                                                tcx.mk_region(borrow.region),
+                                                ty::mt {
+                                                    ty: freevar_ty,
+                                                    mutbl: borrow.kind.to_mutbl_lossy(),
+                                                })
+                                    }
+                                    None => {
+                                        // FIXME(#16640) we should really return None here;
+                                        // but that requires better inference integration,
+                                        // for now gin up something.
+                                        freevar_ty
+                                    }
+                                };
+                                Some(UnboxedClosureUpvar {
+                                    def: freevar.def,
+                                    span: freevar.span,
+                                    ty: freevar_ref_ty,
+                                })
+                            }
+                        }
+                    })
+                    .collect()
         }
     }
 }
@@ -6509,21 +6555,42 @@ impl<'tcx> mc::Typer<'tcx> for ty::ctxt<'tcx> {
         self.region_maps.temporary_scope(rvalue_id)
     }
 
-    fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
-        self.upvar_borrow_map.borrow()[upvar_id].clone()
+    fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
+        Some(self.upvar_borrow_map.borrow()[upvar_id].clone())
     }
 
     fn capture_mode(&self, closure_expr_id: ast::NodeId)
                     -> ast::CaptureClause {
         self.capture_modes.borrow()[closure_expr_id].clone()
     }
+}
 
-    fn unboxed_closures<'a>(&'a self)
-                        -> &'a RefCell<DefIdMap<UnboxedClosure<'tcx>>> {
-        &self.unboxed_closures
+impl<'tcx> UnboxedClosureTyper<'tcx> for ty::ctxt<'tcx> {
+    fn unboxed_closure_kind(&self,
+                            def_id: ast::DefId)
+                            -> ty::UnboxedClosureKind
+    {
+        self.unboxed_closures.borrow()[def_id].kind
+    }
+
+    fn unboxed_closure_type(&self,
+                            def_id: ast::DefId,
+                            substs: &subst::Substs<'tcx>)
+                            -> ty::ClosureTy<'tcx>
+    {
+        self.unboxed_closures.borrow()[def_id].closure_type.subst(self, substs)
+    }
+
+    fn unboxed_closure_upvars(&self,
+                              def_id: ast::DefId,
+                              substs: &Substs<'tcx>)
+                              -> Option<Vec<UnboxedClosureUpvar<'tcx>>>
+    {
+        unboxed_closure_upvars(self, def_id, substs)
     }
 }
 
+
 /// The category of explicit self.
 #[deriving(Clone, Copy, Eq, PartialEq, Show)]
 pub enum ExplicitSelfCategory {
@@ -7040,12 +7107,30 @@ pub trait HasProjectionTypes {
     fn has_projection_types(&self) -> bool;
 }
 
+impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for Vec<T> {
+    fn has_projection_types(&self) -> bool {
+        self.iter().any(|p| p.has_projection_types())
+    }
+}
+
 impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for VecPerParamSpace<T> {
     fn has_projection_types(&self) -> bool {
         self.iter().any(|p| p.has_projection_types())
     }
 }
 
+impl<'tcx> HasProjectionTypes for ClosureTy<'tcx> {
+    fn has_projection_types(&self) -> bool {
+        self.sig.has_projection_types()
+    }
+}
+
+impl<'tcx> HasProjectionTypes for UnboxedClosureUpvar<'tcx> {
+    fn has_projection_types(&self) -> bool {
+        self.ty.has_projection_types()
+    }
+}
+
 impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> {
     fn has_projection_types(&self) -> bool {
         self.predicates.has_projection_types()
@@ -7245,3 +7330,23 @@ impl ReferencesError for Region
         false
     }
 }
+
+impl<'tcx> Repr<'tcx> for ClosureTy<'tcx> {
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("ClosureTy({},{},{},{},{},{})",
+                self.unsafety,
+                self.onceness,
+                self.store,
+                self.bounds.repr(tcx),
+                self.sig.repr(tcx),
+                self.abi)
+    }
+}
+
+impl<'tcx> Repr<'tcx> for UnboxedClosureUpvar<'tcx> {
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("UnboxedClosureUpvar({},{})",
+                self.def.repr(tcx),
+                self.ty.repr(tcx))
+    }
+}
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 1e7605c0f17..83d2f6fb0e6 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -532,6 +532,16 @@ impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for ty::UnboxedClosureUpvar<'tcx> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::UnboxedClosureUpvar<'tcx> {
+        ty::UnboxedClosureUpvar {
+            def: self.def,
+            span: self.span,
+            ty: self.ty.fold_with(folder),
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // "super" routines: these are the default implementations for TypeFolder.
 //
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index d01047c53b9..24a3bb42c90 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -168,7 +168,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             Univariant(mk_struct(cx, ftys[], packed, t), dtor)
         }
         ty::ty_unboxed_closure(def_id, _, substs) => {
-            let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs);
+            let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs).unwrap();
             let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
             Univariant(mk_struct(cx, upvar_types[], false, t), false)
         }
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 47544365426..18155d75680 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -43,7 +43,7 @@ use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
 use middle::subst;
 use middle::weak_lang_items;
 use middle::subst::{Subst, Substs};
-use middle::ty::{mod, Ty};
+use middle::ty::{mod, Ty, UnboxedClosureTyper};
 use session::config::{mod, NoDebugInfo, FullDebugInfo};
 use session::Session;
 use trans::_match;
@@ -257,12 +257,12 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>,
 }
 
 pub fn self_type_for_unboxed_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                     closure_id: ast::DefId,
-                                     fn_ty: Ty<'tcx>)
-                                     -> Ty<'tcx> {
-    let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
-    let unboxed_closure = &(*unboxed_closures)[closure_id];
-    match unboxed_closure.kind {
+                                               closure_id: ast::DefId,
+                                               fn_ty: Ty<'tcx>)
+                                               -> Ty<'tcx>
+{
+    let unboxed_closure_kind = ccx.tcx().unboxed_closure_kind(closure_id);
+    match unboxed_closure_kind {
         ty::FnUnboxedClosureKind => {
             ty::mk_imm_rptr(ccx.tcx(), ccx.tcx().mk_region(ty::ReStatic), fn_ty)
         }
@@ -291,13 +291,15 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, Some(Type::i8p(ccx)))
         }
         ty::ty_unboxed_closure(closure_did, _, substs) => {
-            let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
-            let unboxed_closure = &(*unboxed_closures)[closure_did];
-            let function_type = unboxed_closure.closure_type.clone();
+            let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx());
+            let function_type = typer.unboxed_closure_type(closure_did, substs);
             let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty);
             let llenvironment_type = type_of_explicit_arg(ccx, self_type);
-            (function_type.sig.0.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(),
-             function_type.sig.0.output.subst(ccx.tcx(), substs),
+            debug!("decl_rust_fn: function_type={} self_type={}",
+                   function_type.repr(ccx.tcx()),
+                   self_type.repr(ccx.tcx()));
+            (function_type.sig.0.inputs,
+             function_type.sig.0.output,
              RustCall,
              Some(llenvironment_type))
         }
@@ -729,7 +731,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
       }
       ty::ty_unboxed_closure(def_id, _, substs) => {
           let repr = adt::represent_type(cx.ccx(), t);
-          let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs);
+          let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs).unwrap();
           for (i, upvar) in upvars.iter().enumerate() {
               let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
               cx = f(cx, llupvar, upvar.ty);
@@ -2436,11 +2438,9 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
         ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
         ty::ty_bare_fn(_, ref f) => (f.sig.clone(), f.abi, false),
         ty::ty_unboxed_closure(closure_did, _, substs) => {
-            let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
-            let ref function_type = (*unboxed_closures)[closure_did]
-                                                    .closure_type;
-
-            (function_type.sig.subst(ccx.tcx(), substs), RustCall, true)
+            let typer = common::NormalizingUnboxedClosureTyper::new(ccx.tcx());
+            let function_type = typer.unboxed_closure_type(closure_did, substs);
+            (function_type.sig, RustCall, true)
         }
         _ => ccx.sess().bug("expected closure or function.")
     };
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index 3723ad07a36..93a5b54fde3 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -22,11 +22,11 @@ use trans::common::*;
 use trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
 use trans::debuginfo;
 use trans::expr;
-use trans::monomorphize::MonoId;
+use trans::monomorphize::{mod, MonoId};
 use trans::type_of::*;
 use trans::type_::Type;
-use middle::ty::{mod, Ty};
-use middle::subst::{Subst, Substs};
+use middle::ty::{mod, Ty, UnboxedClosureTyper};
+use middle::subst::{Substs};
 use session::config::FullDebugInfo;
 use util::ppaux::Repr;
 use util::ppaux::ty_to_string;
@@ -464,7 +464,7 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk,
     }
 
     let function_type = ty::node_id_to_type(bcx.tcx(), closure_id.node);
-    let function_type = function_type.subst(bcx.tcx(), substs);
+    let function_type = monomorphize::apply_param_substs(bcx.tcx(), substs, &function_type);
 
     // Normalize type so differences in regions and typedefs don't cause
     // duplicate declarations
@@ -511,7 +511,8 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
                              body: &ast::Block,
                              id: ast::NodeId,
                              dest: expr::Dest)
-                             -> Block<'blk, 'tcx> {
+                             -> Block<'blk, 'tcx>
+{
     let _icx = push_ctxt("closure::trans_unboxed_closure");
 
     debug!("trans_unboxed_closure()");
@@ -522,9 +523,13 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
         closure_id,
         bcx.fcx.param_substs).unwrap();
 
-    let function_type = (*bcx.tcx().unboxed_closures.borrow())[closure_id]
-                                                              .closure_type
-                                                              .clone();
+    // 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_unboxed_closure`) is invoked at the point
+    // of the closure expression.
+    let typer = NormalizingUnboxedClosureTyper::new(bcx.tcx());
+    let function_type = typer.unboxed_closure_type(closure_id, bcx.fcx.param_substs);
     let function_type = ty::mk_closure(bcx.tcx(), function_type);
 
     let freevars: Vec<ty::Freevar> =
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 7c2585becea..aa882240880 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -39,7 +39,7 @@ use middle::ty::{mod, HasProjectionTypes, Ty};
 use middle::ty_fold;
 use middle::ty_fold::{TypeFolder, TypeFoldable};
 use util::ppaux::Repr;
-use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
+use util::nodemap::{FnvHashMap, NodeMap};
 
 use arena::TypedArena;
 use libc::{c_uint, c_char};
@@ -617,13 +617,8 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
         self.tcx().region_maps.temporary_scope(rvalue_id)
     }
 
-    fn unboxed_closures<'a>(&'a self)
-                        -> &'a RefCell<DefIdMap<ty::UnboxedClosure<'tcx>>> {
-        &self.tcx().unboxed_closures
-    }
-
-    fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
-        self.tcx().upvar_borrow_map.borrow()[upvar_id].clone()
+    fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
+        Some(self.tcx().upvar_borrow_map.borrow()[upvar_id].clone())
     }
 
     fn capture_mode(&self, closure_expr_id: ast::NodeId)
@@ -632,6 +627,34 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
     }
 }
 
+impl<'blk, 'tcx> ty::UnboxedClosureTyper<'tcx> for BlockS<'blk, 'tcx> {
+    fn unboxed_closure_kind(&self,
+                            def_id: ast::DefId)
+                            -> ty::UnboxedClosureKind
+    {
+        let typer = NormalizingUnboxedClosureTyper::new(self.tcx());
+        typer.unboxed_closure_kind(def_id)
+    }
+
+    fn unboxed_closure_type(&self,
+                            def_id: ast::DefId,
+                            substs: &subst::Substs<'tcx>)
+                            -> ty::ClosureTy<'tcx>
+    {
+        let typer = NormalizingUnboxedClosureTyper::new(self.tcx());
+        typer.unboxed_closure_type(def_id, substs)
+    }
+
+    fn unboxed_closure_upvars(&self,
+                              def_id: ast::DefId,
+                              substs: &Substs<'tcx>)
+                              -> Option<Vec<ty::UnboxedClosureUpvar<'tcx>>>
+    {
+        let typer = NormalizingUnboxedClosureTyper::new(self.tcx());
+        typer.unboxed_closure_upvars(def_id, substs)
+    }
+}
+
 pub struct Result<'blk, 'tcx: 'blk> {
     pub bcx: Block<'blk, 'tcx>,
     pub val: ValueRef
@@ -924,7 +947,8 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
-    let mut selcx = traits::SelectionContext::new(&infcx, &param_env, tcx);
+    let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx);
+    let mut selcx = traits::SelectionContext::new(&infcx, &param_env, &typer);
     let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
                                              trait_ref.to_poly_trait_predicate());
     let selection = match selcx.select(&obligation) {
@@ -968,6 +992,47 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     vtable
 }
 
+pub struct NormalizingUnboxedClosureTyper<'a,'tcx:'a> {
+    tcx: &'a ty::ctxt<'tcx>
+}
+
+impl<'a,'tcx> NormalizingUnboxedClosureTyper<'a,'tcx> {
+    pub fn new(tcx: &'a ty::ctxt<'tcx>) -> NormalizingUnboxedClosureTyper<'a,'tcx> {
+        NormalizingUnboxedClosureTyper { tcx: tcx }
+    }
+}
+
+impl<'a,'tcx> ty::UnboxedClosureTyper<'tcx> for NormalizingUnboxedClosureTyper<'a,'tcx> {
+    fn unboxed_closure_kind(&self,
+                            def_id: ast::DefId)
+                            -> ty::UnboxedClosureKind
+    {
+        self.tcx.unboxed_closure_kind(def_id)
+    }
+
+    fn unboxed_closure_type(&self,
+                            def_id: ast::DefId,
+                            substs: &subst::Substs<'tcx>)
+                            -> ty::ClosureTy<'tcx>
+    {
+        // the substitutions in `substs` are already monomorphized,
+        // but we still must normalize associated types
+        let closure_ty = self.tcx.unboxed_closure_type(def_id, substs);
+        monomorphize::normalize_associated_type(self.tcx, &closure_ty)
+    }
+
+    fn unboxed_closure_upvars(&self,
+                              def_id: ast::DefId,
+                              substs: &Substs<'tcx>)
+                              -> Option<Vec<ty::UnboxedClosureUpvar<'tcx>>>
+    {
+        // the substitutions in `substs` are already monomorphized,
+        // but we still must normalize associated types
+        let result = ty::unboxed_closure_upvars(self.tcx, def_id, substs);
+        monomorphize::normalize_associated_type(self.tcx, &result)
+    }
+}
+
 pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
                                        infcx: &infer::InferCtxt<'a,'tcx>,
                                        param_env: &ty::ParameterEnvironment<'tcx>,
@@ -982,7 +1047,8 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
     // In principle, we only need to do this so long as `result`
     // contains unbound type parameters. It could be a slight
     // optimization to stop iterating early.
-    match fulfill_cx.select_all_or_error(infcx, param_env, infcx.tcx) {
+    let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx);
+    match fulfill_cx.select_all_or_error(infcx, param_env, &typer) {
         Ok(()) => { }
         Err(errors) => {
             if errors.iter().all(|e| e.is_overflow()) {
diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs
index bce446b7412..c651255226b 100644
--- a/src/librustc_trans/trans/debuginfo.rs
+++ b/src/librustc_trans/trans/debuginfo.rs
@@ -194,13 +194,13 @@ use llvm;
 use llvm::{ModuleRef, ContextRef, ValueRef};
 use llvm::debuginfo::*;
 use metadata::csearch;
-use middle::subst::{mod, Subst, Substs};
+use middle::subst::{mod, Substs};
 use trans::{mod, adt, machine, type_of};
 use trans::common::*;
 use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
 use trans::monomorphize;
 use trans::type_::Type;
-use middle::ty::{mod, Ty};
+use middle::ty::{mod, Ty, UnboxedClosureTyper};
 use middle::pat_util;
 use session::config::{mod, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
 use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet};
@@ -470,9 +470,9 @@ impl<'tcx> TypeMap<'tcx> {
                                                         closure_ty.clone(),
                                                         &mut unique_type_id);
             },
-            ty::ty_unboxed_closure(ref def_id, _, substs) => {
-                let closure_ty = cx.tcx().unboxed_closures.borrow()
-                                   .get(def_id).unwrap().closure_type.subst(cx.tcx(), substs);
+            ty::ty_unboxed_closure(def_id, _, substs) => {
+                let typer = NormalizingUnboxedClosureTyper::new(cx.tcx());
+                let closure_ty = typer.unboxed_closure_type(def_id, substs);
                 self.get_unique_type_id_of_closure_type(cx,
                                                         closure_ty,
                                                         &mut unique_type_id);
@@ -3020,9 +3020,9 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         ty::ty_closure(ref closurety) => {
             subroutine_type_metadata(cx, unique_type_id, &closurety.sig, usage_site_span)
         }
-        ty::ty_unboxed_closure(ref def_id, _, substs) => {
-            let sig = cx.tcx().unboxed_closures.borrow()
-                        .get(def_id).unwrap().closure_type.sig.subst(cx.tcx(), substs);
+        ty::ty_unboxed_closure(def_id, _, substs) => {
+            let typer = NormalizingUnboxedClosureTyper::new(cx.tcx());
+            let sig = typer.unboxed_closure_type(def_id, substs).sig;
             subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span)
         }
         ty::ty_struct(def_id, substs) => {
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 7646aa086eb..7c8ba08d987 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -323,7 +323,8 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
 
     let infcx = infer::new_infer_ctxt(tcx);
     let param_env = ty::empty_parameter_environment();
-    let mut selcx = traits::SelectionContext::new(&infcx, &param_env, tcx);
+    let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx);
+    let mut selcx = traits::SelectionContext::new(&infcx, &param_env, &typer);
     let cause = traits::ObligationCause::dummy();
     let traits::Normalized { value: result, obligations } =
         traits::normalize(&mut selcx, cause, value);
diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs
index 98081e28f2f..5e9843d0e00 100644
--- a/src/librustc_typeck/check/assoc.rs
+++ b/src/librustc_typeck/check/assoc.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use middle::infer::InferCtxt;
-use middle::mem_categorization as mc;
 use middle::traits::{mod, FulfillmentContext, Normalized, MiscObligation,
                      SelectionContext, ObligationCause};
 use middle::ty::{mod, HasProjectionTypes};
@@ -20,7 +19,7 @@ use util::ppaux::Repr;
 
 pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                                 param_env: &ty::ParameterEnvironment<'tcx>,
-                                                typer: &(mc::Typer<'tcx>+'a),
+                                                typer: &(ty::UnboxedClosureTyper<'tcx>+'a),
                                                 fulfillment_cx: &mut FulfillmentContext<'tcx>,
                                                 span: Span,
                                                 body_id: ast::NodeId,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 60bb96a2b84..d4e025a3813 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -319,15 +319,37 @@ impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
     fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
         self.tcx().temporary_scope(rvalue_id)
     }
-    fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
-        self.inh.upvar_borrow_map.borrow()[upvar_id].clone()
+    fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
+        self.inh.upvar_borrow_map.borrow().get(&upvar_id).cloned()
     }
     fn capture_mode(&self, closure_expr_id: ast::NodeId)
                     -> ast::CaptureClause {
         self.ccx.tcx.capture_mode(closure_expr_id)
     }
-    fn unboxed_closures(&self) -> &RefCell<DefIdMap<ty::UnboxedClosure<'tcx>>> {
-        &self.inh.unboxed_closures
+}
+
+impl<'a, 'tcx> ty::UnboxedClosureTyper<'tcx> for FnCtxt<'a, 'tcx> {
+    fn unboxed_closure_kind(&self,
+                            def_id: ast::DefId)
+                            -> ty::UnboxedClosureKind
+    {
+        self.inh.unboxed_closures.borrow()[def_id].kind
+    }
+
+    fn unboxed_closure_type(&self,
+                            def_id: ast::DefId,
+                            substs: &subst::Substs<'tcx>)
+                            -> ty::ClosureTy<'tcx>
+    {
+        self.inh.unboxed_closures.borrow()[def_id].closure_type.subst(self.tcx(), substs)
+    }
+
+    fn unboxed_closure_upvars(&self,
+                              def_id: ast::DefId,
+                              substs: &Substs<'tcx>)
+                              -> Option<Vec<ty::UnboxedClosureUpvar<'tcx>>>
+    {
+        ty::unboxed_closure_upvars(self, def_id, substs)
     }
 }
 
@@ -352,7 +374,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
     }
 
     fn normalize_associated_types_in<T>(&self,
-                                        typer: &mc::Typer<'tcx>,
+                                        typer: &ty::UnboxedClosureTyper<'tcx>,
                                         span: Span,
                                         body_id: ast::NodeId,
                                         value: &T)