about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-05-13 17:56:09 +0000
committerbors <bors@rust-lang.org>2017-05-13 17:56:09 +0000
commit826d8f3850b37a23481dfcf4a899b5dfc82d22e3 (patch)
treea560fcb5a4b63710295641b6d187087560d22104 /src
parent77f1bec6f5eb9ed632c973b97b12701294e6d3a5 (diff)
parent6da4123f5f819608fce49258bfa4f74fe195806b (diff)
downloadrust-826d8f3850b37a23481dfcf4a899b5dfc82d22e3.tar.gz
rust-826d8f3850b37a23481dfcf4a899b5dfc82d22e3.zip
Auto merge of #41914 - eddyb:region-refactor, r=nikomatsakis
rustc: simpler ParameterEnvironment and free regions.

The commits describe the slow transformation but the highlights are:
* `ReEarlyBound` is considered free, with a scope based on the item that defined the lifetime parameter, and the root body of the `RegionMaps` in use, removing the need for `free_substs`
* `liberate_late_bound_regions` and `implicit_region_bound` moved to typeck
* `CodeExtent` not interned at all now - ideally it would be 2 `u32` but it's small anyway

Future work building up on this could include:
* `ParameterEnvironment` becoming just the result of `predicates_of`
  * interning makes my "parent chain" scheme unnecessary
* `implicit_region_bound` could be retrieved from `RegionMaps`
* renaming `CodeExtent` to `Scope`
  * generalizing "call site" to "use site" or something better to include constants
* renaming `RegionMaps` to `ScopeTree` and its API to talk about "parents" explicitly
Diffstat (limited to 'src')
-rw-r--r--src/librustc/cfg/construct.rs5
-rw-r--r--src/librustc/ich/impls_ty.rs27
-rw-r--r--src/librustc/infer/combine.rs10
-rw-r--r--src/librustc/infer/error_reporting/mod.rs53
-rw-r--r--src/librustc/infer/freshen.rs2
-rw-r--r--src/librustc/infer/higher_ranked/mod.rs8
-rw-r--r--src/librustc/infer/mod.rs10
-rw-r--r--src/librustc/infer/region_inference/graphviz.rs22
-rw-r--r--src/librustc/infer/region_inference/mod.rs74
-rw-r--r--src/librustc/middle/expr_use_visitor.rs4
-rw-r--r--src/librustc/middle/free_region.rs74
-rw-r--r--src/librustc/middle/liveness.rs53
-rw-r--r--src/librustc/middle/mem_categorization.rs24
-rw-r--r--src/librustc/middle/region.rs328
-rw-r--r--src/librustc/middle/resolve_lifetime.rs13
-rw-r--r--src/librustc/traits/object_safety.rs3
-rw-r--r--src/librustc/traits/specialize/mod.rs8
-rw-r--r--src/librustc/traits/util.rs4
-rw-r--r--src/librustc/ty/context.rs47
-rw-r--r--src/librustc/ty/fold.rs20
-rw-r--r--src/librustc/ty/layout.rs5
-rw-r--r--src/librustc/ty/maps.rs2
-rw-r--r--src/librustc/ty/mod.rs211
-rw-r--r--src/librustc/ty/outlives.rs2
-rw-r--r--src/librustc/ty/sty.rs24
-rw-r--r--src/librustc/ty/util.rs5
-rw-r--r--src/librustc/util/ppaux.rs14
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs8
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/lifetime.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs25
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mir/mod.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs12
-rw-r--r--src/librustc_const_eval/check_match.rs9
-rw-r--r--src/librustc_driver/test.rs44
-rw-r--r--src/librustc_lint/builtin.rs9
-rw-r--r--src/librustc_metadata/decoder.rs7
-rw-r--r--src/librustc_mir/build/expr/as_operand.rs4
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs4
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs4
-rw-r--r--src/librustc_mir/build/mod.rs38
-rw-r--r--src/librustc_mir/build/scope.rs30
-rw-r--r--src/librustc_mir/hair/cx/block.rs14
-rw-r--r--src/librustc_mir/hair/cx/expr.rs42
-rw-r--r--src/librustc_mir/hair/cx/mod.rs2
-rw-r--r--src/librustc_mir/hair/mod.rs18
-rw-r--r--src/librustc_mir/shim.rs18
-rw-r--r--src/librustc_mir/transform/inline.rs3
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs5
-rw-r--r--src/librustc_mir/transform/type_check.rs2
-rw-r--r--src/librustc_typeck/astconv.rs22
-rw-r--r--src/librustc_typeck/check/closure.rs11
-rw-r--r--src/librustc_typeck/check/compare_method.rs47
-rw-r--r--src/librustc_typeck/check/dropck.rs8
-rw-r--r--src/librustc_typeck/check/mod.rs62
-rw-r--r--src/librustc_typeck/check/regionck.rs35
-rw-r--r--src/librustc_typeck/check/wfcheck.rs92
-rw-r--r--src/librustc_typeck/check/writeback.rs60
-rw-r--r--src/librustc_typeck/coherence/builtin.rs9
-rw-r--r--src/librustc_typeck/collect.rs5
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/test/compile-fail/issue-27942.rs7
-rw-r--r--src/test/compile-fail/issue-37884.rs5
-rw-r--r--src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr14
-rw-r--r--src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr14
-rw-r--r--src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr14
-rw-r--r--src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr14
-rw-r--r--src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr14
-rw-r--r--src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr14
69 files changed, 707 insertions, 1100 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index a8ad49c6582..c1c195852f9 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -10,6 +10,7 @@
 
 use rustc_data_structures::graph;
 use cfg::*;
+use middle::region::CodeExtent;
 use ty::{self, TyCtxt};
 use syntax::ast;
 use syntax::ptr::P;
@@ -586,8 +587,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                         scope_id: ast::NodeId,
                         to_index: CFGIndex) {
         let mut data = CFGEdgeData { exiting_scopes: vec![] };
-        let mut scope = self.tcx.node_extent(from_expr.id);
-        let target_scope = self.tcx.node_extent(scope_id);
+        let mut scope = CodeExtent::Misc(from_expr.id);
+        let target_scope = CodeExtent::Misc(scope_id);
         let region_maps = self.tcx.region_maps(self.owner_def_id);
         while scope != target_scope {
             data.exiting_scopes.push(scope.node_id());
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 52bdb5d0240..3bbac8d6a64 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::subst::Kind<'t
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionKind<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionKind {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a, 'tcx>,
                                           hasher: &mut StableHasher<W>) {
@@ -54,7 +54,8 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionKind<'tc
                 db.depth.hash_stable(hcx, hasher);
                 i.hash_stable(hcx, hasher);
             }
-            ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => {
+            ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => {
+                def_id.hash_stable(hcx, hasher);
                 index.hash_stable(hcx, hasher);
                 name.hash_stable(hcx, hasher);
             }
@@ -409,11 +410,6 @@ impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region {
     Free(call_site_scope_data, decl)
 });
 
-impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData {
-    fn_id,
-    body_id
-});
-
 impl_stable_hash_for!(struct ty::DebruijnIndex {
     depth
 });
@@ -432,25 +428,24 @@ impl_stable_hash_for!(enum ty::cast::CastKind {
     FnPtrAddrCast
 });
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::middle::region::CodeExtentData
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::middle::region::CodeExtent
 {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a, 'tcx>,
                                           hasher: &mut StableHasher<W>) {
-        use middle::region::CodeExtentData;
+        use middle::region::CodeExtent;
 
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
-            CodeExtentData::Misc(node_id) |
-            CodeExtentData::DestructionScope(node_id) => {
+            CodeExtent::Misc(node_id) |
+            CodeExtent::DestructionScope(node_id) => {
                 node_id.hash_stable(hcx, hasher);
             }
-            CodeExtentData::CallSiteScope { fn_id, body_id } |
-            CodeExtentData::ParameterScope { fn_id, body_id } => {
-                fn_id.hash_stable(hcx, hasher);
+            CodeExtent::CallSiteScope(body_id) |
+            CodeExtent::ParameterScope(body_id) => {
                 body_id.hash_stable(hcx, hasher);
             }
-            CodeExtentData::Remainder(block_remainder) => {
+            CodeExtent::Remainder(block_remainder) => {
                 block_remainder.hash_stable(hcx, hasher);
             }
         }
@@ -466,7 +461,7 @@ impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo {
     custom_kind
 });
 
-impl_stable_hash_for!(struct ty::FreeRegion<'tcx> {
+impl_stable_hash_for!(struct ty::FreeRegion {
     scope,
     bound_region
 });
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 82578f6aa61..18909a784d6 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -423,15 +423,6 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
                 return Ok(r);
             }
 
-            // Early-bound regions should really have been substituted away before
-            // we get to this point.
-            ty::ReEarlyBound(..) => {
-                span_bug!(
-                    self.span,
-                    "Encountered early bound region when generalizing: {:?}",
-                    r);
-            }
-
             // Always make a fresh region variable for skolemized regions;
             // the higher-ranked decision procedures rely on this.
             ty::ReSkolemized(..) => { }
@@ -442,6 +433,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
             ty::ReStatic |
             ty::ReScope(..) |
             ty::ReVar(..) |
+            ty::ReEarlyBound(..) |
             ty::ReFree(..) => {
                 match self.ambient_variance {
                     ty::Invariant => return Ok(r),
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 4c27bade0f7..c07b3b3c4be 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -151,19 +151,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         return;
                     }
                 };
-                let scope_decorated_tag = match *scope {
-                    region::CodeExtentData::Misc(_) => tag,
-                    region::CodeExtentData::CallSiteScope { .. } => {
+                let scope_decorated_tag = match scope {
+                    region::CodeExtent::Misc(_) => tag,
+                    region::CodeExtent::CallSiteScope(_) => {
                         "scope of call-site for function"
                     }
-                    region::CodeExtentData::ParameterScope { .. } => {
+                    region::CodeExtent::ParameterScope(_) => {
                         "scope of function body"
                     }
-                    region::CodeExtentData::DestructionScope(_) => {
+                    region::CodeExtent::DestructionScope(_) => {
                         new_string = format!("destruction scope surrounding {}", tag);
                         &new_string[..]
                     }
-                    region::CodeExtentData::Remainder(r) => {
+                    region::CodeExtent::Remainder(r) => {
                         new_string = format!("block suffix following statement {}",
                                              r.first_statement_index);
                         &new_string[..]
@@ -172,19 +172,35 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 explain_span(self, scope_decorated_tag, span)
             }
 
-            ty::ReFree(ref fr) => {
-                let prefix = match fr.bound_region {
-                    ty::BrAnon(idx) => {
-                        format!("the anonymous lifetime #{} defined on", idx + 1)
+            ty::ReEarlyBound(_) |
+            ty::ReFree(_) => {
+                let scope = match *region {
+                    ty::ReEarlyBound(ref br) => {
+                        self.parent_def_id(br.def_id).unwrap()
                     }
-                    ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
-                    _ => {
-                        format!("the lifetime {} as defined on",
-                                fr.bound_region)
+                    ty::ReFree(ref fr) => fr.scope,
+                    _ => bug!()
+                };
+                let prefix = match *region {
+                    ty::ReEarlyBound(ref br) => {
+                        format!("the lifetime {} as defined on", br.name)
+                    }
+                    ty::ReFree(ref fr) => {
+                        match fr.bound_region {
+                            ty::BrAnon(idx) => {
+                                format!("the anonymous lifetime #{} defined on", idx + 1)
+                            }
+                            ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
+                            _ => {
+                                format!("the lifetime {} as defined on",
+                                        fr.bound_region)
+                            }
+                        }
                     }
+                    _ => bug!()
                 };
 
-                let node = fr.scope.map(|s| s.node_id())
+                let node = self.hir.as_local_node_id(scope)
                                    .unwrap_or(DUMMY_NODE_ID);
                 let unknown;
                 let tag = match self.hir.find(node) {
@@ -199,12 +215,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     Some(_) => {
                         unknown = format!("unexpected node ({}) for scope {:?}.  \
                                            Please report a bug.",
-                                          self.hir.node_to_string(node), fr.scope);
+                                          self.hir.node_to_string(node), scope);
                         &unknown
                     }
                     None => {
                         unknown = format!("unknown node for scope {:?}.  \
-                                           Please report a bug.", fr.scope);
+                                           Please report a bug.", scope);
                         &unknown
                     }
                 };
@@ -216,8 +232,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
             ty::ReEmpty => ("the empty lifetime".to_owned(), None),
 
-            ty::ReEarlyBound(ref data) => (data.name.to_string(), None),
-
             // FIXME(#13998) ReSkolemized should probably print like
             // ReFree rather than dumping Debug output on the user.
             //
@@ -797,6 +811,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
 
         let mut err = match *sub {
+            ty::ReEarlyBound(_) |
             ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
                 // Does the required lifetime have a nice name we can print?
                 let mut err = struct_span_err!(self.tcx.sess,
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index ad67ef9a127..a0ef1f65f52 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -85,13 +85,13 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
-            ty::ReEarlyBound(..) |
             ty::ReLateBound(..) => {
                 // leave bound regions alone
                 r
             }
 
             ty::ReStatic |
+            ty::ReEarlyBound(..) |
             ty::ReFree(_) |
             ty::ReScope(_) |
             ty::ReVar(_) |
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index 09f909ef399..dbbcc6cfbec 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -274,7 +274,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
                                              -> ty::Region<'tcx> {
             // Regions that pre-dated the LUB computation stay as they are.
             if !is_var_in_set(new_vars, r0) {
-                assert!(!r0.is_bound());
+                assert!(!r0.is_late_bound());
                 debug!("generalize_region(r0={:?}): not new variable", r0);
                 return r0;
             }
@@ -288,7 +288,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
                 debug!("generalize_region(r0={:?}): \
                         non-new-variables found in {:?}",
                        r0, tainted);
-                assert!(!r0.is_bound());
+                assert!(!r0.is_late_bound());
                 return r0;
             }
 
@@ -371,7 +371,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
                                              r0: ty::Region<'tcx>)
                                              -> ty::Region<'tcx> {
             if !is_var_in_set(new_vars, r0) {
-                assert!(!r0.is_bound());
+                assert!(!r0.is_late_bound());
                 return r0;
             }
 
@@ -424,7 +424,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
                 return rev_lookup(infcx, span, a_map, a_r.unwrap());
             } else if a_r.is_none() && b_r.is_none() {
                 // Not related to bound variables from either fn:
-                assert!(!r0.is_bound());
+                assert!(!r0.is_late_bound());
                 return r0;
             } else {
                 // Other:
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index e91af21c6db..1ecc277c7ca 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -450,10 +450,10 @@ impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
                 -> (Option<&'a ty::TypeckTables<'tcx>>,
                     Option<ty::TypeckTables<'tcx>>,
                     Option<ty::ParameterEnvironment<'tcx>>) {
-        let item_id = tcx.hir.body_owner(self);
-        (Some(tcx.typeck_tables_of(tcx.hir.local_def_id(item_id))),
+        let def_id = tcx.hir.body_owner_def_id(self);
+        (Some(tcx.typeck_tables_of(def_id)),
          None,
-         Some(ty::ParameterEnvironment::for_item(tcx, item_id)))
+         Some(tcx.parameter_environment(def_id)))
     }
 }
 
@@ -1009,7 +1009,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn add_given(&self,
-                     sub: ty::FreeRegion<'tcx>,
+                     sub: ty::Region<'tcx>,
                      sup: ty::RegionVid)
     {
         self.region_vars.add_given(sub, sup);
@@ -1324,7 +1324,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     pub fn resolve_regions_and_report_errors(&self,
                                              region_context: DefId,
-                                             region_map: &RegionMaps<'tcx>,
+                                             region_map: &RegionMaps,
                                              free_regions: &FreeRegionMap<'tcx>) {
         let region_rels = RegionRelations::new(self.tcx,
                                                region_context,
diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs
index c48b8f610a2..cce253c1a1a 100644
--- a/src/librustc/infer/region_inference/graphviz.rs
+++ b/src/librustc/infer/region_inference/graphviz.rs
@@ -124,20 +124,20 @@ struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     graph_name: String,
     region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>,
     map: &'a FxHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>,
-    node_ids: FxHashMap<Node<'tcx>, usize>,
+    node_ids: FxHashMap<Node, usize>,
 }
 
 #[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)]
-enum Node<'tcx> {
+enum Node {
     RegionVid(ty::RegionVid),
-    Region(ty::RegionKind<'tcx>),
+    Region(ty::RegionKind),
 }
 
 // type Edge = Constraint;
 #[derive(Clone, PartialEq, Eq, Debug, Copy)]
 enum Edge<'tcx> {
     Constraint(Constraint<'tcx>),
-    EnclScope(CodeExtent<'tcx>, CodeExtent<'tcx>),
+    EnclScope(CodeExtent, CodeExtent),
 }
 
 impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> {
@@ -176,7 +176,7 @@ impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
-    type Node = Node<'tcx>;
+    type Node = Node;
     type Edge = Edge<'tcx>;
     fn graph_id(&self) -> dot::Id {
         dot::Id::new(&*self.graph_name).unwrap()
@@ -209,7 +209,7 @@ impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
     }
 }
 
-fn constraint_to_nodes<'tcx>(c: &Constraint<'tcx>) -> (Node<'tcx>, Node<'tcx>) {
+fn constraint_to_nodes(c: &Constraint) -> (Node, Node) {
     match *c {
         Constraint::ConstrainVarSubVar(rv_1, rv_2) =>
             (Node::RegionVid(rv_1), Node::RegionVid(rv_2)),
@@ -222,7 +222,7 @@ fn constraint_to_nodes<'tcx>(c: &Constraint<'tcx>) -> (Node<'tcx>, Node<'tcx>) {
     }
 }
 
-fn edge_to_nodes<'tcx>(e: &Edge<'tcx>) -> (Node<'tcx>, Node<'tcx>) {
+fn edge_to_nodes(e: &Edge) -> (Node, Node) {
     match *e {
         Edge::Constraint(ref c) => constraint_to_nodes(c),
         Edge::EnclScope(sub, sup) => {
@@ -233,9 +233,9 @@ fn edge_to_nodes<'tcx>(e: &Edge<'tcx>) -> (Node<'tcx>, Node<'tcx>) {
 }
 
 impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
-    type Node = Node<'tcx>;
+    type Node = Node;
     type Edge = Edge<'tcx>;
-    fn nodes(&self) -> dot::Nodes<Node<'tcx>> {
+    fn nodes(&self) -> dot::Nodes<Node> {
         let mut set = FxHashSet();
         for node in self.node_ids.keys() {
             set.insert(*node);
@@ -250,12 +250,12 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
         debug!("region graph has {} edges", v.len());
         Cow::Owned(v)
     }
-    fn source(&self, edge: &Edge<'tcx>) -> Node<'tcx> {
+    fn source(&self, edge: &Edge<'tcx>) -> Node {
         let (n1, _) = edge_to_nodes(edge);
         debug!("edge {:?} has source {:?}", edge, n1);
         n1
     }
-    fn target(&self, edge: &Edge<'tcx>) -> Node<'tcx> {
+    fn target(&self, edge: &Edge<'tcx>) -> Node {
         let (_, n2) = edge_to_nodes(edge);
         debug!("edge {:?} has target {:?}", edge, n2);
         n2
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index 39554d1fa3a..2e3c2443544 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -29,7 +29,6 @@ use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound, ReErased};
 use ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
 
 use std::cell::{Cell, RefCell};
-use std::cmp::Ordering::{self, Less, Greater, Equal};
 use std::fmt;
 use std::mem;
 use std::u32;
@@ -127,7 +126,7 @@ pub enum UndoLogEntry<'tcx> {
     AddVerify(usize),
 
     /// We added the given `given`
-    AddGiven(ty::FreeRegion<'tcx>, ty::RegionVid),
+    AddGiven(Region<'tcx>, ty::RegionVid),
 
     /// We added a GLB/LUB "combinaton variable"
     AddCombination(CombineMapType, TwoRegions<'tcx>),
@@ -213,7 +212,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // record the fact that `'a <= 'b` is implied by the fn signature,
     // and then ignore the constraint when solving equations. This is
     // a bit of a hack but seems to work.
-    givens: RefCell<FxHashSet<(ty::FreeRegion<'tcx>, ty::RegionVid)>>,
+    givens: RefCell<FxHashSet<(Region<'tcx>, ty::RegionVid)>>,
 
     lubs: RefCell<CombineMap<'tcx>>,
     glbs: RefCell<CombineMap<'tcx>>,
@@ -309,8 +308,7 @@ impl<'a, 'gcx, 'tcx> TaintSet<'tcx> {
                         self.add_edge(a, b);
                     }
                     &AddGiven(a, b) => {
-                        self.add_edge(tcx.mk_region(ReFree(a)),
-                                      tcx.mk_region(ReVar(b)));
+                        self.add_edge(a, tcx.mk_region(ReVar(b)));
                     }
                     &AddVerify(i) => {
                         verifys[i].bound.for_each_region(&mut |b| {
@@ -661,7 +659,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn add_given(&self, sub: ty::FreeRegion<'tcx>, sup: ty::RegionVid) {
+    pub fn add_given(&self, sub: Region<'tcx>, sup: ty::RegionVid) {
         // cannot add givens once regions are resolved
         assert!(self.values_are_none());
 
@@ -702,9 +700,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                origin);
 
         match (sub, sup) {
-            (&ReEarlyBound(..), _) |
             (&ReLateBound(..), _) |
-            (_, &ReEarlyBound(..)) |
             (_, &ReLateBound(..)) => {
                 span_bug!(origin.span(),
                           "cannot relate bound region: {:?} <= {:?}",
@@ -908,8 +904,6 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         match (a, b) {
             (&ReLateBound(..), _) |
             (_, &ReLateBound(..)) |
-            (&ReEarlyBound(..), _) |
-            (_, &ReEarlyBound(..)) |
             (&ReErased, _) |
             (_, &ReErased) => {
                 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
@@ -931,18 +925,31 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                           b);
             }
 
-            (&ReFree(fr), &ReScope(s_id)) |
-            (&ReScope(s_id), &ReFree(fr)) => {
+            (&ReEarlyBound(_), &ReScope(s_id)) |
+            (&ReScope(s_id), &ReEarlyBound(_)) |
+            (&ReFree(_), &ReScope(s_id)) |
+            (&ReScope(s_id), &ReFree(_)) => {
                 // A "free" region can be interpreted as "some region
-                // at least as big as the block fr.scope_id".  So, we can
+                // at least as big as fr.scope".  So, we can
                 // reasonably compare free regions and scopes:
-                if let Some(fr_scope) = fr.scope {
-                    let r_id = region_rels.region_maps.nearest_common_ancestor(fr_scope, s_id);
-                    if r_id == fr_scope {
-                        // if the free region's scope `fr.scope_id` is bigger than
-                        // the scope region `s_id`, then the LUB is the free
-                        // region itself:
-                        return self.tcx.mk_region(ReFree(fr));
+                let fr_scope = match (a, b) {
+                    (&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => {
+                        region_rels.region_maps.early_free_extent(self.tcx, br)
+                    }
+                    (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => {
+                        region_rels.region_maps.free_extent(self.tcx, fr)
+                    }
+                    _ => bug!()
+                };
+                let r_id = region_rels.region_maps.nearest_common_ancestor(fr_scope, s_id);
+                if r_id == fr_scope {
+                    // if the free region's scope `fr.scope` is bigger than
+                    // the scope region `s_id`, then the LUB is the free
+                    // region itself:
+                    match (a, b) {
+                        (_, &ReScope(_)) => return a,
+                        (&ReScope(_), _) => return b,
+                        _ => bug!()
                     }
                 }
 
@@ -959,6 +966,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                 self.tcx.mk_region(ReScope(lub))
             }
 
+            (&ReEarlyBound(_), &ReEarlyBound(_)) |
+            (&ReFree(_), &ReEarlyBound(_)) |
+            (&ReEarlyBound(_), &ReFree(_)) |
             (&ReFree(_), &ReFree(_)) => {
                 region_rels.lub_free_regions(a, b)
             }
@@ -1041,13 +1051,13 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
         let mut givens = self.givens.borrow_mut();
         let seeds: Vec<_> = givens.iter().cloned().collect();
-        for (fr, vid) in seeds {
+        for (r, vid) in seeds {
             let seed_index = NodeIndex(vid.index as usize);
             for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
                 let succ_index = succ_index.0 as u32;
                 if succ_index < self.num_vars() {
                     let succ_vid = RegionVid { index: succ_index };
-                    givens.insert((fr, succ_vid));
+                    givens.insert((r, succ_vid));
                 }
             }
         }
@@ -1096,8 +1106,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
         // Check if this relationship is implied by a given.
         match *a_region {
-            ty::ReFree(fr) => {
-                if self.givens.borrow().contains(&(fr, b_vid)) {
+            ty::ReEarlyBound(_) |
+            ty::ReFree(_) => {
+                if self.givens.borrow().contains(&(a_region, b_vid)) {
                     debug!("given");
                     return false;
                 }
@@ -1333,16 +1344,15 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         // We place free regions first because we are special casing
         // SubSupConflict(ReFree, ReFree) when reporting error, and so
         // the user will more likely get a specific suggestion.
-        fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering {
-            match (a.region, b.region) {
-                (&ReFree(..), &ReFree(..)) => Equal,
-                (&ReFree(..), _) => Less,
-                (_, &ReFree(..)) => Greater,
-                (..) => Equal,
+        fn region_order_key(x: &RegionAndOrigin) -> u8 {
+            match *x.region {
+                ReEarlyBound(_) => 0,
+                ReFree(_) => 1,
+                _ => 2
             }
         }
-        lower_bounds.sort_by(|a, b| free_regions_first(a, b));
-        upper_bounds.sort_by(|a, b| free_regions_first(a, b));
+        lower_bounds.sort_by_key(region_order_key);
+        upper_bounds.sort_by_key(region_order_key);
 
         for lower_bound in &lower_bounds {
             for upper_bound in &upper_bounds {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 41f9311dd80..99b140f690a 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -271,7 +271,7 @@ enum PassArgs {
 
 impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
-               region_maps: &'a RegionMaps<'tcx>,
+               region_maps: &'a RegionMaps,
                infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
                -> Self
     {
@@ -283,7 +283,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
     pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
                         infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-                        region_maps: &'a RegionMaps<'tcx>,
+                        region_maps: &'a RegionMaps,
                         options: mc::MemCategorizationOptions)
                -> Self
     {
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index 2dc7aac04ae..6a21bdc19e0 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -35,7 +35,7 @@ pub struct RegionRelations<'a, 'gcx: 'tcx, 'tcx: 'a> {
     pub context: DefId,
 
     /// region maps for the given context
-    pub region_maps: &'a RegionMaps<'tcx>,
+    pub region_maps: &'a RegionMaps,
 
     /// free-region relationships
     pub free_regions: &'a FreeRegionMap<'tcx>,
@@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
     pub fn new(
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
         context: DefId,
-        region_maps: &'a RegionMaps<'tcx>,
+        region_maps: &'a RegionMaps,
         free_regions: &'a FreeRegionMap<'tcx>,
     ) -> Self {
         Self {
@@ -71,26 +71,27 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
                 (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) =>
                     self.region_maps.is_subscope_of(sub_scope, super_scope),
 
-                (&ty::ReScope(sub_scope), &ty::ReFree(fr)) => {
-                    // 1. It is safe to unwrap `fr.scope` because we
-                    // should only ever wind up comparing against
-                    // `ReScope` in the context of a method or
-                    // body, where `fr.scope` should be `Some`.
-                    self.region_maps.is_subscope_of(sub_scope, fr.scope.unwrap() /*1*/) ||
-                        self.is_static(super_region)
+                (&ty::ReScope(sub_scope), &ty::ReEarlyBound(ref br)) => {
+                    let fr_scope = self.region_maps.early_free_extent(self.tcx, br);
+                    self.region_maps.is_subscope_of(sub_scope, fr_scope)
                 }
 
-                (&ty::ReFree(_), &ty::ReFree(_)) =>
-                    self.free_regions.relation.contains(&sub_region, &super_region) ||
-                        self.is_static(super_region),
+                (&ty::ReScope(sub_scope), &ty::ReFree(ref fr)) => {
+                    let fr_scope = self.region_maps.free_extent(self.tcx, fr);
+                    self.region_maps.is_subscope_of(sub_scope, fr_scope)
+                }
 
-                (&ty::ReStatic, &ty::ReFree(_)) =>
-                    self.is_static(super_region),
+                (&ty::ReEarlyBound(_), &ty::ReEarlyBound(_)) |
+                (&ty::ReFree(_), &ty::ReEarlyBound(_)) |
+                (&ty::ReEarlyBound(_), &ty::ReFree(_)) |
+                (&ty::ReFree(_), &ty::ReFree(_)) =>
+                    self.free_regions.relation.contains(&sub_region, &super_region),
 
                 _ =>
                     false,
             }
         };
+        let result = result || self.is_static(super_region);
         debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
                sub_region, super_region, result);
         result
@@ -101,11 +102,11 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
         debug!("is_static(super_region={:?})", super_region);
         match *super_region {
             ty::ReStatic => true,
-            ty::ReFree(_) => {
+            ty::ReEarlyBound(_) | ty::ReFree(_) => {
                 let re_static = self.tcx.mk_region(ty::ReStatic);
                 self.free_regions.relation.contains(&re_static, &super_region)
             }
-            _ => bug!("only free regions should be given to `is_static`")
+            _ => false
         }
     }
 
@@ -142,11 +143,9 @@ impl<'tcx> FreeRegionMap<'tcx> {
         for implied_bound in implied_bounds {
             debug!("implied bound: {:?}", implied_bound);
             match *implied_bound {
-                ImpliedBound::RegionSubRegion(a @ &ty::ReFree(_), b @ &ty::ReFree(_)) |
-                ImpliedBound::RegionSubRegion(a @ &ty::ReStatic, b @ &ty::ReFree(_)) => {
+                ImpliedBound::RegionSubRegion(a, b) => {
                     self.relate_regions(a, b);
                 }
-                ImpliedBound::RegionSubRegion(..) |
                 ImpliedBound::RegionSubParam(..) |
                 ImpliedBound::RegionSubProjection(..) => {
                 }
@@ -170,32 +169,18 @@ impl<'tcx> FreeRegionMap<'tcx> {
                     // No region bounds here
                 }
                 ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
-                    match (r_a, r_b) {
-                        // `'static: 'x` is not notable
-                        (&ty::ReStatic, &ty::ReFree(_)) => {},
-
-                        (&ty::ReFree(_), &ty::ReStatic) |
-                        (&ty::ReFree(_), &ty::ReFree(_)) => {
-                            // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
-                            self.relate_regions(r_b, r_a);
-                        }
-
-                        _ => {
-                            // All named regions are instantiated with free regions.
-                            bug!("record_region_bounds: non free region: {:?} / {:?}",
-                                 r_a,
-                                 r_b);
-                        }
-                    }
+                    self.relate_regions(r_b, r_a);
                 }
             }
         }
     }
 
+    // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
+    // (with the exception that `'static: 'x` is not notable)
     fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
-        assert!(match *sub { ty::ReFree(_) | ty::ReStatic => true, _ => false });
-        assert!(match *sup { ty::ReFree(_) | ty::ReStatic => true, _ => false });
-        self.relation.add(sub, sup)
+        if (is_free(sub) || *sub == ty::ReStatic) && is_free(sup) {
+            self.relation.add(sub, sup)
+        }
     }
 
     pub fn lub_free_regions<'a, 'gcx>(&self,
@@ -203,8 +188,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
                                       r_a: Region<'tcx>,
                                       r_b: Region<'tcx>)
                                       -> Region<'tcx> {
-        assert!(match *r_a { ty::ReFree(_) => true, _ => false });
-        assert!(match *r_b { ty::ReFree(_) => true, _ => false });
+        assert!(is_free(r_a));
+        assert!(is_free(r_b));
         let result = if r_a == r_b { r_a } else {
             match self.relation.postdom_upper_bound(&r_a, &r_b) {
                 None => tcx.mk_region(ty::ReStatic),
@@ -216,6 +201,13 @@ impl<'tcx> FreeRegionMap<'tcx> {
     }
 }
 
+fn is_free(r: Region) -> bool {
+    match *r {
+        ty::ReEarlyBound(_) | ty::ReFree(_) => true,
+        _ => false
+    }
+}
+
 impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
     relation
 });
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 1ea87cc0a45..ecd350d1273 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -96,9 +96,6 @@
 //!
 //! - `fallthrough_ln`: a live node that represents a fallthrough
 //!
-//! - `no_ret_var`: a synthetic variable that is only 'read' from, the
-//!   fallthrough node.  This allows us to detect functions where we fail
-//!   to return explicitly.
 //! - `clean_exit_var`: a synthetic variable that is only 'read' from the
 //!   fallthrough node.  It is only live if the function could converge
 //!   via means other than an explicit `return` expression. That is, it is
@@ -110,9 +107,7 @@ use self::LiveNodeKind::*;
 use self::VarKind::*;
 
 use hir::def::*;
-use ty::{self, TyCtxt, ParameterEnvironment};
-use traits::{self, Reveal};
-use ty::subst::Subst;
+use ty::{self, TyCtxt};
 use lint;
 use util::nodemap::NodeMap;
 
@@ -256,7 +251,6 @@ struct LocalInfo {
 enum VarKind {
     Arg(NodeId, ast::Name),
     Local(LocalInfo),
-    ImplicitRet,
     CleanExit
 }
 
@@ -313,7 +307,7 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
             Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) => {
                 self.variable_map.insert(node_id, v);
             },
-            ImplicitRet | CleanExit => {}
+            CleanExit => {}
         }
 
         debug!("{:?} is {:?}", v, vk);
@@ -335,7 +329,6 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
             Local(LocalInfo { name, .. }) | Arg(_, name) => {
                 name.to_string()
             },
-            ImplicitRet => "<implicit-ret>".to_string(),
             CleanExit => "<clean-exit>".to_string()
         }
     }
@@ -382,7 +375,6 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
 
     // check for various error conditions
     lsets.visit_body(body);
-    lsets.check_ret(id, sp, entry_ln, body);
     lsets.warn_about_unused_args(body, entry_ln);
 }
 
@@ -500,7 +492,6 @@ fn invalid_users() -> Users {
 struct Specials {
     exit_ln: LiveNode,
     fallthrough_ln: LiveNode,
-    no_ret_var: Variable,
     clean_exit_var: Variable
 }
 
@@ -534,7 +525,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         let specials = Specials {
             exit_ln: ir.add_live_node(ExitNode),
             fallthrough_ln: ir.add_live_node(ExitNode),
-            no_ret_var: ir.add_variable(ImplicitRet),
             clean_exit_var: ir.add_variable(CleanExit)
         };
 
@@ -1420,45 +1410,6 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
 }
 
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
-    fn check_ret(&self,
-                 id: NodeId,
-                 sp: Span,
-                 entry_ln: LiveNode,
-                 body: &hir::Body)
-    {
-        let fn_ty = self.ir.tcx.type_of(self.ir.tcx.hir.local_def_id(id));
-        let fn_sig = match fn_ty.sty {
-            ty::TyClosure(closure_def_id, substs) => {
-                self.ir.tcx.closure_type(closure_def_id)
-                    .subst(self.ir.tcx, substs.substs)
-            }
-            _ => fn_ty.fn_sig()
-        };
-
-        let fn_ret = fn_sig.output();
-
-        // within the fn body, late-bound regions are liberated
-        // and must outlive the *call-site* of the function.
-        let fn_ret =
-            self.ir.tcx.liberate_late_bound_regions(
-                Some(self.ir.tcx.call_site_extent(id, body.value.id)),
-                &fn_ret);
-
-        if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
-            let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
-            let t_ret_subst = fn_ret.subst(self.ir.tcx, &param_env.free_substs);
-            let is_nil = self.ir.tcx.infer_ctxt(param_env, Reveal::All).enter(|infcx| {
-                let cause = traits::ObligationCause::dummy();
-                traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
-            });
-
-            // for nil return types, it is ok to not return a value expl.
-            if !is_nil {
-                span_bug!(sp, "not all control paths return a value");
-            }
-        }
-    }
-
     fn check_lvalue(&mut self, expr: &'tcx Expr) {
         match expr.node {
             hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 11a364f92c3..d0adf51d79e 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -290,7 +290,7 @@ impl ast_node for hir::Pat {
 #[derive(Clone)]
 pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    pub region_maps: &'a RegionMaps<'tcx>,
+    pub region_maps: &'a RegionMaps,
     options: MemCategorizationOptions,
 }
 
@@ -406,7 +406,7 @@ impl MutabilityCategory {
 impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     /// Context should be the `DefId` we use to fetch region-maps.
     pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-               region_maps: &'a RegionMaps<'tcx>)
+               region_maps: &'a RegionMaps)
                -> MemCategorizationContext<'a, 'gcx, 'tcx> {
         MemCategorizationContext::with_options(infcx,
                                                region_maps,
@@ -414,7 +414,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     }
 
     pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-                        region_maps: &'a RegionMaps<'tcx>,
+                        region_maps: &'a RegionMaps,
                         options: MemCategorizationOptions)
                         -> MemCategorizationContext<'a, 'gcx, 'tcx> {
         MemCategorizationContext {
@@ -785,26 +785,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                  cmt_result: cmt_<'tcx>)
                  -> cmt_<'tcx>
     {
-        // Look up the node ID of the closure body so we can construct
-        // a free region within it
-        let fn_body_id = {
-            let fn_expr = match self.tcx().hir.find(upvar_id.closure_expr_id) {
-                Some(hir_map::NodeExpr(e)) => e,
-                _ => bug!()
-            };
-
-            match fn_expr.node {
-                hir::ExprClosure(.., body_id, _) => body_id,
-                _ => bug!()
-            }
-        };
-
         // Region of environment pointer
         let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion {
             // The environment of a closure is guaranteed to
             // outlive any bindings introduced in the body of the
             // closure itself.
-            scope: Some(self.tcx().item_extent(fn_body_id.node_id)),
+            scope: self.tcx().hir.local_def_id(upvar_id.closure_expr_id),
             bound_region: ty::BrEnv
         }));
 
@@ -853,7 +839,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     pub fn temporary_scope(&self, id: ast::NodeId) -> (ty::Region<'tcx>, ty::Region<'tcx>)
     {
         let (scope, old_scope) =
-            self.region_maps.old_and_new_temporary_scope(self.tcx(), id);
+            self.region_maps.old_and_new_temporary_scope(id);
         (self.tcx().mk_region(match scope {
             Some(scope) => ty::ReScope(scope),
             None => ty::ReStatic
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 087ab4b94da..2d632e3feb5 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -22,7 +22,6 @@ use ty;
 
 use std::mem;
 use std::rc::Rc;
-use serialize;
 use syntax::codemap;
 use syntax::ast;
 use syntax_pos::Span;
@@ -35,11 +34,6 @@ use hir::intravisit::{self, Visitor, NestedVisitorMap};
 use hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local};
 use mir::transform::MirSource;
 
-pub type CodeExtent<'tcx> = &'tcx CodeExtentData;
-
-impl<'tcx> serialize::UseSpecializedEncodable for CodeExtent<'tcx> {}
-impl<'tcx> serialize::UseSpecializedDecodable for CodeExtent<'tcx> {}
-
 /// CodeExtent represents a statically-describable extent that can be
 /// used to bound the lifetime/region for values.
 ///
@@ -102,16 +96,16 @@ impl<'tcx> serialize::UseSpecializedDecodable for CodeExtent<'tcx> {}
 /// actually attach a more meaningful ordering to scopes than the one
 /// generated via deriving here.
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, RustcEncodable, RustcDecodable)]
-pub enum CodeExtentData {
+pub enum CodeExtent {
     Misc(ast::NodeId),
 
     // extent of the call-site for a function or closure (outlives
     // the parameters as well as the body).
-    CallSiteScope { fn_id: ast::NodeId, body_id: ast::NodeId },
+    CallSiteScope(hir::BodyId),
 
     // extent of parameters passed to a function or closure (they
     // outlive its body)
-    ParameterScope { fn_id: ast::NodeId, body_id: ast::NodeId },
+    ParameterScope(hir::BodyId),
 
     // extent of destructors for temporaries of node-id
     DestructionScope(ast::NodeId),
@@ -120,23 +114,6 @@ pub enum CodeExtentData {
     Remainder(BlockRemainder)
 }
 
-/// extent of call-site for a function/method.
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
-           RustcDecodable, Debug, Copy)]
-pub struct CallSiteScopeData {
-    pub fn_id: ast::NodeId, pub body_id: ast::NodeId,
-}
-
-impl CallSiteScopeData {
-    pub fn to_code_extent<'a, 'tcx, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> CodeExtent<'tcx> {
-        tcx.intern_code_extent(
-            match *self {
-                CallSiteScopeData { fn_id, body_id } =>
-                    CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id },
-            })
-    }
-}
-
 /// Represents a subscope of `block` for a binding that is introduced
 /// by `block.stmts[first_statement_index]`. Such subscopes represent
 /// a suffix of the block. Note that each subscope does not include
@@ -148,9 +125,9 @@ impl CallSiteScopeData {
 /// * the subscope with `first_statement_index == 0` is scope of both
 ///   `a` and `b`; it does not include EXPR_1, but does include
 ///   everything after that first `let`. (If you want a scope that
-///   includes EXPR_1 as well, then do not use `CodeExtentData::Remainder`,
+///   includes EXPR_1 as well, then do not use `CodeExtent::Remainder`,
 ///   but instead another `CodeExtent` that encompasses the whole block,
-///   e.g. `CodeExtentData::Misc`.
+///   e.g. `CodeExtent::Misc`.
 ///
 /// * the subscope with `first_statement_index == 1` is scope of `c`,
 ///   and thus does not include EXPR_2, but covers the `...`.
@@ -161,21 +138,21 @@ pub struct BlockRemainder {
     pub first_statement_index: u32,
 }
 
-impl CodeExtentData {
+impl CodeExtent {
     /// Returns a node id associated with this scope.
     ///
     /// NB: likely to be replaced as API is refined; e.g. pnkfelix
     /// anticipates `fn entry_node_id` and `fn each_exit_node_id`.
     pub fn node_id(&self) -> ast::NodeId {
         match *self {
-            CodeExtentData::Misc(node_id) => node_id,
+            CodeExtent::Misc(node_id) => node_id,
 
             // These cases all return rough approximations to the
             // precise extent denoted by `self`.
-            CodeExtentData::Remainder(br) => br.block,
-            CodeExtentData::DestructionScope(node_id) => node_id,
-            CodeExtentData::CallSiteScope { fn_id: _, body_id } |
-            CodeExtentData::ParameterScope { fn_id: _, body_id } => body_id,
+            CodeExtent::Remainder(br) => br.block,
+            CodeExtent::DestructionScope(node_id) => node_id,
+            CodeExtent::CallSiteScope(body_id) |
+            CodeExtent::ParameterScope(body_id) => body_id.node_id,
         }
     }
 
@@ -186,12 +163,12 @@ impl CodeExtentData {
         match hir_map.find(self.node_id()) {
             Some(hir_map::NodeBlock(ref blk)) => {
                 match *self {
-                    CodeExtentData::CallSiteScope { .. } |
-                    CodeExtentData::ParameterScope { .. } |
-                    CodeExtentData::Misc(_) |
-                    CodeExtentData::DestructionScope(_) => Some(blk.span),
+                    CodeExtent::CallSiteScope(_) |
+                    CodeExtent::ParameterScope(_) |
+                    CodeExtent::Misc(_) |
+                    CodeExtent::DestructionScope(_) => Some(blk.span),
 
-                    CodeExtentData::Remainder(r) => {
+                    CodeExtent::Remainder(r) => {
                         assert_eq!(r.block, blk.id);
                         // Want span for extent starting after the
                         // indexed statement and ending at end of
@@ -214,21 +191,29 @@ impl CodeExtentData {
 }
 
 /// The region maps encode information about region relationships.
-pub struct RegionMaps<'tcx> {
+pub struct RegionMaps {
+    /// If not empty, this body is the root of this region hierarchy.
+    root_body: Option<hir::BodyId>,
+
+    /// The parent of the root body owner, if the latter is an
+    /// an associated const or method, as impls/traits can also
+    /// have lifetime parameters free in this body.
+    root_parent: Option<ast::NodeId>,
+
     /// `scope_map` maps from a scope id to the enclosing scope id;
     /// this is usually corresponding to the lexical nesting, though
     /// in the case of closures the parent scope is the innermost
     /// conditional expression or repeating block. (Note that the
     /// enclosing scope id for the block associated with a closure is
     /// the closure itself.)
-    scope_map: FxHashMap<CodeExtent<'tcx>, CodeExtent<'tcx>>,
+    scope_map: FxHashMap<CodeExtent, CodeExtent>,
 
     /// `var_map` maps from a variable or binding id to the block in
     /// which that variable is declared.
-    var_map: NodeMap<CodeExtent<'tcx>>,
+    var_map: NodeMap<CodeExtent>,
 
     /// maps from a node-id to the associated destruction scope (if any)
-    destruction_scopes: NodeMap<CodeExtent<'tcx>>,
+    destruction_scopes: NodeMap<CodeExtent>,
 
     /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
     /// larger than the default. The map goes from the expression id
@@ -236,14 +221,14 @@ pub struct RegionMaps<'tcx> {
     /// table, the appropriate cleanup scope is the innermost
     /// enclosing statement, conditional expression, or repeating
     /// block (see `terminating_scopes`).
-    rvalue_scopes: NodeMap<CodeExtent<'tcx>>,
+    rvalue_scopes: NodeMap<CodeExtent>,
 
     /// Records the value of rvalue scopes before they were shrunk by
     /// #36082, for error reporting.
     ///
     /// FIXME: this should be temporary. Remove this by 1.18.0 or
     /// so.
-    shrunk_rvalue_scopes: NodeMap<CodeExtent<'tcx>>,
+    shrunk_rvalue_scopes: NodeMap<CodeExtent>,
 
     /// Encodes the hierarchy of fn bodies. Every fn body (including
     /// closures) forms its own distinct region hierarchy, rooted in
@@ -259,7 +244,7 @@ pub struct RegionMaps<'tcx> {
 }
 
 #[derive(Debug, Copy, Clone)]
-pub struct Context<'tcx> {
+pub struct Context {
     /// the root of the current region tree. This is typically the id
     /// of the innermost fn body. Each fn forms its own disjoint tree
     /// in the region hierarchy. These fn bodies are themselves
@@ -269,21 +254,19 @@ pub struct Context<'tcx> {
     root_id: Option<ast::NodeId>,
 
     /// the scope that contains any new variables declared
-    var_parent: Option<CodeExtent<'tcx>>,
+    var_parent: Option<CodeExtent>,
 
     /// region parent of expressions etc
-    parent: Option<CodeExtent<'tcx>>,
+    parent: Option<CodeExtent>,
 }
 
 struct RegionResolutionVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Generated maps:
-    region_maps: &'a mut RegionMaps<'tcx>,
-
-    cx: Context<'tcx>,
+    region_maps: RegionMaps,
 
-    map: &'a hir_map::Map<'tcx>,
+    cx: Context,
 
     /// `terminating_scopes` is a set containing the ids of each
     /// statement, or conditional/repeating expression. These scopes
@@ -309,9 +292,11 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
 }
 
 
-impl<'tcx> RegionMaps<'tcx> {
+impl<'tcx> RegionMaps {
     pub fn new() -> Self {
         RegionMaps {
+            root_body: None,
+            root_parent: None,
             scope_map: FxHashMap(),
             destruction_scopes: FxHashMap(),
             var_map: NodeMap(),
@@ -322,8 +307,8 @@ impl<'tcx> RegionMaps<'tcx> {
     }
 
     pub fn record_code_extent(&mut self,
-                              child: CodeExtent<'tcx>,
-                              parent: Option<CodeExtent<'tcx>>) {
+                              child: CodeExtent,
+                              parent: Option<CodeExtent>) {
         debug!("{:?}.parent = {:?}", child, parent);
 
         if let Some(p) = parent {
@@ -332,24 +317,24 @@ impl<'tcx> RegionMaps<'tcx> {
         }
 
         // record the destruction scopes for later so we can query them
-        if let &CodeExtentData::DestructionScope(n) = child {
+        if let CodeExtent::DestructionScope(n) = child {
             self.destruction_scopes.insert(n, child);
         }
     }
 
-    pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(CodeExtent<'tcx>, CodeExtent<'tcx>) {
+    pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(CodeExtent, CodeExtent) {
         for (&child, &parent) in &self.scope_map {
             e(child, parent)
         }
     }
 
-    pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, CodeExtent<'tcx>) {
-        for (child, parent) in self.var_map.iter() {
+    pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, CodeExtent) {
+        for (child, &parent) in self.var_map.iter() {
             e(child, parent)
         }
     }
 
-    pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent<'tcx>> {
+    pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent> {
         self.destruction_scopes.get(&n).cloned()
     }
 
@@ -373,48 +358,46 @@ impl<'tcx> RegionMaps<'tcx> {
         }
     }
 
-    fn record_var_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) {
+    fn record_var_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
         debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
         assert!(var != lifetime.node_id());
         self.var_map.insert(var, lifetime);
     }
 
-    fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) {
+    fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
         debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
         assert!(var != lifetime.node_id());
         self.rvalue_scopes.insert(var, lifetime);
     }
 
-    fn record_shrunk_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) {
+    fn record_shrunk_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
         debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
         assert!(var != lifetime.node_id());
         self.shrunk_rvalue_scopes.insert(var, lifetime);
     }
 
-    pub fn opt_encl_scope(&self, id: CodeExtent<'tcx>) -> Option<CodeExtent<'tcx>> {
+    pub fn opt_encl_scope(&self, id: CodeExtent) -> Option<CodeExtent> {
         //! Returns the narrowest scope that encloses `id`, if any.
         self.scope_map.get(&id).cloned()
     }
 
     #[allow(dead_code)] // used in cfg
-    pub fn encl_scope(&self, id: CodeExtent<'tcx>) -> CodeExtent<'tcx> {
+    pub fn encl_scope(&self, id: CodeExtent) -> CodeExtent {
         //! Returns the narrowest scope that encloses `id`, if any.
         self.opt_encl_scope(id).unwrap()
     }
 
     /// Returns the lifetime of the local variable `var_id`
-    pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent<'tcx> {
+    pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent {
         match self.var_map.get(&var_id) {
             Some(&r) => r,
             None => { bug!("no enclosing scope for id {:?}", var_id); }
         }
     }
 
-    pub fn temporary_scope2<'a, 'gcx: 'tcx>(&self,
-                                            tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                            expr_id: ast::NodeId)
-                                            -> (Option<CodeExtent<'tcx>>, bool) {
-        let temporary_scope = self.temporary_scope(tcx, expr_id);
+    pub fn temporary_scope2(&self, expr_id: ast::NodeId)
+                            -> (Option<CodeExtent>, bool) {
+        let temporary_scope = self.temporary_scope(expr_id);
         let was_shrunk = match self.shrunk_rvalue_scopes.get(&expr_id) {
             Some(&s) => {
                 info!("temporary_scope2({:?}, scope={:?}, shrunk={:?})",
@@ -427,23 +410,18 @@ impl<'tcx> RegionMaps<'tcx> {
         (temporary_scope, was_shrunk)
     }
 
-    pub fn old_and_new_temporary_scope<'a, 'gcx: 'tcx>(&self,
-                                                       tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                                       expr_id: ast::NodeId)
-                                                       -> (Option<CodeExtent<'tcx>>,
-                                                           Option<CodeExtent<'tcx>>)
+    pub fn old_and_new_temporary_scope(&self, expr_id: ast::NodeId)
+                                       -> (Option<CodeExtent>,
+                                           Option<CodeExtent>)
     {
-        let temporary_scope = self.temporary_scope(tcx, expr_id);
+        let temporary_scope = self.temporary_scope(expr_id);
         (temporary_scope,
          self.shrunk_rvalue_scopes
              .get(&expr_id).cloned()
              .or(temporary_scope))
     }
 
-    pub fn temporary_scope<'a, 'gcx: 'tcx>(&self,
-                                           tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                           expr_id: ast::NodeId)
-                                           -> Option<CodeExtent<'tcx>> {
+    pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option<CodeExtent> {
         //! Returns the scope when temp created by expr_id will be cleaned up
 
         // check for a designated rvalue scope
@@ -456,11 +434,11 @@ impl<'tcx> RegionMaps<'tcx> {
         // if there's one. Static items, for instance, won't
         // have an enclosing scope, hence no scope will be
         // returned.
-        let mut id = tcx.node_extent(expr_id);
+        let mut id = CodeExtent::Misc(expr_id);
 
-        while let Some(&p) = self.scope_map.get(id) {
-            match *p {
-                CodeExtentData::DestructionScope(..) => {
+        while let Some(&p) = self.scope_map.get(&id) {
+            match p {
+                CodeExtent::DestructionScope(..) => {
                     debug!("temporary_scope({:?}) = {:?} [enclosing]",
                            expr_id, id);
                     return Some(id);
@@ -473,7 +451,7 @@ impl<'tcx> RegionMaps<'tcx> {
         return None;
     }
 
-    pub fn var_region(&self, id: ast::NodeId) -> ty::RegionKind<'tcx> {
+    pub fn var_region(&self, id: ast::NodeId) -> ty::RegionKind {
         //! Returns the lifetime of the variable `id`.
 
         let scope = ty::ReScope(self.var_scope(id));
@@ -515,9 +493,9 @@ impl<'tcx> RegionMaps<'tcx> {
     /// Finds the nearest common ancestor (if any) of two scopes.  That is, finds the smallest
     /// scope which is greater than or equal to both `scope_a` and `scope_b`.
     pub fn nearest_common_ancestor(&self,
-                                   scope_a: CodeExtent<'tcx>,
-                                   scope_b: CodeExtent<'tcx>)
-                                   -> CodeExtent<'tcx> {
+                                   scope_a: CodeExtent,
+                                   scope_b: CodeExtent)
+                                   -> CodeExtent {
         if scope_a == scope_b { return scope_a; }
 
         /// [1] The initial values for `a_buf` and `b_buf` are not used.
@@ -525,9 +503,9 @@ impl<'tcx> RegionMaps<'tcx> {
         /// is re-initialized with new values (or else fallback to a
         /// heap-allocated vector).
         let mut a_buf: [CodeExtent; 32] = [scope_a /* [1] */; 32];
-        let mut a_vec: Vec<CodeExtent<'tcx>> = vec![];
+        let mut a_vec: Vec<CodeExtent> = vec![];
         let mut b_buf: [CodeExtent; 32] = [scope_b /* [1] */; 32];
-        let mut b_vec: Vec<CodeExtent<'tcx>> = vec![];
+        let mut b_vec: Vec<CodeExtent> = vec![];
         let scope_map = &self.scope_map;
         let a_ancestors = ancestors_of(scope_map, scope_a, &mut a_buf, &mut a_vec);
         let b_ancestors = ancestors_of(scope_map, scope_b, &mut b_buf, &mut b_vec);
@@ -551,8 +529,8 @@ impl<'tcx> RegionMaps<'tcx> {
             let a_root_scope = a_ancestors[a_index];
             let b_root_scope = a_ancestors[a_index];
             return match (a_root_scope, b_root_scope) {
-                (&CodeExtentData::DestructionScope(a_root_id),
-                 &CodeExtentData::DestructionScope(b_root_id)) => {
+                (CodeExtent::DestructionScope(a_root_id),
+                 CodeExtent::DestructionScope(b_root_id)) => {
                     if self.fn_is_enclosed_by(a_root_id, b_root_id) {
                         // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
                         scope_b
@@ -583,11 +561,11 @@ impl<'tcx> RegionMaps<'tcx> {
             }
         }
 
-        fn ancestors_of<'a, 'tcx>(scope_map: &FxHashMap<CodeExtent<'tcx>, CodeExtent<'tcx>>,
-                                  scope: CodeExtent<'tcx>,
-                                  buf: &'a mut [CodeExtent<'tcx>; 32],
-                                  vec: &'a mut Vec<CodeExtent<'tcx>>)
-                                  -> &'a [CodeExtent<'tcx>] {
+        fn ancestors_of<'a, 'tcx>(scope_map: &FxHashMap<CodeExtent, CodeExtent>,
+                                  scope: CodeExtent,
+                                  buf: &'a mut [CodeExtent; 32],
+                                  vec: &'a mut Vec<CodeExtent>)
+                                  -> &'a [CodeExtent] {
             // debug!("ancestors_of(scope={:?})", scope);
             let mut scope = scope;
 
@@ -595,7 +573,7 @@ impl<'tcx> RegionMaps<'tcx> {
             while i < 32 {
                 buf[i] = scope;
                 match scope_map.get(&scope) {
-                    Some(superscope) => scope = superscope,
+                    Some(&superscope) => scope = superscope,
                     _ => return &buf[..i+1]
                 }
                 i += 1;
@@ -606,12 +584,55 @@ impl<'tcx> RegionMaps<'tcx> {
             loop {
                 vec.push(scope);
                 match scope_map.get(&scope) {
-                    Some(superscope) => scope = superscope,
+                    Some(&superscope) => scope = superscope,
                     _ => return &*vec
                 }
             }
         }
     }
+
+    /// Assuming that the provided region was defined within this `RegionMaps`,
+    /// returns the outermost `CodeExtent` that the region outlives.
+    pub fn early_free_extent<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                       br: &ty::EarlyBoundRegion)
+                                       -> CodeExtent {
+        let param_owner = tcx.parent_def_id(br.def_id).unwrap();
+
+        let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
+        let body_id = tcx.hir.maybe_body_owned_by(param_owner_id).unwrap_or_else(|| {
+            // The lifetime was defined on node that doesn't own a body,
+            // which in practice can only mean a trait or an impl, that
+            // is the parent of a method, and that is enforced below.
+            assert_eq!(Some(param_owner_id), self.root_parent,
+                       "free_extent: {:?} not recognized by the region maps for {:?}",
+                       param_owner,
+                       self.root_body.map(|body| tcx.hir.body_owner_def_id(body)));
+
+            // The trait/impl lifetime is in scope for the method's body.
+            self.root_body.unwrap()
+        });
+
+        CodeExtent::CallSiteScope(body_id)
+    }
+
+    /// Assuming that the provided region was defined within this `RegionMaps`,
+    /// returns the outermost `CodeExtent` that the region outlives.
+    pub fn free_extent<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, fr: &ty::FreeRegion)
+                                 -> CodeExtent {
+        let param_owner = match fr.bound_region {
+            ty::BoundRegion::BrNamed(def_id, _) => {
+                tcx.parent_def_id(def_id).unwrap()
+            }
+            _ => fr.scope
+        };
+
+        // Ensure that the named late-bound lifetimes were defined
+        // on the same function that they ended up being freed in.
+        assert_eq!(param_owner, fr.scope);
+
+        let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
+        CodeExtent::CallSiteScope(tcx.hir.body_owned_by(param_owner_id))
+    }
 }
 
 /// Records the lifetime of a local variable as `cx.var_parent`
@@ -633,7 +654,6 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
     debug!("resolve_block(blk.id={:?})", blk.id);
 
     let prev_cx = visitor.cx;
-    let block_extent = visitor.new_node_extent_with_dtor(blk.id);
 
     // We treat the tail expression in the block (if any) somewhat
     // differently from the statements. The issue has to do with
@@ -660,11 +680,8 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
     // `other_argument()` has run and also the call to `quux(..)`
     // itself has returned.
 
-    visitor.cx = Context {
-        root_id: prev_cx.root_id,
-        var_parent: Some(block_extent),
-        parent: Some(block_extent),
-    };
+    visitor.enter_node_extent_with_dtor(blk.id);
+    visitor.cx.var_parent = visitor.cx.parent;
 
     {
         // This block should be kept approximately in sync with
@@ -680,17 +697,13 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
                 // has the previous subscope in the block as a parent,
                 // except for the first such subscope, which has the
                 // block itself as a parent.
-                let stmt_extent = visitor.new_code_extent(
-                    CodeExtentData::Remainder(BlockRemainder {
+                visitor.enter_code_extent(
+                    CodeExtent::Remainder(BlockRemainder {
                         block: blk.id,
                         first_statement_index: i as u32
                     })
                 );
-                visitor.cx = Context {
-                    root_id: prev_cx.root_id,
-                    var_parent: Some(stmt_extent),
-                    parent: Some(stmt_extent),
-                };
+                visitor.cx.var_parent = visitor.cx.parent;
             }
             visitor.visit_stmt(statement)
         }
@@ -711,7 +724,7 @@ fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &
 }
 
 fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) {
-    visitor.new_node_extent(pat.id);
+    visitor.record_code_extent(CodeExtent::Misc(pat.id));
 
     // If this is a binding then record the lifetime of that binding.
     if let PatKind::Binding(..) = pat.node {
@@ -731,20 +744,20 @@ fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt:
     // statement plus its destructors, and thus the extent for which
     // regions referenced by the destructors need to survive.
     visitor.terminating_scopes.insert(stmt_id);
-    let stmt_extent = visitor.new_node_extent_with_dtor(stmt_id);
 
     let prev_parent = visitor.cx.parent;
-    visitor.cx.parent = Some(stmt_extent);
+    visitor.enter_node_extent_with_dtor(stmt_id);
+
     intravisit::walk_stmt(visitor, stmt);
+
     visitor.cx.parent = prev_parent;
 }
 
 fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: &'tcx hir::Expr) {
     debug!("resolve_expr(expr.id={:?})", expr.id);
 
-    let expr_extent = visitor.new_node_extent_with_dtor(expr.id);
     let prev_cx = visitor.cx;
-    visitor.cx.parent = Some(expr_extent);
+    visitor.enter_node_extent_with_dtor(expr.id);
 
     {
         let terminating_scopes = &mut visitor.terminating_scopes;
@@ -784,7 +797,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
             }
 
             hir::ExprMatch(..) => {
-                visitor.cx.var_parent = Some(expr_extent);
+                visitor.cx.var_parent = visitor.cx.parent;
             }
 
             hir::ExprAssignOp(..) | hir::ExprIndex(..) |
@@ -971,7 +984,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
     fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>(
         visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
         expr: &hir::Expr,
-        blk_id: CodeExtent<'tcx>)
+        blk_id: CodeExtent)
     {
         match expr.node {
             hir::ExprAddrOf(_, ref subexpr) => {
@@ -1021,7 +1034,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
     /// Note: ET is intended to match "rvalues or lvalues based on rvalues".
     fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
                                      expr: &hir::Expr,
-                                     blk_scope: CodeExtent<'tcx>,
+                                     blk_scope: CodeExtent,
                                      is_shrunk: bool) {
         let mut expr = expr;
         loop {
@@ -1054,43 +1067,28 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
 }
 
 impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
-    pub fn intern_code_extent(&mut self,
-                              data: CodeExtentData,
-                              parent: Option<CodeExtent<'tcx>>)
-                              -> CodeExtent<'tcx> {
-        let code_extent = self.tcx.intern_code_extent(data);
-        self.region_maps.record_code_extent(code_extent, parent);
-        code_extent
-    }
-
-    pub fn intern_node(&mut self,
-                       n: ast::NodeId,
-                       parent: Option<CodeExtent<'tcx>>) -> CodeExtent<'tcx> {
-        self.intern_code_extent(CodeExtentData::Misc(n), parent)
-    }
-
     /// Records the current parent (if any) as the parent of `child_scope`.
-    fn new_code_extent(&mut self, child_scope: CodeExtentData) -> CodeExtent<'tcx> {
+    fn record_code_extent(&mut self, child_scope: CodeExtent) {
         let parent = self.cx.parent;
-        self.intern_code_extent(child_scope, parent)
+        self.region_maps.record_code_extent(child_scope, parent);
     }
 
-    fn new_node_extent(&mut self, child_scope: ast::NodeId) -> CodeExtent<'tcx> {
-        self.new_code_extent(CodeExtentData::Misc(child_scope))
+    /// Records the current parent (if any) as the parent of `child_scope`,
+    /// and sets `child_scope` as the new current parent.
+    fn enter_code_extent(&mut self, child_scope: CodeExtent) {
+        self.record_code_extent(child_scope);
+        self.cx.parent = Some(child_scope);
     }
 
-    fn new_node_extent_with_dtor(&mut self, id: ast::NodeId) -> CodeExtent<'tcx> {
+    fn enter_node_extent_with_dtor(&mut self, id: ast::NodeId) {
         // If node was previously marked as a terminating scope during the
         // recursive visit of its parent node in the AST, then we need to
         // account for the destruction scope representing the extent of
         // the destructors that run immediately after it completes.
         if self.terminating_scopes.contains(&id) {
-            let ds = self.new_code_extent(
-                CodeExtentData::DestructionScope(id));
-            self.intern_node(id, Some(ds))
-        } else {
-            self.new_node_extent(id)
+            self.enter_code_extent(CodeExtent::DestructionScope(id));
         }
+        self.enter_code_extent(CodeExtent::Misc(id));
     }
 }
 
@@ -1105,7 +1103,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
 
     fn visit_body(&mut self, body: &'tcx hir::Body) {
         let body_id = body.id();
-        let owner_id = self.map.body_owner(body_id);
+        let owner_id = self.tcx.hir.body_owner(body_id);
 
         debug!("visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
                owner_id,
@@ -1127,10 +1125,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
         }
         self.cx.root_id = Some(body_id.node_id);
 
-        self.cx.parent = Some(self.new_code_extent(
-            CodeExtentData::CallSiteScope { fn_id: owner_id, body_id: body_id.node_id }));
-        self.cx.parent = Some(self.new_code_extent(
-            CodeExtentData::ParameterScope { fn_id: owner_id, body_id: body_id.node_id }));
+        self.enter_code_extent(CodeExtent::CallSiteScope(body_id));
+        self.enter_code_extent(CodeExtent::ParameterScope(body_id));
 
         // The arguments and `self` are parented to the fn.
         self.cx.var_parent = self.cx.parent.take();
@@ -1165,21 +1161,18 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
 }
 
 fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-    -> Rc<RegionMaps<'tcx>>
+    -> Rc<RegionMaps>
 {
     let closure_base_def_id = tcx.closure_base_def_id(def_id);
     if closure_base_def_id != def_id {
         return tcx.region_maps(closure_base_def_id);
     }
 
-    let mut maps = RegionMaps::new();
-
     let id = tcx.hir.as_local_node_id(def_id).unwrap();
-    if let Some(body) = tcx.hir.maybe_body_owned_by(id) {
+    let maps = if let Some(body) = tcx.hir.maybe_body_owned_by(id) {
         let mut visitor = RegionResolutionVisitor {
-            tcx: tcx,
-            region_maps: &mut maps,
-            map: &tcx.hir,
+            tcx,
+            region_maps: RegionMaps::new(),
             cx: Context {
                 root_id: None,
                 parent: None,
@@ -1188,8 +1181,25 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
             terminating_scopes: NodeSet(),
         };
 
+        visitor.region_maps.root_body = Some(body);
+
+        // If the item is an associated const or a method,
+        // record its impl/trait parent, as it can also have
+        // lifetime parameters free in this body.
+        match tcx.hir.get(id) {
+            hir::map::NodeImplItem(_) |
+            hir::map::NodeTraitItem(_) => {
+                visitor.region_maps.root_parent = Some(tcx.hir.get_parent(id));
+            }
+            _ => {}
+        }
+
         visitor.visit_body(tcx.hir.body(body));
-    }
+
+        visitor.region_maps
+    } else {
+        RegionMaps::new()
+    };
 
     Rc::new(maps)
 }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 67b8dfb2d8e..7d7308d73bb 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -19,7 +19,6 @@ use hir::map::Map;
 use session::Session;
 use hir::def::Def;
 use hir::def_id::DefId;
-use middle::region;
 use ty;
 
 use std::cell::Cell;
@@ -42,7 +41,7 @@ pub enum Region {
     EarlyBound(/* index */ u32, /* lifetime decl */ ast::NodeId),
     LateBound(ty::DebruijnIndex, /* lifetime decl */ ast::NodeId),
     LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32),
-    Free(region::CallSiteScopeData, /* lifetime decl */ ast::NodeId),
+    Free(DefId, /* lifetime decl */ ast::NodeId),
 }
 
 impl Region {
@@ -895,11 +894,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         };
 
         if let Some(mut def) = result {
-            if let Some(body_id) = outermost_body {
+            if let Region::EarlyBound(..) = def {
+                // Do not free early-bound regions, only late-bound ones.
+            } else if let Some(body_id) = outermost_body {
                 let fn_id = self.hir_map.body_owner(body_id);
-                let scope_data = region::CallSiteScopeData {
-                    fn_id: fn_id, body_id: body_id.node_id
-                };
                 match self.hir_map.get(fn_id) {
                     hir::map::NodeItem(&hir::Item {
                         node: hir::ItemFn(..), ..
@@ -910,7 +908,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     hir::map::NodeImplItem(&hir::ImplItem {
                         node: hir::ImplItemKind::Method(..), ..
                     }) => {
-                        def = Region::Free(scope_data, def.id().unwrap());
+                        let scope = self.hir_map.local_def_id(fn_id);
+                        def = Region::Free(scope, def.id().unwrap());
                     }
                     _ => {}
                 }
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index ea1a2f9a982..66e8e503be4 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -206,9 +206,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         };
 
         // Search for a predicate like `Self : Sized` amongst the trait bounds.
-        let free_substs = self.construct_free_substs(def_id, None);
         let predicates = self.predicates_of(def_id);
-        let predicates = predicates.instantiate(self, free_substs).predicates;
+        let predicates = predicates.instantiate_identity(self).predicates;
         elaborate_predicates(self, predicates)
             .any(|predicate| {
                 match predicate {
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index d5d17e3c812..3882e218241 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -179,12 +179,8 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     // create a parameter environment corresponding to a (skolemized) instantiation of impl1
-    let penv = tcx.construct_parameter_environment(DUMMY_SP,
-                                                   impl1_def_id,
-                                                   None);
-    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
-                             .unwrap()
-                             .subst(tcx, &penv.free_substs);
+    let penv = tcx.parameter_environment(impl1_def_id);
+    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
 
     // Create a infcx, taking the predicates of impl1 as assumptions:
     let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| {
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 1d10c3a9695..3f5cf7eca53 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -197,7 +197,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
                 // I want to be conservative. --nmatsakis
                 let ty_max = data.skip_binder().0;
                 let r_min = data.skip_binder().1;
-                if r_min.is_bound() {
+                if r_min.is_late_bound() {
                     return;
                 }
 
@@ -206,7 +206,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
                     tcx.outlives_components(ty_max)
                        .into_iter()
                        .filter_map(|component| match component {
-                           Component::Region(r) => if r.is_bound() {
+                           Component::Region(r) => if r.is_late_bound() {
                                None
                            } else {
                                Some(ty::Predicate::RegionOutlives(
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 74aac7b788b..b9355c264b3 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -21,7 +21,6 @@ use hir::map as hir_map;
 use hir::map::DisambiguatedDefPathData;
 use middle::free_region::FreeRegionMap;
 use middle::lang_items;
-use middle::region::{CodeExtent, CodeExtentData};
 use middle::resolve_lifetime;
 use middle::stability;
 use mir::Mir;
@@ -99,7 +98,7 @@ pub struct CtxtInterners<'tcx> {
     type_: RefCell<FxHashSet<Interned<'tcx, TyS<'tcx>>>>,
     type_list: RefCell<FxHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>,
     substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>,
-    region: RefCell<FxHashSet<Interned<'tcx, RegionKind<'tcx>>>>,
+    region: RefCell<FxHashSet<Interned<'tcx, RegionKind>>>,
     existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
     predicates: RefCell<FxHashSet<Interned<'tcx, Slice<Predicate<'tcx>>>>>,
 }
@@ -548,8 +547,6 @@ pub struct GlobalCtxt<'tcx> {
 
     layout_interner: RefCell<FxHashSet<&'tcx Layout>>,
 
-    code_extent_interner: RefCell<FxHashSet<CodeExtent<'tcx>>>,
-
     /// A vector of every trait accessible in the whole crate
     /// (i.e. including those from subcrates). This is used only for
     /// error reporting, and so is lazily initialised and generally
@@ -651,32 +648,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         interned
     }
 
-    pub fn node_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> {
-        self.intern_code_extent(CodeExtentData::Misc(n))
-    }
-
-    // Returns the code extent for an item - the destruction scope.
-    pub fn item_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> {
-        self.intern_code_extent(CodeExtentData::DestructionScope(n))
-    }
-
-    pub fn call_site_extent(self, fn_id: ast::NodeId, body_id: ast::NodeId) -> CodeExtent<'gcx> {
-        assert!(fn_id != body_id);
-        self.intern_code_extent(CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id })
-    }
-
-    pub fn intern_code_extent(self, data: CodeExtentData) -> CodeExtent<'gcx> {
-        if let Some(st) = self.code_extent_interner.borrow().get(&data) {
-            return st;
-        }
-
-        let interned = self.global_interners.arena.alloc(data);
-        if let Some(prev) = self.code_extent_interner.borrow_mut().replace(interned) {
-            bug!("Tried to overwrite interned code-extent: {:?}", prev)
-        }
-        interned
-    }
-
     pub fn intern_layout(self, layout: Layout) -> &'gcx Layout {
         if let Some(layout) = self.layout_interner.borrow().get(&layout) {
             return layout;
@@ -764,7 +735,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             data_layout: data_layout,
             layout_cache: RefCell::new(FxHashMap()),
             layout_interner: RefCell::new(FxHashSet()),
-            code_extent_interner: RefCell::new(FxHashSet()),
             layout_depth: Cell::new(0),
             derive_macros: RefCell::new(NodeMap()),
             stability_interner: RefCell::new(FxHashSet()),
@@ -843,15 +813,6 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for ty::FreeRegion<'a> {
-    type Lifted = ty::FreeRegion<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        let scope = self.scope.map(|code_extent| tcx.intern_code_extent(*code_extent));
-        let bound_region = self.bound_region;
-        Some(ty::FreeRegion { scope, bound_region })
-    }
-}
-
 impl<'a, 'tcx> Lift<'tcx> for Region<'a> {
     type Lifted = Region<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Region<'tcx>> {
@@ -1115,8 +1076,8 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> {
     }
 }
 
-impl<'tcx> Borrow<RegionKind<'tcx>> for Interned<'tcx, RegionKind<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a RegionKind<'tcx> {
+impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
+    fn borrow<'a>(&'a self) -> &'a RegionKind {
         &self.0
     }
 }
@@ -1215,7 +1176,7 @@ direct_interners!('tcx,
             &ty::ReVar(_) | &ty::ReSkolemized(..) => true,
             _ => false
         }
-    }) -> RegionKind<'tcx>
+    }) -> RegionKind
 );
 
 macro_rules! slice_interners {
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 21ccf6f987b..6de3c018bda 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -39,7 +39,6 @@
 //! These methods return true to indicate that the visitor has found what it is looking for
 //! and does not need to visit anything else.
 
-use middle::region;
 use ty::subst::Substs;
 use ty::adjustment;
 use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
@@ -326,23 +325,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         (result, replacer.map)
     }
 
-
-    /// Replace any late-bound regions bound in `value` with free variants attached to scope-id
-    /// `scope_id`.
-    pub fn liberate_late_bound_regions<T>(self,
-        all_outlive_scope: Option<region::CodeExtent<'tcx>>,
-        value: &Binder<T>)
-        -> T
-        where T : TypeFoldable<'tcx>
-    {
-        self.replace_late_bound_regions(value, |br| {
-            self.mk_region(ty::ReFree(ty::FreeRegion {
-                scope: all_outlive_scope,
-                bound_region: br
-            }))
-        }).0
-    }
-
     /// Flattens two binding levels into one. So `for<'a> for<'b> Foo`
     /// becomes `for<'a,'b> Foo`.
     pub fn flatten_late_bound_regions<T>(self, bound2_value: &Binder<Binder<T>>)
@@ -554,7 +536,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 // regions. See comment on `shift_regions_through_binders` method in
 // `subst.rs` for more details.
 
-pub fn shift_region<'tcx>(region: ty::RegionKind<'tcx>, amount: u32) -> ty::RegionKind<'tcx> {
+pub fn shift_region(region: ty::RegionKind, amount: u32) -> ty::RegionKind {
     match region {
         ty::ReLateBound(debruijn, br) => {
             ty::ReLateBound(debruijn.shifted(amount), br)
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 480b8967a79..bd38a6c3fd3 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1268,11 +1268,10 @@ impl<'a, 'gcx, 'tcx> Layout {
                     let kind = if def.is_enum() || def.variants[0].fields.len() == 0{
                         StructKind::AlwaysSizedUnivariant
                     } else {
-                        let param_env = tcx.construct_parameter_environment(DUMMY_SP,
-                          def.did, None);
+                        let param_env = tcx.parameter_environment(def.did);
                         let fields = &def.variants[0].fields;
                         let last_field = &fields[fields.len()-1];
-                        let always_sized = last_field.ty(tcx, param_env.free_substs)
+                        let always_sized = tcx.type_of(last_field.did)
                           .is_sized(tcx, &param_env, DUMMY_SP);
                         if !always_sized { StructKind::MaybeUnsizedUnivariant }
                         else { StructKind::AlwaysSizedUnivariant }
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 3b5dc2ae164..1fd9e8f7375 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -801,7 +801,7 @@ define_maps! { <'tcx>
     /// Per-function `RegionMaps`. The `DefId` should be the owner-def-id for the fn body;
     /// in the case of closures or "inline" expressions, this will be redirected to the enclosing
     /// fn item.
-    [] region_maps: RegionMaps(DefId) -> Rc<RegionMaps<'tcx>>,
+    [] region_maps: RegionMaps(DefId) -> Rc<RegionMaps>,
 
     [] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>,
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index f5d510c11ae..6ca401d27ac 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -23,8 +23,8 @@ use ich::StableHashingContext;
 use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
-use middle::region::CodeExtent;
 use middle::resolve_lifetime::ObjectLifetimeDefault;
+use middle::region::CodeExtent;
 use mir::Mir;
 use traits;
 use ty;
@@ -732,12 +732,19 @@ pub struct RegionParameterDef {
 impl RegionParameterDef {
     pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion {
         ty::EarlyBoundRegion {
+            def_id: self.def_id,
             index: self.index,
             name: self.name,
         }
     }
 
     pub fn to_bound_region(&self) -> ty::BoundRegion {
+        self.to_early_bound_region_data().to_bound_region()
+    }
+}
+
+impl ty::EarlyBoundRegion {
+    pub fn to_bound_region(&self) -> ty::BoundRegion {
         ty::BoundRegion::BrNamed(self.def_id, self.name)
     }
 }
@@ -816,6 +823,21 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
         instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs)))
     }
 
+    pub fn instantiate_identity(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                                -> InstantiatedPredicates<'tcx> {
+        let mut instantiated = InstantiatedPredicates::empty();
+        self.instantiate_identity_into(tcx, &mut instantiated);
+        instantiated
+    }
+
+    fn instantiate_identity_into(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                 instantiated: &mut InstantiatedPredicates<'tcx>) {
+        if let Some(def_id) = self.parent {
+            tcx.predicates_of(def_id).instantiate_identity_into(tcx, instantiated);
+        }
+        instantiated.predicates.extend(&self.predicates)
+    }
+
     pub fn instantiate_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                   poly_trait_ref: &ty::PolyTraitRef<'tcx>)
                                   -> InstantiatedPredicates<'tcx>
@@ -1241,31 +1263,11 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
 /// more distinctions clearer.
 #[derive(Clone)]
 pub struct ParameterEnvironment<'tcx> {
-    /// See `construct_free_substs` for details.
-    pub free_substs: &'tcx Substs<'tcx>,
-
-    /// Each type parameter has an implicit region bound that
-    /// indicates it must outlive at least the function body (the user
-    /// may specify stronger requirements). This field indicates the
-    /// region of the callee. If it is `None`, then the parameter
-    /// environment is for an item or something where the "callee" is
-    /// not clear.
-    pub implicit_region_bound: Option<ty::Region<'tcx>>,
-
     /// Obligations that the caller must satisfy. This is basically
     /// the set of bounds on the in-scope type parameters, translated
     /// into Obligations, and elaborated and normalized.
     pub caller_bounds: &'tcx [ty::Predicate<'tcx>],
 
-    /// Scope that is attached to free regions for this scope. This is
-    /// usually the id of the fn body, but for more abstract scopes
-    /// like structs we use None or the item extent.
-    ///
-    /// FIXME(#3696). It would be nice to refactor so that free
-    /// regions don't have this implicit scope and instead introduce
-    /// relationships in the environment.
-    pub free_id_outlive: Option<CodeExtent<'tcx>>,
-
     /// A cache for `moves_by_default`.
     pub is_copy_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
 
@@ -1282,120 +1284,12 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                               -> ParameterEnvironment<'tcx>
     {
         ParameterEnvironment {
-            free_substs: self.free_substs,
-            implicit_region_bound: self.implicit_region_bound,
             caller_bounds: caller_bounds,
-            free_id_outlive: self.free_id_outlive,
             is_copy_cache: RefCell::new(FxHashMap()),
             is_sized_cache: RefCell::new(FxHashMap()),
             is_freeze_cache: RefCell::new(FxHashMap()),
         }
     }
-
-    /// Construct a parameter environment given an item, impl item, or trait item
-    pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
-                    -> ParameterEnvironment<'tcx> {
-        match tcx.hir.find(id) {
-            Some(hir_map::NodeImplItem(ref impl_item)) => {
-                match impl_item.node {
-                    hir::ImplItemKind::Type(_) => {
-                        // associated types don't have their own entry (for some reason),
-                        // so for now just grab environment for the impl
-                        let impl_id = tcx.hir.get_parent(id);
-                        let impl_def_id = tcx.hir.local_def_id(impl_id);
-                        tcx.construct_parameter_environment(impl_item.span,
-                                                            impl_def_id,
-                                                            Some(tcx.item_extent(id)))
-                    }
-                    hir::ImplItemKind::Const(_, body) |
-                    hir::ImplItemKind::Method(_, body) => {
-                        tcx.construct_parameter_environment(
-                            impl_item.span,
-                            tcx.hir.local_def_id(id),
-                            Some(tcx.call_site_extent(id, body.node_id)))
-                    }
-                }
-            }
-            Some(hir_map::NodeTraitItem(trait_item)) => {
-                match trait_item.node {
-                    hir::TraitItemKind::Type(..) |
-                    hir::TraitItemKind::Const(_, None) |
-                    hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_))=> {
-                        tcx.construct_parameter_environment(trait_item.span,
-                                                            tcx.hir.local_def_id(id),
-                                                            Some(tcx.item_extent(id)))
-                    }
-                    hir::TraitItemKind::Const(_, Some(body)) |
-                    hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body)) => {
-                        tcx.construct_parameter_environment(
-                            trait_item.span,
-                            tcx.hir.local_def_id(id),
-                            Some(tcx.call_site_extent(id, body.node_id)))
-                    }
-                }
-            }
-            Some(hir_map::NodeItem(item)) => {
-                match item.node {
-                    hir::ItemConst(_, body) |
-                    hir::ItemStatic(.., body) |
-                    hir::ItemFn(.., body) => {
-                        tcx.construct_parameter_environment(
-                            item.span,
-                            tcx.hir.local_def_id(id),
-                            Some(tcx.call_site_extent(id, body.node_id)))
-                    }
-                    hir::ItemEnum(..) |
-                    hir::ItemStruct(..) |
-                    hir::ItemUnion(..) |
-                    hir::ItemTy(..) |
-                    hir::ItemImpl(..) |
-                    hir::ItemTrait(..) => {
-                        let def_id = tcx.hir.local_def_id(id);
-                        tcx.construct_parameter_environment(item.span,
-                                                            def_id,
-                                                            Some(tcx.item_extent(id)))
-                    }
-                    _ => {
-                        span_bug!(item.span,
-                                  "ParameterEnvironment::for_item():
-                                   can't create a parameter \
-                                   environment for this kind of item")
-                    }
-                }
-            }
-            Some(hir_map::NodeExpr(expr)) => {
-                // This is a convenience to allow closures to work.
-                if let hir::ExprClosure(.., body, _) = expr.node {
-                    let def_id = tcx.hir.local_def_id(id);
-                    let base_def_id = tcx.closure_base_def_id(def_id);
-                    tcx.construct_parameter_environment(
-                        expr.span,
-                        base_def_id,
-                        Some(tcx.call_site_extent(id, body.node_id)))
-                } else {
-                    tcx.empty_parameter_environment()
-                }
-            }
-            Some(hir_map::NodeForeignItem(item)) => {
-                let def_id = tcx.hir.local_def_id(id);
-                tcx.construct_parameter_environment(item.span,
-                                                    def_id,
-                                                    None)
-            }
-            Some(hir_map::NodeStructCtor(..)) |
-            Some(hir_map::NodeVariant(..)) => {
-                let def_id = tcx.hir.local_def_id(id);
-                tcx.construct_parameter_environment(tcx.hir.span(id),
-                                                    def_id,
-                                                    None)
-            }
-            it => {
-                bug!("ParameterEnvironment::from_item(): \
-                      `{}` = {:?} is unsupported",
-                     tcx.hir.node_to_string(id), it)
-            }
-        }
-    }
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -2497,64 +2391,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// are no free type/lifetime parameters in scope.
     pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> {
         ty::ParameterEnvironment {
-            free_substs: self.intern_substs(&[]),
             caller_bounds: Slice::empty(),
-            implicit_region_bound: None,
-            free_id_outlive: None,
             is_copy_cache: RefCell::new(FxHashMap()),
             is_sized_cache: RefCell::new(FxHashMap()),
             is_freeze_cache: RefCell::new(FxHashMap()),
         }
     }
 
-    /// Constructs and returns 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
-    /// free parameters. Since we currently represent bound/free type
-    /// parameters in the same way, this only has an effect on regions.
-    pub fn construct_free_substs(self,
-                                 def_id: DefId,
-                                 free_id_outlive: Option<CodeExtent<'gcx>>)
-                                 -> &'gcx Substs<'gcx> {
-
-        let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| {
-            // map bound 'a => free 'a
-            self.global_tcx().mk_region(ReFree(FreeRegion {
-                scope: free_id_outlive,
-                bound_region: def.to_bound_region()
-            }))
-        }, |def, _| {
-            // map T => T
-            self.global_tcx().mk_param_from_def(def)
-        });
-
-        debug!("construct_parameter_environment: {:?}", substs);
-        substs
-    }
-
     /// See `ParameterEnvironment` struct def'n for details.
-    /// If you were using `free_id: NodeId`, you might try `self.region_maps().item_extent(free_id)`
-    /// for the `free_id_outlive` parameter. (But note that this is not always quite right.)
-    pub fn construct_parameter_environment(self,
-                                           span: Span,
-                                           def_id: DefId,
-                                           free_id_outlive: Option<CodeExtent<'gcx>>)
-                                           -> ParameterEnvironment<'gcx>
-    {
-        //
-        // Construct the free substs.
-        //
-
-        let free_substs = self.construct_free_substs(def_id, free_id_outlive);
-
+    pub fn parameter_environment(self, def_id: DefId) -> ParameterEnvironment<'gcx> {
         //
         // Compute the bounds on Self and the type parameters.
         //
 
         let tcx = self.global_tcx();
-        let generic_predicates = tcx.predicates_of(def_id);
-        let bounds = generic_predicates.instantiate(tcx, free_substs);
-        let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds));
+        let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx);
         let predicates = bounds.predicates;
 
         // Finally, we have to normalize the bounds in the environment, in
@@ -2571,23 +2422,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         //
 
         let unnormalized_env = ty::ParameterEnvironment {
-            free_substs: free_substs,
-            implicit_region_bound: free_id_outlive.map(|f| tcx.mk_region(ty::ReScope(f))),
             caller_bounds: tcx.intern_predicates(&predicates),
-            free_id_outlive: free_id_outlive,
             is_copy_cache: RefCell::new(FxHashMap()),
             is_sized_cache: RefCell::new(FxHashMap()),
             is_freeze_cache: RefCell::new(FxHashMap()),
         };
 
-        let body_id = free_id_outlive.map(|f| f.node_id())
-                                     .unwrap_or(DUMMY_NODE_ID);
-        let cause = traits::ObligationCause::misc(span, body_id);
+        let body_id = self.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
+            self.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id)
+        });
+        let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
         traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
     }
 
     pub fn node_scope_region(self, id: NodeId) -> Region<'tcx> {
-        self.mk_region(ty::ReScope(self.node_extent(id)))
+        self.mk_region(ty::ReScope(CodeExtent::Misc(id)))
     }
 
     /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index a544b2dd399..ab1b1b3857d 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -204,7 +204,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
 fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region<'tcx>>) {
     for r in regions {
-        if !r.is_bound() {
+        if !r.is_late_bound() {
             out.push(Component::Region(r));
         }
     }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 89960b0e4f6..cfbf1244db3 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -43,12 +43,8 @@ pub struct TypeAndMut<'tcx> {
          RustcEncodable, RustcDecodable, Copy)]
 /// A "free" region `fr` can be interpreted as "some region
 /// at least as big as the scope `fr.scope`".
-///
-/// If `fr.scope` is None, then this is in some context (e.g., an
-/// impl) where lifetimes are more abstract and the notion of the
-/// caller/callee stack frames are not applicable.
-pub struct FreeRegion<'tcx> {
-    pub scope: Option<region::CodeExtent<'tcx>>,
+pub struct FreeRegion {
+    pub scope: DefId,
     pub bound_region: BoundRegion,
 }
 
@@ -688,7 +684,7 @@ pub struct DebruijnIndex {
     pub depth: u32,
 }
 
-pub type Region<'tcx> = &'tcx RegionKind<'tcx>;
+pub type Region<'tcx> = &'tcx RegionKind;
 
 /// Representation of regions.
 ///
@@ -747,7 +743,7 @@ pub type Region<'tcx> = &'tcx RegionKind<'tcx>;
 /// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
 /// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
 #[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable)]
-pub enum RegionKind<'tcx> {
+pub enum RegionKind {
     // Region bound in a type or fn declaration which will be
     // substituted 'early' -- that is, at the same time when type
     // parameters are substituted.
@@ -760,12 +756,12 @@ pub enum RegionKind<'tcx> {
     /// When checking a function body, the types of all arguments and so forth
     /// that refer to bound region parameters are modified to refer to free
     /// region parameters.
-    ReFree(FreeRegion<'tcx>),
+    ReFree(FreeRegion),
 
     /// A concrete region naming some statically determined extent
     /// (e.g. an expression or sequence of statements) within the
     /// current function.
-    ReScope(region::CodeExtent<'tcx>),
+    ReScope(region::CodeExtent),
 
     /// Static data that has an "infinite" lifetime. Top in the region lattice.
     ReStatic,
@@ -794,6 +790,7 @@ impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {}
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
 pub struct EarlyBoundRegion {
+    pub def_id: DefId,
     pub index: u32,
     pub name: Name,
 }
@@ -909,10 +906,9 @@ impl DebruijnIndex {
 }
 
 /// Region utilities
-impl<'tcx> RegionKind<'tcx> {
-    pub fn is_bound(&self) -> bool {
+impl RegionKind {
+    pub fn is_late_bound(&self) -> bool {
         match *self {
-            ty::ReEarlyBound(..) => true,
             ty::ReLateBound(..) => true,
             _ => false,
         }
@@ -933,7 +929,7 @@ impl<'tcx> RegionKind<'tcx> {
     }
 
     /// Returns the depth of `self` from the (1-based) binding level `depth`
-    pub fn from_depth(&self, depth: u32) -> RegionKind<'tcx> {
+    pub fn from_depth(&self, depth: u32) -> RegionKind {
         match *self {
             ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
                 depth: debruijn.depth - (depth - 1)
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 06d09bd350a..c6c6a0e4700 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -688,9 +688,8 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
                 self.hash(db.depth);
                 self.hash(i);
             }
-            ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => {
-                self.hash(index);
-                self.hash(name.as_str());
+            ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
+                self.def_id(def_id);
             }
             ty::ReLateBound(..) |
             ty::ReFree(..) |
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index d773bb2da08..8ca699339d3 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -458,7 +458,7 @@ impl fmt::Debug for ty::BoundRegion {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::RegionKind<'tcx> {
+impl fmt::Debug for ty::RegionKind {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ty::ReEarlyBound(ref data) => {
@@ -506,17 +506,11 @@ impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ParameterEnvironment(\
-            free_substs={:?}, \
-            implicit_region_bound={:?}, \
-            caller_bounds={:?})",
-            self.free_substs,
-            self.implicit_region_bound,
-            self.caller_bounds)
+        write!(f, "ParameterEnvironment({:?})", self.caller_bounds)
     }
 }
 
-impl<'tcx> fmt::Display for ty::RegionKind<'tcx> {
+impl<'tcx> fmt::Display for ty::RegionKind {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if verbose() {
             return write!(f, "{:?}", *self);
@@ -544,7 +538,7 @@ impl<'tcx> fmt::Display for ty::RegionKind<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::FreeRegion<'tcx> {
+impl fmt::Debug for ty::FreeRegion {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "ReFree({:?}, {:?})",
                self.scope, self.bound_region)
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index adabbe11f5e..eeb5a3fb957 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -232,7 +232,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         })
     }
 
-    pub fn each_in_scope_loan<F>(&self, scope: region::CodeExtent<'tcx>, mut op: F) -> bool where
+    pub fn each_in_scope_loan<F>(&self, scope: region::CodeExtent, mut op: F) -> bool where
         F: FnMut(&Loan<'tcx>) -> bool,
     {
         //! Like `each_issued_loan()`, but only considers loans that are
@@ -248,7 +248,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     }
 
     fn each_in_scope_loan_affecting_path<F>(&self,
-                                            scope: region::CodeExtent<'tcx>,
+                                            scope: region::CodeExtent,
                                             loan_path: &LoanPath<'tcx>,
                                             mut op: F)
                                             -> bool where
@@ -708,7 +708,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         let mut ret = UseOk;
 
         self.each_in_scope_loan_affecting_path(
-            self.tcx().node_extent(expr_id), use_path, |loan| {
+            region::CodeExtent::Misc(expr_id), use_path, |loan| {
             if !compatible_borrow_kinds(loan.kind, borrow_kind) {
                 ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
                 false
@@ -822,7 +822,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
 
         // Check that we don't invalidate any outstanding loans
         if let Some(loan_path) = opt_loan_path(&assignee_cmt) {
-            let scope = self.tcx().node_extent(assignment_id);
+            let scope = region::CodeExtent::Misc(assignment_id);
             self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
                 self.report_illegal_mutation(assignment_span, &loan_path, loan);
                 false
diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
index 12854d3c979..5fc5682a60b 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
@@ -24,7 +24,7 @@ use syntax_pos::Span;
 type R = Result<(),()>;
 
 pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
-                                    item_scope: region::CodeExtent<'tcx>,
+                                    item_scope: region::CodeExtent,
                                     span: Span,
                                     cause: euv::LoanCause,
                                     cmt: mc::cmt<'tcx>,
@@ -52,7 +52,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
 
     // the scope of the function body for the enclosing item
-    item_scope: region::CodeExtent<'tcx>,
+    item_scope: region::CodeExtent,
 
     span: Span,
     cause: euv::LoanCause,
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 8c1bcdc1fe2..4cfee36359c 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -45,7 +45,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         bccx: bccx,
         infcx: &infcx,
         all_loans: Vec::new(),
-        item_ub: bccx.tcx.node_extent(body.node_id),
+        item_ub: region::CodeExtent::Misc(body.node_id),
         move_data: MoveData::new(),
         move_error_collector: move_error::MoveErrorCollector::new(),
     };
@@ -66,7 +66,7 @@ struct GatherLoanCtxt<'a, 'tcx: 'a> {
     all_loans: Vec<Loan<'tcx>>,
     /// `item_ub` is used as an upper-bound on the lifetime whenever we
     /// ask for the scope of an expression categorized as an upvar.
-    item_ub: region::CodeExtent<'tcx>,
+    item_ub: region::CodeExtent,
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
@@ -353,13 +353,18 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                 let loan_scope = match *loan_region {
                     ty::ReScope(scope) => scope,
 
-                    ty::ReFree(ref fr) => fr.scope.unwrap_or(self.item_ub),
+                    ty::ReEarlyBound(ref br) => {
+                        self.bccx.region_maps.early_free_extent(self.tcx(), br)
+                    }
+
+                    ty::ReFree(ref fr) => {
+                        self.bccx.region_maps.free_extent(self.tcx(), fr)
+                    }
 
                     ty::ReStatic => self.item_ub,
 
                     ty::ReEmpty |
                     ty::ReLateBound(..) |
-                    ty::ReEarlyBound(..) |
                     ty::ReVar(..) |
                     ty::ReSkolemized(..) |
                     ty::ReErased => {
@@ -371,7 +376,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                 };
                 debug!("loan_scope = {:?}", loan_scope);
 
-                let borrow_scope = self.tcx().node_extent(borrow_id);
+                let borrow_scope = region::CodeExtent::Misc(borrow_id);
                 let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope);
                 debug!("gen_scope = {:?}", gen_scope);
 
@@ -450,9 +455,9 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
     }
 
     pub fn compute_gen_scope(&self,
-                             borrow_scope: region::CodeExtent<'tcx>,
-                             loan_scope: region::CodeExtent<'tcx>)
-                             -> region::CodeExtent<'tcx> {
+                             borrow_scope: region::CodeExtent,
+                             loan_scope: region::CodeExtent)
+                             -> region::CodeExtent {
         //! Determine when to introduce the loan. Typically the loan
         //! is introduced at the point of the borrow, but in some cases,
         //! notably method arguments, the loan may be introduced only
@@ -465,8 +470,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent<'tcx>, lp: &LoanPath<'tcx>)
-                              -> region::CodeExtent<'tcx> {
+    pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent, lp: &LoanPath<'tcx>)
+                              -> region::CodeExtent {
         //! Determine when the loan restrictions go out of scope.
         //! This is either when the lifetime expires or when the
         //! local variable which roots the loan-path goes out of scope,
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 4b7d52c2517..520a90d940b 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -44,7 +44,7 @@ impl MirPass for ElaborateDrops {
             _ => return
         }
         let id = src.item_id();
-        let param_env = ty::ParameterEnvironment::for_item(tcx, id);
+        let param_env = tcx.parameter_environment(tcx.hir.local_def_id(id));
         let move_data = MoveData::gather_moves(mir, tcx, &param_env);
         let elaborate_patch = {
             let mir = &*mir;
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index 47f708bf583..fbaa60f8445 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -65,7 +65,7 @@ pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
     // steals it, but it forces the `borrowck` query.
     let mir = &tcx.mir_validated(def_id).borrow();
 
-    let param_env = ty::ParameterEnvironment::for_item(tcx, id);
+    let param_env = tcx.parameter_environment(def_id);
     let move_data = MoveData::gather_moves(mir, tcx, &param_env);
     let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
     let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 7eb73a87532..99df1431265 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -208,7 +208,7 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> {
     // Some in `borrowck_fn` and cleared later
     tables: &'a ty::TypeckTables<'tcx>,
 
-    region_maps: Rc<RegionMaps<'tcx>>,
+    region_maps: Rc<RegionMaps>,
 
     owner_def_id: DefId,
 }
@@ -228,13 +228,13 @@ pub struct Loan<'tcx> {
     /// cases, notably method arguments, the loan may be introduced
     /// only later, once it comes into scope.  See also
     /// `GatherLoanCtxt::compute_gen_scope`.
-    gen_scope: region::CodeExtent<'tcx>,
+    gen_scope: region::CodeExtent,
 
     /// kill_scope indicates when the loan goes out of scope.  This is
     /// either when the lifetime expires or when the local variable
     /// which roots the loan-path goes out of scope, whichever happens
     /// faster. See also `GatherLoanCtxt::compute_kill_scope`.
-    kill_scope: region::CodeExtent<'tcx>,
+    kill_scope: region::CodeExtent,
     span: Span,
     cause: euv::LoanCause,
 }
@@ -334,12 +334,12 @@ pub fn closure_to_block(closure_id: ast::NodeId,
 }
 
 impl<'a, 'tcx> LoanPath<'tcx> {
-    pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::CodeExtent<'tcx> {
+    pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::CodeExtent {
         match self.kind {
             LpVar(local_id) => bccx.region_maps.var_scope(local_id),
             LpUpvar(upvar_id) => {
                 let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx);
-                bccx.tcx.node_extent(block_id)
+                region::CodeExtent::Misc(block_id)
             }
             LpDowncast(ref base, _) |
             LpExtend(ref base, ..) => base.kill_scope(bccx),
@@ -513,6 +513,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         match (&err.code, &err.cause) {
             (&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _),
              &BorrowViolation(euv::ClosureCapture(span))) |
+            (&err_out_of_scope(&ty::ReScope(_), &ty::ReEarlyBound(..), _),
+             &BorrowViolation(euv::ClosureCapture(span))) |
             (&err_out_of_scope(&ty::ReScope(_), &ty::ReFree(..), _),
              &BorrowViolation(euv::ClosureCapture(span))) => {
                 return self.report_out_of_scope_escaping_closure_capture(&err, span);
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index cd31290eb55..a18f91a9ee3 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -46,14 +46,13 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
                 b: hir::BodyId, s: Span, id: ast::NodeId) {
         intravisit::walk_fn(self, fk, fd, b, s, id);
 
-        let region_context = self.tcx.hir.local_def_id(id);
-        let region_maps = self.tcx.region_maps(region_context);
+        let def_id = self.tcx.hir.local_def_id(id);
 
         MatchVisitor {
             tcx: self.tcx,
             tables: self.tcx.body_tables(b),
-            region_maps: &region_maps,
-            param_env: &ty::ParameterEnvironment::for_item(self.tcx, id)
+            region_maps: &self.tcx.region_maps(def_id),
+            param_env: &self.tcx.parameter_environment(def_id)
         }.visit_body(self.tcx.hir.body(b));
     }
 }
@@ -71,7 +70,7 @@ struct MatchVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tables: &'a ty::TypeckTables<'tcx>,
     param_env: &'a ty::ParameterEnvironment<'tcx>,
-    region_maps: &'a RegionMaps<'tcx>,
+    region_maps: &'a RegionMaps,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 3b4f2560fc5..e2cbc480715 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -17,7 +17,6 @@ use rustc_resolve::MakeGlobMap;
 use rustc::middle::lang_items;
 use rustc::middle::free_region::FreeRegionMap;
 use rustc::middle::region::{CodeExtent, RegionMaps};
-use rustc::middle::region::CodeExtentData;
 use rustc::middle::resolve_lifetime;
 use rustc::middle::stability;
 use rustc::ty::subst::{Kind, Subst};
@@ -45,7 +44,7 @@ use rustc::hir;
 
 struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>,
-    region_maps: &'a mut RegionMaps<'tcx>,
+    region_maps: &'a mut RegionMaps,
 }
 
 struct RH<'a> {
@@ -168,8 +167,8 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn create_region_hierarchy(&mut self, rh: &RH, parent: CodeExtent<'tcx>) {
-        let me = self.tcx().intern_code_extent(CodeExtentData::Misc(rh.id));
+    pub fn create_region_hierarchy(&mut self, rh: &RH, parent: CodeExtent) {
+        let me = CodeExtent::Misc(rh.id);
         self.region_maps.record_code_extent(me, Some(parent));
         for child_rh in rh.sub {
             self.create_region_hierarchy(child_rh, me);
@@ -181,7 +180,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
         // children of 1, etc
 
         let node = ast::NodeId::from_u32;
-        let dscope = self.tcx().intern_code_extent(CodeExtentData::DestructionScope(node(1)));
+        let dscope = CodeExtent::DestructionScope(node(1));
         self.region_maps.record_code_extent(dscope, None);
         self.create_region_hierarchy(&RH {
                                          id: node(1),
@@ -296,8 +295,9 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> {
         let name = Symbol::intern(name);
         self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
-            index: index,
-            name: name,
+            def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
+            index,
+            name,
         }))
     }
 
@@ -326,19 +326,19 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     }
 
     pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
-        let r = ty::ReScope(self.tcx().node_extent(ast::NodeId::from_u32(id)));
+        let r = ty::ReScope(CodeExtent::Misc(ast::NodeId::from_u32(id)));
         self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
     }
 
-    pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region<'tcx> {
+    pub fn re_free(&self, id: u32) -> ty::Region<'tcx> {
         self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion {
-            scope: Some(self.tcx().node_extent(nid)),
+            scope: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
             bound_region: ty::BrAnon(id),
         }))
     }
 
-    pub fn t_rptr_free(&self, nid: u32, id: u32) -> Ty<'tcx> {
-        let r = self.re_free(ast::NodeId::from_u32(nid), id);
+    pub fn t_rptr_free(&self, id: u32) -> Ty<'tcx> {
+        let r = self.re_free(id);
         self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
     }
 
@@ -464,7 +464,7 @@ fn sub_free_bound_false() {
 
     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
-        let t_rptr_free1 = env.t_rptr_free(1, 1);
+        let t_rptr_free1 = env.t_rptr_free(1);
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
         env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
                           env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
@@ -482,7 +482,7 @@ fn sub_bound_free_true() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(1, 1);
+        let t_rptr_free1 = env.t_rptr_free(1);
         env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
     })
@@ -518,7 +518,7 @@ fn lub_free_bound_infer() {
         env.create_simple_region_hierarchy();
         let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(1, 1);
+        let t_rptr_free1 = env.t_rptr_free(1);
         env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
@@ -541,7 +541,7 @@ fn lub_bound_free() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(1, 1);
+        let t_rptr_free1 = env.t_rptr_free(1);
         env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
@@ -574,8 +574,8 @@ fn lub_bound_bound_inverse_order() {
 fn lub_free_free() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
-        let t_rptr_free1 = env.t_rptr_free(1, 1);
-        let t_rptr_free2 = env.t_rptr_free(1, 2);
+        let t_rptr_free1 = env.t_rptr_free(1);
+        let t_rptr_free2 = env.t_rptr_free(2);
         let t_rptr_static = env.t_rptr_static();
         env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
@@ -600,8 +600,8 @@ fn lub_returning_scope() {
 fn glb_free_free_with_common_scope() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
-        let t_rptr_free1 = env.t_rptr_free(1, 1);
-        let t_rptr_free2 = env.t_rptr_free(1, 2);
+        let t_rptr_free1 = env.t_rptr_free(1);
+        let t_rptr_free2 = env.t_rptr_free(2);
         let t_rptr_scope = env.t_rptr_scope(1);
         env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
@@ -625,7 +625,7 @@ fn glb_bound_free() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(1, 1);
+        let t_rptr_free1 = env.t_rptr_free(1);
         env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
@@ -751,7 +751,7 @@ fn escaping() {
 
         assert!(!env.t_nil().has_escaping_regions());
 
-        let t_rptr_free1 = env.t_rptr_free(1, 1);
+        let t_rptr_free1 = env.t_rptr_free(1);
         assert!(!t_rptr_free1.has_escaping_regions());
 
         let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 3b6516af35a..6423d65a4c2 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -990,12 +990,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
                         traits::Obligation::new(traits::ObligationCause::misc(span, expr_id),
                                                 trait_ref.to_poly_trait_predicate());
 
-                    // unwrap() is ok here b/c `method` is the method
-                    // defined in this crate whose body we are
-                    // checking, so it's always local
-                    let node_id = tcx.hir.as_local_node_id(method.def_id).unwrap();
-
-                    let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
+                    let param_env = tcx.parameter_environment(method.def_id);
                     tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
                         let mut selcx = traits::SelectionContext::new(&infcx);
                         match selcx.select(&obligation) {
@@ -1263,7 +1258,7 @@ impl LintPass for UnionsWithDropFields {
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields {
     fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) {
         if let hir::ItemUnion(ref vdata, _) = item.node {
-            let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id);
+            let param_env = &ctx.tcx.parameter_environment(ctx.tcx.hir.local_def_id(item.id));
             for field in vdata.fields() {
                 let field_ty = ctx.tcx.type_of(ctx.tcx.hir.local_def_id(field.id));
                 if field_ty.needs_drop(ctx.tcx, param_env) {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index ea845f722c3..819095e2628 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -21,7 +21,6 @@ use rustc::middle::cstore::LinkagePreference;
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc::middle::lang_items;
-use rustc::middle::region;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
@@ -360,12 +359,6 @@ impl<'a, 'tcx> SpecializedDecoder<ty::Region<'tcx>> for DecodeContext<'a, 'tcx>
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<region::CodeExtent<'tcx>> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<region::CodeExtent<'tcx>, Self::Error> {
-        Ok(self.tcx().intern_code_extent(Decodable::decode(self)?))
-    }
-}
-
 impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<Ty<'tcx>>> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<Ty<'tcx>>, Self::Error> {
         Ok(self.tcx().mk_type_list((0..self.read_usize()?).map(|_| Decodable::decode(self)))?)
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index f7534737edc..a3680214432 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -39,7 +39,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// The operand is known to be live until the end of `scope`.
     pub fn as_operand<M>(&mut self,
                          block: BasicBlock,
-                         scope: Option<CodeExtent<'tcx>>,
+                         scope: Option<CodeExtent>,
                          expr: M) -> BlockAnd<Operand<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
@@ -49,7 +49,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     fn expr_as_operand(&mut self,
                        mut block: BasicBlock,
-                       scope: Option<CodeExtent<'tcx>>,
+                       scope: Option<CodeExtent>,
                        expr: Expr<'tcx>)
                        -> BlockAnd<Operand<'tcx>> {
         debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 46e2408c38d..7b29cd970d7 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -38,7 +38,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     }
 
     /// Compile `expr`, yielding an rvalue.
-    pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent<'tcx>>, expr: M)
+    pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent>, expr: M)
                         -> BlockAnd<Rvalue<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
@@ -48,7 +48,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     fn expr_as_rvalue(&mut self,
                       mut block: BasicBlock,
-                      scope: Option<CodeExtent<'tcx>>,
+                      scope: Option<CodeExtent>,
                       expr: Expr<'tcx>)
                       -> BlockAnd<Rvalue<'tcx>> {
         debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index db4561af734..a334923546f 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -21,7 +21,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// up rvalues so as to freeze the value that will be consumed.
     pub fn as_temp<M>(&mut self,
                       block: BasicBlock,
-                      temp_lifetime: Option<CodeExtent<'tcx>>,
+                      temp_lifetime: Option<CodeExtent>,
                       expr: M)
                       -> BlockAnd<Lvalue<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
@@ -32,7 +32,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     fn expr_as_temp(&mut self,
                     mut block: BasicBlock,
-                    temp_lifetime: Option<CodeExtent<'tcx>>,
+                    temp_lifetime: Option<CodeExtent>,
                     expr: Expr<'tcx>)
                     -> BlockAnd<Lvalue<'tcx>> {
         debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 8c057b02df2..fb173e2487b 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -14,7 +14,7 @@ use hair::cx::Cx;
 use hair::Pattern;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::middle::region::{CodeExtent, CodeExtentData};
+use rustc::middle::region::CodeExtent;
 use rustc::mir::*;
 use rustc::mir::transform::MirSource;
 use rustc::mir::visit::MutVisitor;
@@ -172,7 +172,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let span = tcx.hir.span(ctor_id);
     if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
-        let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id);
+        let pe = tcx.parameter_environment(tcx.hir.local_def_id(ctor_id));
         tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
             let (mut mir, src) =
                 shim::build_adt_ctor(&infcx, ctor_id, fields, span);
@@ -206,13 +206,14 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              -> Ty<'tcx> {
     let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
 
+    let closure_def_id = tcx.hir.local_def_id(closure_expr_id);
     let region = ty::ReFree(ty::FreeRegion {
-        scope: Some(tcx.item_extent(body_id.node_id)),
+        scope: closure_def_id,
         bound_region: ty::BoundRegion::BrEnv,
     });
     let region = tcx.mk_region(region);
 
-    match tcx.closure_kind(tcx.hir.local_def_id(closure_expr_id)) {
+    match tcx.closure_kind(closure_def_id) {
         ty::ClosureKind::Fn =>
             tcx.mk_ref(region,
                        ty::TypeAndMut { ty: closure_ty,
@@ -337,12 +338,8 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let span = tcx.hir.span(fn_id);
     let mut builder = Builder::new(hir.clone(), span, arguments.len(), return_ty);
 
-    let call_site_extent =
-        tcx.intern_code_extent(
-            CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body.value.id });
-    let arg_extent =
-        tcx.intern_code_extent(
-            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.value.id });
+    let call_site_extent = CodeExtent::CallSiteScope(body.id());
+    let arg_extent = CodeExtent::ParameterScope(body.id());
     let mut block = START_BLOCK;
     unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
         unpack!(block = builder.in_scope(arg_extent, block, |builder| {
@@ -405,22 +402,15 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
     let span = tcx.hir.span(owner_id);
     let mut builder = Builder::new(hir.clone(), span, 0, ty);
 
-    let extent = hir.region_maps.temporary_scope(tcx, ast_expr.id)
-                                .unwrap_or(tcx.item_extent(owner_id));
     let mut block = START_BLOCK;
-    let _ = builder.in_scope(extent, block, |builder| {
-        let expr = builder.hir.mirror(ast_expr);
-        unpack!(block = builder.into(&Lvalue::Local(RETURN_POINTER), block, expr));
+    let expr = builder.hir.mirror(ast_expr);
+    unpack!(block = builder.into_expr(&Lvalue::Local(RETURN_POINTER), block, expr));
 
-        let source_info = builder.source_info(span);
-        let return_block = builder.return_block();
-        builder.cfg.terminate(block, source_info,
-                              TerminatorKind::Goto { target: return_block });
-        builder.cfg.terminate(return_block, source_info,
-                              TerminatorKind::Return);
+    let source_info = builder.source_info(span);
+    builder.cfg.terminate(block, source_info, TerminatorKind::Return);
 
-        return_block.unit()
-    });
+    // Constants can't `return` so a return block should not be created.
+    assert_eq!(builder.cached_return_block, None);
 
     builder.finish(vec![], ty)
 }
@@ -490,7 +480,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn args_and_body(&mut self,
                      mut block: BasicBlock,
                      arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
-                     argument_extent: CodeExtent<'tcx>,
+                     argument_extent: CodeExtent,
                      ast_body: &'gcx hir::Expr)
                      -> BlockAnd<()>
     {
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 6043a696183..ae47f4c4244 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -87,7 +87,7 @@ should go to.
 */
 
 use build::{BlockAnd, BlockAndExtension, Builder, CFG};
-use rustc::middle::region::{CodeExtent, CodeExtentData};
+use rustc::middle::region::CodeExtent;
 use rustc::middle::lang_items;
 use rustc::middle::const_val::ConstVal;
 use rustc::ty::subst::{Kind, Subst};
@@ -102,7 +102,7 @@ pub struct Scope<'tcx> {
     visibility_scope: VisibilityScope,
 
     /// the extent of this scope within source code.
-    extent: CodeExtent<'tcx>,
+    extent: CodeExtent,
 
     /// Whether there's anything to do for the cleanup path, that is,
     /// when unwinding through this scope. This includes destructors,
@@ -137,7 +137,7 @@ pub struct Scope<'tcx> {
     free: Option<FreeData<'tcx>>,
 
     /// The cache for drop chain on “normal” exit into a particular BasicBlock.
-    cached_exits: FxHashMap<(BasicBlock, CodeExtent<'tcx>), BasicBlock>,
+    cached_exits: FxHashMap<(BasicBlock, CodeExtent), BasicBlock>,
 }
 
 struct DropData<'tcx> {
@@ -180,7 +180,7 @@ struct FreeData<'tcx> {
 #[derive(Clone, Debug)]
 pub struct BreakableScope<'tcx> {
     /// Extent of the loop
-    pub extent: CodeExtent<'tcx>,
+    pub extent: CodeExtent,
     /// Where the body of the loop begins. `None` if block
     pub continue_block: Option<BasicBlock>,
     /// Block to branch into when the loop or block terminates (either by being `break`-en out
@@ -271,7 +271,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Convenience wrapper that pushes a scope and then executes `f`
     /// to build its contents, popping the scope afterwards.
     pub fn in_scope<F, R>(&mut self,
-                          extent: CodeExtent<'tcx>,
+                          extent: CodeExtent,
                           mut block: BasicBlock,
                           f: F)
                           -> BlockAnd<R>
@@ -289,7 +289,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// scope and call `pop_scope` afterwards. Note that these two
     /// calls must be paired; using `in_scope` as a convenience
     /// wrapper maybe preferable.
-    pub fn push_scope(&mut self, extent: CodeExtent<'tcx>) {
+    pub fn push_scope(&mut self, extent: CodeExtent) {
         debug!("push_scope({:?})", extent);
         let vis_scope = self.visibility_scope;
         self.scopes.push(Scope {
@@ -306,7 +306,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// drops onto the end of `block` that are needed.  This must
     /// match 1-to-1 with `push_scope`.
     pub fn pop_scope(&mut self,
-                     extent: CodeExtent<'tcx>,
+                     extent: CodeExtent,
                      mut block: BasicBlock)
                      -> BlockAnd<()> {
         debug!("pop_scope({:?}, {:?})", extent, block);
@@ -330,7 +330,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// module comment for details.
     pub fn exit_scope(&mut self,
                       span: Span,
-                      extent: CodeExtent<'tcx>,
+                      extent: CodeExtent,
                       mut block: BasicBlock,
                       target: BasicBlock) {
         debug!("exit_scope(extent={:?}, block={:?}, target={:?})", extent, block, target);
@@ -391,7 +391,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// resolving `break` and `continue`.
     pub fn find_breakable_scope(&mut self,
                            span: Span,
-                           label: CodeExtent<'tcx>)
+                           label: CodeExtent)
                            -> &mut BreakableScope<'tcx> {
         // find the loop-scope with the correct id
         self.breakable_scopes.iter_mut()
@@ -411,12 +411,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     /// Returns the extent of the scope which should be exited by a
     /// return.
-    pub fn extent_of_return_scope(&self) -> CodeExtent<'tcx> {
+    pub fn extent_of_return_scope(&self) -> CodeExtent {
         // The outermost scope (`scopes[0]`) will be the `CallSiteScope`.
         // We want `scopes[1]`, which is the `ParameterScope`.
         assert!(self.scopes.len() >= 2);
-        assert!(match *self.scopes[1].extent {
-            CodeExtentData::ParameterScope { .. } => true,
+        assert!(match self.scopes[1].extent {
+            CodeExtent::ParameterScope(_) => true,
             _ => false,
         });
         self.scopes[1].extent
@@ -424,7 +424,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     /// Returns the topmost active scope, which is known to be alive until
     /// the next scope expression.
-    pub fn topmost_scope(&self) -> CodeExtent<'tcx> {
+    pub fn topmost_scope(&self) -> CodeExtent {
         self.scopes.last().expect("topmost_scope: no scopes present").extent
     }
 
@@ -434,7 +434,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// `extent`.
     pub fn schedule_drop(&mut self,
                          span: Span,
-                         extent: CodeExtent<'tcx>,
+                         extent: CodeExtent,
                          lvalue: &Lvalue<'tcx>,
                          lvalue_ty: Ty<'tcx>) {
         let needs_drop = self.hir.needs_drop(lvalue_ty);
@@ -524,7 +524,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// There may only be one “free” scheduled in any given scope.
     pub fn schedule_box_free(&mut self,
                              span: Span,
-                             extent: CodeExtent<'tcx>,
+                             extent: CodeExtent,
                              value: &Lvalue<'tcx>,
                              item_ty: Ty<'tcx>) {
         for scope in self.scopes.iter_mut().rev() {
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 2ec4a8a07df..920da306116 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -11,7 +11,7 @@
 use hair::*;
 use hair::cx::Cx;
 use hair::cx::to_ref::ToRef;
-use rustc::middle::region::{BlockRemainder, CodeExtentData};
+use rustc::middle::region::{BlockRemainder, CodeExtent};
 use rustc::hir;
 use syntax::ast;
 
@@ -24,7 +24,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
         let stmts = mirror_stmts(cx, self.id, &*self.stmts);
         Block {
             targeted_by_break: self.targeted_by_break,
-            extent: cx.tcx.node_extent(self.id),
+            extent: CodeExtent::Misc(self.id),
             span: self.span,
             stmts: stmts,
             expr: self.expr.to_ref(),
@@ -44,7 +44,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 result.push(StmtRef::Mirror(Box::new(Stmt {
                     span: stmt.span,
                     kind: StmtKind::Expr {
-                        scope: cx.tcx.node_extent(id),
+                        scope: CodeExtent::Misc(id),
                         expr: expr.to_ref(),
                     },
                 })))
@@ -55,19 +55,17 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         // ignore for purposes of the MIR
                     }
                     hir::DeclLocal(ref local) => {
-                        let remainder_extent = CodeExtentData::Remainder(BlockRemainder {
+                        let remainder_extent = CodeExtent::Remainder(BlockRemainder {
                             block: block_id,
                             first_statement_index: index as u32,
                         });
-                        let remainder_extent =
-                            cx.tcx.intern_code_extent(remainder_extent);
 
                         let pattern = Pattern::from_hir(cx.tcx, cx.tables(), &local.pat);
                         result.push(StmtRef::Mirror(Box::new(Stmt {
                             span: stmt.span,
                             kind: StmtKind::Let {
                                 remainder_scope: remainder_extent,
-                                init_scope: cx.tcx.node_extent(id),
+                                init_scope: CodeExtent::Misc(id),
                                 pattern: pattern,
                                 initializer: local.init.to_ref(),
                             },
@@ -84,7 +82,7 @@ pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                    block: &'tcx hir::Block)
                                    -> ExprRef<'tcx> {
     let block_ty = cx.tables().node_id_to_type(block.id);
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, block.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(block.id);
     let expr = Expr {
         ty: block_ty,
         temp_lifetime: temp_lifetime,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 6a1817aba09..b180d982e86 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -14,7 +14,6 @@ use rustc_const_math::ConstInt;
 use hair::cx::Cx;
 use hair::cx::block;
 use hair::cx::to_ref::ToRef;
-use rustc::hir::map;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
@@ -26,8 +25,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     type Output = Expr<'tcx>;
 
     fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
-        let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, self.id);
-        let expr_extent = cx.tcx.node_extent(self.id);
+        let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(self.id);
+        let expr_extent = CodeExtent::Misc(self.id);
 
         debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
 
@@ -238,7 +237,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                           expr: &'tcx hir::Expr)
                                           -> Expr<'tcx> {
     let expr_ty = cx.tables().expr_ty(expr);
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
 
     let kind = match expr.node {
         // Here comes the interesting stuff:
@@ -610,7 +609,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             match dest.target_id {
                 hir::ScopeTarget::Block(target_id) |
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break {
-                    label: cx.tcx.node_extent(target_id),
+                    label: CodeExtent::Misc(target_id),
                     value: value.to_ref(),
                 },
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
@@ -621,7 +620,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             match dest.target_id {
                 hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"),
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue {
-                    label: cx.tcx.node_extent(loop_id),
+                    label: CodeExtent::Misc(loop_id),
                 },
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
                     bug!("invalid loop id for continue: {}", err)
@@ -686,7 +685,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprBox(ref value) => {
             ExprKind::Box {
                 value: value.to_ref(),
-                value_extents: cx.tcx.node_extent(value.id),
+                value_extents: CodeExtent::Misc(value.id),
             }
         }
         hir::ExprArray(ref fields) => ExprKind::Array { fields: fields.to_ref() },
@@ -707,7 +706,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                  method_call: ty::MethodCall)
                                  -> Expr<'tcx> {
     let callee = cx.tables().method_map[&method_call];
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
     Expr {
         temp_lifetime: temp_lifetime,
         temp_lifetime_was_shrunk: was_shrunk,
@@ -791,7 +790,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                expr: &'tcx hir::Expr,
                                def: Def)
                                -> ExprKind<'tcx> {
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
 
     match def {
         Def::Local(def_id) => {
@@ -807,33 +806,20 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                    closure_expr_id);
             let var_ty = cx.tables().node_id_to_type(id_var);
 
-            let body_id = match cx.tcx.hir.find(closure_expr_id) {
-                Some(map::NodeExpr(expr)) => {
-                    match expr.node {
-                        hir::ExprClosure(.., body, _) => body.node_id,
-                        _ => {
-                            span_bug!(expr.span, "closure expr is not a closure expr");
-                        }
-                    }
-                }
-                _ => {
-                    span_bug!(expr.span, "ast-map has garbage for closure expr");
-                }
-            };
-
             // FIXME free regions in closures are not right
             let closure_ty = cx.tables().node_id_to_type(closure_expr_id);
 
             // FIXME we're just hard-coding the idea that the
             // signature will be &self or &mut self and hence will
             // have a bound region with number 0
+            let closure_def_id = cx.tcx.hir.local_def_id(closure_expr_id);
             let region = ty::ReFree(ty::FreeRegion {
-                scope: Some(cx.tcx.node_extent(body_id)),
+                scope: closure_def_id,
                 bound_region: ty::BoundRegion::BrAnon(0),
             });
             let region = cx.tcx.mk_region(region);
 
-            let self_expr = match cx.tcx.closure_kind(cx.tcx.hir.local_def_id(closure_expr_id)) {
+            let self_expr = match cx.tcx.closure_kind(closure_def_id) {
                 ty::ClosureKind::Fn => {
                     let ref_closure_ty = cx.tcx.mk_ref(region,
                                                        ty::TypeAndMut {
@@ -979,7 +965,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         PassArgs::ByRef => {
             let region = cx.tcx.node_scope_region(expr.id);
             let (temp_lifetime, was_shrunk) =
-                cx.region_maps.temporary_scope2(cx.tcx, expr.id);
+                cx.region_maps.temporary_scope2(expr.id);
             argrefs.extend(args.iter()
                 .map(|arg| {
                     let arg_ty = cx.tables().expr_ty_adjusted(arg);
@@ -1031,7 +1017,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
     // construct the complete expression `foo()` for the overloaded call,
     // which will yield the &T type
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
     let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
     let ref_expr = Expr {
         temp_lifetime: temp_lifetime,
@@ -1056,7 +1042,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         closure_expr_id: closure_expr.id,
     };
     let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap();
-    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, closure_expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(closure_expr.id);
     let var_ty = cx.tables().node_id_to_type(id_var);
     let captured_var = Expr {
         temp_lifetime: temp_lifetime,
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index ee8547e5dd6..9ffce18fe15 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -35,7 +35,7 @@ use std::rc::Rc;
 pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    pub region_maps: Rc<RegionMaps<'tcx>>,
+    pub region_maps: Rc<RegionMaps>,
     constness: hir::Constness,
 
     /// True if this constant/function needs overflow checks.
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 0e8992e62ea..1af9d722599 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -32,7 +32,7 @@ pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPatt
 #[derive(Clone, Debug)]
 pub struct Block<'tcx> {
     pub targeted_by_break: bool,
-    pub extent: CodeExtent<'tcx>,
+    pub extent: CodeExtent,
     pub span: Span,
     pub stmts: Vec<StmtRef<'tcx>>,
     pub expr: Option<ExprRef<'tcx>>,
@@ -53,7 +53,7 @@ pub struct Stmt<'tcx> {
 pub enum StmtKind<'tcx> {
     Expr {
         /// scope for this statement; may be used as lifetime of temporaries
-        scope: CodeExtent<'tcx>,
+        scope: CodeExtent,
 
         /// expression being evaluated in this statement
         expr: ExprRef<'tcx>,
@@ -62,11 +62,11 @@ pub enum StmtKind<'tcx> {
     Let {
         /// scope for variables bound in this let; covers this and
         /// remaining statements in block
-        remainder_scope: CodeExtent<'tcx>,
+        remainder_scope: CodeExtent,
 
         /// scope for the initialization itself; might be used as
         /// lifetime of temporaries
-        init_scope: CodeExtent<'tcx>,
+        init_scope: CodeExtent,
 
         /// let <PAT> = ...
         pattern: Pattern<'tcx>,
@@ -97,7 +97,7 @@ pub struct Expr<'tcx> {
 
     /// lifetime of this expression if it should be spilled into a
     /// temporary; should be None only if in a constant context
-    pub temp_lifetime: Option<CodeExtent<'tcx>>,
+    pub temp_lifetime: Option<CodeExtent>,
 
     /// whether this temp lifetime was shrunk by #36082.
     pub temp_lifetime_was_shrunk: bool,
@@ -112,12 +112,12 @@ pub struct Expr<'tcx> {
 #[derive(Clone, Debug)]
 pub enum ExprKind<'tcx> {
     Scope {
-        extent: CodeExtent<'tcx>,
+        extent: CodeExtent,
         value: ExprRef<'tcx>,
     },
     Box {
         value: ExprRef<'tcx>,
-        value_extents: CodeExtent<'tcx>,
+        value_extents: CodeExtent,
     },
     Call {
         ty: ty::Ty<'tcx>,
@@ -210,11 +210,11 @@ pub enum ExprKind<'tcx> {
         arg: ExprRef<'tcx>,
     },
     Break {
-        label: CodeExtent<'tcx>,
+        label: CodeExtent,
         value: Option<ExprRef<'tcx>>,
     },
     Continue {
-        label: CodeExtent<'tcx>,
+        label: CodeExtent,
     },
     Return {
         value: Option<ExprRef<'tcx>>,
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index a6f9952b23c..6f4480bf6dd 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -15,7 +15,7 @@ use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
 use rustc::mir::transform::MirSource;
 use rustc::ty::{self, Ty};
-use rustc::ty::subst::{Kind, Subst};
+use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::ty::maps::Providers;
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -41,8 +41,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 {
     debug!("make_shim({:?})", instance);
     let did = instance.def_id();
-    let span = tcx.def_span(did);
-    let param_env = tcx.construct_parameter_environment(span, did, None);
+    let param_env = tcx.parameter_environment(did);
 
     let mut result = match instance {
         ty::InstanceDef::Item(..) =>
@@ -66,7 +65,6 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 
             build_call_shim(
                 tcx,
-                &param_env,
                 def_id,
                 adjustment,
                 CallKind::Indirect,
@@ -78,7 +76,6 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
             // trans::mir knows to turn to an actual virtual call.
             build_call_shim(
                 tcx,
-                &param_env,
                 def_id,
                 Adjustment::Identity,
                 CallKind::Direct(def_id),
@@ -94,7 +91,6 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 
             build_call_shim(
                 tcx,
-                &param_env,
                 call_once,
                 Adjustment::RefMut,
                 CallKind::Direct(call_mut),
@@ -158,7 +154,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
     let substs = if let Some(ty) = ty {
         tcx.mk_substs(iter::once(Kind::from(ty)))
     } else {
-        param_env.free_substs
+        Substs::identity_for_item(tcx, def_id)
     };
     let fn_ty = tcx.type_of(def_id).subst(tcx, substs);
     let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
@@ -272,7 +268,6 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
 /// If `untuple_args` is a vec of types, the second argument of the
 /// function will be untupled as these types.
 fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
-                             param_env: &ty::ParameterEnvironment<'tcx>,
                              def_id: DefId,
                              rcvr_adjustment: Adjustment,
                              call_kind: CallKind,
@@ -283,7 +278,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
             call_kind={:?}, untuple_args={:?})",
            def_id, rcvr_adjustment, call_kind, untuple_args);
 
-    let fn_ty = tcx.type_of(def_id).subst(tcx, param_env.free_substs);
+    let fn_ty = tcx.type_of(def_id);
     let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
     let span = tcx.def_span(def_id);
 
@@ -325,9 +320,10 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
         CallKind::Direct(def_id) => (
             Operand::Constant(box Constant {
                 span: span,
-                ty: tcx.type_of(def_id).subst(tcx, param_env.free_substs),
+                ty: tcx.type_of(def_id),
                 literal: Literal::Value {
-                    value: ConstVal::Function(def_id, param_env.free_substs),
+                    value: ConstVal::Function(def_id,
+                        Substs::identity_for_item(tcx, def_id)),
                 },
             }),
             vec![rcvr]
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index f60dcbed6ba..e6d62dc6460 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -219,7 +219,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
 
         // FIXME: Give a bonus to functions with only a single caller
 
-        let param_env = ty::ParameterEnvironment::for_item(tcx, self.source.item_id());
+        let def_id = tcx.hir.local_def_id(self.source.item_id());
+        let param_env = tcx.parameter_environment(def_id);
 
         let mut first_block = true;
         let mut cost = 0;
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index df837a32133..72edf68f403 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -937,8 +937,7 @@ fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         return Qualif::NOT_CONST.bits();
     }
 
-    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
-    let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
+    let param_env = tcx.parameter_environment(def_id);
 
     let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, Mode::Const);
     qualifier.qualify_const().bits()
@@ -966,7 +965,7 @@ impl MirPass for QualifyAndPromoteConstants {
             MirSource::Const(_) |
             MirSource::Promoted(..) => return
         };
-        let param_env = ty::ParameterEnvironment::for_item(tcx, id);
+        let param_env = tcx.parameter_environment(def_id);
 
         if mode == Mode::Fn || mode == Mode::ConstFn {
             // This is ugly because Qualifier holds onto mir,
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index be384218a41..82c0d2c1b01 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -751,7 +751,7 @@ impl MirPass for TypeckMir {
             // broken MIR, so try not to report duplicate errors.
             return;
         }
-        let param_env = ty::ParameterEnvironment::for_item(tcx, item_id);
+        let param_env = tcx.parameter_environment(def_id);
         tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
             let mut checker = TypeChecker::new(&infcx, item_id);
             {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index adcb3d682ca..9e8352fde80 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -41,12 +41,6 @@ pub trait AstConv<'gcx, 'tcx> {
     fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
                                  -> ty::GenericPredicates<'tcx>;
 
-    /// Return an (optional) substitution to convert bound type parameters that
-    /// are in scope into free ones. This function should only return Some
-    /// within a fn body.
-    /// See ParameterEnvironment::free_substs for more information.
-    fn get_free_substs(&self) -> Option<&Substs<'tcx>>;
-
     /// What lifetime should we use when a lifetime is omitted (and not elided)?
     fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
                 -> Option<ty::Region<'tcx>>;
@@ -121,6 +115,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             Some(&rl::Region::EarlyBound(index, id)) => {
                 let name = tcx.hir.name(id);
                 tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+                    def_id: tcx.hir.local_def_id(id),
                     index: index,
                     name: name
                 }))
@@ -129,7 +124,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             Some(&rl::Region::Free(scope, id)) => {
                 let name = tcx.hir.name(id);
                 tcx.mk_region(ty::ReFree(ty::FreeRegion {
-                    scope: Some(scope.to_code_extent(tcx)),
+                    scope,
                     bound_region: ty::BrNamed(tcx.hir.local_def_id(id), name)
                 }))
 
@@ -857,12 +852,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     }
                 };
 
-                let trait_ref = if let Some(free_substs) = self.get_free_substs() {
-                    trait_ref.subst(tcx, free_substs)
-                } else {
-                    trait_ref
-                };
-
                 let candidates =
                     traits::supertraits(tcx, ty::Binder(trait_ref))
                     .filter(|r| self.trait_defines_associated_type_named(r.def_id(),
@@ -1020,12 +1009,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_type_params(&path.segments);
 
-                let ty = tcx.at(span).type_of(def_id);
-                if let Some(free_substs) = self.get_free_substs() {
-                    ty.subst(tcx, free_substs)
-                } else {
-                    ty
-                }
+                tcx.at(span).type_of(def_id)
             }
             Def::SelfTy(Some(_), None) => {
                 // Self in trait.
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index fb3be849319..4c3d5c8aaca 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -15,6 +15,7 @@ use super::{check_fn, Expectation, FnCtxt};
 use astconv::AstConv;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::ty::{self, ToPolyTraitRef, Ty};
+use rustc::ty::subst::Substs;
 use std::cmp;
 use std::iter;
 use syntax::abi::Abi;
@@ -60,12 +61,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                          decl,
                                          Abi::RustCall,
                                          expected_sig);
+        // `deduce_expectations_from_expected_type` introduces late-bound
+        // lifetimes defined elsewhere, which we need to anonymize away.
+        let sig = self.tcx.anonymize_late_bound_regions(&sig);
 
         // Create type variables (for now) to represent the transformed
         // types of upvars. These will be unified during the upvar
         // inference phase (`upvar.rs`).
+        let base_substs = Substs::identity_for_item(self.tcx,
+            self.tcx.closure_base_def_id(expr_def_id));
         let closure_type = self.tcx.mk_closure(expr_def_id,
-            self.parameter_environment.free_substs.extend_to(self.tcx, expr_def_id,
+            base_substs.extend_to(self.tcx, expr_def_id,
                 |_, _| span_bug!(expr.span, "closure has region param"),
                 |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span))
             )
@@ -73,8 +79,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
 
-        let extent = self.tcx.call_site_extent(expr.id, body.value.id);
-        let fn_sig = self.tcx.liberate_late_bound_regions(Some(extent), &sig);
+        let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig);
         let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
                                                             body.value.id, &fn_sig);
 
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 0579bb15fd6..d9f77e8f04f 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -167,16 +167,15 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Create a parameter environment that represents the implementation's
     // method.
-    let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_m_node_id);
+    let impl_param_env = tcx.parameter_environment(impl_m.def_id);
 
     // Create mapping from impl to skolemized.
-    let impl_to_skol_substs = &impl_param_env.free_substs;
+    let impl_to_skol_substs = Substs::identity_for_item(tcx, impl_m.def_id);
 
     // Create mapping from trait to skolemized.
     let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
                                                                impl_m.container.id(),
-                                                               trait_to_impl_substs.subst(tcx,
-                                                                          impl_to_skol_substs));
+                                                               trait_to_impl_substs);
     debug!("compare_impl_method: trait_to_skol_substs={:?}",
            trait_to_skol_substs);
 
@@ -191,8 +190,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        impl_m,
                                        &trait_m_generics,
                                        &impl_m_generics,
-                                       trait_to_skol_substs,
-                                       impl_to_skol_substs)?;
+                                       trait_to_skol_substs)?;
 
     // Create obligations for each predicate declared by the impl
     // definition in the context of the trait's parameter
@@ -200,7 +198,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // however, because we want to replace all late-bound regions with
     // region variables.
     let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
-    let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs);
+    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
 
     debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
 
@@ -226,7 +224,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                                normalize_cause.clone());
 
     tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| {
-        let inh = Inherited::new(infcx);
+        let inh = Inherited::new(infcx, impl_m.def_id);
         let infcx = &inh.infcx;
 
         debug!("compare_impl_method: caller_bounds={:?}",
@@ -274,16 +272,14 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                             infer::HigherRankedType,
                                                             &m_sig(impl_m));
         let impl_sig =
-            impl_sig.subst(tcx, impl_to_skol_substs);
-        let impl_sig =
             inh.normalize_associated_types_in(impl_m_span,
                                               impl_m_node_id,
                                               &impl_sig);
         let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
-        let trait_sig = tcx.liberate_late_bound_regions(
-            infcx.parameter_environment.free_id_outlive,
+        let trait_sig = inh.liberate_late_bound_regions(
+            impl_m.def_id,
             &m_sig(trait_m));
         let trait_sig =
             trait_sig.subst(tcx, trait_to_skol_substs);
@@ -370,8 +366,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 impl_m: &ty::AssociatedItem,
                                                 trait_generics: &ty::Generics,
                                                 impl_generics: &ty::Generics,
-                                                trait_to_skol_substs: &Substs<'tcx>,
-                                                impl_to_skol_substs: &Substs<'tcx>)
+                                                trait_to_skol_substs: &Substs<'tcx>)
                                                 -> Result<(), ErrorReported> {
     let trait_params = &trait_generics.regions[..];
     let impl_params = &impl_generics.regions[..];
@@ -379,12 +374,10 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("check_region_bounds_on_impl_method: \
             trait_generics={:?} \
             impl_generics={:?} \
-            trait_to_skol_substs={:?} \
-            impl_to_skol_substs={:?}",
+            trait_to_skol_substs={:?}",
            trait_generics,
            impl_generics,
-           trait_to_skol_substs,
-           impl_to_skol_substs);
+           trait_to_skol_substs);
 
     // Must have same number of early-bound lifetime parameters.
     // Unfortunately, if the user screws up the bounds, then this
@@ -726,7 +719,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
     tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
-        let inh = Inherited::new(infcx);
+        let inh = Inherited::new(infcx, impl_c.def_id);
         let infcx = &inh.infcx;
 
         // The below is for the most part highly similar to the procedure
@@ -739,22 +732,10 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // Create a parameter environment that represents the implementation's
         // method.
         let impl_c_node_id = tcx.hir.as_local_node_id(impl_c.def_id).unwrap();
-        let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_c_node_id);
-
-        // Create mapping from impl to skolemized.
-        let impl_to_skol_substs = &impl_param_env.free_substs;
-
-        // Create mapping from trait to skolemized.
-        let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
-                                                                   impl_c.container.id(),
-                                                                   trait_to_impl_substs.subst(tcx,
-                                                                              impl_to_skol_substs));
-        debug!("compare_const_impl: trait_to_skol_substs={:?}",
-               trait_to_skol_substs);
 
         // Compute skolemized form of impl and trait const tys.
-        let impl_ty = tcx.type_of(impl_c.def_id).subst(tcx, impl_to_skol_substs);
-        let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_skol_substs);
+        let impl_ty = tcx.type_of(impl_c.def_id);
+        let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
         let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id);
 
         // There is no "body" here, so just pass dummy id.
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index c20777a403a..e0293325596 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -76,17 +76,15 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
     -> Result<(), ErrorReported>
 {
     let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
-    let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
 
     // check that the impl type can be made to match the trait type.
 
-    let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
+    let impl_param_env = tcx.parameter_environment(self_type_did);
     tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| {
         let tcx = infcx.tcx;
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
         let named_type = tcx.type_of(self_type_did);
-        let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs);
 
         let drop_impl_span = tcx.def_span(drop_impl_did);
         let fresh_impl_substs =
@@ -99,7 +97,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
                 fulfillment_cx.register_predicate_obligations(infcx, obligations);
             }
             Err(_) => {
-                let item_span = tcx.hir.span(self_type_node_id);
+                let item_span = tcx.def_span(self_type_did);
                 struct_span_err!(tcx.sess, drop_impl_span, E0366,
                                  "Implementations of Drop cannot be specialized")
                     .span_note(item_span,
@@ -272,7 +270,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
     rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>,
     ty: ty::Ty<'tcx>,
     span: Span,
-    scope: region::CodeExtent<'tcx>)
+    scope: region::CodeExtent)
     -> Result<(), ErrorReported>
 {
     debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 127ffc60cf4..70d2867c08c 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -88,10 +88,10 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_back::slice::ref_slice;
 use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
 use rustc::infer::type_variable::{TypeVariableOrigin};
+use rustc::middle::region::CodeExtent;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal};
-use rustc::ty::{ParamTy, ParameterEnvironment};
-use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
+use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
 use rustc::ty::{self, Ty, TyCtxt, Visibility};
 use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
@@ -177,6 +177,14 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // variables to get the concrete type, which can be used to
     // deanonymize TyAnon, after typeck is done with all functions.
     anon_types: RefCell<NodeMap<Ty<'tcx>>>,
+
+    /// Each type parameter has an implicit region bound that
+    /// indicates it must outlive at least the function body (the user
+    /// may specify stronger requirements). This field indicates the
+    /// region of the callee. If it is `None`, then the parameter
+    /// environment is for an item or something where the "callee" is
+    /// not clear.
+    implicit_region_bound: Option<ty::Region<'tcx>>,
 }
 
 impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
@@ -523,16 +531,18 @@ impl<'a, 'gcx, 'tcx> Deref for FnCtxt<'a, 'gcx, 'tcx> {
 /// Necessary because we can't write the following bound:
 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Inherited<'b, 'gcx, 'tcx>).
 pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    infcx: infer::InferCtxtBuilder<'a, 'gcx, 'tcx>
+    infcx: infer::InferCtxtBuilder<'a, 'gcx, 'tcx>,
+    def_id: DefId,
 }
 
 impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
-    pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId)
+    pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId)
                  -> InheritedBuilder<'a, 'gcx, 'tcx> {
         let tables = ty::TypeckTables::empty();
-        let param_env = ParameterEnvironment::for_item(tcx, id);
+        let param_env = tcx.parameter_environment(def_id);
         InheritedBuilder {
-            infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing)
+            infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing),
+            def_id,
         }
     }
 }
@@ -541,12 +551,20 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
     fn enter<F, R>(&'tcx mut self, f: F) -> R
         where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R
     {
-        self.infcx.enter(|infcx| f(Inherited::new(infcx)))
+        let def_id = self.def_id;
+        self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
     }
 }
 
 impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
-    fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
+    fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> Self {
+        let tcx = infcx.tcx;
+        let item_id = tcx.hir.as_local_node_id(def_id);
+        let body_id = item_id.and_then(|id| tcx.hir.maybe_body_owned_by(id));
+        let implicit_region_bound = body_id.map(|body| {
+            tcx.mk_region(ty::ReScope(CodeExtent::CallSiteScope(body)))
+        });
+
         Inherited {
             infcx: infcx,
             fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
@@ -554,6 +572,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
             deferred_call_resolutions: RefCell::new(DefIdMap()),
             deferred_cast_checks: RefCell::new(Vec::new()),
             anon_types: RefCell::new(NodeMap()),
+            implicit_region_bound,
         }
     }
 
@@ -606,6 +625,22 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
             obligations);
         InferOk { value, obligations }
     }
+
+    /// Replace any late-bound regions bound in `value` with
+    /// free variants attached to `all_outlive_scope`.
+    fn liberate_late_bound_regions<T>(&self,
+        all_outlive_scope: DefId,
+        value: &ty::Binder<T>)
+        -> T
+        where T: TypeFoldable<'tcx>
+    {
+        self.tcx.replace_late_bound_regions(value, |br| {
+            self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
+                scope: all_outlive_scope,
+                bound_region: br
+            }))
+        }).0
+    }
 }
 
 struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
@@ -772,18 +807,15 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     });
     let body = tcx.hir.body(body_id);
 
-    Inherited::build(tcx, id).enter(|inh| {
+    Inherited::build(tcx, def_id).enter(|inh| {
         let fcx = if let Some(decl) = fn_decl {
             let fn_sig = tcx.type_of(def_id).fn_sig();
 
             check_abi(tcx, span, fn_sig.abi());
 
             // Compute the fty from point of view of inside fn.
-            let fn_scope = inh.tcx.call_site_extent(id, body_id.node_id);
-            let fn_sig =
-                fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
             let fn_sig =
-                inh.tcx.liberate_late_bound_regions(Some(fn_scope), &fn_sig);
+                inh.liberate_late_bound_regions(def_id, &fn_sig);
             let fn_sig =
                 inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
 
@@ -1518,10 +1550,6 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
 
-    fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
-        Some(&self.parameter_environment.free_substs)
-    }
-
     fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
                                  -> ty::GenericPredicates<'tcx>
     {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index e4936dfc47b..754bd288bfa 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -87,7 +87,7 @@ use check::FnCtxt;
 use middle::free_region::FreeRegionMap;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::Categorization;
-use middle::region::{self, CodeExtent, RegionMaps};
+use middle::region::{CodeExtent, RegionMaps};
 use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
@@ -178,7 +178,7 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
     region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
 
-    pub region_maps: Rc<RegionMaps<'tcx>>,
+    pub region_maps: Rc<RegionMaps>,
 
     free_region_map: FreeRegionMap<'tcx>,
 
@@ -186,7 +186,7 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     body_id: ast::NodeId,
 
     // call_site scope of innermost fn
-    call_site_scope: Option<CodeExtent<'tcx>>,
+    call_site_scope: Option<CodeExtent>,
 
     // id of innermost fn or loop
     repeating_scope: ast::NodeId,
@@ -224,8 +224,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn set_call_site_scope(&mut self, call_site_scope: Option<CodeExtent<'tcx>>)
-                           -> Option<CodeExtent<'tcx>> {
+    fn set_call_site_scope(&mut self, call_site_scope: Option<CodeExtent>)
+                           -> Option<CodeExtent> {
         mem::replace(&mut self.call_site_scope, call_site_scope)
     }
 
@@ -286,8 +286,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         let body_id = body.id();
 
-        let call_site = self.tcx.intern_code_extent(
-            region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
+        let call_site = CodeExtent::CallSiteScope(body_id);
         let old_call_site_scope = self.set_call_site_scope(Some(call_site));
 
         let fn_sig = {
@@ -312,7 +311,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         let old_body_id = self.set_body_id(body_id.node_id);
         self.relate_free_regions(&fn_sig_tys[..], body_id.node_id, span);
-        self.link_fn_args(self.tcx.node_extent(body_id.node_id), &body.arguments);
+        self.link_fn_args(CodeExtent::Misc(body_id.node_id), &body.arguments);
         self.visit_body(body);
         self.visit_region_obligations(body_id.node_id);
 
@@ -398,9 +397,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             for implication in implied_bounds {
                 debug!("implication: {:?}", implication);
                 match implication {
-                    ImpliedBound::RegionSubRegion(&ty::ReFree(free_a),
+                    ImpliedBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_),
+                                                  &ty::ReVar(vid_b)) |
+                    ImpliedBound::RegionSubRegion(r_a @ &ty::ReFree(_),
                                                   &ty::ReVar(vid_b)) => {
-                        self.add_given(free_a, vid_b);
+                        self.add_given(r_a, vid_b);
                     }
                     ImpliedBound::RegionSubParam(r_a, param_b) => {
                         self.region_bound_pairs.push((r_a, GenericKind::Param(param_b)));
@@ -876,7 +877,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         // call occurs.
         //
         // FIXME(#6268) to support nested method calls, should be callee_id
-        let callee_scope = self.tcx.node_extent(call_expr.id);
+        let callee_scope = CodeExtent::Misc(call_expr.id);
         let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope));
 
         debug!("callee_region={:?}", callee_region);
@@ -1029,7 +1030,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         debug!("constrain_index(index_expr=?, indexed_ty={}",
                self.ty_to_string(indexed_ty));
 
-        let r_index_expr = ty::ReScope(self.tcx.node_extent(index_expr.id));
+        let r_index_expr = ty::ReScope(CodeExtent::Misc(index_expr.id));
         if let ty::TyRef(r_ptr, mt) = indexed_ty.sty {
             match mt.ty.sty {
                 ty::TySlice(_) | ty::TyStr => {
@@ -1109,7 +1110,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// Computes the guarantors for any ref bindings in a match and
     /// then ensures that the lifetime of the resulting pointer is
     /// linked to the lifetime of its guarantor (if any).
-    fn link_fn_args(&self, body_scope: CodeExtent<'tcx>, args: &[hir::Arg]) {
+    fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
         debug!("regionck::link_fn_args(body_scope={:?})", body_scope);
         let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
         for arg in args {
@@ -1175,7 +1176,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// must outlive `callee_scope`.
     fn link_by_ref(&self,
                    expr: &hir::Expr,
-                   callee_scope: CodeExtent<'tcx>) {
+                   callee_scope: CodeExtent) {
         debug!("link_by_ref(expr={:?}, callee_scope={:?})",
                expr, callee_scope);
         let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
@@ -1613,8 +1614,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
-        let param_env = &self.parameter_environment;
-
         debug!("param_bound(param_ty={:?})",
                param_ty);
 
@@ -1622,7 +1621,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         // Add in the default bound of fn body that applies to all in
         // scope type parameters:
-        param_bounds.extend(param_env.implicit_region_bound);
+        param_bounds.extend(self.implicit_region_bound);
 
         VerifyBound::AnyRegion(param_bounds)
     }
@@ -1667,7 +1666,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         }
 
         let mut regions = ty.regions();
-        regions.retain(|r| !r.is_bound()); // ignore late-bound regions
+        regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
         bounds.push(VerifyBound::AllRegions(regions));
 
         // remove bounds that must hold, since they are not interesting
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 93529aecac0..6895d738625 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -13,7 +13,6 @@ use check::{Inherited, FnCtxt};
 use constrained_type_params::{identify_constrained_type_params, Parameter};
 
 use hir::def_id::DefId;
-use middle::region::{CodeExtent};
 use rustc::traits::{self, ObligationCauseCode};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
@@ -117,8 +116,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                     error_192(tcx, item.span);
                 }
             }
-            hir::ItemFn(.., body_id) => {
-                self.check_item_fn(item, body_id);
+            hir::ItemFn(..) => {
+                self.check_item_fn(item);
             }
             hir::ItemStatic(..) => {
                 self.check_item_type(item);
@@ -160,9 +159,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                              sig_if_method: Option<&hir::MethodSig>) {
         let code = self.code.clone();
         self.for_id(item_id, span).with_fcx(|fcx, this| {
-            let free_substs = &fcx.parameter_environment.free_substs;
-            let free_id_outlive = fcx.parameter_environment.free_id_outlive;
-
             let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id));
 
             let (mut implied_bounds, self_ty) = match item.container {
@@ -174,25 +170,26 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
             match item.kind {
                 ty::AssociatedKind::Const => {
                     let ty = fcx.tcx.type_of(item.def_id);
-                    let ty = fcx.instantiate_type_scheme(span, free_substs, &ty);
+                    let ty = fcx.normalize_associated_types_in(span, &ty);
                     fcx.register_wf_obligation(ty, span, code.clone());
                 }
                 ty::AssociatedKind::Method => {
                     reject_shadowing_type_parameters(fcx.tcx, item.def_id);
                     let method_ty = fcx.tcx.type_of(item.def_id);
-                    let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty);
-                    let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs);
+                    let method_ty = fcx.normalize_associated_types_in(span, &method_ty);
+                    let predicates = fcx.tcx.predicates_of(item.def_id)
+                        .instantiate_identity(fcx.tcx);
+                    let predicates = fcx.normalize_associated_types_in(span, &predicates);
                     let sig = method_ty.fn_sig();
                     this.check_fn_or_method(fcx, span, sig, &predicates,
-                                            free_id_outlive, &mut implied_bounds);
+                                            item.def_id, &mut implied_bounds);
                     let sig_if_method = sig_if_method.expect("bad signature for method");
-                    this.check_method_receiver(fcx, sig_if_method, &item,
-                                               free_id_outlive, self_ty);
+                    this.check_method_receiver(fcx, sig_if_method, &item, self_ty);
                 }
                 ty::AssociatedKind::Type => {
                     if item.defaultness.has_value() {
                         let ty = fcx.tcx.type_of(item.def_id);
-                        let ty = fcx.instantiate_type_scheme(span, free_substs, &ty);
+                        let ty = fcx.normalize_associated_types_in(span, &ty);
                         fcx.register_wf_obligation(ty, span, code.clone());
                     }
                 }
@@ -210,7 +207,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
     fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
                     -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
         CheckWfFcxBuilder {
-            inherited: Inherited::build(self.tcx, id),
+            inherited: Inherited::build(self.tcx, self.tcx.hir.local_def_id(id)),
             code: self.code.clone(),
             id: id,
             span: span
@@ -242,9 +239,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                 }
             }
 
-            let free_substs = &fcx.parameter_environment.free_substs;
             let def_id = fcx.tcx.hir.local_def_id(item.id);
-            let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
+            let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
+            let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
             this.check_where_clauses(fcx, item.span, &predicates);
 
             vec![] // no implied bounds in a struct def'n
@@ -320,30 +317,26 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
         }
 
         self.for_item(item).with_fcx(|fcx, this| {
-            let free_substs = &fcx.parameter_environment.free_substs;
-            let predicates = fcx.instantiate_bounds(item.span, trait_def_id, free_substs);
+            let predicates = fcx.tcx.predicates_of(trait_def_id).instantiate_identity(fcx.tcx);
+            let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
             this.check_where_clauses(fcx, item.span, &predicates);
             vec![]
         });
     }
 
-    fn check_item_fn(&mut self,
-                     item: &hir::Item,
-                     body_id: hir::BodyId)
-    {
+    fn check_item_fn(&mut self, item: &hir::Item) {
         self.for_item(item).with_fcx(|fcx, this| {
-            let free_substs = &fcx.parameter_environment.free_substs;
             let def_id = fcx.tcx.hir.local_def_id(item.id);
             let ty = fcx.tcx.type_of(def_id);
-            let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &ty);
+            let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
             let sig = item_ty.fn_sig();
 
-            let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
+            let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
+            let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
 
             let mut implied_bounds = vec![];
-            let free_id_outlive = fcx.tcx.call_site_extent(item.id, body_id.node_id);
             this.check_fn_or_method(fcx, item.span, sig, &predicates,
-                                    Some(free_id_outlive), &mut implied_bounds);
+                                    def_id, &mut implied_bounds);
             implied_bounds
         })
     }
@@ -355,10 +348,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
 
         self.for_item(item).with_fcx(|fcx, this| {
             let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
-            let item_ty = fcx.instantiate_type_scheme(item.span,
-                                                      &fcx.parameter_environment
-                                                          .free_substs,
-                                                      &ty);
+            let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
 
             fcx.register_wf_obligation(item_ty, item.span, this.code.clone());
 
@@ -374,15 +364,14 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
         debug!("check_impl: {:?}", item);
 
         self.for_item(item).with_fcx(|fcx, this| {
-            let free_substs = &fcx.parameter_environment.free_substs;
             let item_def_id = fcx.tcx.hir.local_def_id(item.id);
 
             match *ast_trait_ref {
                 Some(ref ast_trait_ref) => {
                     let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
                     let trait_ref =
-                        fcx.instantiate_type_scheme(
-                            ast_trait_ref.path.span, free_substs, &trait_ref);
+                        fcx.normalize_associated_types_in(
+                            ast_trait_ref.path.span, &trait_ref);
                     let obligations =
                         ty::wf::trait_obligations(fcx,
                                                   fcx.body_id,
@@ -394,12 +383,13 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                 }
                 None => {
                     let self_ty = fcx.tcx.type_of(item_def_id);
-                    let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty);
+                    let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty);
                     fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone());
                 }
             }
 
-            let predicates = fcx.instantiate_bounds(item.span, item_def_id, free_substs);
+            let predicates = fcx.tcx.predicates_of(item_def_id).instantiate_identity(fcx.tcx);
+            let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
             this.check_where_clauses(fcx, item.span, &predicates);
 
             fcx.impl_implied_bounds(item_def_id, item.span)
@@ -429,12 +419,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                                       span: Span,
                                       sig: ty::PolyFnSig<'tcx>,
                                       predicates: &ty::InstantiatedPredicates<'tcx>,
-                                      free_id_outlive: Option<CodeExtent<'tcx>>,
+                                      def_id: DefId,
                                       implied_bounds: &mut Vec<Ty<'tcx>>)
     {
-        let free_substs = &fcx.parameter_environment.free_substs;
-        let sig = fcx.instantiate_type_scheme(span, free_substs, &sig);
-        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &sig);
+        let sig = fcx.normalize_associated_types_in(span, &sig);
+        let sig = fcx.liberate_late_bound_regions(def_id, &sig);
 
         for input_ty in sig.inputs() {
             fcx.register_wf_obligation(&input_ty, span, self.code.clone());
@@ -453,7 +442,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                                          fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                                          method_sig: &hir::MethodSig,
                                          method: &ty::AssociatedItem,
-                                         free_id_outlive: Option<CodeExtent<'tcx>>,
                                          self_ty: ty::Ty<'tcx>)
     {
         // check that the type of the method's receiver matches the
@@ -467,10 +455,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
 
         let span = method_sig.decl.inputs[0].span;
 
-        let free_substs = &fcx.parameter_environment.free_substs;
         let method_ty = fcx.tcx.type_of(method.def_id);
-        let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty);
-        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig());
+        let fty = fcx.normalize_associated_types_in(span, &method_ty);
+        let sig = fcx.liberate_late_bound_regions(method.def_id, &fty.fn_sig());
 
         debug!("check_method_receiver: sig={:?}", sig);
 
@@ -485,9 +472,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
             }
             ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty)
         };
-        let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty);
-        let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive,
-                                                          &ty::Binder(rcvr_ty));
+        let rcvr_ty = fcx.normalize_associated_types_in(span, &rcvr_ty);
+        let rcvr_ty = fcx.liberate_late_bound_regions(method.def_id,
+                                                      &ty::Binder(rcvr_ty));
 
         debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
 
@@ -632,10 +619,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             struct_def.fields().iter()
             .map(|field| {
                 let field_ty = self.tcx.type_of(self.tcx.hir.local_def_id(field.id));
-                let field_ty = self.instantiate_type_scheme(field.span,
-                                                            &self.parameter_environment
-                                                                 .free_substs,
-                                                            &field_ty);
+                let field_ty = self.normalize_associated_types_in(field.span,
+                                                                  &field_ty);
                 AdtField { ty: field_ty, span: field.span }
             })
             .collect();
@@ -649,19 +634,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
-        let free_substs = &self.parameter_environment.free_substs;
         match self.tcx.impl_trait_ref(impl_def_id) {
             Some(ref trait_ref) => {
                 // Trait impl: take implied bounds from all types that
                 // appear in the trait reference.
-                let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref);
+                let trait_ref = self.normalize_associated_types_in(span, trait_ref);
                 trait_ref.substs.types().collect()
             }
 
             None => {
                 // Inherent impl: take implied bounds from the self type.
                 let self_ty = self.tcx.type_of(impl_def_id);
-                let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty);
+                let self_ty = self.normalize_associated_types_in(span, &self_ty);
                 vec![self_ty]
             }
         }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 49440037af5..b43e2423757 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -19,7 +19,7 @@ use rustc::infer::{InferCtxt};
 use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{TypeFolder,TypeFoldable};
-use rustc::util::nodemap::{DefIdMap, DefIdSet};
+use rustc::util::nodemap::DefIdSet;
 use syntax::ast;
 use syntax_pos::Span;
 use std::mem;
@@ -71,55 +71,17 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
 
     tables: ty::TypeckTables<'gcx>,
 
-    // Mapping from free regions of the function to the
-    // early-bound versions of them, visible from the
-    // outside of the function. This is needed by, and
-    // only populated if there are any `impl Trait`.
-    free_to_bound_regions: DefIdMap<ty::Region<'gcx>>,
-
     body: &'gcx hir::Body,
 }
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, body: &'gcx hir::Body)
         -> WritebackCx<'cx, 'gcx, 'tcx> {
-        let mut wbcx = WritebackCx {
+        WritebackCx {
             fcx: fcx,
             tables: ty::TypeckTables::empty(),
-            free_to_bound_regions: DefIdMap(),
             body: body
-        };
-
-        // Only build the reverse mapping if `impl Trait` is used.
-        if fcx.anon_types.borrow().is_empty() {
-            return wbcx;
         }
-
-        let gcx = fcx.tcx.global_tcx();
-        let free_substs = fcx.parameter_environment.free_substs;
-        for (i, k) in free_substs.iter().enumerate() {
-            let r = if let Some(r) = k.as_region() {
-                r
-            } else {
-                continue;
-            };
-            match *r {
-                ty::ReFree(ty::FreeRegion {
-                    bound_region: ty::BoundRegion::BrNamed(def_id, name), ..
-                }) => {
-                    let bound_region = gcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
-                        index: i as u32,
-                        name: name,
-                    }));
-                    wbcx.free_to_bound_regions.insert(def_id, bound_region);
-                }
-                _ => {
-                    bug!("{:?} is not a free region for an early-bound lifetime", r);
-                }
-            }
-        }
-
-        wbcx
     }
 
     fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
@@ -285,22 +247,16 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             let inside_ty = self.resolve(&concrete_ty, &node_id);
 
             // Convert the type from the function into a type valid outside
-            // the function, by replacing free regions with early-bound ones.
+            // the function, by replacing invalid regions with 'static,
+            // after producing an error for each of them.
             let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
                 match *r {
-                    // 'static is valid everywhere.
-                    ty::ReStatic => gcx.types.re_static,
-                    ty::ReEmpty => gcx.types.re_empty,
-
-                    // Free regions that come from early-bound regions are valid.
-                    ty::ReFree(ty::FreeRegion {
-                        bound_region: ty::BoundRegion::BrNamed(def_id, ..), ..
-                    }) if self.free_to_bound_regions.contains_key(&def_id) => {
-                        self.free_to_bound_regions[&def_id]
-                    }
+                    // 'static and early-bound regions are valid.
+                    ty::ReStatic |
+                    ty::ReEarlyBound(_) |
+                    ty::ReEmpty => r,
 
                     ty::ReFree(_) |
-                    ty::ReEarlyBound(_) |
                     ty::ReLateBound(..) |
                     ty::ReScope(_) |
                     ty::ReSkolemized(..) => {
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 743bfbb44ab..d40a68e6056 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -17,10 +17,8 @@ use rustc::middle::lang_items::UnsizeTraitLangItem;
 
 use rustc::traits::{self, ObligationCause, Reveal};
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::ParameterEnvironment;
 use rustc::ty::TypeFoldable;
 use rustc::ty::adjustment::CoerceUnsizedInfo;
-use rustc::ty::subst::Subst;
 use rustc::ty::util::CopyImplementationError;
 use rustc::infer;
 
@@ -107,8 +105,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            self_type);
 
     let span = tcx.hir.span(impl_node_id);
-    let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
-    let self_type = self_type.subst(tcx, &param_env.free_substs);
+    let param_env = tcx.parameter_environment(impl_did);
     assert!(!self_type.has_escaping_regions());
 
     debug!("visit_implementation_of_copy: self_type={:?} (free)",
@@ -202,9 +199,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            target);
 
     let span = tcx.hir.span(impl_node_id);
-    let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
-    let source = source.subst(tcx, &param_env.free_substs);
-    let target = target.subst(tcx, &param_env.free_substs);
+    let param_env = tcx.parameter_environment(impl_did);
     assert!(!source.has_escaping_regions());
 
     let err_info = CoerceUnsizedInfo { custom_kind: None };
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index ec200241ee6..7c6c70024ce 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -205,10 +205,6 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         self.tcx.at(span).type_param_predicates((self.item_def_id, def_id))
     }
 
-    fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
-        None
-    }
-
     fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>)
                 -> Option<ty::Region<'tcx>> {
         None
@@ -1299,6 +1295,7 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut index = parent_count + has_own_self as u32;
     for param in early_bound_lifetimes_from_generics(tcx, ast_generics) {
         let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+            def_id: tcx.hir.local_def_id(param.lifetime.id),
             index: index,
             name: param.lifetime.name
         }));
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2dde6d9d4ee..61f941e57b2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -820,7 +820,7 @@ impl Clean<Lifetime> for ty::RegionParameterDef {
     }
 }
 
-impl<'tcx> Clean<Option<Lifetime>> for ty::RegionKind<'tcx> {
+impl Clean<Option<Lifetime>> for ty::RegionKind {
     fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
         match *self {
             ty::ReStatic => Some(Lifetime::statik()),
diff --git a/src/test/compile-fail/issue-27942.rs b/src/test/compile-fail/issue-27942.rs
index 595e4bfb0d7..22e7de3838d 100644
--- a/src/test/compile-fail/issue-27942.rs
+++ b/src/test/compile-fail/issue-27942.rs
@@ -11,17 +11,18 @@
 pub trait Resources<'a> {}
 
 pub trait Buffer<'a, R: Resources<'a>> {
+    //~^ NOTE the lifetime 'a as defined on the trait at 13:0...
+    //~| NOTE ...does not necessarily outlive the lifetime 'a as defined on the trait
+
     fn select(&self) -> BufferViewHandle<R>;
     //~^ ERROR mismatched types
     //~| lifetime mismatch
     //~| NOTE expected type `Resources<'_>`
-    //~| NOTE the lifetime 'a as defined on the method body at 14:4...
     //~| NOTE ...does not necessarily outlive the anonymous lifetime #1 defined on the method body
     //~| ERROR mismatched types
     //~| lifetime mismatch
     //~| NOTE expected type `Resources<'_>`
-    //~| NOTE the anonymous lifetime #1 defined on the method body at 14:4...
-    //~| NOTE ...does not necessarily outlive the lifetime 'a as defined on the method body
+    //~| NOTE the anonymous lifetime #1 defined on the method body at 17:4...
 }
 
 pub struct BufferViewHandle<'a, R: 'a+Resources<'a>>(&'a R);
diff --git a/src/test/compile-fail/issue-37884.rs b/src/test/compile-fail/issue-37884.rs
index 6e1b9b2fbed..6313293bf2b 100644
--- a/src/test/compile-fail/issue-37884.rs
+++ b/src/test/compile-fail/issue-37884.rs
@@ -11,14 +11,15 @@
 struct RepeatMut<'a, T>(T, &'a ());
 
 impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
+    //~^ NOTE ...does not necessarily outlive the lifetime 'a as defined on the impl
+
     type Item = &'a mut T;
     fn next(&'a mut self) -> Option<Self::Item>
     //~^ ERROR method not compatible with trait
     //~| lifetime mismatch
     //~| NOTE expected type `fn(&mut RepeatMut<'a, T>) -> std::option::Option<&mut T>`
+    //~| NOTE the anonymous lifetime #1 defined on the method body
     {
-    //~^ NOTE the anonymous lifetime #1 defined on the body
-    //~| NOTE ...does not necessarily outlive the lifetime 'a as defined on the body
         Some(&mut self.0)
     }
 }
diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr
index cf272b63128..55723ee8cd9 100644
--- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr
+++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr
@@ -4,19 +4,17 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content...
 12 |     if x > y { x } else { y }
    |                           ^
    |
-note: ...the reference is valid for the lifetime 'a as defined on the body at 11:43...
-  --> $DIR/ex1-return-one-existing-name-if-else.rs:11:44
+note: ...the reference is valid for the lifetime 'a as defined on the function body at 11:0...
+  --> $DIR/ex1-return-one-existing-name-if-else.rs:11:1
    |
-11 |   fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
-   |  ____________________________________________^
+11 | / fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
 12 | |     if x > y { x } else { y }
 13 | | }
    | |_^
-note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the body at 11:43
-  --> $DIR/ex1-return-one-existing-name-if-else.rs:11:44
+note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the function body at 11:0
+  --> $DIR/ex1-return-one-existing-name-if-else.rs:11:1
    |
-11 |   fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
-   |  ____________________________________________^
+11 | / fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
 12 | |     if x > y { x } else { y }
 13 | | }
    | |_^
diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr
index 6e03e66dd25..b7d985feca9 100644
--- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr
+++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr
@@ -6,19 +6,17 @@ error[E0308]: mismatched types
    |
    = note: expected type `Ref<'a, _>`
               found type `Ref<'_, _>`
-note: the anonymous lifetime #2 defined on the body at 15:51...
-  --> $DIR/ex2a-push-one-existing-name.rs:15:52
+note: the anonymous lifetime #2 defined on the function body at 15:0...
+  --> $DIR/ex2a-push-one-existing-name.rs:15:1
    |
-15 |   fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
-   |  ____________________________________________________^
+15 | / fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
 16 | |     x.push(y);
 17 | | }
    | |_^
-note: ...does not necessarily outlive the lifetime 'a as defined on the body at 15:51
-  --> $DIR/ex2a-push-one-existing-name.rs:15:52
+note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 15:0
+  --> $DIR/ex2a-push-one-existing-name.rs:15:1
    |
-15 |   fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
-   |  ____________________________________________________^
+15 | / fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
 16 | |     x.push(y);
 17 | | }
    | |_^
diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
index 028f54ce978..3a6e94f2b1c 100644
--- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
+++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr
@@ -6,19 +6,17 @@ error[E0308]: mismatched types
    |
    = note: expected type `Ref<'_, _>`
               found type `Ref<'_, _>`
-note: the anonymous lifetime #3 defined on the body at 15:43...
-  --> $DIR/ex2b-push-no-existing-names.rs:15:44
+note: the anonymous lifetime #3 defined on the function body at 15:0...
+  --> $DIR/ex2b-push-no-existing-names.rs:15:1
    |
-15 |   fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
-   |  ____________________________________________^
+15 | / fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
 16 | |     x.push(y);
 17 | | }
    | |_^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 15:43
-  --> $DIR/ex2b-push-no-existing-names.rs:15:44
+note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 15:0
+  --> $DIR/ex2b-push-no-existing-names.rs:15:1
    |
-15 |   fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
-   |  ____________________________________________^
+15 | / fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
 16 | |     x.push(y);
 17 | | }
    | |_^
diff --git a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr
index 4621214419e..3d7064a4f71 100644
--- a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr
+++ b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr
@@ -4,11 +4,10 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
 16 |     let z = Ref { data: y.data };
    |             ^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'c as defined on the body at 15:66...
-  --> $DIR/ex2c-push-inference-variable.rs:15:67
+note: first, the lifetime cannot outlive the lifetime 'c as defined on the function body at 15:0...
+  --> $DIR/ex2c-push-inference-variable.rs:15:1
    |
-15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^
+15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
 16 | |     let z = Ref { data: y.data };
 17 | |     x.push(z);
 18 | | }
@@ -18,11 +17,10 @@ note: ...so that reference does not outlive borrowed content
    |
 16 |     let z = Ref { data: y.data };
    |                         ^^^^^^
-note: but, the lifetime must be valid for the lifetime 'b as defined on the body at 15:66...
-  --> $DIR/ex2c-push-inference-variable.rs:15:67
+note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 15:0...
+  --> $DIR/ex2c-push-inference-variable.rs:15:1
    |
-15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^
+15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
 16 | |     let z = Ref { data: y.data };
 17 | |     x.push(z);
 18 | | }
diff --git a/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr
index a69694fdc2e..aced855bf66 100644
--- a/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr
+++ b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr
@@ -4,11 +4,10 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
 17 |     let b = Ref { data: y.data };
    |             ^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'c as defined on the body at 15:66...
-  --> $DIR/ex2d-push-inference-variable-2.rs:15:67
+note: first, the lifetime cannot outlive the lifetime 'c as defined on the function body at 15:0...
+  --> $DIR/ex2d-push-inference-variable-2.rs:15:1
    |
-15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^
+15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
 16 | |     let a: &mut Vec<Ref<i32>> = x;
 17 | |     let b = Ref { data: y.data };
 18 | |     a.push(b);
@@ -19,11 +18,10 @@ note: ...so that reference does not outlive borrowed content
    |
 17 |     let b = Ref { data: y.data };
    |                         ^^^^^^
-note: but, the lifetime must be valid for the lifetime 'b as defined on the body at 15:66...
-  --> $DIR/ex2d-push-inference-variable-2.rs:15:67
+note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 15:0...
+  --> $DIR/ex2d-push-inference-variable-2.rs:15:1
    |
-15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^
+15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
 16 | |     let a: &mut Vec<Ref<i32>> = x;
 17 | |     let b = Ref { data: y.data };
 18 | |     a.push(b);
diff --git a/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr
index eff15bb794b..07e2316b63d 100644
--- a/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr
+++ b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr
@@ -4,11 +4,10 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
 17 |     let b = Ref { data: y.data };
    |             ^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'c as defined on the body at 15:66...
-  --> $DIR/ex2e-push-inference-variable-3.rs:15:67
+note: first, the lifetime cannot outlive the lifetime 'c as defined on the function body at 15:0...
+  --> $DIR/ex2e-push-inference-variable-3.rs:15:1
    |
-15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^
+15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
 16 | |     let a: &mut Vec<Ref<i32>> = x;
 17 | |     let b = Ref { data: y.data };
 18 | |     Vec::push(a, b);
@@ -19,11 +18,10 @@ note: ...so that reference does not outlive borrowed content
    |
 17 |     let b = Ref { data: y.data };
    |                         ^^^^^^
-note: but, the lifetime must be valid for the lifetime 'b as defined on the body at 15:66...
-  --> $DIR/ex2e-push-inference-variable-3.rs:15:67
+note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 15:0...
+  --> $DIR/ex2e-push-inference-variable-3.rs:15:1
    |
-15 |   fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
-   |  ___________________________________________________________________^
+15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
 16 | |     let a: &mut Vec<Ref<i32>> = x;
 17 | |     let b = Ref { data: y.data };
 18 | |     Vec::push(a, b);