about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-01-02 04:09:35 -0500
committerNiko Matsakis <niko@alum.mit.edu>2015-01-03 07:01:21 -0500
commit7474be066022d2cd0b0695a466651570c00f3700 (patch)
tree83eb0f9d208ac3b3e14c81694ad348ee2b473923
parent83ef3042de889db07b819fc6b2802cd0ace7e21c (diff)
Make `ty::ParameterEnvironment`, not `ty::ctxt`, implement `Typer` and
`UnboxedClosureTyper`. This requires adding a `tcx` field to
`ParameterEnvironment` but generally simplifies everything since we
only need to pass along an `UnboxedClosureTyper` or `Typer`.
-rw-r--r--src/librustc/middle/check_match.rs7
-rw-r--r--src/librustc/middle/check_rvalues.rs4
-rw-r--r--src/librustc/middle/check_static.rs10
-rw-r--r--src/librustc/middle/expr_use_visitor.rs9
-rw-r--r--src/librustc/middle/intrinsicck.rs2
-rw-r--r--src/librustc/middle/mem_categorization.rs144
-rw-r--r--src/librustc/middle/traits/coherence.rs4
-rw-r--r--src/librustc/middle/traits/fulfill.rs12
-rw-r--r--src/librustc/middle/traits/select.rs23
-rw-r--r--src/librustc/middle/ty.rs123
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs6
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs10
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs70
-rw-r--r--src/librustc_trans/trans/_match.rs9
-rw-r--r--src/librustc_trans/trans/adt.rs5
-rw-r--r--src/librustc_trans/trans/base.rs4
-rw-r--r--src/librustc_trans/trans/common.rs50
-rw-r--r--src/librustc_trans/trans/datum.rs1
-rw-r--r--src/librustc_trans/trans/monomorphize.rs7
-rw-r--r--src/librustc_typeck/check/assoc.rs3
-rw-r--r--src/librustc_typeck/check/method/mod.rs4
-rw-r--r--src/librustc_typeck/check/method/probe.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs28
-rw-r--r--src/librustc_typeck/check/vtable.rs8
24 files changed, 288 insertions, 259 deletions
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 7952c99dd79..9cb8674c3e1 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -99,7 +99,7 @@ impl<'a> FromIterator<Vec<&'a Pat>> for Matrix<'a> {
 
 pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
     pub tcx: &'a ty::ctxt<'tcx>,
-    pub param_env: ParameterEnvironment<'tcx>,
+    pub param_env: ParameterEnvironment<'a, 'tcx>,
 }
 
 #[deriving(Clone, PartialEq)]
@@ -148,7 +148,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchCheckCtxt<'a, 'tcx> {
 pub fn check_crate(tcx: &ty::ctxt) {
     visit::walk_crate(&mut MatchCheckCtxt {
         tcx: tcx,
-        param_env: ty::empty_parameter_environment(),
+        param_env: ty::empty_parameter_environment(tcx),
     }, tcx.map.krate());
     tcx.sess.abort_if_errors();
 }
@@ -1061,8 +1061,7 @@ fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
         cx: cx,
     };
     let mut visitor = ExprUseVisitor::new(&mut checker,
-                                          checker.cx.tcx,
-                                          &cx.param_env);
+                                          &checker.cx.param_env);
     visitor.walk_expr(guard);
 }
 
diff --git a/src/librustc/middle/check_rvalues.rs b/src/librustc/middle/check_rvalues.rs
index 1a7a642f82a..c383b1579ef 100644
--- a/src/librustc/middle/check_rvalues.rs
+++ b/src/librustc/middle/check_rvalues.rs
@@ -41,7 +41,7 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
         {
             let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
             let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: &param_env };
-            let mut euv = euv::ExprUseVisitor::new(&mut delegate, self.tcx, &param_env);
+            let mut euv = euv::ExprUseVisitor::new(&mut delegate, &param_env);
             euv.walk_fn(fd, b);
         }
         visit::walk_fn(self, fk, fd, b, s)
@@ -50,7 +50,7 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
 
 struct RvalueContextDelegate<'a, 'tcx: 'a> {
     tcx: &'a ty::ctxt<'tcx>,
-    param_env: &'a ty::ParameterEnvironment<'tcx>,
+    param_env: &'a ty::ParameterEnvironment<'a,'tcx>,
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs
index fb20df020ac..9c9e68002c9 100644
--- a/src/librustc/middle/check_static.rs
+++ b/src/librustc/middle/check_static.rs
@@ -54,7 +54,7 @@ struct CheckStaticVisitor<'a, 'tcx: 'a> {
 }
 
 struct GlobalVisitor<'a,'b,'tcx:'a+'b>(
-    euv::ExprUseVisitor<'a,'b,'tcx,ty::ctxt<'tcx>>);
+    euv::ExprUseVisitor<'a,'b,'tcx,ty::ParameterEnvironment<'b,'tcx>>);
 struct GlobalChecker {
     static_consumptions: NodeSet,
     const_borrows: NodeSet,
@@ -70,8 +70,8 @@ pub fn check_crate(tcx: &ty::ctxt) {
         static_local_borrows: NodeSet::new(),
     };
     {
-        let param_env = ty::empty_parameter_environment();
-        let visitor = euv::ExprUseVisitor::new(&mut checker, tcx, &param_env);
+        let param_env = ty::empty_parameter_environment(tcx);
+        let visitor = euv::ExprUseVisitor::new(&mut checker, &param_env);
         visit::walk_crate(&mut GlobalVisitor(visitor), tcx.map.krate());
     }
     visit::walk_crate(&mut CheckStaticVisitor {
@@ -121,8 +121,8 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> {
         let mut fulfill_cx = traits::FulfillmentContext::new();
         let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
         fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
-        let env = ty::empty_parameter_environment();
-        match fulfill_cx.select_all_or_error(&infcx, &env, self.tcx) {
+        let env = ty::empty_parameter_environment(self.tcx);
+        match fulfill_cx.select_all_or_error(&infcx, &env) {
             Ok(()) => { },
             Err(ref errors) => {
                 traits::report_fulfillment_errors(&infcx, errors);
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index b2d866cf586..f5cf4af1230 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -23,7 +23,7 @@ use self::OverloadedCallType::*;
 use middle::{def, region, pat_util};
 use middle::mem_categorization as mc;
 use middle::mem_categorization::Typer;
-use middle::ty::{mod, ParameterEnvironment, Ty};
+use middle::ty::{mod};
 use middle::ty::{MethodCall, MethodObject, MethodTraitObject};
 use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam};
 use middle::ty::{MethodStatic, MethodStaticUnboxedClosure};
@@ -299,7 +299,8 @@ pub struct ExprUseVisitor<'d,'t,'tcx:'t,TYPER:'t> {
     typer: &'t TYPER,
     mc: mc::MemCategorizationContext<'t,TYPER>,
     delegate: &'d mut (Delegate<'tcx>+'d),
-    param_env: &'t ParameterEnvironment<'tcx>,
+}
+
 // If the TYPER results in an error, it's because the type check
 // failed (or will fail, when the error is uncovered and reported
 // during writeback). In this case, we just ignore this part of the
@@ -324,14 +325,12 @@ enum PassArgs {
 
 impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
     pub fn new(delegate: &'d mut Delegate<'tcx>,
-               typer: &'t TYPER,
-               param_env: &'t ParameterEnvironment<'tcx>)
+               typer: &'t TYPER)
                -> ExprUseVisitor<'d,'t,'tcx,TYPER> {
         ExprUseVisitor {
             typer: typer,
             mc: mc::MemCategorizationContext::new(typer),
             delegate: delegate,
-            param_env: param_env,
         }
     }
 
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 89ffcbf37a9..2962b7b7c8e 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -41,7 +41,7 @@ struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
     // environments for each function we encounter. When we find a
     // call to `transmute`, we can check it in the context of the top
     // of the stack (which ought not to be empty).
-    param_envs: Vec<ty::ParameterEnvironment<'tcx>>,
+    param_envs: Vec<ty::ParameterEnvironment<'a,'tcx>>,
 
     // Dummy sized/unsized types that use to substitute for type
     // parameters in order to estimate how big a type will be for any
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 59a9b73e978..722fe82d41c 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -272,7 +272,6 @@ pub type McResult<T> = Result<T, ()>;
 /// can be sure that only `Ok` results will occur.
 pub trait Typer<'tcx> : ty::UnboxedClosureTyper<'tcx> {
     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
-    fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx>;
     fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>>;
     fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>>;
     fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool;
@@ -1292,77 +1291,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
               self.tcx().sess.span_bug(pat.span, "unexpanded macro");
           }
         }
-    }
 
-    pub fn cmt_to_string(&self, cmt: &cmt_<'tcx>) -> String {
-        fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
-            if upvar.is_unboxed {
-                let kind = match upvar.kind {
-                    ty::FnUnboxedClosureKind => "Fn",
-                    ty::FnMutUnboxedClosureKind => "FnMut",
-                    ty::FnOnceUnboxedClosureKind => "FnOnce"
-                };
-                format!("captured outer variable in an `{}` closure", kind)
-            } else {
-                (match (upvar.kind, is_copy) {
-                    (ty::FnOnceUnboxedClosureKind, true) => "captured outer variable in a proc",
-                    _ => "captured outer variable"
-                }).to_string()
-            }
-        }
-
-        match cmt.cat {
-          cat_static_item => {
-              "static item".to_string()
-          }
-          cat_rvalue(..) => {
-              "non-lvalue".to_string()
-          }
-          cat_local(vid) => {
-              match self.tcx().map.find(vid) {
-                  Some(ast_map::NodeArg(_)) => {
-                      "argument".to_string()
-                  }
-                  _ => "local variable".to_string()
-              }
-          }
-          cat_deref(_, _, pk) => {
-              let upvar = cmt.upvar();
-              match upvar.as_ref().map(|i| &i.cat) {
-                  Some(&cat_upvar(ref var)) => {
-                      upvar_to_string(var, false)
-                  }
-                  Some(_) => unreachable!(),
-                  None => {
-                      match pk {
-                          Implicit(..) => {
-                            "dereference (dereference is implicit, due to indexing)".to_string()
-                          }
-                          Unique => format!("dereference of `{}`", ptr_sigil(pk)),
-                          _ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
-                      }
-                  }
-              }
-          }
-          cat_interior(_, InteriorField(NamedField(_))) => {
-              "field".to_string()
-          }
-          cat_interior(_, InteriorField(PositionalField(_))) => {
-              "anonymous field".to_string()
-          }
-          cat_interior(_, InteriorElement(VecElement)) => {
-              "vec content".to_string()
-          }
-          cat_interior(_, InteriorElement(OtherElement)) => {
-              "indexed content".to_string()
-          }
-          cat_upvar(ref var) => {
-              upvar_to_string(var, true)
-          }
-          cat_downcast(ref cmt, _) => {
-            self.cmt_to_string(&**cmt)
-          }
-        }
+        Ok(())
     }
 }
 
@@ -1474,6 +1404,78 @@ impl<'tcx> cmt_<'tcx> {
             NoteNone => None
         }
     }
+
+
+    pub fn descriptive_string(&self, tcx: &ty::ctxt) -> String {
+        fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
+            if upvar.is_unboxed {
+                let kind = match upvar.kind {
+                    ty::FnUnboxedClosureKind => "Fn",
+                    ty::FnMutUnboxedClosureKind => "FnMut",
+                    ty::FnOnceUnboxedClosureKind => "FnOnce"
+                };
+                format!("captured outer variable in an `{}` closure", kind)
+            } else {
+                (match (upvar.kind, is_copy) {
+                    (ty::FnOnceUnboxedClosureKind, true) => "captured outer variable in a proc",
+                    _ => "captured outer variable"
+                }).to_string()
+            }
+        }
+
+        match self.cat {
+            cat_static_item => {
+                "static item".to_string()
+            }
+            cat_rvalue(..) => {
+                "non-lvalue".to_string()
+            }
+            cat_local(vid) => {
+                match tcx.map.find(vid) {
+                    Some(ast_map::NodeArg(_)) => {
+                        "argument".to_string()
+                    }
+                    _ => "local variable".to_string()
+                }
+            }
+            cat_deref(_, _, pk) => {
+                let upvar = self.upvar();
+                match upvar.as_ref().map(|i| &i.cat) {
+                    Some(&cat_upvar(ref var)) => {
+                        upvar_to_string(var, false)
+                    }
+                    Some(_) => unreachable!(),
+                    None => {
+                        match pk {
+                            Implicit(..) => {
+                                "dereference (dereference is implicit, due to indexing)".to_string()
+                            }
+                            Unique => format!("dereference of `{}`", ptr_sigil(pk)),
+                            _ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
+                        }
+                    }
+                }
+            }
+            cat_interior(_, InteriorField(NamedField(_))) => {
+                "field".to_string()
+            }
+            cat_interior(_, InteriorField(PositionalField(_))) => {
+                "anonymous field".to_string()
+            }
+            cat_interior(_, InteriorElement(VecElement)) => {
+                "vec content".to_string()
+            }
+            cat_interior(_, InteriorElement(OtherElement)) => {
+                "indexed content".to_string()
+            }
+            cat_upvar(ref var) => {
+                upvar_to_string(var, true)
+            }
+            cat_downcast(ref cmt, _) => {
+                cmt.descriptive_string(tcx)
+            }
+        }
+    }
 }
 
 impl<'tcx> Repr<'tcx> for cmt_<'tcx> {
diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
index 4aff36c2624..6a8b6d49cc0 100644
--- a/src/librustc/middle/traits/coherence.rs
+++ b/src/librustc/middle/traits/coherence.rs
@@ -42,8 +42,8 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
 
     // Determine whether `impl2` can provide an implementation for those
     // same types.
-    let param_env = ty::empty_parameter_environment();
-    let mut selcx = SelectionContext::intercrate(infcx, &param_env, infcx.tcx);
+    let param_env = ty::empty_parameter_environment(infcx.tcx);
+    let mut selcx = SelectionContext::intercrate(infcx, &param_env);
     let obligation = Obligation::new(ObligationCause::dummy(),
                                      ty::Binder(ty::TraitPredicate {
                                          trait_ref: Rc::new(impl1_trait_ref),
diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index 2dbb15b215e..e8a22e3d1d8 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -109,7 +109,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
     /// `projection_ty` again.
     pub fn normalize_projection_type<'a>(&mut self,
                                          infcx: &InferCtxt<'a,'tcx>,
-                                         param_env: &ty::ParameterEnvironment<'tcx>,
                                          typer: &ty::UnboxedClosureTyper<'tcx>,
                                          projection_ty: ty::ProjectionTy<'tcx>,
                                          cause: ObligationCause<'tcx>)
@@ -122,7 +121,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
 
         // FIXME(#20304) -- cache
 
-        let mut selcx = SelectionContext::new(infcx, param_env, typer);
+        let mut selcx = SelectionContext::new(infcx, typer);
         let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0);
 
         for obligation in normalized.obligations.into_iter() {
@@ -186,11 +185,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
 
     pub fn select_all_or_error<'a>(&mut self,
                                    infcx: &InferCtxt<'a,'tcx>,
-                                   param_env: &ty::ParameterEnvironment<'tcx>,
                                    typer: &ty::UnboxedClosureTyper<'tcx>)
                                    -> Result<(),Vec<FulfillmentError<'tcx>>>
     {
-        try!(self.select_where_possible(infcx, param_env, typer));
+        try!(self.select_where_possible(infcx, typer));
 
         // Anything left is ambiguous.
         let errors: Vec<FulfillmentError> =
@@ -212,21 +210,19 @@ impl<'tcx> FulfillmentContext<'tcx> {
     /// results in `O(n^2)` performance (#18208).
     pub fn select_new_obligations<'a>(&mut self,
                                       infcx: &InferCtxt<'a,'tcx>,
-                                      param_env: &ty::ParameterEnvironment<'tcx>,
                                       typer: &ty::UnboxedClosureTyper<'tcx>)
                                       -> Result<(),Vec<FulfillmentError<'tcx>>>
     {
-        let mut selcx = SelectionContext::new(infcx, param_env, typer);
+        let mut selcx = SelectionContext::new(infcx, typer);
         self.select(&mut selcx, true)
     }
 
     pub fn select_where_possible<'a>(&mut self,
                                      infcx: &InferCtxt<'a,'tcx>,
-                                     param_env: &ty::ParameterEnvironment<'tcx>,
                                      typer: &ty::UnboxedClosureTyper<'tcx>)
                                      -> Result<(),Vec<FulfillmentError<'tcx>>>
     {
-        let mut selcx = SelectionContext::new(infcx, param_env, typer);
+        let mut selcx = SelectionContext::new(infcx, typer);
         self.select(&mut selcx, false)
     }
 
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index d09f2a250b0..7da33babaeb 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -46,7 +46,6 @@ use util::ppaux::Repr;
 
 pub struct SelectionContext<'cx, 'tcx:'cx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
-    param_env: &'cx ty::ParameterEnvironment<'tcx>,
     closure_typer: &'cx (ty::UnboxedClosureTyper<'tcx>+'cx),
 
     /// Freshener used specifically for skolemizing entries on the
@@ -181,12 +180,10 @@ enum EvaluationResult<'tcx> {
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>,
-               param_env: &'cx ty::ParameterEnvironment<'tcx>,
                closure_typer: &'cx ty::UnboxedClosureTyper<'tcx>)
                -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
             infcx: infcx,
-            param_env: param_env,
             closure_typer: closure_typer,
             freshener: infcx.freshener(),
             intercrate: false,
@@ -194,12 +191,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>,
-                      param_env: &'cx ty::ParameterEnvironment<'tcx>,
                       closure_typer: &'cx ty::UnboxedClosureTyper<'tcx>)
                       -> SelectionContext<'cx, 'tcx> {
         SelectionContext {
             infcx: infcx,
-            param_env: param_env,
             closure_typer: closure_typer,
             freshener: infcx.freshener(),
             intercrate: true,
@@ -210,14 +205,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         self.infcx
     }
 
-    pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'tcx> {
-        self.param_env
-    }
-
     pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
         self.infcx.tcx
     }
 
+    pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'cx, 'tcx> {
+        self.closure_typer.param_env()
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Selection
     //
@@ -650,7 +645,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // it's not worth going to more trouble to increase the
         // hit-rate I don't think.
         if self.intercrate {
-            return &self.param_env.selection_cache;
+            return &self.param_env().selection_cache;
         }
 
         // If the trait refers to any parameters in scope, then use
@@ -659,7 +654,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             cache_fresh_trait_pred.0.input_types().iter().any(
                 |&t| ty::type_has_self(t) || ty::type_has_params(t))
         {
-            return &self.param_env.selection_cache;
+            return &self.param_env().selection_cache;
         }
 
         // If the trait refers to unbound type variables, and there
@@ -668,11 +663,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // common case, then we can use the global environment.
         // See the discussion in doc.rs for more details.
         if
-            !self.param_env.caller_bounds.is_empty() &&
+            !self.param_env().caller_bounds.is_empty() &&
             cache_fresh_trait_pred.0.input_types().iter().any(
                 |&t| ty::type_has_ty_infer(t))
         {
-            return &self.param_env.selection_cache;
+            return &self.param_env().selection_cache;
         }
 
         // Otherwise, we can use the global cache.
@@ -902,7 +897,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                obligation.repr(self.tcx()));
 
         let caller_trait_refs: Vec<_> =
-            self.param_env.caller_bounds.predicates.iter()
+            self.param_env().caller_bounds.predicates.iter()
             .filter_map(|o| o.to_opt_poly_trait_ref())
             .collect();
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index fd32e798689..c720032bef2 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -2058,7 +2058,9 @@ impl<'tcx> TraitRef<'tcx> {
 /// future I hope to refine the representation of types so as to make
 /// more distinctions clearer.
 #[deriving(Clone)]
-pub struct ParameterEnvironment<'tcx> {
+pub struct ParameterEnvironment<'a, 'tcx:'a> {
+    pub tcx: &'a ctxt<'tcx>,
+
     /// A substitution that can be applied to move from
     /// the "outer" view of a type or method to the "inner" view.
     /// In general, this means converting from bound parameters to
@@ -2082,8 +2084,8 @@ pub struct ParameterEnvironment<'tcx> {
     pub selection_cache: traits::SelectionCache<'tcx>,
 }
 
-impl<'tcx> ParameterEnvironment<'tcx> {
-    pub fn for_item(cx: &ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'tcx> {
+impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
+    pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx> {
         match cx.map.find(id) {
             Some(ast_map::NodeImplItem(ref impl_item)) => {
                 match **impl_item {
@@ -2272,6 +2274,8 @@ impl UnboxedClosureKind {
 }
 
 pub trait UnboxedClosureTyper<'tcx> {
+    fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx>;
+
     fn unboxed_closure_kind(&self,
                             def_id: ast::DefId)
                             -> ty::UnboxedClosureKind;
@@ -2424,6 +2428,21 @@ impl<'tcx> ctxt<'tcx> {
         self.region_interner.borrow_mut().insert(region, region);
         region
     }
+
+    pub fn unboxed_closure_kind(&self,
+                            def_id: ast::DefId)
+                            -> ty::UnboxedClosureKind
+    {
+        self.unboxed_closures.borrow()[def_id].kind
+    }
+
+    pub 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)
+    }
 }
 
 // Interns a type/name combination, stores the resulting box in cx.interner,
@@ -3377,7 +3396,8 @@ 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).unwrap();
+                let param_env = ty::empty_parameter_environment(cx);
+                let upvars = unboxed_closure_upvars(&param_env, did, substs).unwrap();
                 TypeContents::union(upvars.as_slice(),
                                     |f| tc_ty(cx, f.ty, cache))
                     | borrowed_contents(*r, MutMutable)
@@ -3526,12 +3546,12 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
     }
 }
 
-fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
-                          cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
-                          param_env: &ParameterEnvironment<'tcx>,
-                          ty: Ty<'tcx>,
-                          bound: ty::BuiltinBound)
-                          -> bool
+fn type_impls_bound<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
+                             cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
+                             ty: Ty<'tcx>,
+                             bound: ty::BuiltinBound,
+                             span: Span)
+                             -> bool
 {
     assert!(!ty::type_needs_infer(ty));
 
@@ -3540,7 +3560,7 @@ fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
             None => {}
             Some(&result) => {
                 debug!("type_impls_bound({}, {}) = {} (cached)",
-                       ty_to_string(cx, ty),
+                       ty.repr(param_env.tcx),
                        bound,
                        result);
                 return result
@@ -3625,8 +3645,6 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool {
             ty_str |
             ty_bare_fn(..) |
             ty_closure(_) |
-            ty_infer(_) |
-            ty_err |
             ty_param(_) |
             ty_projection(_) |
             ty_vec(_, None) => {
@@ -3659,9 +3677,12 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool {
                 r
             }
 
-            ty_unboxed_closure(did, _, substs) => {
-                let upvars = unboxed_closure_upvars(cx, did, substs).unwrap();
-                upvars.iter().any(|f| type_requires(cx, seen, r_ty, f.ty))
+            ty_err |
+            ty_infer(_) |
+            ty_unboxed_closure(..) => {
+                // this check is run on type definitions, so we don't expect to see
+                // inference by-products or unboxed closure types
+                cx.sess.bug(format!("requires check invoked on inapplicable type: {}", ty)[])
             }
 
             ty_tup(ref ts) => {
@@ -3751,9 +3772,10 @@ 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).unwrap();
-                find_nonrepresentable(cx, sp, seen, upvars.iter().map(|f| f.ty))
+            ty_unboxed_closure(..) => {
+                // this check is run on type definitions, so we don't expect to see
+                // unboxed closure types
+                cx.sess.bug(format!("requires check invoked on inapplicable type: {}", ty)[])
             }
             _ => Representable,
         }
@@ -6377,19 +6399,20 @@ impl Variance {
 
 /// Construct a parameter environment suitable for static contexts or other contexts where there
 /// are no free type/lifetime parameters in scope.
-pub fn empty_parameter_environment<'tcx>() -> ParameterEnvironment<'tcx> {
-    ty::ParameterEnvironment { free_substs: Substs::empty(),
+pub fn empty_parameter_environment<'a,'tcx>(cx: &'a ctxt<'tcx>) -> ParameterEnvironment<'a,'tcx> {
+    ty::ParameterEnvironment { tcx: cx,
+                               free_substs: Substs::empty(),
                                caller_bounds: GenericBounds::empty(),
                                implicit_region_bound: ty::ReEmpty,
                                selection_cache: traits::SelectionCache::new(), }
 }
 
 /// See `ParameterEnvironment` struct def'n for details
-pub fn construct_parameter_environment<'tcx>(
-    tcx: &ctxt<'tcx>,
+pub fn construct_parameter_environment<'a,'tcx>(
+    tcx: &'a ctxt<'tcx>,
     generics: &ty::Generics<'tcx>,
     free_id: ast::NodeId)
-    -> ParameterEnvironment<'tcx>
+    -> ParameterEnvironment<'a, 'tcx>
 {
 
     //
@@ -6432,6 +6455,7 @@ pub fn construct_parameter_environment<'tcx>(
            bounds.repr(tcx));
 
     return ty::ParameterEnvironment {
+        tcx: tcx,
         free_substs: free_substs,
         implicit_region_bound: ty::ReScope(free_id_scope),
         caller_bounds: bounds,
@@ -6522,48 +6546,59 @@ impl BorrowKind {
     }
 }
 
-impl<'tcx> mc::Typer<'tcx> for ty::ctxt<'tcx> {
-    fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
-        self
+impl<'tcx> ctxt<'tcx> {
+    pub fn capture_mode(&self, closure_expr_id: ast::NodeId)
+                    -> ast::CaptureClause {
+        self.capture_modes.borrow()[closure_expr_id].clone()
+    }
+
+    pub fn is_method_call(&self, expr_id: ast::NodeId) -> bool {
+        self.method_map.borrow().contains_key(&MethodCall::expr(expr_id))
     }
+}
 
-    fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
-        ty::node_id_to_type(self, id)
+impl<'a,'tcx> mc::Typer<'tcx> for ParameterEnvironment<'a,'tcx> {
+    fn tcx(&self) -> &ty::ctxt<'tcx> {
+        self.tcx
     }
 
-    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> {
-        ty::expr_ty_adjusted(self, expr)
+    fn node_ty(&self, id: ast::NodeId) -> mc::McResult<Ty<'tcx>> {
+        Ok(ty::node_id_to_type(self.tcx, id))
+    }
+
+    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> mc::McResult<Ty<'tcx>> {
+        Ok(ty::expr_ty_adjusted(self.tcx, expr))
     }
 
     fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>> {
-        self.method_map.borrow().get(&method_call).map(|method| method.ty)
+        self.tcx.method_map.borrow().get(&method_call).map(|method| method.ty)
     }
 
     fn node_method_origin(&self, method_call: ty::MethodCall)
                           -> Option<ty::MethodOrigin<'tcx>>
     {
-        self.method_map.borrow().get(&method_call).map(|method| method.origin.clone())
+        self.tcx.method_map.borrow().get(&method_call).map(|method| method.origin.clone())
     }
 
-    fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>> {
-        &self.adjustments
+    fn adjustments(&self) -> &RefCell<NodeMap<ty::AutoAdjustment<'tcx>>> {
+        &self.tcx.adjustments
     }
 
     fn is_method_call(&self, id: ast::NodeId) -> bool {
-        self.method_map.borrow().contains_key(&MethodCall::expr(id))
+        self.tcx.is_method_call(id)
     }
 
     fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> {
-        self.region_maps.temporary_scope(rvalue_id)
+        self.tcx.region_maps.temporary_scope(rvalue_id)
     }
 
     fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
-        Some(self.upvar_borrow_map.borrow()[upvar_id].clone())
+        Some(self.tcx.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()
+        self.tcx.capture_mode(closure_expr_id)
     }
 
     fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
@@ -6571,12 +6606,16 @@ impl<'tcx> mc::Typer<'tcx> for ty::ctxt<'tcx> {
     }
 }
 
-impl<'tcx> UnboxedClosureTyper<'tcx> for ty::ctxt<'tcx> {
+impl<'a,'tcx> UnboxedClosureTyper<'tcx> for ty::ParameterEnvironment<'a,'tcx> {
+    fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
+        self
+    }
+
     fn unboxed_closure_kind(&self,
                             def_id: ast::DefId)
                             -> ty::UnboxedClosureKind
     {
-        self.unboxed_closures.borrow()[def_id].kind
+        self.tcx.unboxed_closure_kind(def_id)
     }
 
     fn unboxed_closure_type(&self,
@@ -6584,7 +6623,7 @@ impl<'tcx> UnboxedClosureTyper<'tcx> for ty::ctxt<'tcx> {
                             substs: &subst::Substs<'tcx>)
                             -> ty::ClosureTy<'tcx>
     {
-        self.unboxed_closures.borrow()[def_id].closure_type.subst(self, substs)
+        self.tcx.unboxed_closure_type(def_id, substs)
     }
 
     fn unboxed_closure_upvars(&self,
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 2062685f4c8..17a3f4a88e5 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -87,7 +87,7 @@ struct CheckLoanCtxt<'a, 'tcx: 'a> {
     dfcx_loans: &'a LoanDataFlow<'a, 'tcx>,
     move_data: move_data::FlowedMoveData<'a, 'tcx>,
     all_loans: &'a [Loan<'tcx>],
-    param_env: &'a ty::ParameterEnvironment<'tcx>,
+    param_env: &'a ty::ParameterEnvironment<'a, 'tcx>,
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
@@ -208,9 +208,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     };
 
     {
-        let mut euv = euv::ExprUseVisitor::new(&mut clcx,
-                                               bccx.tcx,
-                                               &param_env);
+        let mut euv = euv::ExprUseVisitor::new(&mut clcx, &param_env);
         euv.walk_fn(decl, body);
     }
 }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 7854c8acb47..1e9e5b22aa0 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -51,9 +51,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
 
     {
-        let mut euv = euv::ExprUseVisitor::new(&mut glcx,
-                                               bccx.tcx,
-                                               &param_env);
+        let mut euv = euv::ExprUseVisitor::new(&mut glcx, &param_env);
         euv.walk_fn(decl, body);
     }
 
@@ -485,13 +483,15 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
 /// This visitor walks static initializer's expressions and makes
 /// sure the loans being taken are sound.
 struct StaticInitializerCtxt<'a, 'tcx: 'a> {
-    bccx: &'a BorrowckCtxt<'a, 'tcx>
+    bccx: &'a BorrowckCtxt<'a, 'tcx>,
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &Expr) {
         if let ast::ExprAddrOf(mutbl, ref base) = ex.node {
-            let base_cmt = self.bccx.cat_expr(&**base);
+            let param_env = ty::empty_parameter_environment(self.bccx.tcx);
+            let mc = mc::MemCategorizationContext::new(&param_env);
+            let base_cmt = mc.cat_expr(&**base).unwrap();
             let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
             // Check that we don't allow borrows of unsafe static items.
             if check_aliasability(self.bccx, ex.span, euv::AddrOf,
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index c27b7b30e13..d81974d1ae0 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -511,14 +511,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
     }
 
-    pub fn mc(&self) -> mc::MemCategorizationContext<'a, ty::ctxt<'tcx>> {
-        mc::MemCategorizationContext::new(self.tcx)
-    }
-
-    pub fn cat_expr(&self, expr: &ast::Expr) -> mc::cmt<'tcx> {
-        self.mc().cat_expr(expr)
-    }
-
     pub fn report(&self, err: BckError<'tcx>) {
         self.span_err(
             err.span,
@@ -526,13 +518,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         self.note_and_explain_bckerr(err);
     }
 
-    pub fn report_use_of_moved_value(&self,
-                                     use_span: Span,
-                                     use_kind: MovedValueUseKind,
-                                     lp: &LoanPath<'tcx>,
-                                     the_move: &move_data::Move,
-                                     moved_lp: &LoanPath<'tcx>,
-                                     param_env: &ty::ParameterEnvironment<'tcx>) {
+    pub fn report_use_of_moved_value<'b>(&self,
+                                         use_span: Span,
+                                         use_kind: MovedValueUseKind,
+                                         lp: &LoanPath<'tcx>,
+                                         the_move: &move_data::Move,
+                                         moved_lp: &LoanPath<'tcx>,
+                                         param_env: &ty::ParameterEnvironment<'b,'tcx>) {
         let verb = match use_kind {
             MovedInUse => "use",
             MovedInCapture => "capture",
@@ -608,8 +600,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                                                   r)[])
                     }
                 };
-                let (suggestion, _) = move_suggestion(self.tcx, param_env, expr_ty,
-                        ("moved by default", ""));
+                let (suggestion, _) =
+                    move_suggestion(param_env, expr_span, expr_ty, ("moved by default", ""));
                 self.tcx.sess.span_note(
                     expr_span,
                     format!("`{}` moved here{} because it has type `{}`, which is {}",
@@ -646,11 +638,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                                                   r)[])
                     }
                 };
-                let (suggestion, help) = move_suggestion(self.tcx,
-                                                         param_env,
-                                                         expr_ty,
-                        ("moved by default", "make a copy and \
-                         capture that instead to override"));
+                let (suggestion, help) =
+                    move_suggestion(param_env,
+                                    expr_span,
+                                    expr_ty,
+                                    ("moved by default",
+                                     "make a copy and capture that instead to override"));
                 self.tcx.sess.span_note(
                     expr_span,
                     format!("`{}` moved into closure environment here{} because it \
@@ -663,22 +656,27 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
             }
         }
 
-        fn move_suggestion<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                 param_env: &ty::ParameterEnvironment<'tcx>,
-                                 ty: Ty<'tcx>,
-                                 default_msgs: (&'static str, &'static str))
-                                 -> (&'static str, &'static str) {
+        fn move_suggestion<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
+                                    span: Span,
+                                    ty: Ty<'tcx>,
+                                    default_msgs: (&'static str, &'static str))
+                                    -> (&'static str, &'static str) {
             match ty.sty {
                 ty::ty_closure(box ty::ClosureTy {
-                        store: ty::RegionTraitStore(..),
-                        ..
-                    }) =>
+                    store: ty::RegionTraitStore(..),
+                    ..
+                }) => {
                     ("a non-copyable stack closure",
-                     "capture it in a new closure, e.g. `|x| f(x)`, to override"),
-                _ if ty::type_moves_by_default(tcx, ty, param_env) =>
-                    ("non-copyable",
-                     "perhaps you meant to use `clone()`?"),
-                _ => default_msgs,
+                     "capture it in a new closure, e.g. `|x| f(x)`, to override")
+                }
+                _ => {
+                    if ty::type_moves_by_default(param_env, span, ty) {
+                        ("non-copyable",
+                         "perhaps you meant to use `clone()`?")
+                    } else {
+                        default_msgs
+                    }
+                }
             }
         }
     }
@@ -991,7 +989,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
     }
 
     pub fn cmt_to_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
-        self.mc().cmt_to_string(cmt)
+        cmt.descriptive_string(self.tcx)
     }
 }
 
diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs
index 0b1dfcb378b..19781a51d57 100644
--- a/src/librustc_trans/trans/_match.rs
+++ b/src/librustc_trans/trans/_match.rs
@@ -542,7 +542,7 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>(
             check_match::Constructor::Variant(def_id)
     };
 
-    let param_env = ty::empty_parameter_environment();
+    let param_env = ty::empty_parameter_environment(bcx.tcx());
     let mcx = check_match::MatchCheckCtxt {
         tcx: bcx.tcx(),
         param_env: param_env,
@@ -1008,7 +1008,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     let mcx = check_match::MatchCheckCtxt {
         tcx: bcx.tcx(),
-        param_env: ty::empty_parameter_environment(),
+        param_env: ty::empty_parameter_environment(bcx.tcx()),
     };
     let adt_vals = if any_irrefutable_adt_pat(bcx.tcx(), m, col) {
         let repr = adt::represent_type(bcx.ccx(), left_ty);
@@ -1262,8 +1262,7 @@ fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool
         reassigned: false
     };
     {
-        let param_env = ty::empty_parameter_environment();
-        let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx, &param_env);
+        let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx);
         visitor.walk_expr(body);
     }
     rc.reassigned
@@ -1321,7 +1320,7 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat,
         let variable_ty = node_id_type(bcx, p_id);
         let llvariable_ty = type_of::type_of(ccx, variable_ty);
         let tcx = bcx.tcx();
-        let param_env = ty::empty_parameter_environment();
+        let param_env = ty::empty_parameter_environment(tcx);
 
         let llmatch;
         let trmode;
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index 24a3bb42c90..85a7ec33069 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -61,7 +61,7 @@ use trans::datum;
 use trans::machine;
 use trans::type_::Type;
 use trans::type_of;
-use middle::ty::{mod, Ty};
+use middle::ty::{mod, Ty, UnboxedClosureTyper};
 use middle::ty::Disr;
 use syntax::ast;
 use syntax::attr;
@@ -168,7 +168,8 @@ 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).unwrap();
+            let typer = NormalizingUnboxedClosureTyper::new(cx.tcx());
+            let upvars = typer.unboxed_closure_upvars(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 bf53885e9e5..4c29467d93a 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -731,7 +731,8 @@ 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).unwrap();
+          let typer = common::NormalizingUnboxedClosureTyper::new(cx.tcx());
+          let upvars = typer.unboxed_closure_upvars(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);
@@ -1451,6 +1452,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
           llfn: llfndecl,
           llenv: None,
           llretslotptr: Cell::new(None),
+          param_env: ty::empty_parameter_environment(ccx.tcx()),
           alloca_insert_pt: Cell::new(None),
           llreturn: Cell::new(None),
           needs_ret_allocas: nested_returns,
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 660b7aeeb00..6efdcc2f0fa 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -302,6 +302,9 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
     // section of the executable we're generating.
     pub llfn: ValueRef,
 
+    // always an empty parameter-environment
+    pub param_env: ty::ParameterEnvironment<'a, 'tcx>,
+
     // The environment argument in a closure.
     pub llenv: Option<ValueRef>,
 
@@ -579,12 +582,12 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
         self.tcx()
     }
 
-    fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
-        node_id_type(self, id)
+    fn node_ty(&self, id: ast::NodeId) -> mc::McResult<Ty<'tcx>> {
+        Ok(node_id_type(self, id))
     }
 
-    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> {
-        expr_ty_adjusted(self, expr)
+    fn expr_ty_adjusted(&self, expr: &ast::Expr) -> mc::McResult<Ty<'tcx>> {
+        Ok(expr_ty_adjusted(self, expr))
     }
 
     fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>> {
@@ -627,11 +630,15 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
     }
 
     fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
-        self.param_env().type_moves_by_default(span, ty)
+        self.fcx.param_env.type_moves_by_default(span, ty)
     }
 }
 
 impl<'blk, 'tcx> ty::UnboxedClosureTyper<'tcx> for BlockS<'blk, 'tcx> {
+    fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx> {
+        &self.fcx.param_env
+    }
+
     fn unboxed_closure_kind(&self,
                             def_id: ast::DefId)
                             -> ty::UnboxedClosureKind
@@ -945,14 +952,10 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id());
     let infcx = infer::new_infer_ctxt(tcx);
 
-    // Parameter environment is used to give details about type parameters,
-    // but since we are in trans, everything is fully monomorphized.
-    let param_env = ty::empty_parameter_environment();
-
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
-    let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx);
-    let mut selcx = traits::SelectionContext::new(&infcx, &param_env, &typer);
+    let typer = NormalizingUnboxedClosureTyper::new(tcx);
+    let mut selcx = traits::SelectionContext::new(&infcx, &typer);
     let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
                                              trait_ref.to_poly_trait_predicate());
     let selection = match selcx.select(&obligation) {
@@ -987,7 +990,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let vtable = selection.map_move_nested(|predicate| {
         fulfill_cx.register_predicate_obligation(&infcx, predicate);
     });
-    let vtable = drain_fulfillment_cx(span, &infcx, &param_env, &mut fulfill_cx, &vtable);
+    let vtable = drain_fulfillment_cx(span, &infcx, &mut fulfill_cx, &vtable);
 
     info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
     ccx.trait_cache().borrow_mut().insert(trait_ref,
@@ -997,21 +1000,27 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 }
 
 pub struct NormalizingUnboxedClosureTyper<'a,'tcx:'a> {
-    tcx: &'a ty::ctxt<'tcx>
+    param_env: ty::ParameterEnvironment<'a, 'tcx>
 }
 
 impl<'a,'tcx> NormalizingUnboxedClosureTyper<'a,'tcx> {
     pub fn new(tcx: &'a ty::ctxt<'tcx>) -> NormalizingUnboxedClosureTyper<'a,'tcx> {
-        NormalizingUnboxedClosureTyper { tcx: tcx }
+        // Parameter environment is used to give details about type parameters,
+        // but since we are in trans, everything is fully monomorphized.
+        NormalizingUnboxedClosureTyper { param_env: ty::empty_parameter_environment(tcx) }
     }
 }
 
 impl<'a,'tcx> ty::UnboxedClosureTyper<'tcx> for NormalizingUnboxedClosureTyper<'a,'tcx> {
+    fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
+        &self.param_env
+    }
+
     fn unboxed_closure_kind(&self,
                             def_id: ast::DefId)
                             -> ty::UnboxedClosureKind
     {
-        self.tcx.unboxed_closure_kind(def_id)
+        self.param_env.tcx.unboxed_closure_kind(def_id)
     }
 
     fn unboxed_closure_type(&self,
@@ -1021,8 +1030,8 @@ impl<'a,'tcx> ty::UnboxedClosureTyper<'tcx> for NormalizingUnboxedClosureTyper<'
     {
         // 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)
+        let closure_ty = self.param_env.tcx.unboxed_closure_type(def_id, substs);
+        monomorphize::normalize_associated_type(self.param_env.tcx, &closure_ty)
     }
 
     fn unboxed_closure_upvars(&self,
@@ -1032,14 +1041,13 @@ impl<'a,'tcx> ty::UnboxedClosureTyper<'tcx> for NormalizingUnboxedClosureTyper<'
     {
         // 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)
+        let result = ty::unboxed_closure_upvars(&self.param_env, def_id, substs);
+        monomorphize::normalize_associated_type(self.param_env.tcx, &result)
     }
 }
 
 pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
                                        infcx: &infer::InferCtxt<'a,'tcx>,
-                                       param_env: &ty::ParameterEnvironment<'tcx>,
                                        fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
                                        result: &T)
                                        -> T
@@ -1052,7 +1060,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
     // contains unbound type parameters. It could be a slight
     // optimization to stop iterating early.
     let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx);
-    match fulfill_cx.select_all_or_error(infcx, param_env, &typer) {
+    match fulfill_cx.select_all_or_error(infcx, &typer) {
         Ok(()) => { }
         Err(errors) => {
             if errors.iter().all(|e| e.is_overflow()) {
diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs
index 0afe3a8ef8d..72074040a2c 100644
--- a/src/librustc_trans/trans/datum.rs
+++ b/src/librustc_trans/trans/datum.rs
@@ -28,6 +28,7 @@ use util::ppaux::{ty_to_string};
 
 use std::fmt;
 use syntax::ast;
+use syntax::codemap::DUMMY_SP;
 
 /// A `Datum` encapsulates the result of evaluating an expression.  It
 /// describes where the value is stored, what Rust type the value has,
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 7c8ba08d987..cc259e6765c 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -322,9 +322,8 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
     // FIXME(#20304) -- cache
 
     let infcx = infer::new_infer_ctxt(tcx);
-    let param_env = ty::empty_parameter_environment();
-    let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx);
-    let mut selcx = traits::SelectionContext::new(&infcx, &param_env, &typer);
+    let typer = NormalizingUnboxedClosureTyper::new(tcx);
+    let mut selcx = traits::SelectionContext::new(&infcx, &typer);
     let cause = traits::ObligationCause::dummy();
     let traits::Normalized { value: result, obligations } =
         traits::normalize(&mut selcx, cause, value);
@@ -337,7 +336,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
     for obligation in obligations.into_iter() {
         fulfill_cx.register_predicate_obligation(&infcx, obligation);
     }
-    let result = drain_fulfillment_cx(DUMMY_SP, &infcx, &param_env, &mut fulfill_cx, &result);
+    let result = drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
 
     result
 }
diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs
index 5e9843d0e00..6950850e5f3 100644
--- a/src/librustc_typeck/check/assoc.rs
+++ b/src/librustc_typeck/check/assoc.rs
@@ -18,7 +18,6 @@ use syntax::codemap::Span;
 use util::ppaux::Repr;
 
 pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
-                                                param_env: &ty::ParameterEnvironment<'tcx>,
                                                 typer: &(ty::UnboxedClosureTyper<'tcx>+'a),
                                                 fulfillment_cx: &mut FulfillmentContext<'tcx>,
                                                 span: Span,
@@ -28,7 +27,7 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
     where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
 {
     debug!("normalize_associated_types_in(value={})", value.repr(infcx.tcx));
-    let mut selcx = SelectionContext::new(infcx, param_env, typer);
+    let mut selcx = SelectionContext::new(infcx, typer);
     let cause = ObligationCause::new(span, body_id, MiscObligation);
     let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);
     debug!("normalize_associated_types_in: result={} predicates={}",
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 4e6593deddd..92b8c2bbcf7 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -169,9 +169,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
                                               poly_trait_ref.as_predicate());
 
     // Now we want to know if this can be matched
-    let mut selcx = traits::SelectionContext::new(fcx.infcx(),
-                                                  &fcx.inh.param_env,
-                                                  fcx);
+    let mut selcx = traits::SelectionContext::new(fcx.infcx(), fcx);
     if !selcx.evaluate_obligation(&obligation) {
         debug!("--> Cannot match obligation");
         return None; // Cannot be matched, no such method resolution is possible.
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 52860abb6f9..cd97d89b246 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -788,9 +788,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                     debug!("impl_obligations={}", obligations.repr(self.tcx()));
 
                     // Evaluate those obligations to see if they might possibly hold.
-                    let mut selcx = traits::SelectionContext::new(self.infcx(),
-                                                                  &self.fcx.inh.param_env,
-                                                                  self.fcx);
+                    let mut selcx = traits::SelectionContext::new(self.infcx(), self.fcx);
                     obligations.all(|o| selcx.evaluate_obligation(o))
                 }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 37ec24ae23b..ed4c55cea5d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -87,6 +87,7 @@ use middle::{const_eval, def};
 use middle::infer;
 use middle::lang_items::IteratorItem;
 use middle::mem_categorization as mc;
+use middle::mem_categorization::McResult;
 use middle::pat_util::{mod, pat_id_map};
 use middle::region::CodeExtent;
 use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace};
@@ -146,7 +147,7 @@ mod callee;
 pub struct Inherited<'a, 'tcx: 'a> {
     infcx: infer::InferCtxt<'a, 'tcx>,
     locals: RefCell<NodeMap<Ty<'tcx>>>,
-    param_env: ty::ParameterEnvironment<'tcx>,
+    param_env: ty::ParameterEnvironment<'a, 'tcx>,
 
     // Temporary tables:
     node_types: RefCell<NodeMap<Ty<'tcx>>>,
@@ -288,7 +289,6 @@ impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
     fn tcx(&self) -> &ty::ctxt<'tcx> {
         self.ccx.tcx
     }
-    fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
     fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
         let ty = self.node_ty(id);
         self.resolve_type_vars_or_error(&ty)
@@ -322,7 +322,7 @@ impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
         self.inh.method_map.borrow().contains_key(&ty::MethodCall::expr(id))
     }
     fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
-        self.tcx().temporary_scope(rvalue_id)
+        self.param_env().temporary_scope(rvalue_id)
     }
     fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
         self.inh.upvar_borrow_map.borrow().get(&upvar_id).cloned()
@@ -334,6 +334,10 @@ impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> ty::UnboxedClosureTyper<'tcx> for FnCtxt<'a, 'tcx> {
+    fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
+        &self.inh.param_env
+    }
+
     fn unboxed_closure_kind(&self,
                             def_id: ast::DefId)
                             -> ty::UnboxedClosureKind
@@ -360,7 +364,7 @@ impl<'a, 'tcx> ty::UnboxedClosureTyper<'tcx> for FnCtxt<'a, 'tcx> {
 
 impl<'a, 'tcx> Inherited<'a, 'tcx> {
     fn new(tcx: &'a ty::ctxt<'tcx>,
-           param_env: ty::ParameterEnvironment<'tcx>)
+           param_env: ty::ParameterEnvironment<'a, 'tcx>)
            -> Inherited<'a, 'tcx> {
         Inherited {
             infcx: infer::new_infer_ctxt(tcx),
@@ -388,7 +392,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
     {
         let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
         assoc::normalize_associated_types_in(&self.infcx,
-                                             &self.param_env,
                                              typer,
                                              &mut *fulfillment_cx, span,
                                              body_id,
@@ -418,7 +421,7 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>)
                                     -> Inherited<'a, 'tcx> {
     // It's kind of a kludge to manufacture a fake function context
     // and statement context, but we might as well do write the code only once
-    let param_env = ty::empty_parameter_environment();
+    let param_env = ty::empty_parameter_environment(ccx.tcx);
     Inherited::new(ccx.tcx, param_env)
 }
 
@@ -462,7 +465,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            body: &ast::Block,
                            id: ast::NodeId,
                            raw_fty: Ty<'tcx>,
-                           param_env: ty::ParameterEnvironment<'tcx>) {
+                           param_env: ty::ParameterEnvironment<'a, 'tcx>) {
     match raw_fty.sty {
         ty::ty_bare_fn(_, ref fn_ty) => {
             let inh = Inherited::new(ccx.tcx, param_env);
@@ -473,7 +476,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             let fn_sig =
                 liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig);
             let fn_sig =
-                inh.normalize_associated_types_in(ccx.tcx, body.span, body.id, &fn_sig);
+                inh.normalize_associated_types_in(&inh.param_env, body.span, body.id, &fn_sig);
 
             let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_sig,
                                decl, id, body, &inh);
@@ -1225,7 +1228,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         let impl_sig =
             assoc::normalize_associated_types_in(&infcx,
                                                  &impl_param_env,
-                                                 infcx.tcx,
                                                  &mut fulfillment_cx,
                                                  impl_m_span,
                                                  impl_m_body_id,
@@ -1246,7 +1248,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         let trait_sig =
             assoc::normalize_associated_types_in(&infcx,
                                                  &impl_param_env,
-                                                 infcx.tcx,
                                                  &mut fulfillment_cx,
                                                  impl_m_span,
                                                  impl_m_body_id,
@@ -1282,7 +1283,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     // Run the fulfillment context to completion to accommodate any
     // associated type normalizations that may have occurred.
-    match fulfillment_cx.select_all_or_error(&infcx, &impl_param_env, tcx) {
+    match fulfillment_cx.select_all_or_error(&infcx, &impl_param_env) {
         Ok(()) => { }
         Err(errors) => {
             traits::report_fulfillment_errors(&infcx, &errors);
@@ -1660,11 +1661,11 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
 
-    pub fn infcx(&self) -> &infer::InferCtxt<'a, 'tcx> {
+    pub fn infcx(&self) -> &infer::InferCtxt<'a,'tcx> {
         &self.inh.infcx
     }
 
-    pub fn param_env(&self) -> &ty::ParameterEnvironment<'tcx> {
+    pub fn param_env(&self) -> &ty::ParameterEnvironment<'a,'tcx> {
         &self.inh.param_env
     }
 
@@ -1835,7 +1836,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.inh.fulfillment_cx
             .borrow_mut()
             .normalize_projection_type(self.infcx(),
-                                       &self.inh.param_env,
                                        self,
                                        ty::ProjectionTy {
                                            trait_ref: trait_ref,
diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs
index 1ef6c114032..8566d1f1e12 100644
--- a/src/librustc_typeck/check/vtable.rs
+++ b/src/librustc_typeck/check/vtable.rs
@@ -287,9 +287,7 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
     fcx.default_type_parameters();
 
     let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
-    let r = fulfillment_cx.select_all_or_error(fcx.infcx(),
-                                               &fcx.inh.param_env,
-                                               fcx);
+    let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx);
     match r {
         Ok(()) => { }
         Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
@@ -302,7 +300,7 @@ pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
     match
         fcx.inh.fulfillment_cx
         .borrow_mut()
-        .select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx)
+        .select_where_possible(fcx.infcx(), fcx)
     {
         Ok(()) => { }
         Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
@@ -316,7 +314,7 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
     match
         fcx.inh.fulfillment_cx
         .borrow_mut()
-        .select_new_obligations(fcx.infcx(), &fcx.inh.param_env, fcx)
+        .select_new_obligations(fcx.infcx(), fcx)
     {
         Ok(()) => { }
         Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }