about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/metadata/tydecode.rs59
-rw-r--r--src/librustc/metadata/tyencode.rs44
-rw-r--r--src/librustc/middle/astencode.rs187
-rw-r--r--src/librustc/middle/cfg/construct.rs8
-rw-r--r--src/librustc/middle/expr_use_visitor.rs10
-rw-r--r--src/librustc/middle/free_region.rs7
-rw-r--r--src/librustc/middle/infer/combine.rs4
-rw-r--r--src/librustc/middle/infer/error_reporting.rs30
-rw-r--r--src/librustc/middle/infer/freshen.rs3
-rw-r--r--src/librustc/middle/infer/higher_ranked/mod.rs8
-rw-r--r--src/librustc/middle/infer/mod.rs2
-rw-r--r--src/librustc/middle/infer/region_inference/mod.rs53
-rw-r--r--src/librustc/middle/infer/resolve.rs2
-rw-r--r--src/librustc/middle/liveness.rs3
-rw-r--r--src/librustc/middle/mem_categorization.rs3
-rw-r--r--src/librustc/middle/region.rs634
-rw-r--r--src/librustc/middle/ty.rs63
-rw-r--r--src/librustc/util/ppaux.rs10
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs35
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs9
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs10
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs4
-rw-r--r--src/librustc_driver/test.rs54
-rw-r--r--src/librustc_trans/trans/cleanup.rs22
-rw-r--r--src/librustc_typeck/astconv.rs2
-rw-r--r--src/librustc_typeck/check/closure.rs3
-rw-r--r--src/librustc_typeck/check/mod.rs5
-rw-r--r--src/librustc_typeck/check/regionck.rs32
-rw-r--r--src/librustc_typeck/check/wf.rs8
-rw-r--r--src/librustc_typeck/check/wfcheck.rs3
-rw-r--r--src/librustc_typeck/collect.rs4
-rw-r--r--src/librustc_typeck/variance.rs4
-rw-r--r--src/librustdoc/clean/mod.rs3
33 files changed, 664 insertions, 664 deletions
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 59f938d9489..0c802356af1 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -207,6 +207,10 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
             }
             'B' => {
                 assert_eq!(self.next(), '[');
+                // this is the wrong NodeId, but `param_id` is only accessed
+                // by the receiver-matching code in collect, which won't
+                // be going down this code path, and anyway I will kill it
+                // the moment wfcheck becomes the standard.
                 let node_id = self.parse_uint() as ast::NodeId;
                 assert_eq!(self.next(), '|');
                 let space = self.parse_param_space();
@@ -223,7 +227,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
             }
             'f' => {
                 assert_eq!(self.next(), '[');
-                let scope = self.parse_destruction_scope_data();
+                let scope = self.parse_scope();
                 assert_eq!(self.next(), '|');
                 let br = self.parse_bound_region();
                 assert_eq!(self.next(), ']');
@@ -246,43 +250,44 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
     }
 
     fn parse_scope(&mut self) -> region::CodeExtent {
-        match self.next() {
+        self.tcx.region_maps.bogus_code_extent(match self.next() {
+            // This creates scopes with the wrong NodeId. This isn't
+            // actually a problem because scopes only exist *within*
+            // functions, and functions aren't loaded until trans which
+            // doesn't care about regions.
+            //
+            // May still be worth fixing though.
             'P' => {
                 assert_eq!(self.next(), '[');
                 let fn_id = self.parse_uint() as ast::NodeId;
                 assert_eq!(self.next(), '|');
                 let body_id = self.parse_uint() as ast::NodeId;
                 assert_eq!(self.next(), ']');
-                region::CodeExtent::ParameterScope {
+                region::CodeExtentData::ParameterScope {
                     fn_id: fn_id, body_id: body_id
                 }
             }
             'M' => {
                 let node_id = self.parse_uint() as ast::NodeId;
-                region::CodeExtent::Misc(node_id)
+                region::CodeExtentData::Misc(node_id)
             }
             'D' => {
                 let node_id = self.parse_uint() as ast::NodeId;
-                region::CodeExtent::DestructionScope(node_id)
+                region::CodeExtentData::DestructionScope(node_id)
             }
             'B' => {
                 assert_eq!(self.next(), '[');
                 let node_id = self.parse_uint() as ast::NodeId;
                 assert_eq!(self.next(), '|');
-                let first_stmt_index = self.parse_uint();
+                let first_stmt_index = self.parse_u32();
                 assert_eq!(self.next(), ']');
                 let block_remainder = region::BlockRemainder {
                     block: node_id, first_statement_index: first_stmt_index,
                 };
-                region::CodeExtent::Remainder(block_remainder)
+                region::CodeExtentData::Remainder(block_remainder)
             }
             _ => panic!("parse_scope: bad input")
-        }
-    }
-
-    fn parse_destruction_scope_data(&mut self) -> region::DestructionScopeData {
-        let node_id = self.parse_uint() as ast::NodeId;
-        region::DestructionScopeData::new(node_id)
+        })
     }
 
     fn parse_opt<T, F>(&mut self, f: F) -> Option<T>
@@ -619,6 +624,33 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
         }
     }
 
+    pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef {
+        let name = self.parse_name(':');
+        let def_id = self.parse_def(NominalType);
+        let space = self.parse_param_space();
+        assert_eq!(self.next(), '|');
+        let index = self.parse_u32();
+        assert_eq!(self.next(), '|');
+        let mut bounds = vec![];
+        loop {
+            match self.next() {
+                'R' => bounds.push(self.parse_region()),
+                '.' => { break; }
+                c => {
+                    panic!("parse_region_param_def: bad bounds ('{}')", c)
+                }
+            }
+        }
+        ty::RegionParameterDef {
+            name: name,
+            def_id: def_id,
+            space: space,
+            index: index,
+            bounds: bounds
+        }
+    }
+
+
     fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault {
         match self.next() {
             'a' => ty::ObjectLifetimeDefault::Ambiguous,
@@ -717,4 +749,3 @@ fn parse_unsafety(c: char) -> ast::Unsafety {
         _ => panic!("parse_unsafety: bad unsafety {}", c)
     }
 }
-
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 65bb04309d0..70345dc8bad 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -255,7 +255,7 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) {
         }
         ty::ReFree(ref fr) => {
             mywrite!(w, "f[");
-            enc_destruction_scope_data(w, fr.scope);
+            enc_scope(w, cx, fr.scope);
             mywrite!(w, "|");
             enc_bound_region(w, cx, fr.bound_region);
             mywrite!(w, "]");
@@ -271,29 +271,24 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) {
         ty::ReEmpty => {
             mywrite!(w, "e");
         }
-        ty::ReInfer(_) => {
+        ty::ReVar(_) | ty::ReSkolemized(..) => {
             // these should not crop up after typeck
             cx.diag.handler().bug("cannot encode region variables");
         }
     }
 }
 
-fn enc_scope(w: &mut Encoder, _cx: &ctxt, scope: region::CodeExtent) {
-    match scope {
-        region::CodeExtent::ParameterScope {
+fn enc_scope(w: &mut Encoder, cx: &ctxt, scope: region::CodeExtent) {
+    match cx.tcx.region_maps.code_extent_data(scope) {
+        region::CodeExtentData::ParameterScope {
             fn_id, body_id } => mywrite!(w, "P[{}|{}]", fn_id, body_id),
-        region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id),
-        region::CodeExtent::Remainder(region::BlockRemainder {
+        region::CodeExtentData::Misc(node_id) => mywrite!(w, "M{}", node_id),
+        region::CodeExtentData::Remainder(region::BlockRemainder {
             block: b, first_statement_index: i }) => mywrite!(w, "B[{}|{}]", b, i),
-        region::CodeExtent::DestructionScope(node_id) => mywrite!(w, "D{}", node_id),
+        region::CodeExtentData::DestructionScope(node_id) => mywrite!(w, "D{}", node_id),
     }
 }
 
-fn enc_destruction_scope_data(w: &mut Encoder,
-                              d: region::DestructionScopeData) {
-    mywrite!(w, "{}", d.node_id);
-}
-
 fn enc_bound_region(w: &mut Encoder, cx: &ctxt, br: ty::BoundRegion) {
     match br {
         ty::BrAnon(idx) => {
@@ -396,17 +391,6 @@ pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder,
     mywrite!(w, ".");
 }
 
-pub fn enc_region_bounds<'a, 'tcx>(w: &mut Encoder,
-                            cx: &ctxt<'a, 'tcx>,
-                            rs: &[ty::Region]) {
-    for &r in rs {
-        mywrite!(w, "R");
-        enc_region(w, cx, r);
-    }
-
-    mywrite!(w, ".");
-}
-
 pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
                                     v: &ty::TypeParameterDef<'tcx>) {
     mywrite!(w, "{}:{}|{}|{}|{}|",
@@ -416,6 +400,18 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
     enc_object_lifetime_default(w, cx, v.object_lifetime_default);
 }
 
+pub fn enc_region_param_def(w: &mut Encoder, cx: &ctxt,
+                            v: &ty::RegionParameterDef) {
+    mywrite!(w, "{}:{}|{}|{}|",
+             v.name, (cx.ds)(v.def_id),
+             v.space.to_uint(), v.index);
+    for &r in &v.bounds {
+        mywrite!(w, "R");
+        enc_region(w, cx, r);
+    }
+    mywrite!(w, ".");
+}
+
 fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder,
                                          cx: &ctxt<'a, 'tcx>,
                                          default: ty::ObjectLifetimeDefault)
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index d7fe8e95ae7..4ea55d2d4e4 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -479,67 +479,6 @@ impl tr for def::Def {
 }
 
 // ______________________________________________________________________
-// Encoding and decoding of ancillary information
-
-impl tr for ty::Region {
-    fn tr(&self, dcx: &DecodeContext) -> ty::Region {
-        match *self {
-            ty::ReLateBound(debruijn, br) => {
-                ty::ReLateBound(debruijn, br.tr(dcx))
-            }
-            ty::ReEarlyBound(data) => {
-                ty::ReEarlyBound(ty::EarlyBoundRegion {
-                    param_id: dcx.tr_id(data.param_id),
-                    space: data.space,
-                    index: data.index,
-                    name: data.name,
-                })
-            }
-            ty::ReScope(scope) => {
-                ty::ReScope(scope.tr(dcx))
-            }
-            ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => {
-                *self
-            }
-            ty::ReFree(ref fr) => {
-                ty::ReFree(fr.tr(dcx))
-            }
-        }
-    }
-}
-
-impl tr for ty::FreeRegion {
-    fn tr(&self, dcx: &DecodeContext) -> ty::FreeRegion {
-        ty::FreeRegion { scope: self.scope.tr(dcx),
-                         bound_region: self.bound_region.tr(dcx) }
-    }
-}
-
-impl tr for region::CodeExtent {
-    fn tr(&self, dcx: &DecodeContext) -> region::CodeExtent {
-        self.map_id(|id| dcx.tr_id(id))
-    }
-}
-
-impl tr for region::DestructionScopeData {
-    fn tr(&self, dcx: &DecodeContext) -> region::DestructionScopeData {
-        region::DestructionScopeData { node_id: dcx.tr_id(self.node_id) }
-    }
-}
-
-impl tr for ty::BoundRegion {
-    fn tr(&self, dcx: &DecodeContext) -> ty::BoundRegion {
-        match *self {
-            ty::BrAnon(_) |
-            ty::BrFresh(_) |
-            ty::BrEnv => *self,
-            ty::BrNamed(id, ident) => ty::BrNamed(dcx.tr_def_id(id),
-                                                    ident),
-        }
-    }
-}
-
-// ______________________________________________________________________
 // Encoding and decoding of freevar information
 
 fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &ty::Freevar) {
@@ -574,24 +513,6 @@ impl tr for ty::Freevar {
     }
 }
 
-impl tr for ty::UpvarBorrow {
-    fn tr(&self, dcx: &DecodeContext) -> ty::UpvarBorrow {
-        ty::UpvarBorrow {
-            kind: self.kind,
-            region: self.region.tr(dcx)
-        }
-    }
-}
-
-impl tr for ty::UpvarCapture {
-    fn tr(&self, dcx: &DecodeContext) -> ty::UpvarCapture {
-        match *self {
-            ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
-            ty::UpvarCapture::ByRef(ref data) => ty::UpvarCapture::ByRef(data.tr(dcx)),
-        }
-    }
-}
-
 // ______________________________________________________________________
 // Encoding and decoding of MethodCallee
 
@@ -703,10 +624,13 @@ impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> {
 trait rbml_writer_helpers<'tcx> {
     fn emit_closure_type<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                              closure_type: &ty::ClosureTy<'tcx>);
+    fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region);
     fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
     fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]);
     fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                                type_param_def: &ty::TypeParameterDef<'tcx>);
+    fn emit_region_param_def(&mut self, ecx: &e::EncodeContext,
+                             region_param_def: &ty::RegionParameterDef);
     fn emit_predicate<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                           predicate: &ty::Predicate<'tcx>);
     fn emit_trait_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
@@ -718,9 +642,11 @@ trait rbml_writer_helpers<'tcx> {
     fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>,
                                    bounds: &ty::ExistentialBounds<'tcx>);
     fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds);
+    fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture);
     fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                                 adj: &ty::AutoAdjustment<'tcx>);
-    fn emit_autoref<'a>(&mut self, autoref: &ty::AutoRef<'tcx>);
+    fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
+                        autoref: &ty::AutoRef<'tcx>);
     fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                                auto_deref_ref: &ty::AutoDerefRef<'tcx>);
 }
@@ -734,6 +660,10 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
         });
     }
 
+    fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) {
+        self.emit_opaque(|this| Ok(e::write_region(ecx, this, r)));
+    }
+
     fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) {
         self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty)));
     }
@@ -755,7 +685,14 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
                                          type_param_def))
         });
     }
-
+    fn emit_region_param_def(&mut self, ecx: &e::EncodeContext,
+                             region_param_def: &ty::RegionParameterDef) {
+        self.emit_opaque(|this| {
+            Ok(tyencode::enc_region_param_def(this,
+                                              &ecx.ty_str_ctxt(),
+                                              region_param_def))
+        });
+    }
     fn emit_predicate<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
                           predicate: &ty::Predicate<'tcx>) {
         self.emit_opaque(|this| {
@@ -781,7 +718,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
                     this.emit_struct_field("regions", 1, |this| {
                         Ok(encode_vec_per_param_space(
                             this, &type_scheme.generics.regions,
-                            |this, def| def.encode(this).unwrap()))
+                            |this, def| this.emit_region_param_def(ecx, def)))
                     })
                 })
             });
@@ -804,6 +741,26 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
                                                                 bounds)));
     }
 
+    fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture) {
+        use serialize::Encoder;
+
+        self.emit_enum("UpvarCapture", |this| {
+            match *capture {
+                ty::UpvarCapture::ByValue => {
+                    this.emit_enum_variant("ByValue", 1, 0, |_| Ok(()))
+                }
+                ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, region }) => {
+                    this.emit_enum_variant("ByRef", 2, 0, |this| {
+                        this.emit_enum_variant_arg(0,
+                            |this| kind.encode(this));
+                        this.emit_enum_variant_arg(1,
+                            |this| Ok(this.emit_region(ecx, region)))
+                    })
+                }
+            }
+        }).unwrap()
+    }
+
     fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
                        substs: &subst::Substs<'tcx>) {
         self.emit_opaque(|this| Ok(tyencode::enc_substs(this,
@@ -837,14 +794,16 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
         });
     }
 
-    fn emit_autoref<'b>(&mut self, autoref: &ty::AutoRef<'tcx>) {
+    fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
+                        autoref: &ty::AutoRef<'tcx>) {
         use serialize::Encoder;
 
         self.emit_enum("AutoRef", |this| {
             match autoref {
                 &ty::AutoPtr(r, m) => {
                     this.emit_enum_variant("AutoPtr", 0, 2, |this| {
-                        this.emit_enum_variant_arg(0, |this| r.encode(this));
+                        this.emit_enum_variant_arg(0,
+                            |this| Ok(this.emit_region(ecx, *r)));
                         this.emit_enum_variant_arg(1, |this| m.encode(this))
                     })
                 }
@@ -868,7 +827,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
                 this.emit_option(|this| {
                     match auto_deref_ref.autoref {
                         None => this.emit_option_none(),
-                        Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))),
+                        Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))),
                     }
                 })
             });
@@ -983,7 +942,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
                                        .unwrap()
                                        .clone();
                 var_id.encode(rbml_w);
-                upvar_capture.encode(rbml_w);
+                rbml_w.emit_upvar_capture(ecx, &upvar_capture);
             })
         }
     }
@@ -1080,6 +1039,7 @@ trait rbml_decoder_decoder_helpers<'tcx> {
                                      f: F) -> R
         where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R;
 
+    fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region;
     fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>;
     fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec<Ty<'tcx>>;
     fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -1088,6 +1048,8 @@ trait rbml_decoder_decoder_helpers<'tcx> {
                                    -> ty::PolyTraitRef<'tcx>;
     fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                                    -> ty::TypeParameterDef<'tcx>;
+    fn read_region_param_def(&mut self, dcx: &DecodeContext)
+                             -> ty::RegionParameterDef;
     fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                               -> ty::Predicate<'tcx>;
     fn read_type_scheme<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -1096,6 +1058,8 @@ trait rbml_decoder_decoder_helpers<'tcx> {
                                        -> ty::ExistentialBounds<'tcx>;
     fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                            -> subst::Substs<'tcx>;
+    fn read_upvar_capture(&mut self, dcx: &DecodeContext)
+                          -> ty::UpvarCapture;
     fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                                     -> ty::AutoAdjustment<'tcx>;
     fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -1180,13 +1144,14 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
             str
         }
     }
-
-    fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> {
+    fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region {
         // Note: regions types embed local node ids.  In principle, we
         // should translate these node ids into the new decode
         // context.  However, we do not bother, because region types
-        // are not used during trans.
-
+        // are not used during trans. This also applies to read_ty.
+        return self.read_ty_encoded(dcx, |decoder| decoder.parse_region());
+    }
+    fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> {
         return self.read_ty_encoded(dcx, |decoder| decoder.parse_ty());
     }
 
@@ -1209,7 +1174,10 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
                                    -> ty::TypeParameterDef<'tcx> {
         self.read_ty_encoded(dcx, |decoder| decoder.parse_type_param_def())
     }
-
+    fn read_region_param_def(&mut self, dcx: &DecodeContext)
+                             -> ty::RegionParameterDef {
+        self.read_ty_encoded(dcx, |decoder| decoder.parse_region_param_def())
+    }
     fn read_predicate<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
                               -> ty::Predicate<'tcx>
     {
@@ -1232,7 +1200,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
                             regions:
                             this.read_struct_field("regions", 1, |this| {
                                 Ok(this.read_vec_per_param_space(
-                                    |this| Decodable::decode(this).unwrap()))
+                                    |this| this.read_region_param_def(dcx)))
                             }).unwrap(),
                         })
                     })
@@ -1258,7 +1226,23 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
                .parse_substs())
         }).unwrap()
     }
-
+    fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture {
+        self.read_enum("UpvarCapture", |this| {
+            let variants = ["ByValue", "ByRef"];
+            this.read_enum_variant(&variants, |this, i| {
+                Ok(match i {
+                    1 => ty::UpvarCapture::ByValue,
+                    2 => ty::UpvarCapture::ByRef(ty::UpvarBorrow {
+                        kind: this.read_enum_variant_arg(0,
+                                  |this| Decodable::decode(this)).unwrap(),
+                        region: this.read_enum_variant_arg(1,
+                                    |this| Ok(this.read_region(dcx))).unwrap()
+                    }),
+                    _ => panic!("bad enum variant for ty::UpvarCapture")
+                })
+            })
+        }).unwrap()
+    }
     fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
                                     -> ty::AutoAdjustment<'tcx> {
         self.read_enum("AutoAdjustment", |this| {
@@ -1317,11 +1301,15 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
                 Ok(match i {
                     0 => {
                         let r: ty::Region =
-                            this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
+                            this.read_enum_variant_arg(0, |this| {
+                                Ok(this.read_region(dcx))
+                            }).unwrap();
                         let m: ast::Mutability =
-                            this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
+                            this.read_enum_variant_arg(1, |this| {
+                                Decodable::decode(this)
+                            }).unwrap();
 
-                        ty::AutoPtr(dcx.tcx.mk_region(r.tr(dcx)), m)
+                        ty::AutoPtr(dcx.tcx.mk_region(r), m)
                     }
                     1 => {
                         let m: ast::Mutability =
@@ -1376,6 +1364,9 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
     /// case. We translate them with `tr_def_id()` which will map
     /// the crate numbers back to the original source crate.
     ///
+    /// Scopes will end up as being totally bogus. This can actually
+    /// be fixed though.
+    ///
     /// Unboxed closures are cloned along with the function being
     /// inlined, and all side tables use interned node IDs, so we
     /// translate their def IDs accordingly.
@@ -1453,8 +1444,8 @@ fn decode_side_tables(dcx: &DecodeContext,
                             var_id: dcx.tr_id(var_id),
                             closure_expr_id: id
                         };
-                        let ub: ty::UpvarCapture = Decodable::decode(val_dsr).unwrap();
-                        dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub.tr(dcx));
+                        let ub = val_dsr.read_upvar_capture(dcx);
+                        dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub);
                     }
                     c::tag_table_tcache => {
                         let type_scheme = val_dsr.read_type_scheme(dcx);
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index d4737f9d604..91e35c0679b 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -12,7 +12,6 @@ use rustc_data_structures::graph;
 use middle::cfg::*;
 use middle::def;
 use middle::pat_util;
-use middle::region::CodeExtent;
 use middle::ty;
 use syntax::ast;
 use syntax::ast_util;
@@ -585,11 +584,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                         to_loop: LoopScope,
                         to_index: CFGIndex) {
         let mut data = CFGEdgeData {exiting_scopes: vec!() };
-        let mut scope = CodeExtent::from_node_id(from_expr.id);
-        let target_scope = CodeExtent::from_node_id(to_loop.loop_id);
+        let mut scope = self.tcx.region_maps.node_extent(from_expr.id);
+        let target_scope = self.tcx.region_maps.node_extent(to_loop.loop_id);
         while scope != target_scope {
-
-            data.exiting_scopes.push(scope.node_id());
+            data.exiting_scopes.push(scope.node_id(&self.tcx.region_maps));
             scope = self.tcx.region_maps.encl_scope(scope);
         }
         self.graph.add_edge(from_index, to_index, data);
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 30e8dfb293d..ce03e10418d 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -20,7 +20,7 @@ pub use self::MatchMode::*;
 use self::TrackMatchMode::*;
 use self::OverloadedCallType::*;
 
-use middle::{def, region, pat_util};
+use middle::{def, pat_util};
 use middle::def_id::{DefId};
 use middle::infer;
 use middle::mem_categorization as mc;
@@ -296,7 +296,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
         for arg in &decl.inputs {
             let arg_ty = return_if_err!(self.typer.node_ty(arg.pat.id));
 
-            let fn_body_scope = region::CodeExtent::from_node_id(body.id);
+            let fn_body_scope = self.tcx().region_maps.node_extent(body.id);
             let arg_cmt = self.mc.cat_rvalue(
                 arg.id,
                 arg.pat.span,
@@ -579,7 +579,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
         let callee_ty = return_if_err!(self.typer.expr_ty_adjusted(callee));
         debug!("walk_callee: callee={:?} callee_ty={:?}",
                callee, callee_ty);
-        let call_scope = region::CodeExtent::from_node_id(call.id);
+        let call_scope = self.tcx().region_maps.node_extent(call.id);
         match callee_ty.sty {
             ty::TyBareFn(..) => {
                 self.consume_expr(callee);
@@ -862,7 +862,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
                 // Converting from a &T to *T (or &mut T to *mut T) is
                 // treated as borrowing it for the enclosing temporary
                 // scope.
-                let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id));
+                let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
 
                 self.delegate.borrow(expr.id,
                                      expr.span,
@@ -917,7 +917,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
         // methods are implicitly autoref'd which sadly does not use
         // adjustments, so we must hardcode the borrow here.
 
-        let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id));
+        let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
         let bk = ty::ImmBorrow;
 
         for &arg in &rhs {
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index 744ceb3701d..c39c3fd3027 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -135,7 +135,7 @@ impl FreeRegionMap {
                     tcx.region_maps.is_subscope_of(sub_scope, super_scope),
 
                 (ty::ReScope(sub_scope), ty::ReFree(fr)) =>
-                    tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()) ||
+                    tcx.region_maps.is_subscope_of(sub_scope, fr.scope) ||
                     self.is_static(fr),
 
                 (ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
@@ -162,8 +162,8 @@ impl FreeRegionMap {
 
 #[cfg(test)]
 fn free_region(index: u32) -> FreeRegion {
-    use middle::region::DestructionScopeData;
-    FreeRegion { scope: DestructionScopeData::new(0),
+    use middle::region::DUMMY_CODE_EXTENT;
+    FreeRegion { scope: DUMMY_CODE_EXTENT,
                  bound_region: ty::BoundRegion::BrAnon(index) }
 }
 
@@ -177,4 +177,3 @@ fn lub() {
     map.relate_free_regions(frs[1], frs[2]);
     assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2]));
 }
-
diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs
index 94c76e23999..cfeec1c4f73 100644
--- a/src/librustc/middle/infer/combine.rs
+++ b/src/librustc/middle/infer/combine.rs
@@ -340,14 +340,14 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
 
             // Always make a fresh region variable for skolemized regions;
             // the higher-ranked decision procedures rely on this.
-            ty::ReInfer(ty::ReSkolemized(..)) => { }
+            ty::ReSkolemized(..) => { }
 
             // For anything else, we make a region variable, unless we
             // are *equating*, in which case it's just wasteful.
             ty::ReEmpty |
             ty::ReStatic |
             ty::ReScope(..) |
-            ty::ReInfer(ty::ReVar(..)) |
+            ty::ReVar(..) |
             ty::ReFree(..) => {
                 if !self.make_region_vars {
                     return r;
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index 44eceb1f213..61fa08c4620 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -121,11 +121,11 @@ impl<'tcx> ty::ctxt<'tcx> {
                     format!("{}unknown scope: {:?}{}.  Please report a bug.",
                             prefix, scope, suffix)
                 };
-                let span = match scope.span(&self.map) {
+                let span = match scope.span(&self.region_maps, &self.map) {
                     Some(s) => s,
                     None => return self.sess.note(&unknown_scope())
                 };
-                let tag = match self.map.find(scope.node_id()) {
+                let tag = match self.map.find(scope.node_id(&self.region_maps)) {
                     Some(ast_map::NodeBlock(_)) => "block",
                     Some(ast_map::NodeExpr(expr)) => match expr.node {
                         ast::ExprCall(..) => "call",
@@ -142,16 +142,16 @@ impl<'tcx> ty::ctxt<'tcx> {
                         return self.sess.span_note(span, &unknown_scope());
                     }
                 };
-                let scope_decorated_tag = match scope {
-                    region::CodeExtent::Misc(_) => tag,
-                    region::CodeExtent::ParameterScope { .. } => {
+                let scope_decorated_tag = match self.region_maps.code_extent_data(scope) {
+                    region::CodeExtentData::Misc(_) => tag,
+                    region::CodeExtentData::ParameterScope { .. } => {
                         "scope of parameters for function"
                     }
-                    region::CodeExtent::DestructionScope(_) => {
+                    region::CodeExtentData::DestructionScope(_) => {
                         new_string = format!("destruction scope surrounding {}", tag);
                         &new_string[..]
                     }
-                    region::CodeExtent::Remainder(r) => {
+                    region::CodeExtentData::Remainder(r) => {
                         new_string = format!("block suffix following statement {}",
                                              r.first_statement_index);
                         &new_string[..]
@@ -172,7 +172,7 @@ impl<'tcx> ty::ctxt<'tcx> {
                     }
                 };
 
-                match self.map.find(fr.scope.node_id) {
+                match self.map.find(fr.scope.node_id(&self.region_maps)) {
                     Some(ast_map::NodeBlock(ref blk)) => {
                         let (msg, opt_span) = explain_span(self, "block", blk.span);
                         (format!("{} {}", prefix, msg), opt_span)
@@ -183,7 +183,8 @@ impl<'tcx> ty::ctxt<'tcx> {
                         (format!("{} {}", prefix, msg), opt_span)
                     }
                     Some(_) | None => {
-                        // this really should not happen
+                        // this really should not happen, but it does:
+                        // FIXME(#27942)
                         (format!("{} unknown free region bounded by scope {:?}",
                                  prefix, fr.scope), None)
                     }
@@ -196,9 +197,12 @@ impl<'tcx> ty::ctxt<'tcx> {
 
             ty::ReEarlyBound(ref data) => (data.name.to_string(), None),
 
-            // I believe these cases should not occur (except when debugging,
-            // perhaps)
-            ty::ReInfer(_) | ty::ReLateBound(..) => {
+            // FIXME(#13998) ReSkolemized should probably print like
+            // ReFree rather than dumping Debug output on the user.
+            //
+            // We shouldn't really be having unification failures with ReVar
+            // and ReLateBound though.
+            ty::ReSkolemized(..) | ty::ReVar(_) | ty::ReLateBound(..) => {
                 (format!("lifetime {:?}", region), None)
             }
         };
@@ -419,7 +423,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                         return None
                     }
                     assert!(fr1.scope == fr2.scope);
-                    (fr1.scope.node_id, fr1, fr2)
+                    (fr1.scope.node_id(&tcx.region_maps), fr1, fr2)
                 },
                 _ => return None
             };
diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs
index d65c4061f11..c72a4fc0db3 100644
--- a/src/librustc/middle/infer/freshen.rs
+++ b/src/librustc/middle/infer/freshen.rs
@@ -95,7 +95,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
             ty::ReStatic |
             ty::ReFree(_) |
             ty::ReScope(_) |
-            ty::ReInfer(_) |
+            ty::ReVar(_) |
+            ty::ReSkolemized(..) |
             ty::ReEmpty => {
                 // replace all free regions with 'static
                 ty::ReStatic
diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs
index 5f2f4df2f16..fb8da9b65da 100644
--- a/src/librustc/middle/infer/higher_ranked/mod.rs
+++ b/src/librustc/middle/infer/higher_ranked/mod.rs
@@ -335,7 +335,7 @@ fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>,
                      -> Vec<ty::RegionVid> {
     map.iter()
        .map(|(_, r)| match *r {
-           ty::ReInfer(ty::ReVar(r)) => { r }
+           ty::ReVar(r) => { r }
            r => {
                fields.tcx().sess.span_bug(
                    fields.trace.origin.span(),
@@ -347,7 +347,7 @@ fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>,
 
 fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
     match r {
-        ty::ReInfer(ty::ReVar(ref v)) => new_vars.iter().any(|x| x == v),
+        ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
         _ => false
     }
 }
@@ -443,7 +443,7 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
         }
 
         region_vars.retain(|&region_vid| {
-            let r = ty::ReInfer(ty::ReVar(region_vid));
+            let r = ty::ReVar(region_vid);
             !escaping_region_vars.contains(&r)
         });
 
@@ -561,7 +561,7 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
             // Each skolemized should only be relatable to itself
             // or new variables:
             match tainted_region {
-                ty::ReInfer(ty::ReVar(vid)) => {
+                ty::ReVar(vid) => {
                     if new_vars.iter().any(|&x| x == vid) { continue; }
                 }
                 _ => {
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 4d558ed5663..4e8ed01c6b9 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -1059,7 +1059,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region {
-        ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin)))
+        ty::ReVar(self.region_vars.new_region_var(origin))
     }
 
     pub fn region_vars_for_defs(&self,
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index e04f2955ddc..1785fe09f87 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -25,7 +25,7 @@ use middle::free_region::FreeRegionMap;
 use middle::region;
 use middle::ty::{self, Ty, TypeError};
 use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
-use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
+use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound};
 use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
 use middle::ty_relate::RelateResult;
 use util::common::indenter;
@@ -373,7 +373,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
 
         let sc = self.skolemization_count.get();
         self.skolemization_count.set(sc + 1);
-        ReInfer(ReSkolemized(sc, br))
+        ReSkolemized(sc, br)
     }
 
     pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {
@@ -510,13 +510,13 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
           (_, ReStatic) => {
             // all regions are subregions of static, so we can ignore this
           }
-          (ReInfer(ReVar(sub_id)), ReInfer(ReVar(sup_id))) => {
+          (ReVar(sub_id), ReVar(sup_id)) => {
             self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
           }
-          (r, ReInfer(ReVar(sup_id))) => {
+          (r, ReVar(sup_id)) => {
             self.add_constraint(ConstrainRegSubVar(r, sup_id), origin);
           }
-          (ReInfer(ReVar(sub_id)), r) => {
+          (ReVar(sub_id), r) => {
             self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
           }
           _ => {
@@ -621,7 +621,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         let vars = TwoRegions { a: a, b: b };
         match self.combine_map(t).borrow().get(&vars) {
             Some(&c) => {
-                return ReInfer(ReVar(c));
+                return ReVar(c);
             }
             None => {}
         }
@@ -630,10 +630,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         if self.in_snapshot() {
             self.undo_log.borrow_mut().push(AddCombination(t, vars));
         }
-        relate(self, a, ReInfer(ReVar(c)));
-        relate(self, b, ReInfer(ReVar(c)));
+        relate(self, a, ReVar(c));
+        relate(self, b, ReVar(c));
         debug!("combine_vars() c={:?}", c);
-        ReInfer(ReVar(c))
+        ReVar(c)
     }
 
     pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot)
@@ -672,22 +672,22 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                     &AddConstraint(ConstrainVarSubVar(a, b)) => {
                         consider_adding_bidirectional_edges(
                             &mut result_set, r,
-                            ReInfer(ReVar(a)), ReInfer(ReVar(b)));
+                            ReVar(a), ReVar(b));
                     }
                     &AddConstraint(ConstrainRegSubVar(a, b)) => {
                         consider_adding_bidirectional_edges(
                             &mut result_set, r,
-                            a, ReInfer(ReVar(b)));
+                            a, ReVar(b));
                     }
                     &AddConstraint(ConstrainVarSubReg(a, b)) => {
                         consider_adding_bidirectional_edges(
                             &mut result_set, r,
-                            ReInfer(ReVar(a)), b);
+                            ReVar(a), b);
                     }
                     &AddGiven(a, b) => {
                         consider_adding_bidirectional_edges(
                             &mut result_set, r,
-                            ReFree(a), ReInfer(ReVar(b)));
+                            ReFree(a), ReVar(b));
                     }
                     &AddVerify(i) => {
                         match (*self.verifys.borrow())[i] {
@@ -775,7 +775,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
             r // everything lives longer than empty
           }
 
-          (ReInfer(ReVar(v_id)), _) | (_, ReInfer(ReVar(v_id))) => {
+          (ReVar(v_id), _) | (_, ReVar(v_id)) => {
             self.tcx.sess.span_bug(
                 (*self.var_origins.borrow())[v_id.index as usize].span(),
                 &format!("lub_concrete_regions invoked with \
@@ -790,10 +790,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
             // A "free" region can be interpreted as "some region
             // at least as big as the block fr.scope_id".  So, we can
             // reasonably compare free regions and scopes:
-            let fr_scope = fr.scope.to_code_extent();
-            let r_id = self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id);
+            let r_id = self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id);
 
-            if r_id == fr_scope {
+            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:
@@ -818,8 +817,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
 
           // For these types, we cannot define any additional
           // relationship:
-          (ReInfer(ReSkolemized(..)), _) |
-          (_, ReInfer(ReSkolemized(..))) => {
+          (ReSkolemized(..), _) |
+          (_, ReSkolemized(..)) => {
             if a == b {a} else {ReStatic}
           }
         }
@@ -853,8 +852,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                 Ok(ReEmpty)
             }
 
-            (ReInfer(ReVar(v_id)), _) |
-            (_, ReInfer(ReVar(v_id))) => {
+            (ReVar(v_id), _) |
+            (_, ReVar(v_id)) => {
                 self.tcx.sess.span_bug(
                     (*self.var_origins.borrow())[v_id.index as usize].span(),
                     &format!("glb_concrete_regions invoked with \
@@ -871,8 +870,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                 // than the scope `s_id`, then we can say that the GLB
                 // is the scope `s_id`.  Otherwise, as we do not know
                 // big the free region is precisely, the GLB is undefined.
-                let fr_scope = fr.scope.to_code_extent();
-                if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope ||
+                if self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) == fr.scope ||
                         free_regions.is_static(fr) {
                     Ok(s)
                 } else {
@@ -890,8 +888,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
 
             // For these types, we cannot define any additional
             // relationship:
-            (ReInfer(ReSkolemized(..)), _) |
-            (_, ReInfer(ReSkolemized(..))) => {
+            (ReSkolemized(..), _) |
+            (_, ReSkolemized(..)) => {
                 if a == b {
                     Ok(a)
                 } else {
@@ -927,8 +925,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                 Ok(ty::ReFree(*b))
             } else {
                 this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
-                                      a.scope.to_code_extent(),
-                                      b.scope.to_code_extent())
+                                      a.scope, b.scope)
             }
         }
     }
@@ -1632,7 +1629,7 @@ impl<'tcx> fmt::Debug for Verify<'tcx> {
 
 fn normalize(values: &Vec<VarValue>, r: ty::Region) -> ty::Region {
     match r {
-        ty::ReInfer(ReVar(rid)) => lookup(values, rid),
+        ty::ReVar(rid) => lookup(values, rid),
         _ => r
     }
 }
diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs
index 39807002b58..9cc9f148ce1 100644
--- a/src/librustc/middle/infer/resolve.rs
+++ b/src/librustc/middle/infer/resolve.rs
@@ -106,7 +106,7 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
 
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         match r {
-          ty::ReInfer(ty::ReVar(rid)) => self.infcx.region_vars.resolve_var(rid),
+          ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid),
           _ => r,
         }
     }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 87b8e72f56f..e1866d878bd 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -111,7 +111,6 @@ use self::VarKind::*;
 
 use middle::def::*;
 use middle::pat_util;
-use middle::region;
 use middle::ty;
 use lint;
 use util::nodemap::NodeMap;
@@ -1509,7 +1508,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         // within the fn body, late-bound regions are liberated:
         let fn_ret =
             self.ir.tcx.liberate_late_bound_regions(
-                region::DestructionScopeData::new(body.id),
+                self.ir.tcx.region_maps.item_extent(body.id),
                 &self.fn_ret(id));
 
         match fn_ret {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 0cab4b610be..a9914073102 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -77,7 +77,6 @@ use middle::def_id::DefId;
 use middle::infer;
 use middle::check_const;
 use middle::def;
-use middle::region;
 use middle::ty::{self, Ty};
 
 use syntax::ast::{MutImmutable, MutMutable};
@@ -749,7 +748,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
             // The environment of a closure is guaranteed to
             // outlive any bindings introduced in the body of the
             // closure itself.
-            scope: region::DestructionScopeData::new(fn_body_id),
+            scope: self.tcx().region_maps.item_extent(fn_body_id),
             bound_region: ty::BrEnv
         });
 
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index dafc1e900f3..37b9d8aa645 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -20,16 +20,27 @@ use ast_map;
 use metadata::inline::InlinedItem;
 use middle::ty::{self, Ty};
 use session::Session;
-use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
+use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
 
 use std::cell::RefCell;
+use std::collections::hash_map::Entry;
+use std::mem;
 use syntax::codemap::{self, Span};
 use syntax::{ast, visit};
 use syntax::ast::{Block, Item, FnDecl, NodeId, Arm, Pat, Stmt, Expr, Local};
 use syntax::ast_util::stmt_id;
-use syntax::ptr::P;
 use syntax::visit::{Visitor, FnKind};
 
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
+           RustcDecodable, Debug, Copy)]
+pub struct CodeExtent(u32);
+
+/// The root of everything. I should be using NonZero or profiling
+/// instead of this (probably).
+pub const ROOT_CODE_EXTENT : CodeExtent = CodeExtent(0);
+/// A placeholder used in trans to stand for real code extents
+pub const DUMMY_CODE_EXTENT : CodeExtent = CodeExtent(1);
+
 /// CodeExtent represents a statically-describable extent that can be
 /// used to bound the lifetime/region for values.
 ///
@@ -91,9 +102,8 @@ use syntax::visit::{Visitor, FnKind};
 /// placate the same deriving in `ty::FreeRegion`, but we may want to
 /// actually attach a more meaningful ordering to scopes than the one
 /// generated via deriving here.
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
-           RustcDecodable, Debug, Copy)]
-pub enum CodeExtent {
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy)]
+pub enum CodeExtentData {
     Misc(ast::NodeId),
 
     // extent of parameters passed to a function or closure (they
@@ -118,8 +128,9 @@ impl DestructionScopeData {
     pub fn new(node_id: ast::NodeId) -> DestructionScopeData {
         DestructionScopeData { node_id: node_id }
     }
-    pub fn to_code_extent(&self) -> CodeExtent {
-        CodeExtent::DestructionScope(self.node_id)
+    pub fn to_code_extent(&self, region_maps: &RegionMaps) -> CodeExtent {
+        region_maps.lookup_code_extent(
+            CodeExtentData::DestructionScope(self.node_id))
     }
 }
 
@@ -134,9 +145,9 @@ impl DestructionScopeData {
 /// * 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 `CodeExtent::Remainder`,
+///   includes EXPR_1 as well, then do not use `CodeExtentData::Remainder`,
 ///   but instead another `CodeExtent` that encompasses the whole block,
-///   e.g. `CodeExtent::Misc`.
+///   e.g. `CodeExtentData::Misc`.
 ///
 /// * the subscope with `first_statement_index == 1` is scope of `c`,
 ///   and thus does not include EXPR_2, but covers the `...`.
@@ -144,61 +155,52 @@ impl DestructionScopeData {
          RustcDecodable, Debug, Copy)]
 pub struct BlockRemainder {
     pub block: ast::NodeId,
-    pub first_statement_index: usize,
+    pub first_statement_index: u32,
 }
 
-impl CodeExtent {
-    /// Creates a scope that represents the dynamic extent associated
-    /// with `node_id`.
-    pub fn from_node_id(node_id: ast::NodeId) -> CodeExtent {
-        CodeExtent::Misc(node_id)
-    }
-
+impl CodeExtentData {
     /// 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 {
-            CodeExtent::Misc(node_id) => node_id,
+            CodeExtentData::Misc(node_id) => node_id,
 
             // These cases all return rough approximations to the
             // precise extent denoted by `self`.
-            CodeExtent::Remainder(br) => br.block,
-            CodeExtent::DestructionScope(node_id) => node_id,
-            CodeExtent::ParameterScope { fn_id: _, body_id } => body_id,
+            CodeExtentData::Remainder(br) => br.block,
+            CodeExtentData::DestructionScope(node_id) => node_id,
+            CodeExtentData::ParameterScope { fn_id: _, body_id } => body_id,
         }
     }
+}
 
-    /// Maps this scope to a potentially new one according to the
-    /// NodeId transformer `f_id`.
-    pub fn map_id<F>(&self, mut f_id: F) -> CodeExtent where
-        F: FnMut(ast::NodeId) -> ast::NodeId,
-    {
-        match *self {
-            CodeExtent::Misc(node_id) => CodeExtent::Misc(f_id(node_id)),
-            CodeExtent::Remainder(br) =>
-                CodeExtent::Remainder(BlockRemainder {
-                    block: f_id(br.block), first_statement_index: br.first_statement_index }),
-            CodeExtent::DestructionScope(node_id) =>
-                CodeExtent::DestructionScope(f_id(node_id)),
-            CodeExtent::ParameterScope { fn_id, body_id } =>
-                CodeExtent::ParameterScope { fn_id: f_id(fn_id), body_id: f_id(body_id) },
+impl CodeExtent {
+    #[inline]
+    fn into_option(self) -> Option<CodeExtent> {
+        if self == ROOT_CODE_EXTENT {
+            None
+        } else {
+            Some(self)
         }
     }
+    pub fn node_id(&self, region_maps: &RegionMaps) -> ast::NodeId {
+        region_maps.code_extent_data(*self).node_id()
+    }
 
     /// Returns the span of this CodeExtent.  Note that in general the
     /// returned span may not correspond to the span of any node id in
     /// the AST.
-    pub fn span(&self, ast_map: &ast_map::Map) -> Option<Span> {
-        match ast_map.find(self.node_id()) {
+    pub fn span(&self, region_maps: &RegionMaps, ast_map: &ast_map::Map) -> Option<Span> {
+        match ast_map.find(self.node_id(region_maps)) {
             Some(ast_map::NodeBlock(ref blk)) => {
-                match *self {
-                    CodeExtent::ParameterScope { .. } |
-                    CodeExtent::Misc(_) |
-                    CodeExtent::DestructionScope(_) => Some(blk.span),
+                match region_maps.code_extent_data(*self) {
+                    CodeExtentData::ParameterScope { .. } |
+                    CodeExtentData::Misc(_) |
+                    CodeExtentData::DestructionScope(_) => Some(blk.span),
 
-                    CodeExtent::Remainder(r) => {
+                    CodeExtentData::Remainder(r) => {
                         assert_eq!(r.block, blk.id);
                         // Want span for extent starting after the
                         // indexed statement and ending at end of
@@ -207,7 +209,7 @@ impl CodeExtent {
                         //
                         // (This is the special case aluded to in the
                         // doc-comment for this method)
-                        let stmt_span = blk.stmts[r.first_statement_index].span;
+                        let stmt_span = blk.stmts[r.first_statement_index as usize].span;
                         Some(Span { lo: stmt_span.hi, ..blk.span })
                     }
                 }
@@ -222,13 +224,15 @@ impl CodeExtent {
 
 /// The region maps encode information about region relationships.
 pub struct RegionMaps {
+    code_extents: RefCell<Vec<CodeExtentData>>,
+    code_extent_interner: RefCell<FnvHashMap<CodeExtentData, CodeExtent>>,
     /// `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: RefCell<FnvHashMap<CodeExtent, CodeExtent>>,
+    scope_map: RefCell<Vec<CodeExtent>>,
 
     /// `var_map` maps from a variable or binding id to the block in
     /// which that variable is declared.
@@ -242,26 +246,6 @@ pub struct RegionMaps {
     /// block (see `terminating_scopes`).
     rvalue_scopes: RefCell<NodeMap<CodeExtent>>,
 
-    /// `terminating_scopes` is a set containing the ids of each
-    /// statement, or conditional/repeating expression. These scopes
-    /// are calling "terminating scopes" because, when attempting to
-    /// find the scope of a temporary, by default we search up the
-    /// enclosing scopes until we encounter the terminating scope. A
-    /// conditional/repeating expression is one which is not
-    /// guaranteed to execute exactly once upon entering the parent
-    /// scope. This could be because the expression only executes
-    /// conditionally, such as the expression `b` in `a && b`, or
-    /// because the expression may execute many times, such as a loop
-    /// body. The reason that we distinguish such expressions is that,
-    /// upon exiting the parent scope, we cannot statically know how
-    /// many times the expression executed, and thus if the expression
-    /// creates temporaries we cannot know statically how many such
-    /// temporaries we would have to cleanup. Therefore we ensure that
-    /// the temporaries never outlast the conditional/repeating
-    /// expression, preventing the need for dynamic checks and/or
-    /// arbitrary amounts of stack space.
-    terminating_scopes: RefCell<FnvHashSet<CodeExtent>>,
-
     /// Encodes the hierarchy of fn bodies. Every fn body (including
     /// closures) forms its own distinct region hierarchy, rooted in
     /// the block that is the fn body. This map points from the id of
@@ -275,75 +259,6 @@ pub struct RegionMaps {
     fn_tree: RefCell<NodeMap<ast::NodeId>>,
 }
 
-/// Carries the node id for the innermost block or match expression,
-/// for building up the `var_map` which maps ids to the blocks in
-/// which they were declared.
-#[derive(PartialEq, Eq, Debug, Copy, Clone)]
-enum InnermostDeclaringBlock {
-    None,
-    Block(ast::NodeId),
-    Statement(DeclaringStatementContext),
-    Match(ast::NodeId),
-    FnDecl { fn_id: ast::NodeId, body_id: ast::NodeId },
-}
-
-impl InnermostDeclaringBlock {
-    fn to_code_extent(&self) -> Option<CodeExtent> {
-        let extent = match *self {
-            InnermostDeclaringBlock::None => {
-                return Option::None;
-            }
-            InnermostDeclaringBlock::FnDecl { fn_id, body_id } =>
-                CodeExtent::ParameterScope { fn_id: fn_id, body_id: body_id },
-            InnermostDeclaringBlock::Block(id) |
-            InnermostDeclaringBlock::Match(id) => CodeExtent::from_node_id(id),
-            InnermostDeclaringBlock::Statement(s) =>  s.to_code_extent(),
-        };
-        Option::Some(extent)
-    }
-}
-
-/// Contextual information for declarations introduced by a statement
-/// (i.e. `let`). It carries node-id's for statement and enclosing
-/// block both, as well as the statement's index within the block.
-#[derive(PartialEq, Eq, Debug, Copy, Clone)]
-struct DeclaringStatementContext {
-    stmt_id: ast::NodeId,
-    block_id: ast::NodeId,
-    stmt_index: usize,
-}
-
-impl DeclaringStatementContext {
-    fn to_code_extent(&self) -> CodeExtent {
-        CodeExtent::Remainder(BlockRemainder {
-            block: self.block_id,
-            first_statement_index: self.stmt_index,
-        })
-    }
-}
-
-#[derive(PartialEq, Eq, Debug, Copy, Clone)]
-enum InnermostEnclosingExpr {
-    None,
-    Some(ast::NodeId),
-    Statement(DeclaringStatementContext),
-}
-
-impl InnermostEnclosingExpr {
-    fn to_code_extent(&self) -> Option<CodeExtent> {
-        let extent = match *self {
-            InnermostEnclosingExpr::None => {
-                return Option::None;
-            }
-            InnermostEnclosingExpr::Statement(s) =>
-                s.to_code_extent(),
-            InnermostEnclosingExpr::Some(parent_id) =>
-                CodeExtent::from_node_id(parent_id),
-        };
-        Some(extent)
-    }
-}
-
 #[derive(Debug, Copy, Clone)]
 pub struct Context {
     /// the root of the current region tree. This is typically the id
@@ -355,10 +270,10 @@ pub struct Context {
     root_id: Option<ast::NodeId>,
 
     /// the scope that contains any new variables declared
-    var_parent: InnermostDeclaringBlock,
+    var_parent: CodeExtent,
 
     /// region parent of expressions etc
-    parent: InnermostEnclosingExpr,
+    parent: CodeExtent
 }
 
 struct RegionResolutionVisitor<'a> {
@@ -367,14 +282,98 @@ struct RegionResolutionVisitor<'a> {
     // Generated maps:
     region_maps: &'a RegionMaps,
 
-    cx: Context
+    cx: Context,
+
+    /// `terminating_scopes` is a set containing the ids of each
+    /// statement, or conditional/repeating expression. These scopes
+    /// are calling "terminating scopes" because, when attempting to
+    /// find the scope of a temporary, by default we search up the
+    /// enclosing scopes until we encounter the terminating scope. A
+    /// conditional/repeating expression is one which is not
+    /// guaranteed to execute exactly once upon entering the parent
+    /// scope. This could be because the expression only executes
+    /// conditionally, such as the expression `b` in `a && b`, or
+    /// because the expression may execute many times, such as a loop
+    /// body. The reason that we distinguish such expressions is that,
+    /// upon exiting the parent scope, we cannot statically know how
+    /// many times the expression executed, and thus if the expression
+    /// creates temporaries we cannot know statically how many such
+    /// temporaries we would have to cleanup. Therefore we ensure that
+    /// the temporaries never outlast the conditional/repeating
+    /// expression, preventing the need for dynamic checks and/or
+    /// arbitrary amounts of stack space. Terminating scopes end
+    /// up being contained in a DestructionScope that contains the
+    /// destructor's execution.
+    terminating_scopes: NodeSet
 }
 
 
 impl RegionMaps {
+    /// create a bogus code extent for the regions in astencode types. Nobody
+    /// really cares about the contents of these.
+    pub fn bogus_code_extent(&self, e: CodeExtentData) -> CodeExtent {
+        self.intern_code_extent(e, DUMMY_CODE_EXTENT)
+    }
+    pub fn lookup_code_extent(&self, e: CodeExtentData) -> CodeExtent {
+        self.code_extent_interner.borrow()[&e]
+    }
+    pub fn node_extent(&self, n: ast::NodeId) -> CodeExtent {
+        self.lookup_code_extent(CodeExtentData::Misc(n))
+    }
+    // Returns the code extent for an item - the destruction scope.
+    pub fn item_extent(&self, n: ast::NodeId) -> CodeExtent {
+        self.lookup_code_extent(CodeExtentData::DestructionScope(n))
+    }
+    pub fn intern_code_extent(&self,
+                              e: CodeExtentData,
+                              parent: CodeExtent) -> CodeExtent {
+        match self.code_extent_interner.borrow_mut().entry(e) {
+            Entry::Occupied(o) => {
+                // this can happen when the bogus code extents from tydecode
+                // have (bogus) NodeId-s that overlap items created during
+                // inlining.
+                // We probably shouldn't be creating bogus code extents
+                // though.
+                let idx = *o.get();
+                if parent == DUMMY_CODE_EXTENT {
+                    info!("CodeExtent({}) = {:?} [parent={}] BOGUS!",
+                          idx.0, e, parent.0);
+                } else {
+                    assert_eq!(self.scope_map.borrow()[idx.0 as usize],
+                               DUMMY_CODE_EXTENT);
+                    info!("CodeExtent({}) = {:?} [parent={}] RECLAIMED!",
+                          idx.0, e, parent.0);
+                    self.scope_map.borrow_mut()[idx.0 as usize] = parent;
+                }
+                idx
+            }
+            Entry::Vacant(v) => {
+                if self.code_extents.borrow().len() > 0xffffffffusize {
+                    unreachable!() // should pass a sess,
+                                   // but this isn't the only place
+                }
+                let idx = CodeExtent(self.code_extents.borrow().len() as u32);
+                info!("CodeExtent({}) = {:?} [parent={}]", idx.0, e, parent.0);
+                self.code_extents.borrow_mut().push(e);
+                self.scope_map.borrow_mut().push(parent);
+                *v.insert(idx)
+            }
+        }
+    }
+    pub fn intern_node(&self,
+                       n: ast::NodeId,
+                       parent: CodeExtent) -> CodeExtent {
+        self.intern_code_extent(CodeExtentData::Misc(n), parent)
+    }
+    pub fn code_extent_data(&self, e: CodeExtent) -> CodeExtentData {
+        self.code_extents.borrow()[e.0 as usize]
+    }
     pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(&CodeExtent, &CodeExtent) {
-        for (child, parent) in self.scope_map.borrow().iter() {
-            e(child, parent)
+        for child_id in (1..self.code_extents.borrow().len()) {
+            let child = CodeExtent(child_id as u32);
+            if let Some(parent) = self.opt_encl_scope(child) {
+                e(&child, &parent)
+            }
         }
     }
     pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExtent) {
@@ -387,12 +386,6 @@ impl RegionMaps {
             e(child, parent)
         }
     }
-    pub fn each_terminating_scope<E>(&self, mut e:E) where E: FnMut(&CodeExtent) {
-        for scope in self.terminating_scopes.borrow().iter() {
-            e(scope)
-        }
-    }
-
     /// Records that `sub_fn` is defined within `sup_fn`. These ids
     /// should be the id of the block that is the fn body, which is
     /// also the root of the region hierarchy for that fn.
@@ -414,44 +407,27 @@ impl RegionMaps {
         }
     }
 
-    pub fn record_encl_scope(&self, sub: CodeExtent, sup: CodeExtent) {
-        debug!("record_encl_scope(sub={:?}, sup={:?})", sub, sup);
-        assert!(sub != sup);
-        self.scope_map.borrow_mut().insert(sub, sup);
-    }
-
     fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
         debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
-        assert!(var != lifetime.node_id());
+        assert!(var != lifetime.node_id(self));
         self.var_map.borrow_mut().insert(var, lifetime);
     }
 
     fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
         debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
-        assert!(var != lifetime.node_id());
+        assert!(var != lifetime.node_id(self));
         self.rvalue_scopes.borrow_mut().insert(var, lifetime);
     }
 
-    /// Records that a scope is a TERMINATING SCOPE. Whenever we create automatic temporaries --
-    /// e.g. by an expression like `a().f` -- they will be freed within the innermost terminating
-    /// scope.
-    fn mark_as_terminating_scope(&self, scope_id: CodeExtent) {
-        debug!("record_terminating_scope(scope_id={:?})", scope_id);
-        self.terminating_scopes.borrow_mut().insert(scope_id);
-    }
-
     pub fn opt_encl_scope(&self, id: CodeExtent) -> Option<CodeExtent> {
         //! Returns the narrowest scope that encloses `id`, if any.
-        self.scope_map.borrow().get(&id).cloned()
+        self.scope_map.borrow()[id.0 as usize].into_option()
     }
 
     #[allow(dead_code)] // used in middle::cfg
     pub fn encl_scope(&self, id: CodeExtent) -> CodeExtent {
         //! Returns the narrowest scope that encloses `id`, if any.
-        match self.scope_map.borrow().get(&id) {
-            Some(&r) => r,
-            None => { panic!("no enclosing scope for id {:?}", id); }
-        }
+        self.opt_encl_scope(id).unwrap()
     }
 
     /// Returns the lifetime of the local variable `var_id`
@@ -474,28 +450,33 @@ impl RegionMaps {
             None => { }
         }
 
+        let scope_map : &[CodeExtent] = &self.scope_map.borrow();
+        let code_extents: &[CodeExtentData] = &self.code_extents.borrow();
+
         // else, locate the innermost terminating scope
         // if there's one. Static items, for instance, won't
         // have an enclosing scope, hence no scope will be
         // returned.
-        let mut id = match self.opt_encl_scope(CodeExtent::from_node_id(expr_id)) {
+        let expr_extent = self.node_extent(expr_id);
+        // For some reason, the expr's scope itself is skipped here.
+        let mut id = match scope_map[expr_extent.0 as usize].into_option() {
             Some(i) => i,
-            None => { return None; }
+            _ => return None
         };
 
-        while !self.terminating_scopes.borrow().contains(&id) {
-            match self.opt_encl_scope(id) {
-                Some(p) => {
-                    id = p;
-                }
-                None => {
-                    debug!("temporary_scope({:?}) = None", expr_id);
-                    return None;
+        while let Some(p) = scope_map[id.0 as usize].into_option() {
+            match code_extents[p.0 as usize] {
+                CodeExtentData::DestructionScope(..) => {
+                    debug!("temporary_scope({:?}) = {:?} [enclosing]",
+                           expr_id, id);
+                    return Some(id);
                 }
+                _ => id = p
             }
         }
-        debug!("temporary_scope({:?}) = {:?} [enclosing]", expr_id, id);
-        return Some(id);
+
+        debug!("temporary_scope({:?}) = None", expr_id);
+        return None;
     }
 
     pub fn var_region(&self, id: ast::NodeId) -> ty::Region {
@@ -519,15 +500,15 @@ impl RegionMaps {
                           superscope: CodeExtent)
                           -> bool {
         let mut s = subscope;
+        debug!("is_subscope_of({:?}, {:?})", subscope, superscope);
         while superscope != s {
-            match self.scope_map.borrow().get(&s) {
+            match self.opt_encl_scope(s) {
                 None => {
                     debug!("is_subscope_of({:?}, {:?}, s={:?})=false",
                            subscope, superscope, s);
-
                     return false;
                 }
-                Some(&scope) => s = scope
+                Some(scope) => s = scope
             }
         }
 
@@ -545,8 +526,15 @@ impl RegionMaps {
                                    -> CodeExtent {
         if scope_a == scope_b { return scope_a; }
 
-        let a_ancestors = ancestors_of(self, scope_a);
-        let b_ancestors = ancestors_of(self, scope_b);
+        let mut a_buf: [CodeExtent; 32] = [ROOT_CODE_EXTENT; 32];
+        let mut a_vec: Vec<CodeExtent> = vec![];
+        let mut b_buf: [CodeExtent; 32] = [ROOT_CODE_EXTENT; 32];
+        let mut b_vec: Vec<CodeExtent> = vec![];
+        let scope_map : &[CodeExtent] = &self.scope_map.borrow();
+        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);
         let mut a_index = a_ancestors.len() - 1;
         let mut b_index = b_ancestors.len() - 1;
 
@@ -564,11 +552,11 @@ impl RegionMaps {
             // nesting. The reasoning behind this is subtle.  See the
             // "Modeling closures" section of the README in
             // middle::infer::region_inference for more details.
-            let a_root_scope = a_ancestors[a_index];
-            let b_root_scope = a_ancestors[a_index];
+            let a_root_scope = self.code_extent_data(a_ancestors[a_index]);
+            let b_root_scope = self.code_extent_data(a_ancestors[a_index]);
             return match (a_root_scope, b_root_scope) {
-                (CodeExtent::DestructionScope(a_root_id),
-                 CodeExtent::DestructionScope(b_root_id)) => {
+                (CodeExtentData::DestructionScope(a_root_id),
+                 CodeExtentData::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
@@ -599,47 +587,48 @@ impl RegionMaps {
             }
         }
 
-        fn ancestors_of(this: &RegionMaps, scope: CodeExtent) -> Vec<CodeExtent> {
+        fn ancestors_of<'a>(scope_map: &[CodeExtent],
+                            scope: CodeExtent,
+                            buf: &'a mut [CodeExtent; 32],
+                            vec: &'a mut Vec<CodeExtent>) -> &'a [CodeExtent] {
             // debug!("ancestors_of(scope={:?})", scope);
-            let mut result = vec!(scope);
             let mut scope = scope;
+
+            let mut i = 0;
+            while i < 32 {
+                buf[i] = scope;
+                match scope_map[scope.0 as usize].into_option() {
+                    Some(superscope) => scope = superscope,
+                    _ => return &buf[..i+1]
+                }
+                i += 1;
+            }
+
+            *vec = Vec::with_capacity(64);
+            vec.push_all(buf);
             loop {
-                match this.scope_map.borrow().get(&scope) {
-                    None => return result,
-                    Some(&superscope) => {
-                        result.push(superscope);
-                        scope = superscope;
-                    }
+                vec.push(scope);
+                match scope_map[scope.0 as usize].into_option() {
+                    Some(superscope) => scope = superscope,
+                    _ => return &*vec
                 }
-                // debug!("ancestors_of_loop(scope={:?})", scope);
             }
         }
     }
 }
 
-/// Records the current parent (if any) as the parent of `child_scope`.
-fn record_superlifetime(visitor: &mut RegionResolutionVisitor,
-                        child_scope: CodeExtent,
-                        _sp: Span) {
-    match visitor.cx.parent.to_code_extent() {
-        Some(parent_scope) =>
-            visitor.region_maps.record_encl_scope(child_scope, parent_scope),
-        None => {}
-    }
-}
-
 /// Records the lifetime of a local variable as `cx.var_parent`
 fn record_var_lifetime(visitor: &mut RegionResolutionVisitor,
                        var_id: ast::NodeId,
                        _sp: Span) {
-    match visitor.cx.var_parent.to_code_extent() {
-        Some(parent_scope) =>
-            visitor.region_maps.record_var_scope(var_id, parent_scope),
-        None => {
+    match visitor.cx.var_parent {
+        ROOT_CODE_EXTENT => {
             // this can happen in extern fn declarations like
             //
             // extern fn isalnum(c: c_int) -> c_int
         }
+        parent_scope =>
+            visitor.region_maps.record_var_scope(var_id, parent_scope),
     }
 }
 
@@ -647,21 +636,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
     debug!("resolve_block(blk.id={:?})", blk.id);
 
     let prev_cx = visitor.cx;
-
-    let blk_scope = CodeExtent::Misc(blk.id);
-
-    // If block 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 the the block itself
-    // completes.
-    if visitor.region_maps.terminating_scopes.borrow().contains(&blk_scope) {
-        let dtor_scope = CodeExtent::DestructionScope(blk.id);
-        record_superlifetime(visitor, dtor_scope, blk.span);
-        visitor.region_maps.record_encl_scope(blk_scope, dtor_scope);
-    } else {
-        record_superlifetime(visitor, blk_scope, blk.span);
-    }
+    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
@@ -690,35 +665,34 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
 
     visitor.cx = Context {
         root_id: prev_cx.root_id,
-        var_parent: InnermostDeclaringBlock::Block(blk.id),
-        parent: InnermostEnclosingExpr::Some(blk.id),
+        var_parent: block_extent,
+        parent: block_extent,
     };
 
     {
         // This block should be kept approximately in sync with
         // `visit::walk_block`. (We manually walk the block, rather
         // than call `walk_block`, in order to maintain precise
-        // `InnermostDeclaringBlock` information.)
+        // index information.)
 
         for (i, statement) in blk.stmts.iter().enumerate() {
-            if let ast::StmtDecl(_, stmt_id) = statement.node {
+            if let ast::StmtDecl(..) = statement.node {
                 // Each StmtDecl introduces a subscope for bindings
                 // introduced by the declaration; this subscope covers
                 // a suffix of the block . Each subscope in a block
                 // 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 declaring = DeclaringStatementContext {
-                    stmt_id: stmt_id,
-                    block_id: blk.id,
-                    stmt_index: i,
-                };
-                record_superlifetime(
-                    visitor, declaring.to_code_extent(), statement.span);
+                let stmt_extent = visitor.new_code_extent(
+                    CodeExtentData::Remainder(BlockRemainder {
+                        block: blk.id,
+                        first_statement_index: i as u32
+                    })
+                );
                 visitor.cx = Context {
                     root_id: prev_cx.root_id,
-                    var_parent: InnermostDeclaringBlock::Statement(declaring),
-                    parent: InnermostEnclosingExpr::Statement(declaring),
+                    var_parent: stmt_extent,
+                    parent: stmt_extent,
                 };
             }
             visitor.visit_stmt(&**statement)
@@ -730,22 +704,17 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
 }
 
 fn resolve_arm(visitor: &mut RegionResolutionVisitor, arm: &ast::Arm) {
-    let arm_body_scope = CodeExtent::from_node_id(arm.body.id);
-    visitor.region_maps.mark_as_terminating_scope(arm_body_scope);
+    visitor.terminating_scopes.insert(arm.body.id);
 
-    match arm.guard {
-        Some(ref expr) => {
-            let guard_scope = CodeExtent::from_node_id(expr.id);
-            visitor.region_maps.mark_as_terminating_scope(guard_scope);
-        }
-        None => { }
+    if let Some(ref expr) = arm.guard {
+        visitor.terminating_scopes.insert(expr.id);
     }
 
     visit::walk_arm(visitor, arm);
 }
 
 fn resolve_pat(visitor: &mut RegionResolutionVisitor, pat: &ast::Pat) {
-    record_superlifetime(visitor, CodeExtent::from_node_id(pat.id), pat.span);
+    visitor.new_node_extent(pat.id);
 
     // If this is a binding (or maybe a binding, I'm too lazy to check
     // the def map) then record the lifetime of that binding.
@@ -763,20 +732,16 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) {
     let stmt_id = stmt_id(stmt);
     debug!("resolve_stmt(stmt.id={:?})", stmt_id);
 
-    let stmt_scope = CodeExtent::from_node_id(stmt_id);
-
     // Every statement will clean up the temporaries created during
     // execution of that statement. Therefore each statement has an
     // associated destruction scope that represents the extent of the
     // statement plus its destructors, and thus the extent for which
     // regions referenced by the destructors need to survive.
-    visitor.region_maps.mark_as_terminating_scope(stmt_scope);
-    let dtor_scope = CodeExtent::DestructionScope(stmt_id);
-    visitor.region_maps.record_encl_scope(stmt_scope, dtor_scope);
-    record_superlifetime(visitor, dtor_scope, stmt.span);
+    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 = InnermostEnclosingExpr::Some(stmt_id);
+    visitor.cx.parent = stmt_extent;
     visit::walk_stmt(visitor, stmt);
     visitor.cx.parent = prev_parent;
 }
@@ -784,32 +749,14 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) {
 fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) {
     debug!("resolve_expr(expr.id={:?})", expr.id);
 
-    let expr_scope = CodeExtent::Misc(expr.id);
-    // If expr 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 the the expression
-    // itself completes.
-    if visitor.region_maps.terminating_scopes.borrow().contains(&expr_scope) {
-        let dtor_scope = CodeExtent::DestructionScope(expr.id);
-        record_superlifetime(visitor, dtor_scope, expr.span);
-        visitor.region_maps.record_encl_scope(expr_scope, dtor_scope);
-    } else {
-        record_superlifetime(visitor, expr_scope, expr.span);
-    }
-
+    let expr_extent = visitor.new_node_extent_with_dtor(expr.id);
     let prev_cx = visitor.cx;
-    visitor.cx.parent = InnermostEnclosingExpr::Some(expr.id);
+    visitor.cx.parent = expr_extent;
 
     {
-        let region_maps = &mut visitor.region_maps;
-        let terminating = |e: &P<ast::Expr>| {
-            let scope = CodeExtent::from_node_id(e.id);
-            region_maps.mark_as_terminating_scope(scope)
-        };
-        let terminating_block = |b: &P<ast::Block>| {
-            let scope = CodeExtent::from_node_id(b.id);
-            region_maps.mark_as_terminating_scope(scope)
+        let terminating_scopes = &mut visitor.terminating_scopes;
+        let mut terminating = |id: ast::NodeId| {
+            terminating_scopes.insert(id);
         };
         match expr.node {
             // Conditional or repeating scopes are always terminating
@@ -820,30 +767,30 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) {
             ast::ExprBinary(codemap::Spanned { node: ast::BiOr, .. }, _, ref r) => {
                 // For shortcircuiting operators, mark the RHS as a terminating
                 // scope since it only executes conditionally.
-                terminating(r);
+                terminating(r.id);
             }
 
             ast::ExprIf(_, ref then, Some(ref otherwise)) => {
-                terminating_block(then);
-                terminating(otherwise);
+                terminating(then.id);
+                terminating(otherwise.id);
             }
 
             ast::ExprIf(ref expr, ref then, None) => {
-                terminating(expr);
-                terminating_block(then);
+                terminating(expr.id);
+                terminating(then.id);
             }
 
             ast::ExprLoop(ref body, _) => {
-                terminating_block(body);
+                terminating(body.id);
             }
 
             ast::ExprWhile(ref expr, ref body, _) => {
-                terminating(expr);
-                terminating_block(body);
+                terminating(expr.id);
+                terminating(body.id);
             }
 
             ast::ExprMatch(..) => {
-                visitor.cx.var_parent = InnermostDeclaringBlock::Match(expr.id);
+                visitor.cx.var_parent = expr_extent;
             }
 
             ast::ExprAssignOp(..) | ast::ExprIndex(..) |
@@ -883,10 +830,8 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) {
     // For convenience in trans, associate with the local-id the var
     // scope that will be used for any bindings declared in this
     // pattern.
-    let blk_scope = visitor.cx.var_parent.to_code_extent()
-        .unwrap_or_else(|| visitor.sess.span_bug(
-            local.span, "local without enclosing block"));
-
+    let blk_scope = visitor.cx.var_parent;
+    assert!(blk_scope != ROOT_CODE_EXTENT); // locals must be within a block
     visitor.region_maps.record_var_scope(local.id, blk_scope);
 
     // As an exception to the normal rules governing temporary
@@ -1109,13 +1054,16 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) {
 fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &ast::Item) {
     // Items create a new outer block scope as far as we're concerned.
     let prev_cx = visitor.cx;
+    let prev_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
     visitor.cx = Context {
         root_id: None,
-        var_parent: InnermostDeclaringBlock::None,
-        parent: InnermostEnclosingExpr::None
+        var_parent: ROOT_CODE_EXTENT,
+        parent: ROOT_CODE_EXTENT
     };
     visit::walk_item(visitor, item);
+    visitor.create_item_scope_if_needed(item.id);
     visitor.cx = prev_cx;
+    visitor.terminating_scopes = prev_ts;
 }
 
 fn resolve_fn(visitor: &mut RegionResolutionVisitor,
@@ -1133,51 +1081,76 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
            body.id,
            visitor.cx.parent);
 
-    // This scope covers the function body, which includes the
-    // bindings introduced by let statements as well as temporaries
-    // created by the fn's tail expression (if any). It does *not*
-    // include the fn parameters (see below).
-    let body_scope = CodeExtent::from_node_id(body.id);
-    visitor.region_maps.mark_as_terminating_scope(body_scope);
-
-    let dtor_scope = CodeExtent::DestructionScope(body.id);
-    visitor.region_maps.record_encl_scope(body_scope, dtor_scope);
-
-    let fn_decl_scope = CodeExtent::ParameterScope { fn_id: id, body_id: body.id };
-    visitor.region_maps.record_encl_scope(dtor_scope, fn_decl_scope);
-
-    record_superlifetime(visitor, fn_decl_scope, body.span);
+    let fn_decl_scope = visitor.new_code_extent(
+        CodeExtentData::ParameterScope { fn_id: id, body_id: body.id });
 
     if let Some(root_id) = visitor.cx.root_id {
         visitor.region_maps.record_fn_parent(body.id, root_id);
     }
 
     let outer_cx = visitor.cx;
+    let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
+    visitor.terminating_scopes.insert(body.id);
 
     // The arguments and `self` are parented to the fn.
     visitor.cx = Context {
         root_id: Some(body.id),
-        parent: InnermostEnclosingExpr::None,
-        var_parent: InnermostDeclaringBlock::FnDecl {
-            fn_id: id, body_id: body.id
-        },
+        parent: ROOT_CODE_EXTENT,
+        var_parent: fn_decl_scope,
     };
+
     visit::walk_fn_decl(visitor, decl);
 
     // The body of the every fn is a root scope.
     visitor.cx = Context {
         root_id: Some(body.id),
-        parent: InnermostEnclosingExpr::None,
-        var_parent: InnermostDeclaringBlock::None
+        parent: fn_decl_scope,
+        var_parent: fn_decl_scope
     };
     visitor.visit_block(body);
 
     // Restore context we had at the start.
     visitor.cx = outer_cx;
+    visitor.terminating_scopes = outer_ts;
 }
 
-impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
+impl<'a> RegionResolutionVisitor<'a> {
+    /// Records the current parent (if any) as the parent of `child_scope`.
+    fn new_code_extent(&mut self, child_scope: CodeExtentData) -> CodeExtent {
+        self.region_maps.intern_code_extent(child_scope, self.cx.parent)
+    }
 
+    fn new_node_extent(&mut self, child_scope: ast::NodeId) -> CodeExtent {
+        self.new_code_extent(CodeExtentData::Misc(child_scope))
+    }
+
+    fn new_node_extent_with_dtor(&mut self, id: ast::NodeId) -> CodeExtent {
+        // 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.region_maps.intern_node(id, ds)
+        } else {
+            self.new_node_extent(id)
+        }
+    }
+
+    fn create_item_scope_if_needed(&mut self, id: ast::NodeId) {
+        // create a region for the destruction scope - this is needed
+        // for constructing parameter environments based on the item.
+        // functions put their destruction scopes *inside* their parameter
+        // scopes.
+        let scope = CodeExtentData::DestructionScope(id);
+        if !self.region_maps.code_extent_interner.borrow().contains_key(&scope) {
+            self.region_maps.intern_code_extent(scope, ROOT_CODE_EXTENT);
+        }
+    }
+}
+
+impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
     fn visit_block(&mut self, b: &Block) {
         resolve_block(self, b);
     }
@@ -1186,6 +1159,16 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
         resolve_item(self, i);
     }
 
+    fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+        visit::walk_impl_item(self, ii);
+        self.create_item_scope_if_needed(ii.id);
+    }
+
+    fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+        visit::walk_trait_item(self, ti);
+        self.create_item_scope_if_needed(ti.id);
+    }
+
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
                 b: &'v Block, s: Span, n: NodeId) {
         resolve_fn(self, fk, fd, b, s, n);
@@ -1209,21 +1192,29 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
 
 pub fn resolve_crate(sess: &Session, krate: &ast::Crate) -> RegionMaps {
     let maps = RegionMaps {
-        scope_map: RefCell::new(FnvHashMap()),
+        code_extents: RefCell::new(vec![]),
+        code_extent_interner: RefCell::new(FnvHashMap()),
+        scope_map: RefCell::new(vec![]),
         var_map: RefCell::new(NodeMap()),
         rvalue_scopes: RefCell::new(NodeMap()),
-        terminating_scopes: RefCell::new(FnvHashSet()),
         fn_tree: RefCell::new(NodeMap()),
     };
+    let root_extent = maps.bogus_code_extent(
+        CodeExtentData::DestructionScope(ast::DUMMY_NODE_ID));
+    assert_eq!(root_extent, ROOT_CODE_EXTENT);
+    let bogus_extent = maps.bogus_code_extent(
+        CodeExtentData::Misc(ast::DUMMY_NODE_ID));
+    assert_eq!(bogus_extent, DUMMY_CODE_EXTENT);
     {
         let mut visitor = RegionResolutionVisitor {
             sess: sess,
             region_maps: &maps,
             cx: Context {
                 root_id: None,
-                parent: InnermostEnclosingExpr::None,
-                var_parent: InnermostDeclaringBlock::None,
-            }
+                parent: ROOT_CODE_EXTENT,
+                var_parent: ROOT_CODE_EXTENT
+            },
+            terminating_scopes: NodeSet()
         };
         visit::walk_crate(&mut visitor, krate);
     }
@@ -1238,9 +1229,10 @@ pub fn resolve_inlined_item(sess: &Session,
         region_maps: region_maps,
         cx: Context {
             root_id: None,
-            parent: InnermostEnclosingExpr::None,
-            var_parent: InnermostDeclaringBlock::None
-        }
+            parent: ROOT_CODE_EXTENT,
+            var_parent: ROOT_CODE_EXTENT
+        },
+        terminating_scopes: NodeSet()
     };
     item.visit(&mut visitor);
 }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 7418d81ed3d..eff560653c1 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -12,7 +12,6 @@
 #![allow(non_camel_case_types)]
 
 pub use self::InferTy::*;
-pub use self::InferRegion::*;
 pub use self::ImplOrTraitItemId::*;
 pub use self::ClosureKind::*;
 pub use self::Variance::*;
@@ -1504,7 +1503,7 @@ pub struct DebruijnIndex {
 }
 
 /// Representation of regions:
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, Copy)]
 pub enum Region {
     // Region bound in a type or fn declaration which will be
     // substituted 'early' -- that is, at the same time when type
@@ -1529,7 +1528,11 @@ pub enum Region {
     ReStatic,
 
     /// A region variable.  Should not exist after typeck.
-    ReInfer(InferRegion),
+    ReVar(RegionVid),
+
+    /// A skolemized region - basically the higher-ranked version of ReFree.
+    /// Should not exist after typeck.
+    ReSkolemized(u32, BoundRegion),
 
     /// Empty lifetime is for data that is never accessed.
     /// Bottom in the region lattice. We treat ReEmpty somewhat
@@ -1606,7 +1609,7 @@ pub enum BorrowKind {
 
 /// Information describing the capture of an upvar. This is computed
 /// during `typeck`, specifically by `regionck`.
-#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(PartialEq, Clone, Debug, Copy)]
 pub enum UpvarCapture {
     /// Upvar is captured by value. This is always true when the
     /// closure is labeled `move`, but can also be true in other cases
@@ -1617,7 +1620,7 @@ pub enum UpvarCapture {
     ByRef(UpvarBorrow),
 }
 
-#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Copy)]
+#[derive(PartialEq, Clone, Copy)]
 pub struct UpvarBorrow {
     /// The kind of borrow: by-ref upvars have access to shared
     /// immutable borrows, which are not part of the normal language
@@ -1648,7 +1651,7 @@ impl Region {
 
     pub fn needs_infer(&self) -> bool {
         match *self {
-            ty::ReInfer(..) => true,
+            ty::ReVar(..) | ty::ReSkolemized(..) => true,
             _ => false
         }
     }
@@ -1676,7 +1679,7 @@ impl Region {
 /// A "free" region `fr` can be interpreted as "some region
 /// at least as big as the scope `fr.scope`".
 pub struct FreeRegion {
-    pub scope: region::DestructionScopeData,
+    pub scope: region::CodeExtent,
     pub bound_region: BoundRegion
 }
 
@@ -2187,29 +2190,6 @@ pub enum UnconstrainedNumeric {
 }
 
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Eq, Hash, Debug, Copy)]
-pub enum InferRegion {
-    ReVar(RegionVid),
-    ReSkolemized(u32, BoundRegion)
-}
-
-impl cmp::PartialEq for InferRegion {
-    fn eq(&self, other: &InferRegion) -> bool {
-        match ((*self), *other) {
-            (ReVar(rva), ReVar(rvb)) => {
-                rva == rvb
-            }
-            (ReSkolemized(rva, _), ReSkolemized(rvb, _)) => {
-                rva == rvb
-            }
-            _ => false
-        }
-    }
-    fn ne(&self, other: &InferRegion) -> bool {
-        !((*self) == (*other))
-    }
-}
-
 impl fmt::Debug for TyVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "_#{}t", self.index)
@@ -2291,7 +2271,7 @@ pub struct TypeParameterDef<'tcx> {
     pub object_lifetime_default: ObjectLifetimeDefault,
 }
 
-#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
+#[derive(Clone, Debug)]
 pub struct RegionParameterDef {
     pub name: ast::Name,
     pub def_id: DefId,
@@ -3722,7 +3702,8 @@ impl FlagComputation {
 
     fn add_region(&mut self, r: Region) {
         match r {
-            ty::ReInfer(_) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
+            ty::ReVar(..) |
+            ty::ReSkolemized(..) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
             ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
             ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
             ty::ReStatic => {}
@@ -5728,7 +5709,7 @@ impl<'tcx> ctxt<'tcx> {
                 self.note_and_explain_region("concrete lifetime that was found is ",
                                            conc_region, "");
             }
-            RegionsOverlyPolymorphic(_, ty::ReInfer(ty::ReVar(_))) => {
+            RegionsOverlyPolymorphic(_, ty::ReVar(_)) => {
                 // don't bother to print out the message below for
                 // inference variables, it's not very illuminating.
             }
@@ -6479,7 +6460,8 @@ impl<'tcx> ctxt<'tcx> {
                     ReLateBound(..) |
                     ReFree(..) |
                     ReScope(..) |
-                    ReInfer(..) => {
+                    ReVar(..) |
+                    ReSkolemized(..) => {
                         tcx.sess.bug("unexpected region found when hashing a type")
                     }
                 }
@@ -6628,7 +6610,7 @@ impl<'tcx> ctxt<'tcx> {
             types.push(def.space, self.mk_param_from_def(def));
         }
 
-        let free_id_outlive = region::DestructionScopeData::new(free_id);
+        let free_id_outlive = self.region_maps.item_extent(free_id);
 
         // map bound 'a => free 'a
         let mut regions = VecPerParamSpace::empty();
@@ -6659,7 +6641,7 @@ impl<'tcx> ctxt<'tcx> {
         //
 
         let free_substs = self.construct_free_substs(generics, free_id);
-        let free_id_outlive = region::DestructionScopeData::new(free_id);
+        let free_id_outlive = self.region_maps.item_extent(free_id);
 
         //
         // Compute the bounds on Self and the type parameters.
@@ -6691,7 +6673,7 @@ impl<'tcx> ctxt<'tcx> {
         let unnormalized_env = ty::ParameterEnvironment {
             tcx: self,
             free_substs: free_substs,
-            implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()),
+            implicit_region_bound: ty::ReScope(free_id_outlive),
             caller_bounds: predicates,
             selection_cache: traits::SelectionCache::new(),
             free_id: free_id,
@@ -6855,7 +6837,7 @@ impl<'tcx> ctxt<'tcx> {
     /// 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: region::DestructionScopeData,
+        all_outlive_scope: region::CodeExtent,
         value: &Binder<T>)
         -> T
         where T : TypeFoldable<'tcx>
@@ -7338,8 +7320,9 @@ impl HasTypeFlags for Region {
             }
         }
         if flags.intersects(TypeFlags::HAS_RE_INFER) {
-            if let ty::ReInfer(_) = *self {
-                return true;
+            match *self {
+                ty::ReVar(_) | ty::ReSkolemized(..) => { return true }
+                _ => {}
             }
         }
         false
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index b94711065df..48c2e1e6dca 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -13,7 +13,7 @@ use middle::def_id::DefId;
 use middle::subst::{self, Subst};
 use middle::ty::{BoundRegion, BrAnon, BrNamed};
 use middle::ty::{ReEarlyBound, BrFresh, ctxt};
-use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty};
+use middle::ty::{ReFree, ReScope, ReStatic, Region, ReEmpty};
 use middle::ty::{ReSkolemized, ReVar, BrEnv};
 use middle::ty::{TyBool, TyChar, TyStruct, TyEnum};
 use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyBareFn};
@@ -413,11 +413,11 @@ impl fmt::Debug for ty::Region {
 
             ty::ReStatic => write!(f, "ReStatic"),
 
-            ty::ReInfer(ReVar(ref vid)) => {
+            ty::ReVar(ref vid) => {
                 write!(f, "{:?}", vid)
             }
 
-            ty::ReInfer(ReSkolemized(id, ref bound_region)) => {
+            ty::ReSkolemized(id, ref bound_region) => {
                 write!(f, "ReSkolemized({}, {:?})", id, bound_region)
             }
 
@@ -442,11 +442,11 @@ impl fmt::Display for ty::Region {
             }
             ty::ReLateBound(_, br) |
             ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
-            ty::ReInfer(ReSkolemized(_, br)) => {
+            ty::ReSkolemized(_, br) => {
                 write!(f, "{}", br)
             }
             ty::ReScope(_) |
-            ty::ReInfer(ReVar(_)) => Ok(()),
+            ty::ReVar(_) => Ok(()),
             ty::ReStatic => write!(f, "'static"),
             ty::ReEmpty => write!(f, "'<empty>"),
         }
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 62cb1f73cf8..3e3ce5c7be0 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -144,7 +144,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
             None => { }
         }
 
-        self.check_for_conflicting_loans(region::CodeExtent::from_node_id(borrow_id));
+        self.check_for_conflicting_loans(borrow_id);
     }
 
     fn mutate(&mut self,
@@ -230,16 +230,16 @@ fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
 impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.bccx.tcx }
 
-    pub fn each_issued_loan<F>(&self, scope: region::CodeExtent, mut op: F) -> bool where
+    pub fn each_issued_loan<F>(&self, node: ast::NodeId, mut op: F) -> bool where
         F: FnMut(&Loan<'tcx>) -> bool,
     {
         //! Iterates over each loan that has been issued
-        //! on entrance to `scope`, regardless of whether it is
+        //! on entrance to `node`, regardless of whether it is
         //! actually *in scope* at that point.  Sometimes loans
         //! are issued for future scopes and thus they may have been
         //! *issued* but not yet be in effect.
 
-        self.dfcx_loans.each_bit_on_entry(scope.node_id(), |loan_index| {
+        self.dfcx_loans.each_bit_on_entry(node, |loan_index| {
             let loan = &self.all_loans[loan_index];
             op(loan)
         })
@@ -252,7 +252,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         //! currently in scope.
 
         let tcx = self.tcx();
-        self.each_issued_loan(scope, |loan| {
+        self.each_issued_loan(scope.node_id(&tcx.region_maps), |loan| {
             if tcx.region_maps.is_subscope_of(scope, loan.kill_scope) {
                 op(loan)
             } else {
@@ -336,33 +336,33 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         return true;
     }
 
-    pub fn loans_generated_by(&self, scope: region::CodeExtent) -> Vec<usize> {
+    pub fn loans_generated_by(&self, node: ast::NodeId) -> Vec<usize> {
         //! Returns a vector of the loans that are generated as
-        //! we enter `scope`.
+        //! we enter `node`.
 
         let mut result = Vec::new();
-        self.dfcx_loans.each_gen_bit(scope.node_id(), |loan_index| {
+        self.dfcx_loans.each_gen_bit(node, |loan_index| {
             result.push(loan_index);
             true
         });
         return result;
     }
 
-    pub fn check_for_conflicting_loans(&self, scope: region::CodeExtent) {
+    pub fn check_for_conflicting_loans(&self, node: ast::NodeId) {
         //! Checks to see whether any of the loans that are issued
-        //! on entrance to `scope` conflict with loans that have already been
-        //! issued when we enter `scope` (for example, we do not
+        //! on entrance to `node` conflict with loans that have already been
+        //! issued when we enter `node` (for example, we do not
         //! permit two `&mut` borrows of the same variable).
         //!
         //! (Note that some loans can be *issued* without necessarily
         //! taking effect yet.)
 
-        debug!("check_for_conflicting_loans(scope={:?})", scope);
+        debug!("check_for_conflicting_loans(node={:?})", node);
 
-        let new_loan_indices = self.loans_generated_by(scope);
+        let new_loan_indices = self.loans_generated_by(node);
         debug!("new_loan_indices = {:?}", new_loan_indices);
 
-        self.each_issued_loan(scope, |issued_loan| {
+        self.each_issued_loan(node, |issued_loan| {
             for &new_loan_index in &new_loan_indices {
                 let new_loan = &self.all_loans[new_loan_index];
                 self.report_error_if_loans_conflict(issued_loan, new_loan);
@@ -557,7 +557,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                 old_loan.span,
                 &format!("{}; {}", borrow_summary, rule_summary));
 
-            let old_loan_span = self.tcx().map.span(old_loan.kill_scope.node_id());
+            let old_loan_span = self.tcx().map.span(
+                old_loan.kill_scope.node_id(&self.tcx().region_maps));
             self.bccx.span_end_note(old_loan_span,
                                     "previous borrow ends here");
 
@@ -673,7 +674,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         let mut ret = UseOk;
 
         self.each_in_scope_loan_affecting_path(
-            region::CodeExtent::from_node_id(expr_id), use_path, |loan| {
+            self.tcx().region_maps.node_extent(expr_id), use_path, |loan| {
             if !compatible_borrow_kinds(loan.kind, borrow_kind) {
                 ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
                 false
@@ -787,7 +788,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 = region::CodeExtent::from_node_id(assignment_id);
+            let scope = self.tcx().region_maps.node_extent(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/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 6899892a245..cbdd0020a30 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -44,7 +44,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     let mut glcx = GatherLoanCtxt {
         bccx: bccx,
         all_loans: Vec::new(),
-        item_ub: region::CodeExtent::from_node_id(body.id),
+        item_ub: bccx.tcx.region_maps.node_extent(body.id),
         move_data: MoveData::new(),
         move_error_collector: move_error::MoveErrorCollector::new(),
     };
@@ -360,7 +360,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                 let loan_scope = match loan_region {
                     ty::ReScope(scope) => scope,
 
-                    ty::ReFree(ref fr) => fr.scope.to_code_extent(),
+                    ty::ReFree(ref fr) => fr.scope,
 
                     ty::ReStatic => {
                         // If we get here, an error must have been
@@ -377,7 +377,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                     ty::ReEmpty |
                     ty::ReLateBound(..) |
                     ty::ReEarlyBound(..) |
-                    ty::ReInfer(..) => {
+                    ty::ReVar(..) |
+                    ty::ReSkolemized(..) => {
                         self.tcx().sess.span_bug(
                             cmt.span,
                             &format!("invalid borrow lifetime: {:?}",
@@ -386,7 +387,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                 };
                 debug!("loan_scope = {:?}", loan_scope);
 
-                let borrow_scope = region::CodeExtent::from_node_id(borrow_id);
+                let borrow_scope = self.tcx().region_maps.node_extent(borrow_id);
                 let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope);
                 debug!("gen_scope = {:?}", gen_scope);
 
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 187d4b4e5de..9a684021fcd 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -191,6 +191,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                                           -> AnalysisData<'a, 'tcx>
 {
     // Check the body of fn items.
+    let tcx = this.tcx;
     let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id);
     let (all_loans, move_data) =
         gather_loans::gather_loans_in_fn(this, id, decl, body);
@@ -204,8 +205,9 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                              id_range,
                              all_loans.len());
     for (loan_idx, loan) in all_loans.iter().enumerate() {
-        loan_dfcx.add_gen(loan.gen_scope.node_id(), loan_idx);
-        loan_dfcx.add_kill(KillFrom::ScopeEnd, loan.kill_scope.node_id(), loan_idx);
+        loan_dfcx.add_gen(loan.gen_scope.node_id(&tcx.region_maps), loan_idx);
+        loan_dfcx.add_kill(KillFrom::ScopeEnd,
+                           loan.kill_scope.node_id(&tcx.region_maps), loan_idx);
     }
     loan_dfcx.add_kills_from_flow_exits(cfg);
     loan_dfcx.propagate(cfg, body);
@@ -414,7 +416,7 @@ impl<'tcx> LoanPath<'tcx> {
             LpVar(local_id) => tcx.region_maps.var_scope(local_id),
             LpUpvar(upvar_id) => {
                 let block_id = closure_to_block(upvar_id.closure_expr_id, tcx);
-                region::CodeExtent::from_node_id(block_id)
+                tcx.region_maps.node_extent(block_id)
             }
             LpDowncast(ref base, _) |
             LpExtend(ref base, _, _) => base.kill_scope(tcx),
@@ -1135,7 +1137,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 fn statement_scope_span(tcx: &ty::ctxt, region: ty::Region) -> Option<Span> {
     match region {
         ty::ReScope(scope) => {
-            match tcx.map.find(scope.node_id()) {
+            match tcx.map.find(scope.node_id(&tcx.region_maps)) {
                 Some(ast_map::NodeStmt(stmt)) => Some(stmt.span),
                 _ => None
             }
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index ec25dcc7e83..a389095df79 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -494,7 +494,7 @@ impl<'tcx> MoveData<'tcx> {
                 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
                     let kill_scope = path.loan_path.kill_scope(tcx);
                     let path = *self.path_map.borrow().get(&path.loan_path).unwrap();
-                    self.kill_moves(path, kill_scope.node_id(),
+                    self.kill_moves(path, kill_scope.node_id(&tcx.region_maps),
                                     KillFrom::ScopeEnd, dfcx_moves);
                 }
                 LpExtend(..) => {}
@@ -509,7 +509,7 @@ impl<'tcx> MoveData<'tcx> {
                 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
                     let kill_scope = lp.kill_scope(tcx);
                     dfcx_assign.add_kill(KillFrom::ScopeEnd,
-                                         kill_scope.node_id(),
+                                         kill_scope.node_id(&tcx.region_maps),
                                          assignment_index);
                 }
                 LpExtend(..) => {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 7d50395aca3..3277e07dfc1 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -17,7 +17,8 @@ use rustc_lint;
 use rustc_resolve as resolve;
 use rustc_typeck::middle::lang_items;
 use rustc_typeck::middle::free_region::FreeRegionMap;
-use rustc_typeck::middle::region::{self, CodeExtent, DestructionScopeData};
+use rustc_typeck::middle::region::{self, CodeExtent};
+use rustc_typeck::middle::region::CodeExtentData;
 use rustc_typeck::middle::resolve_lifetime;
 use rustc_typeck::middle::stability;
 use rustc_typeck::middle::subst;
@@ -153,24 +154,25 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn create_region_hierarchy(&self, rh: &RH) {
+    pub fn create_region_hierarchy(&self, rh: &RH, parent: CodeExtent) {
+        let me = self.infcx.tcx.region_maps.intern_node(rh.id, parent);
         for child_rh in rh.sub {
-            self.create_region_hierarchy(child_rh);
-            self.infcx.tcx.region_maps.record_encl_scope(
-                CodeExtent::from_node_id(child_rh.id),
-                CodeExtent::from_node_id(rh.id));
+            self.create_region_hierarchy(child_rh, me);
         }
     }
 
     pub fn create_simple_region_hierarchy(&self) {
         // creates a region hierarchy where 1 is root, 10 and 11 are
         // children of 1, etc
+        let dscope = self.infcx.tcx.region_maps.intern_code_extent(
+            CodeExtentData::DestructionScope(1), region::ROOT_CODE_EXTENT);
         self.create_region_hierarchy(
             &RH {id: 1,
                  sub: &[RH {id: 10,
                             sub: &[]},
                         RH {id: 11,
-                            sub: &[]}]});
+                            sub: &[]}]},
+            dscope);
     }
 
     #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
@@ -321,14 +323,16 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
     }
 
     pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
-        let r = ty::ReScope(CodeExtent::from_node_id(id));
+        let r = ty::ReScope(self.tcx().region_maps.node_extent(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 {
-        ty::ReFree(ty::FreeRegion { scope: DestructionScopeData::new(nid),
-                                    bound_region: ty::BrAnon(id)})
+        ty::ReFree(ty::FreeRegion {
+            scope: self.tcx().region_maps.item_extent(nid),
+            bound_region: ty::BrAnon(id)
+        })
     }
 
     pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> {
@@ -462,7 +466,8 @@ fn sub_free_bound_false() {
     //! does NOT hold.
 
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        env.create_simple_region_hierarchy();
+        let t_rptr_free1 = env.t_rptr_free(1, 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));
@@ -478,8 +483,9 @@ fn sub_bound_free_true() {
     //! DOES hold.
 
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        env.create_simple_region_hierarchy();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        let t_rptr_free1 = env.t_rptr_free(1, 1);
         env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
     })
@@ -512,9 +518,10 @@ fn lub_free_bound_infer() {
     //! anyhow.
 
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        env.create_simple_region_hierarchy();
         let t_infer1 = env.infcx.next_ty_var();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        let t_rptr_free1 = env.t_rptr_free(1, 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));
@@ -535,8 +542,9 @@ fn lub_bound_bound() {
 #[test]
 fn lub_bound_free() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        env.create_simple_region_hierarchy();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        let t_rptr_free1 = env.t_rptr_free(1, 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));
@@ -568,8 +576,9 @@ fn lub_bound_bound_inverse_order() {
 #[test]
 fn lub_free_free() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_free1 = env.t_rptr_free(0, 1);
-        let t_rptr_free2 = env.t_rptr_free(0, 2);
+        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_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),
@@ -594,9 +603,10 @@ fn lub_returning_scope() {
 #[test]
 fn glb_free_free_with_common_scope() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_free1 = env.t_rptr_free(0, 1);
-        let t_rptr_free2 = env.t_rptr_free(0, 2);
-        let t_rptr_scope = env.t_rptr_scope(0);
+        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_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),
                       env.t_fn(&[t_rptr_scope], env.tcx().types.isize));
@@ -617,8 +627,9 @@ fn glb_bound_bound() {
 #[test]
 fn glb_bound_free() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        env.create_simple_region_hierarchy();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        let t_rptr_free1 = env.t_rptr_free(1, 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));
@@ -738,10 +749,11 @@ fn escaping() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         // Situation:
         // Theta = [A -> &'a foo]
+        env.create_simple_region_hierarchy();
 
         assert!(!env.t_nil().has_escaping_regions());
 
-        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        let t_rptr_free1 = env.t_rptr_free(1, 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_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs
index 5e472e45775..ecfbaf57903 100644
--- a/src/librustc_trans/trans/cleanup.rs
+++ b/src/librustc_trans/trans/cleanup.rs
@@ -253,18 +253,16 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
         // now we just say that if there is already an AST scope on the stack,
         // this new AST scope had better be its immediate child.
         let top_scope = self.top_ast_scope();
+        let region_maps = &self.ccx.tcx().region_maps;
         if top_scope.is_some() {
-            assert!((self.ccx
-                     .tcx()
-                     .region_maps
-                     .opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id))
-                     .map(|s|s.node_id()) == top_scope)
+            assert!((region_maps
+                     .opt_encl_scope(region_maps.node_extent(debug_loc.id))
+                     .map(|s|s.node_id(region_maps)) == top_scope)
                     ||
-                    (self.ccx
-                     .tcx()
-                     .region_maps
-                     .opt_encl_scope(region::CodeExtent::DestructionScope(debug_loc.id))
-                     .map(|s|s.node_id()) == top_scope));
+                    (region_maps
+                     .opt_encl_scope(region_maps.lookup_code_extent(
+                         region::CodeExtentData::DestructionScope(debug_loc.id)))
+                     .map(|s|s.node_id(region_maps)) == top_scope));
         }
 
         self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id),
@@ -1111,7 +1109,7 @@ pub fn temporary_scope(tcx: &ty::ctxt,
                        -> ScopeId {
     match tcx.region_maps.temporary_scope(id) {
         Some(scope) => {
-            let r = AstScope(scope.node_id());
+            let r = AstScope(scope.node_id(&tcx.region_maps));
             debug!("temporary_scope({}) = {:?}", id, r);
             r
         }
@@ -1125,7 +1123,7 @@ pub fn temporary_scope(tcx: &ty::ctxt,
 pub fn var_scope(tcx: &ty::ctxt,
                  id: ast::NodeId)
                  -> ScopeId {
-    let r = AstScope(tcx.region_maps.var_scope(id).node_id());
+    let r = AstScope(tcx.region_maps.var_scope(id).node_id(&tcx.region_maps));
     debug!("var_scope({}) = {:?}", id, r);
     r
 }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index f14f196f1ae..944169fc45e 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -179,7 +179,7 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
 
         Some(&rl::DefFreeRegion(scope, id)) => {
             ty::ReFree(ty::FreeRegion {
-                    scope: scope,
+                    scope: tcx.region_maps.item_extent(scope.node_id),
                     bound_region: ty::BrNamed(DefId::local(id),
                                               lifetime.name)
                 })
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 6d7919a84ef..a3714fead8e 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -14,7 +14,6 @@ use super::{check_fn, Expectation, FnCtxt};
 
 use astconv;
 use middle::def_id::DefId;
-use middle::region;
 use middle::subst;
 use middle::ty::{self, ToPolyTraitRef, Ty};
 use std::cmp;
@@ -77,7 +76,7 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     fcx.write_ty(expr.id, closure_type);
 
     let fn_sig = fcx.tcx().liberate_late_bound_regions(
-        region::DestructionScopeData::new(body.id), &fn_ty.sig);
+        fcx.tcx().region_maps.item_extent(body.id), &fn_ty.sig);
 
     check_fn(fcx.ccx,
              ast::Unsafety::Normal,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index bbea2552573..cf08490d720 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -91,7 +91,6 @@ use middle::infer;
 use middle::infer::type_variable;
 use middle::pat_util::{self, pat_id_map};
 use middle::privacy::{AllPublic, LastMod};
-use middle::region::{self};
 use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
 use middle::traits::{self, report_fulfillment_errors};
 use middle::ty::{FnSig, GenericPredicates, TypeScheme};
@@ -455,11 +454,11 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             let inh = Inherited::new(ccx.tcx, &tables, param_env);
 
             // Compute the fty from point of view of inside fn.
+            let fn_scope = ccx.tcx.region_maps.item_extent(body.id);
             let fn_sig =
                 fn_ty.sig.subst(ccx.tcx, &inh.infcx.parameter_environment.free_substs);
             let fn_sig =
-                ccx.tcx.liberate_late_bound_regions(region::DestructionScopeData::new(body.id),
-                                                    &fn_sig);
+                ccx.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
             let fn_sig =
                 inh.normalize_associated_types_in(body.span,
                                                   body.id,
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index ced3ee82de2..847cbfdbec6 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -294,7 +294,9 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
 
         let old_body_id = self.set_body_id(body.id);
         self.relate_free_regions(&fn_sig[..], body.id, span);
-        link_fn_args(self, CodeExtent::from_node_id(body.id), &fn_decl.inputs[..]);
+        link_fn_args(self,
+                     self.tcx().region_maps.node_extent(body.id),
+                     &fn_decl.inputs[..]);
         self.visit_block(body);
         self.visit_region_obligations(body.id);
 
@@ -428,7 +430,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
                 debug!("implication: {:?}", implication);
                 match implication {
                     ImpliedBound::RegionSubRegion(ty::ReFree(free_a),
-                                                  ty::ReInfer(ty::ReVar(vid_b))) => {
+                                                  ty::ReVar(vid_b)) => {
                         self.fcx.inh.infcx.add_given(free_a, vid_b);
                     }
                     ImpliedBound::RegionSubParam(r_a, param_b) => {
@@ -564,17 +566,15 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
     // No matter what, the type of each expression must outlive the
     // scope of that expression. This also guarantees basic WF.
     let expr_ty = rcx.resolve_node_type(expr.id);
-
+    // the region corresponding to this expression
+    let expr_region = ty::ReScope(rcx.tcx().region_maps.node_extent(expr.id));
     type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span),
-                      expr_ty, ty::ReScope(CodeExtent::from_node_id(expr.id)));
+                      expr_ty, expr_region);
 
     let method_call = MethodCall::expr(expr.id);
     let opt_method_callee = rcx.fcx.inh.tables.borrow().method_map.get(&method_call).cloned();
     let has_method_map = opt_method_callee.is_some();
 
-    // the region corresponding to this expression
-    let expr_region = ty::ReScope(CodeExtent::from_node_id(expr.id));
-
     // If we are calling a method (either explicitly or via an
     // overloaded operator), check that all of the types provided as
     // arguments for its type parameters are well-formed, and all the regions
@@ -609,7 +609,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
                     // FIXME(#6268) remove to support nested method calls
                     type_of_node_must_outlive(
                         rcx, infer::AutoBorrow(expr.span),
-                        expr.id, ty::ReScope(CodeExtent::from_node_id(expr.id)));
+                        expr.id, expr_region);
                 }
             }
             /*
@@ -726,7 +726,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
                 type_must_outlive(rcx,
                                   infer::Operand(expr.span),
                                   ty,
-                                  ty::ReScope(CodeExtent::from_node_id(expr.id)));
+                                  expr_region);
             }
             visit::walk_expr(rcx, expr);
         }
@@ -756,7 +756,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             };
             if let ty::TyRef(r_ptr, _) = base_ty.sty {
                 mk_subregion_due_to_dereference(
-                    rcx, expr.span, ty::ReScope(CodeExtent::from_node_id(expr.id)), *r_ptr);
+                    rcx, expr.span, expr_region, *r_ptr);
             }
 
             visit::walk_expr(rcx, expr);
@@ -789,8 +789,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             //
             // FIXME(#6268) nested method calls requires that this rule change
             let ty0 = rcx.resolve_node_type(expr.id);
-            type_must_outlive(rcx, infer::AddrOf(expr.span),
-                              ty0, ty::ReScope(CodeExtent::from_node_id(expr.id)));
+            type_must_outlive(rcx, infer::AddrOf(expr.span), ty0, expr_region);
             visit::walk_expr(rcx, expr);
         }
 
@@ -919,7 +918,7 @@ fn constrain_call<'a, I: Iterator<Item=&'a ast::Expr>>(rcx: &mut Rcx,
     // call occurs.
     //
     // FIXME(#6268) to support nested method calls, should be callee_id
-    let callee_scope = CodeExtent::from_node_id(call_expr.id);
+    let callee_scope = rcx.tcx().region_maps.node_extent(call_expr.id);
     let callee_region = ty::ReScope(callee_scope);
 
     debug!("callee_region={:?}", callee_region);
@@ -966,7 +965,8 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
            derefs,
            derefd_ty);
 
-    let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id));
+    let s_deref_expr = rcx.tcx().region_maps.node_extent(deref_expr.id);
+    let r_deref_expr = ty::ReScope(s_deref_expr);
     for i in 0..derefs {
         let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
         debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
@@ -1083,7 +1083,7 @@ fn constrain_index<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
     debug!("constrain_index(index_expr=?, indexed_ty={}",
            rcx.fcx.infcx().ty_to_string(indexed_ty));
 
-    let r_index_expr = ty::ReScope(CodeExtent::from_node_id(index_expr.id));
+    let r_index_expr = ty::ReScope(rcx.tcx().region_maps.node_extent(index_expr.id));
     if let ty::TyRef(r_ptr, mt) = indexed_ty.sty {
         match mt.ty.sty {
             ty::TySlice(_) | ty::TyStr => {
@@ -1234,7 +1234,7 @@ fn link_autoref(rcx: &Rcx,
         }
 
         ty::AutoUnsafe(m) => {
-            let r = ty::ReScope(CodeExtent::from_node_id(expr.id));
+            let r = ty::ReScope(rcx.tcx().region_maps.node_extent(expr.id));
             link_region(rcx, expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt);
         }
     }
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index d1e159d4456..0ef1d4b81ac 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -466,10 +466,7 @@ pub struct BoundsChecker<'cx,'tcx:'cx> {
     fcx: &'cx FnCtxt<'cx,'tcx>,
     span: Span,
 
-    // This field is often attached to item impls; it is not clear
-    // that `CodeExtent` is well-defined for such nodes, so pnkfelix
-    // has left it as a NodeId rather than porting to CodeExtent.
-    scope: ast::NodeId,
+    scope: region::CodeExtent,
 
     binding_count: usize,
     cache: Option<&'cx mut HashSet<Ty<'tcx>>>,
@@ -480,6 +477,7 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
                scope: ast::NodeId,
                cache: Option<&'cx mut HashSet<Ty<'tcx>>>)
                -> BoundsChecker<'cx,'tcx> {
+        let scope = fcx.tcx().region_maps.item_extent(scope);
         BoundsChecker { fcx: fcx, span: DUMMY_SP, scope: scope,
                         cache: cache, binding_count: 0 }
     }
@@ -532,7 +530,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
     {
         self.binding_count += 1;
         let value = self.fcx.tcx().liberate_late_bound_regions(
-            region::DestructionScopeData::new(self.scope),
+            self.scope,
             binder);
         debug!("BoundsChecker::fold_binder: late-bound regions replaced: {:?} at scope: {:?}",
                value, self.scope);
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index cdad1257533..4280e392d18 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -13,7 +13,6 @@ use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck};
 use constrained_type_params::{identify_constrained_type_params, Parameter};
 use CrateCtxt;
 use middle::def_id::DefId;
-use middle::region::DestructionScopeData;
 use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
 use middle::traits;
 use middle::ty::{self, Ty};
@@ -362,7 +361,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
     {
         let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
         let fty = fcx.instantiate_type_scheme(span, free_substs, fty);
-        let free_id_outlive = DestructionScopeData::new(free_id);
+        let free_id_outlive = fcx.tcx().region_maps.item_extent(free_id);
         let sig = fcx.tcx().liberate_late_bound_regions(free_id_outlive, &fty.sig);
 
         for &input_ty in &sig.inputs {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index d3e414fd9c0..544f6d9f0ed 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2311,7 +2311,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
             _ => typ,
         };
 
-        let body_scope = region::DestructionScopeData::new(body_id);
+        let body_scope = tcx.region_maps.item_extent(body_id);
 
         // "Required type" comes from the trait definition. It may
         // contain late-bound regions from the method, but not the
@@ -2363,7 +2363,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
 
     fn liberate_early_bound_regions<'tcx,T>(
         tcx: &ty::ctxt<'tcx>,
-        scope: region::DestructionScopeData,
+        scope: region::CodeExtent,
         value: &T)
         -> T
         where T : TypeFoldable<'tcx>
diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs
index 8165da95aed..98058b804ee 100644
--- a/src/librustc_typeck/variance.rs
+++ b/src/librustc_typeck/variance.rs
@@ -1025,8 +1025,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 // methods or in fn types.
             }
 
-            ty::ReFree(..) | ty::ReScope(..) | ty::ReInfer(..) |
-            ty::ReEmpty => {
+            ty::ReFree(..) | ty::ReScope(..) | ty::ReVar(..) |
+            ty::ReSkolemized(..) | ty::ReEmpty => {
                 // We don't expect to see anything but 'static or bound
                 // regions when visiting member types or method types.
                 self.tcx()
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 6a2d0b46ad4..9cd376f8d31 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -772,7 +772,8 @@ impl Clean<Option<Lifetime>> for ty::Region {
             ty::ReLateBound(..) |
             ty::ReFree(..) |
             ty::ReScope(..) |
-            ty::ReInfer(..) |
+            ty::ReVar(..) |
+            ty::ReSkolemized(..) |
             ty::ReEmpty(..) => None
         }
     }