about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-03-05 06:03:43 -0800
committerbors <bors@rust-lang.org>2013-03-05 06:03:43 -0800
commit9ec7f3fa2252261b647c99ead9d6ebec0b959e05 (patch)
tree9e4a0892e948214950be6cd4f6b5b4d1c1fea664
parent65986ba0c0b20803dd02a5b0b71e269cbeb8336d (diff)
parentcbfd88a4863ff88bdfc55f0b05dded82f0bfeb32 (diff)
downloadrust-9ec7f3fa2252261b647c99ead9d6ebec0b959e05.tar.gz
rust-9ec7f3fa2252261b647c99ead9d6ebec0b959e05.zip
auto merge of #5225 : nikomatsakis/rust/issue-5224, r=nikomatsakis
Update region inference for traits so that a method with explicit self doesn't incorrectly cause the entire trait to be tagged as being region-parameterized.

Fixes #5224.

r? @pcwalton


-rw-r--r--src/librustc/middle/check_const.rs1
-rw-r--r--src/librustc/middle/check_match.rs1
-rw-r--r--src/librustc/middle/kind.rs1
-rw-r--r--src/librustc/middle/region.rs79
-rw-r--r--src/librustc/middle/trans/base.rs1
-rw-r--r--src/librustc/middle/typeck/astconv.rs54
-rw-r--r--src/librustc/middle/typeck/check/mod.rs43
-rw-r--r--src/librustc/middle/typeck/collect.rs119
-rw-r--r--src/librustc/middle/typeck/rscope.rs113
-rw-r--r--src/libsyntax/ast.rs9
-rw-r--r--src/libsyntax/print/pprust.rs1
-rw-r--r--src/test/compile-fail/map-types.rs2
-rw-r--r--src/test/run-pass/regions-parameterization-self-types-issue-5224.rs28
13 files changed, 263 insertions, 189 deletions
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 713a5f354e9..6eb698d34d2 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -16,7 +16,6 @@ use middle::ty;
 use middle::typeck;
 use util::ppaux;
 
-use core::option;
 use syntax::ast::*;
 use syntax::codemap;
 use syntax::{visit, ast_util, ast_map};
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 5e0831ecbb8..51cb305ab02 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -19,7 +19,6 @@ use middle::typeck::method_map;
 use middle::moves;
 use util::ppaux::ty_to_str;
 
-use core::option;
 use core::uint;
 use core::vec;
 use std::sort;
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index d5772383a0a..98a05d9b8df 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -18,7 +18,6 @@ use middle::ty;
 use middle::typeck;
 use util::ppaux::{ty_to_str, tys_to_str};
 
-use core::option;
 use core::str;
 use core::vec;
 use std::oldmap::HashMap;
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index f8dcf6e2a9f..4d874fc4ef9 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -416,9 +416,13 @@ pub struct DetermineRpCtxt {
     item_id: ast::node_id,
 
     // true when we are within an item but not within a method.
-    // see long discussion on region_is_relevant()
+    // see long discussion on region_is_relevant().
     anon_implies_rp: bool,
 
+    // true when we are not within an &self method.
+    // see long discussion on region_is_relevant().
+    self_implies_rp: bool,
+
     // encodes the context of the current type; invariant if
     // mutable, covariant otherwise
     ambient_variance: region_variance,
@@ -458,14 +462,14 @@ pub fn add_variance(+ambient_variance: region_variance,
 }
 
 pub impl DetermineRpCtxt {
-    fn add_variance(@mut self, variance: region_variance) -> region_variance {
+    fn add_variance(&self, variance: region_variance) -> region_variance {
         add_variance(self.ambient_variance, variance)
     }
 
     /// Records that item `id` is region-parameterized with the
     /// variance `variance`.  If `id` was already parameterized, then
     /// the new variance is joined with the old variance.
-    fn add_rp(@mut self, id: ast::node_id, variance: region_variance) {
+    fn add_rp(&mut self, id: ast::node_id, variance: region_variance) {
         assert id != 0;
         let old_variance = self.region_paramd_items.find(&id);
         let joined_variance = match old_variance {
@@ -490,7 +494,7 @@ pub impl DetermineRpCtxt {
     /// `from`.  Put another way, it indicates that the current item
     /// contains a value of type `from`, so if `from` is
     /// region-parameterized, so is the current item.
-    fn add_dep(@mut self, from: ast::node_id) {
+    fn add_dep(&mut self, from: ast::node_id) {
         debug!("add dependency from %d -> %d (%s -> %s) with variance %?",
                from, self.item_id,
                ast_map::node_id_to_str(self.ast_map, from,
@@ -515,42 +519,46 @@ pub impl DetermineRpCtxt {
     }
 
     // Determines whether a reference to a region that appears in the
-    // AST implies that the enclosing type is region-parameterized.
-    //
-    // This point is subtle.  Here are four examples to make it more
+    // AST implies that the enclosing type is region-parameterized (RP).
+    // This point is subtle.  Here are some examples to make it more
     // concrete.
     //
     // 1. impl foo for &int { ... }
     // 2. impl foo for &self/int { ... }
-    // 3. impl foo for bar { fn m() -> &self/int { ... } }
-    // 4. impl foo for bar { fn m() -> &int { ... } }
+    // 3. impl foo for bar { fn m(@self) -> &self/int { ... } }
+    // 4. impl foo for bar { fn m(&self) -> &self/int { ... } }
+    // 5. impl foo for bar { fn m(&self) -> &int { ... } }
     //
     // In case 1, the anonymous region is being referenced,
     // but it appears in a context where the anonymous region
-    // resolves to self, so the impl foo is region-parameterized.
+    // resolves to self, so the impl foo is RP.
     //
     // In case 2, the self parameter is written explicitly.
     //
-    // In case 3, the method refers to self, so that implies that the
-    // impl must be region parameterized.  (If the type bar is not
-    // region parameterized, that is an error, because the self region
-    // is effectively unconstrained, but that is detected elsewhere).
+    // In case 3, the method refers to the region `self`, so that
+    // implies that the impl must be region parameterized.  (If the
+    // type bar is not region parameterized, that is an error, because
+    // the self region is effectively unconstrained, but that is
+    // detected elsewhere).
+    //
+    // In case 4, the method refers to the region `self`, but the
+    // `self` region is bound by the `&self` receiver, and so this
+    // does not require that `bar` be RP.
     //
-    // In case 4, the anonymous region is referenced, but it
+    // In case 5, the anonymous region is referenced, but it
     // bound by the method, so it does not refer to self.  This impl
     // need not be region parameterized.
     //
-    // So the rules basically are: the `self` region always implies
-    // that the enclosing type is region parameterized.  The anonymous
-    // region also does, unless it appears within a method, in which
-    // case it is bound.  We handle this by setting a flag
-    // (anon_implies_rp) to true when we enter an item and setting
-    // that flag to false when we enter a method.
-    fn region_is_relevant(@mut self, r: @ast::region) -> bool {
+    // Normally, & or &self implies that the enclosing item is RP.
+    // However, within a function, & is always bound.  Within a method
+    // with &self type, &self is also bound.  We detect those last two
+    // cases via flags (anon_implies_rp and self_implies_rp) that are
+    // true when the anon or self region implies RP.
+    fn region_is_relevant(&self, r: @ast::region) -> bool {
         match r.node {
             ast::re_static => false,
             ast::re_anon => self.anon_implies_rp,
-            ast::re_self => true,
+            ast::re_self => self.self_implies_rp,
             ast::re_named(_) => false
         }
     }
@@ -561,7 +569,7 @@ pub impl DetermineRpCtxt {
     //
     // If the region is explicitly specified, then we follows the
     // normal rules.
-    fn opt_region_is_relevant(@mut self,
+    fn opt_region_is_relevant(&self,
                               opt_r: Option<@ast::region>)
                            -> bool {
         debug!("opt_region_is_relevant: %? (anon_implies_rp=%b)",
@@ -575,16 +583,23 @@ pub impl DetermineRpCtxt {
     fn with(@mut self,
             item_id: ast::node_id,
             anon_implies_rp: bool,
+            self_implies_rp: bool,
             f: &fn()) {
         let old_item_id = self.item_id;
         let old_anon_implies_rp = self.anon_implies_rp;
+        let old_self_implies_rp = self.self_implies_rp;
         self.item_id = item_id;
         self.anon_implies_rp = anon_implies_rp;
-        debug!("with_item_id(%d, %b)", item_id, anon_implies_rp);
+        self.self_implies_rp = self_implies_rp;
+        debug!("with_item_id(%d, %b, %b)",
+               item_id,
+               anon_implies_rp,
+               self_implies_rp);
         let _i = ::util::common::indenter();
         f();
         self.item_id = old_item_id;
         self.anon_implies_rp = old_anon_implies_rp;
+        self.self_implies_rp = old_self_implies_rp;
     }
 
     fn with_ambient_variance(@mut self, variance: region_variance, f: &fn()) {
@@ -598,7 +613,7 @@ pub impl DetermineRpCtxt {
 pub fn determine_rp_in_item(item: @ast::item,
                             &&cx: @mut DetermineRpCtxt,
                             visitor: visit::vt<@mut DetermineRpCtxt>) {
-    do cx.with(item.id, true) {
+    do cx.with(item.id, true, true) {
         visit::visit_item(item, cx, visitor);
     }
 }
@@ -610,7 +625,12 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind,
                           _: ast::node_id,
                           &&cx: @mut DetermineRpCtxt,
                           visitor: visit::vt<@mut DetermineRpCtxt>) {
-    do cx.with(cx.item_id, false) {
+    let self_implies_rp = match fk {
+        &visit::fk_method(_, _, m) => !m.self_ty.node.is_borrowed(),
+        _ => true
+    };
+
+    do cx.with(cx.item_id, false, self_implies_rp) {
         do cx.with_ambient_variance(rv_contravariant) {
             for decl.inputs.each |a| {
                 (visitor.visit_ty)(a.ty, cx, visitor);
@@ -626,7 +646,7 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind,
 pub fn determine_rp_in_ty_method(ty_m: &ast::ty_method,
                                  &&cx: @mut DetermineRpCtxt,
                                  visitor: visit::vt<@mut DetermineRpCtxt>) {
-    do cx.with(cx.item_id, false) {
+    do cx.with(cx.item_id, false, !ty_m.self_ty.node.is_borrowed()) {
         visit::visit_ty_method(ty_m, cx, visitor);
     }
 }
@@ -735,7 +755,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
       ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => {
         // fn() binds the & region, so do not consider &T types that
         // appear *inside* a fn() type to affect the enclosing item:
-        do cx.with(cx.item_id, false) {
+        do cx.with(cx.item_id, false, true) {
             // parameters are contravariant
             do cx.with_ambient_variance(rv_contravariant) {
                 for decl.inputs.each |a| {
@@ -796,6 +816,7 @@ pub fn determine_rp_in_crate(sess: Session,
         worklist: ~[],
         item_id: 0,
         anon_implies_rp: false,
+        self_implies_rp: true,
         ambient_variance: rv_covariant
     };
 
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index ccea1a561e4..76c62919dfa 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -69,7 +69,6 @@ use core::hash;
 use core::int;
 use core::io;
 use core::libc::{c_uint, c_ulonglong};
-use core::option;
 use core::uint;
 use std::oldmap::HashMap;
 use std::{oldmap, time, list};
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 8a0bea62795..8472d956cd2 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -69,12 +69,11 @@ use syntax::print::pprust::path_to_str;
 use util::common::indenter;
 
 pub trait AstConv {
-    fn tcx(@mut self) -> ty::ctxt;
-    fn ccx(@mut self) -> @mut CrateCtxt;
-    fn get_item_ty(@mut self, id: ast::def_id) -> ty::ty_param_bounds_and_ty;
+    fn tcx(&self) -> ty::ctxt;
+    fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty;
 
     // what type should we use when a type is omitted?
-    fn ty_infer(@mut self, span: span) -> ty::t;
+    fn ty_infer(&self, span: span) -> ty::t;
 }
 
 pub fn get_region_reporting_err(tcx: ty::ctxt,
@@ -92,8 +91,8 @@ pub fn get_region_reporting_err(tcx: ty::ctxt,
 }
 
 pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Copy + Durable>(
-        self: @mut AC,
-        rscope: RS,
+        self: &AC,
+        rscope: &RS,
         span: span,
         a_r: @ast::region)
      -> ty::Region {
@@ -108,8 +107,8 @@ pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Copy + Durable>(
 }
 
 pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
-        self: @mut AC,
-        rscope: RS,
+        self: &AC,
+        rscope: &RS,
         did: ast::def_id,
         path: @ast::path)
      -> ty_param_substs_and_ty {
@@ -164,8 +163,8 @@ pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
 }
 
 pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
-        self: @mut AC,
-        rscope: RS,
+        self: &AC,
+        rscope: &RS,
         did: ast::def_id,
         path: @ast::path,
         path_id: ast::node_id)
@@ -189,11 +188,11 @@ pub const NO_TPS: uint = 2;
 // Parses the programmer's textual representation of a type into our
 // internal notion of a type. `getter` is a function that returns the type
 // corresponding to a definition ID:
-pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
-    self: @mut AC, rscope: RS, &&ast_ty: @ast::Ty) -> ty::t {
+pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + Durable>(
+    self: &AC, rscope: &RS, &&ast_ty: @ast::Ty) -> ty::t {
 
-    fn ast_mt_to_mt<AC:AstConv,RS:region_scope + Copy + Durable>(
-        self: @mut AC, rscope: RS, mt: ast::mt) -> ty::mt {
+    fn ast_mt_to_mt<AC:AstConv, RS:region_scope + Copy + Durable>(
+        self: &AC, rscope: &RS, mt: ast::mt) -> ty::mt {
 
         ty::mt {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl}
     }
@@ -202,8 +201,8 @@ pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
     // If a_seq_ty is a str or a vec, make it an estr/evec.
     // Also handle function sigils and first-class trait types.
     fn mk_pointer<AC:AstConv,RS:region_scope + Copy + Durable>(
-        self: @mut AC,
-        rscope: RS,
+        self: &AC,
+        rscope: &RS,
         a_seq_ty: ast::mt,
         vst: ty::vstore,
         constr: fn(ty::mt) -> ty::t) -> ty::t
@@ -316,7 +315,8 @@ pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
       }
       ast::ty_rptr(region, mt) => {
         let r = ast_region_to_region(self, rscope, ast_ty.span, region);
-        mk_pointer(self, in_anon_rscope(rscope, r), mt, ty::vstore_slice(r),
+        let anon_rscope = in_anon_rscope(rscope, r);
+        mk_pointer(self, &anon_rscope, mt, ty::vstore_slice(r),
                    |tmt| ty::mk_rptr(tcx, r, tmt))
       }
       ast::ty_tup(fields) => {
@@ -419,8 +419,8 @@ pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
 }
 
 pub fn ty_of_arg<AC:AstConv,RS:region_scope + Copy + Durable>(
-        self: @mut AC,
-        rscope: RS,
+        self: &AC,
+        rscope: &RS,
         a: ast::arg,
         expected_ty: Option<ty::arg>)
      -> ty::arg {
@@ -467,8 +467,8 @@ pub fn ty_of_arg<AC:AstConv,RS:region_scope + Copy + Durable>(
 }
 
 pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
-        self: @mut AC,
-        rscope: RS,
+        self: &AC,
+        rscope: &RS,
         purity: ast::purity,
         abi: ast::Abi,
         decl: &ast::fn_decl)
@@ -479,10 +479,10 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
     // that function type
     let rb = in_binding_rscope(rscope);
 
-    let input_tys = decl.inputs.map(|a| ty_of_arg(self, rb, *a, None));
+    let input_tys = decl.inputs.map(|a| ty_of_arg(self, &rb, *a, None));
     let output_ty = match decl.output.node {
         ast::ty_infer => self.ty_infer(decl.output.span),
-        _ => ast_ty_to_ty(self, rb, decl.output)
+        _ => ast_ty_to_ty(self, &rb, decl.output)
     };
 
     ty::BareFnTy {
@@ -493,8 +493,8 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
 }
 
 pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
-        self: @mut AC,
-        rscope: RS,
+        self: &AC,
+        rscope: &RS,
         sigil: ast::Sigil,
         purity: ast::purity,
         onceness: ast::Onceness,
@@ -538,14 +538,14 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
             // were supplied
             if i < e.inputs.len() {Some(e.inputs[i])} else {None}
         };
-        ty_of_arg(self, rb, *a, expected_arg_ty)
+        ty_of_arg(self, &rb, *a, expected_arg_ty)
     };
 
     let expected_ret_ty = expected_tys.map(|e| e.output);
     let output_ty = match decl.output.node {
         ast::ty_infer if expected_ret_ty.is_some() => expected_ret_ty.get(),
         ast::ty_infer => self.ty_infer(decl.output.span),
-        _ => ast_ty_to_ty(self, rb, decl.output)
+        _ => ast_ty_to_ty(self, &rb, decl.output)
     };
 
     ty::ClosureTy {
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 6b637ee0884..06163d746c2 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -581,7 +581,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
         let rp = ccx.tcx.region_paramd_items.find(&it.id);
         debug!("item_impl %s with id %d rp %?",
                *ccx.tcx.sess.str_of(it.ident), it.id, rp);
-        let self_ty = ccx.to_ty(rscope::type_rscope(rp), ty);
+        let self_ty = ccx.to_ty(&rscope::type_rscope(rp), ty);
         for ms.each |m| {
             check_method(ccx, *m, self_ty, local_def(it.id));
         }
@@ -636,21 +636,20 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
 }
 
 impl AstConv for FnCtxt {
-    fn tcx(@mut self) -> ty::ctxt { self.ccx.tcx }
-    fn ccx(@mut self) -> @mut CrateCtxt { self.ccx }
+    fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
 
-    fn get_item_ty(@mut self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
+    fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
         ty::lookup_item_type(self.tcx(), id)
     }
 
-    fn ty_infer(@mut self, _span: span) -> ty::t {
+    fn ty_infer(&self, _span: span) -> ty::t {
         self.infcx().next_ty_var()
     }
 }
 
 pub impl FnCtxt {
-    fn infcx(@mut self) -> @mut infer::InferCtxt { self.inh.infcx }
-    fn search_in_scope_regions(@mut self,
+    fn infcx(&self) -> @mut infer::InferCtxt { self.inh.infcx }
+    fn search_in_scope_regions(&self,
                                br: ty::bound_region)
                             -> Result<ty::Region, ~str> {
         let in_scope_regions = self.in_scope_regions;
@@ -669,25 +668,17 @@ pub impl FnCtxt {
     }
 }
 
-impl region_scope for @mut FnCtxt {
-    pure fn anon_region(&self, span: span) -> Result<ty::Region, ~str> {
-        // XXX: Unsafe to work around purity
-        unsafe {
-            result::Ok(self.infcx().next_region_var_nb(span))
-        }
+impl region_scope for FnCtxt {
+    fn anon_region(&self, span: span) -> Result<ty::Region, ~str> {
+        result::Ok(self.infcx().next_region_var_nb(span))
     }
-    pure fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
-        // XXX: Unsafe to work around purity
-        unsafe {
-            self.search_in_scope_regions(ty::br_self)
-        }
+    fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
+        self.search_in_scope_regions(ty::br_self)
     }
-    pure fn named_region(&self, _span: span, id: ast::ident)
-                      -> Result<ty::Region, ~str> {
-        // XXX: Unsafe to work around purity
-        unsafe {
-            self.search_in_scope_regions(ty::br_named(id))
-        }
+    fn named_region(&self,
+                    _span: span,
+                    id: ast::ident) -> Result<ty::Region, ~str> {
+        self.search_in_scope_regions(ty::br_named(id))
     }
 }
 
@@ -710,7 +701,7 @@ pub impl FnCtxt {
              pprust::expr_to_str(expr, self.tcx().sess.intr()))
     }
 
-    fn block_region(@mut self) -> ty::Region {
+    fn block_region(&self) -> ty::Region {
         ty::re_scope(self.region_lb)
     }
 
@@ -1076,7 +1067,7 @@ pub fn impl_self_ty(vcx: &VtableContext,
               }, _)) => {
             (ts.ty_params.len(),
              region_param,
-             vcx.ccx.to_ty(rscope::type_rscope(region_param), st))
+             vcx.ccx.to_ty(&rscope::type_rscope(region_param), st))
           }
           Some(ast_map::node_item(@ast::item {
                   node: ast::item_struct(_, ref ts),
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 7aae70b0d6e..2938f25291d 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -47,7 +47,6 @@ use util::common::{indenter, pluralize};
 use util::ppaux;
 
 use core::dvec;
-use core::option;
 use core::vec;
 use syntax::ast::{RegionTyParamBound, TraitTyParamBound};
 use syntax::ast;
@@ -108,24 +107,24 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: @ast::crate) {
     visit::visit_crate(
         *crate, (),
         visit::mk_simple_visitor(@visit::SimpleVisitor {
-            visit_item: |a|convert(ccx, a),
+            visit_item: |a| convert(ccx, a),
             visit_foreign_item: |a|convert_foreign(ccx, a),
             .. *visit::default_simple_visitor()
         }));
 }
 
-pub impl @mut CrateCtxt {
-    fn to_ty<RS:region_scope + Copy + Durable>(rs: RS, ast_ty: @ast::Ty)
-                                         -> ty::t {
+impl CrateCtxt {
+    fn to_ty<RS:region_scope + Copy + Durable>(
+        &self, rs: &RS, ast_ty: @ast::Ty) -> ty::t
+    {
         ast_ty_to_ty(self, rs, ast_ty)
     }
 }
 
 impl AstConv for CrateCtxt {
-    fn tcx(@mut self) -> ty::ctxt { self.tcx }
-    fn ccx(@mut self) -> @mut CrateCtxt { self }
+    fn tcx(&self) -> ty::ctxt { self.tcx }
 
-    fn get_item_ty(@mut self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
+    fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
         if id.crate != ast::local_crate {
             csearch::get_type(self.tcx, id)
         } else {
@@ -144,13 +143,13 @@ impl AstConv for CrateCtxt {
         }
     }
 
-    fn ty_infer(@mut self, span: span) -> ty::t {
+    fn ty_infer(&self, span: span) -> ty::t {
         self.tcx.sess.span_bug(span,
                                ~"found `ty_infer` in unexpected place");
     }
 }
 
-pub fn get_enum_variant_types(ccx: @mut CrateCtxt,
+pub fn get_enum_variant_types(ccx: &CrateCtxt,
                               enum_ty: ty::t,
                               variants: &[ast::variant],
                               generics: &ast::Generics,
@@ -165,7 +164,7 @@ pub fn get_enum_variant_types(ccx: @mut CrateCtxt,
         match variant.node.kind {
             ast::tuple_variant_kind(ref args) if args.len() > 0 => {
                 let rs = type_rscope(rp);
-                let input_tys = args.map(|va| ccx.to_ty(rs, va.ty));
+                let input_tys = args.map(|va| ccx.to_ty(&rs, va.ty));
                 result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty));
             }
 
@@ -217,17 +216,17 @@ pub fn get_enum_variant_types(ccx: @mut CrateCtxt,
     }
 }
 
-pub fn ensure_trait_methods(ccx: @mut CrateCtxt,
+pub fn ensure_trait_methods(ccx: &CrateCtxt,
                             id: ast::node_id,
                             trait_ty: ty::t) {
-    fn store_methods<T>(ccx: @mut CrateCtxt,
+    fn store_methods<T>(ccx: &CrateCtxt,
                         id: ast::node_id,
                         stuff: ~[T],
                         f: &fn(v: &T) -> ty::method) {
         ty::store_trait_methods(ccx.tcx, id, @vec::map(stuff, f));
     }
 
-    fn make_static_method_ty(ccx: @mut CrateCtxt,
+    fn make_static_method_ty(ccx: &CrateCtxt,
                              am: &ast::ty_method,
                              rp: Option<ty::region_variance>,
                              m: ty::method,
@@ -308,7 +307,7 @@ pub fn ensure_trait_methods(ccx: @mut CrateCtxt,
     }
 }
 
-pub fn ensure_supertraits(ccx: @mut CrateCtxt,
+pub fn ensure_supertraits(ccx: &CrateCtxt,
                           id: ast::node_id,
                           sp: codemap::span,
                           rp: Option<ty::region_variance>,
@@ -492,7 +491,7 @@ pub fn compare_impl_method(tcx: ty::ctxt,
     }
 }
 
-pub fn check_methods_against_trait(ccx: @mut CrateCtxt,
+pub fn check_methods_against_trait(ccx: &CrateCtxt,
                                    generics: &ast::Generics,
                                    rp: Option<ty::region_variance>,
                                    selfty: ty::t,
@@ -544,11 +543,11 @@ pub fn check_methods_against_trait(ccx: @mut CrateCtxt,
     }
 } // fn
 
-pub fn convert_field(ccx: @mut CrateCtxt,
+pub fn convert_field(ccx: &CrateCtxt,
                      rp: Option<ty::region_variance>,
                      bounds: @~[ty::param_bounds],
                      v: @ast::struct_field) {
-    let tt = ccx.to_ty(type_rscope(rp), v.node.ty);
+    let tt = ccx.to_ty(&type_rscope(rp), v.node.ty);
     write_ty_to_tcx(ccx.tcx, v.node.id, tt);
     /* add the field to the tcache */
     ccx.tcx.tcache.insert(local_def(v.node.id),
@@ -566,8 +565,8 @@ pub struct ConvertedMethod {
     body_id: ast::node_id
 }
 
-pub fn convert_methods(ccx: @mut CrateCtxt,
-                       ms: ~[@ast::method],
+pub fn convert_methods(ccx: &CrateCtxt,
+                       ms: &[@ast::method],
                        rp: Option<ty::region_variance>,
                        rcvr_bounds: @~[ty::param_bounds])
                     -> ~[ConvertedMethod] {
@@ -593,7 +592,7 @@ pub fn convert_methods(ccx: @mut CrateCtxt,
     }
 }
 
-pub fn ensure_no_ty_param_bounds(ccx: @mut CrateCtxt,
+pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
                                  span: span,
                                  generics: &ast::Generics,
                                  thing: &static/str) {
@@ -607,7 +606,7 @@ pub fn ensure_no_ty_param_bounds(ccx: @mut CrateCtxt,
     }
 }
 
-pub fn convert(ccx: @mut CrateCtxt, it: @ast::item) {
+pub fn convert(ccx: &CrateCtxt, it: @ast::item) {
     let tcx = ccx.tcx;
     let rp = tcx.region_paramd_items.find(&it.id);
     debug!("convert: item %s with id %d rp %?",
@@ -627,7 +626,7 @@ pub fn convert(ccx: @mut CrateCtxt, it: @ast::item) {
       }
       ast::item_impl(ref generics, trait_ref, selfty, ref ms) => {
         let i_bounds = ty_param_bounds(ccx, generics);
-        let selfty = ccx.to_ty(type_rscope(rp), selfty);
+        let selfty = ccx.to_ty(&type_rscope(rp), selfty);
         write_ty_to_tcx(tcx, it.id, selfty);
         tcx.tcache.insert(local_def(it.id),
                           ty_param_bounds_and_ty {
@@ -636,7 +635,7 @@ pub fn convert(ccx: @mut CrateCtxt, it: @ast::item) {
                             ty: selfty});
 
         // XXX: Bad copy of `ms` below.
-        let cms = convert_methods(ccx, /*bad*/copy *ms, rp, i_bounds);
+        let cms = convert_methods(ccx, *ms, rp, i_bounds);
         for trait_ref.each |t| {
             check_methods_against_trait(ccx, generics, rp, selfty,
                                         *t, /*bad*/copy cms);
@@ -680,7 +679,7 @@ pub fn convert(ccx: @mut CrateCtxt, it: @ast::item) {
     }
 }
 
-pub fn convert_struct(ccx: @mut CrateCtxt,
+pub fn convert_struct(ccx: &CrateCtxt,
                       rp: Option<ty::region_variance>,
                       struct_def: @ast::struct_def,
                       generics: &ast::Generics,
@@ -693,7 +692,7 @@ pub fn convert_struct(ccx: @mut CrateCtxt,
         let t_dtor = ty::mk_bare_fn(
             tcx,
             astconv::ty_of_bare_fn(
-                ccx, type_rscope(rp),
+                ccx, &type_rscope(rp),
                 ast::impure_fn, ast::RustAbi,
                 &ast_util::dtor_dec()));
         write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
@@ -738,7 +737,7 @@ pub fn convert_struct(ccx: @mut CrateCtxt,
     }
 }
 
-pub fn convert_foreign(ccx: @mut CrateCtxt, i: @ast::foreign_item) {
+pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) {
     // As above, this call populates the type table with the converted
     // type of the foreign item. We simply write it into the node type
     // table.
@@ -747,13 +746,18 @@ pub fn convert_foreign(ccx: @mut CrateCtxt, i: @ast::foreign_item) {
     ccx.tcx.tcache.insert(local_def(i.id), tpt);
 }
 
-pub fn ty_of_method(ccx: @mut CrateCtxt,
+pub fn ty_of_method(ccx: &CrateCtxt,
                     m: @ast::method,
                     rp: Option<ty::region_variance>) -> ty::method {
+    let rscope = MethodRscope {
+        self_ty: m.self_ty.node,
+        region_parameterization: rp
+    };
+
     ty::method {
         ident: m.ident,
         tps: ty_param_bounds(ccx, &m.generics),
-        fty: astconv::ty_of_bare_fn(ccx, type_rscope(rp), m.purity,
+        fty: astconv::ty_of_bare_fn(ccx, &rscope, m.purity,
                                     ast::RustAbi, &m.decl),
         self_ty: m.self_ty.node,
         vis: m.vis,
@@ -761,14 +765,19 @@ pub fn ty_of_method(ccx: @mut CrateCtxt,
     }
 }
 
-pub fn ty_of_ty_method(self: @mut CrateCtxt,
+pub fn ty_of_ty_method(self: &CrateCtxt,
                        m: &ast::ty_method,
                        rp: Option<ty::region_variance>,
                        id: ast::def_id) -> ty::method {
+    let rscope = MethodRscope {
+        self_ty: m.self_ty.node,
+        region_parameterization: rp
+    };
+
     ty::method {
         ident: m.ident,
         tps: ty_param_bounds(self, &m.generics),
-        fty: astconv::ty_of_bare_fn(self, type_rscope(rp), m.purity,
+        fty: astconv::ty_of_bare_fn(self, &rscope, m.purity,
                                     ast::RustAbi, &m.decl),
         // assume public, because this is only invoked on trait methods
         self_ty: m.self_ty.node,
@@ -782,7 +791,7 @@ pub fn ty_of_ty_method(self: @mut CrateCtxt,
   it's bound to a valid trait type. Returns the def_id for the defining
   trait. Fails if the type is a type other than an trait type.
  */
-pub fn instantiate_trait_ref(ccx: @mut CrateCtxt, t: @ast::trait_ref,
+pub fn instantiate_trait_ref(ccx: &CrateCtxt, t: @ast::trait_ref,
                              rp: Option<ty::region_variance>)
     -> (ast::def_id, ty_param_substs_and_ty) {
 
@@ -793,7 +802,7 @@ pub fn instantiate_trait_ref(ccx: @mut CrateCtxt, t: @ast::trait_ref,
 
     match lookup_def_tcx(ccx.tcx, t.path.span, t.ref_id) {
       ast::def_ty(t_id) => {
-        let tpt = astconv::ast_path_to_ty(ccx, rscope, t_id, t.path,
+        let tpt = astconv::ast_path_to_ty(ccx, &rscope, t_id, t.path,
                                           t.ref_id);
         match ty::get(tpt.ty).sty {
            ty::ty_trait(*) => {
@@ -806,7 +815,7 @@ pub fn instantiate_trait_ref(ccx: @mut CrateCtxt, t: @ast::trait_ref,
     }
 }
 
-pub fn ty_of_item(ccx: @mut CrateCtxt, it: @ast::item)
+pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item)
                -> ty::ty_param_bounds_and_ty {
     let def_id = local_def(it.id);
     let tcx = ccx.tcx;
@@ -817,14 +826,14 @@ pub fn ty_of_item(ccx: @mut CrateCtxt, it: @ast::item)
     let rp = tcx.region_paramd_items.find(&it.id);
     match it.node {
       ast::item_const(t, _) => {
-        let typ = ccx.to_ty(empty_rscope, t);
+        let typ = ccx.to_ty(&empty_rscope, t);
         let tpt = no_params(typ);
         tcx.tcache.insert(local_def(it.id), tpt);
         return tpt;
       }
       ast::item_fn(ref decl, purity, ref generics, _) => {
         let bounds = ty_param_bounds(ccx, generics);
-        let tofd = astconv::ty_of_bare_fn(ccx, empty_rscope, purity,
+        let tofd = astconv::ty_of_bare_fn(ccx, &empty_rscope, purity,
                                           ast::RustAbi, decl);
         let tpt = ty_param_bounds_and_ty {
             bounds: bounds,
@@ -847,7 +856,7 @@ pub fn ty_of_item(ccx: @mut CrateCtxt, it: @ast::item)
         let rp = tcx.region_paramd_items.find(&it.id);
         let tpt = {
             let ty = {
-                let t0 = ccx.to_ty(type_rscope(rp), t);
+                let t0 = ccx.to_ty(&type_rscope(rp), t);
                 // Do not associate a def id with a named, parameterized type
                 // like "foo<X>".  This is because otherwise ty_to_str will
                 // print the name as merely "foo", as it has no way to
@@ -906,23 +915,21 @@ pub fn ty_of_item(ccx: @mut CrateCtxt, it: @ast::item)
     }
 }
 
-pub fn ty_of_foreign_item(ccx: @mut CrateCtxt, it: @ast::foreign_item)
+pub fn ty_of_foreign_item(ccx: &CrateCtxt, it: @ast::foreign_item)
     -> ty::ty_param_bounds_and_ty {
-    match /*bad*/copy it.node {
+    match it.node {
         ast::foreign_item_fn(ref fn_decl, _, ref generics) => {
-            ty_of_foreign_fn_decl(
-                ccx,
-                fn_decl,
-                local_def(it.id),
-                generics
-            )
+            ty_of_foreign_fn_decl(ccx,
+                                  fn_decl,
+                                  local_def(it.id),
+                                  generics)
         }
         ast::foreign_item_const(t) => {
-            let rb = in_binding_rscope(empty_rscope);
+            let rb = in_binding_rscope(&empty_rscope);
             ty::ty_param_bounds_and_ty {
                 bounds: @~[],
                 region_param: None,
-                ty: ast_ty_to_ty(ccx, rb, t)
+                ty: ast_ty_to_ty(ccx, &rb, t)
             }
         }
     }
@@ -932,14 +939,14 @@ pub fn ty_of_foreign_item(ccx: @mut CrateCtxt, it: @ast::foreign_item)
 // of a newtyped Ty or a region) to ty's notion of ty param bounds, which can
 // either be user-defined traits, or one of the four built-in traits (formerly
 // known as kinds): Const, Copy, Durable, and Send.
-pub fn compute_bounds(ccx: @mut CrateCtxt,
+pub fn compute_bounds(ccx: &CrateCtxt,
                       ast_bounds: @OptVec<ast::TyParamBound>)
                    -> ty::param_bounds {
     @ast_bounds.flat_map_to_vec(|b| {
         match b {
             &TraitTyParamBound(b) => {
                 let li = &ccx.tcx.lang_items;
-                let ity = ast_ty_to_ty(ccx, empty_rscope, b);
+                let ity = ast_ty_to_ty(ccx, &empty_rscope, b);
                 match ty::get(ity).sty {
                     ty::ty_trait(did, _, _) => {
                         if did == li.owned_trait() {
@@ -968,7 +975,7 @@ pub fn compute_bounds(ccx: @mut CrateCtxt,
     })
 }
 
-pub fn ty_param_bounds(ccx: @mut CrateCtxt,
+pub fn ty_param_bounds(ccx: &CrateCtxt,
                        generics: &ast::Generics)
                     -> @~[ty::param_bounds] {
     @do generics.ty_params.map_to_vec |param| {
@@ -983,15 +990,15 @@ pub fn ty_param_bounds(ccx: @mut CrateCtxt,
     }
 }
 
-pub fn ty_of_foreign_fn_decl(ccx: @mut CrateCtxt,
+pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
                              decl: &ast::fn_decl,
                              def_id: ast::def_id,
                              generics: &ast::Generics)
                           -> ty::ty_param_bounds_and_ty {
     let bounds = ty_param_bounds(ccx, generics);
-    let rb = in_binding_rscope(empty_rscope);
-    let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, rb, *a, None) );
-    let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
+    let rb = in_binding_rscope(&empty_rscope);
+    let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, &rb, *a, None) );
+    let output_ty = ast_ty_to_ty(ccx, &rb, decl.output);
 
     let t_fn = ty::mk_bare_fn(
         ccx.tcx,
@@ -1009,7 +1016,7 @@ pub fn ty_of_foreign_fn_decl(ccx: @mut CrateCtxt,
     return tpt;
 }
 
-pub fn mk_generics(ccx: @mut CrateCtxt, generics: &ast::Generics)
+pub fn mk_generics(ccx: &CrateCtxt, generics: &ast::Generics)
     -> (@~[ty::param_bounds], ~[ty::t])
 {
     let mut i = 0u;
@@ -1022,7 +1029,7 @@ pub fn mk_generics(ccx: @mut CrateCtxt, generics: &ast::Generics)
      }))
 }
 
-pub fn mk_substs(ccx: @mut CrateCtxt,
+pub fn mk_substs(ccx: &CrateCtxt,
                  generics: &ast::Generics,
                  rp: Option<ty::region_variance>)
               -> (@~[ty::param_bounds], ty::substs)
diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs
index 7b3fb02e1d8..84c68197e0c 100644
--- a/src/librustc/middle/typeck/rscope.rs
+++ b/src/librustc/middle/typeck/rscope.rs
@@ -18,41 +18,59 @@ use syntax::ast;
 use syntax::codemap::span;
 
 pub trait region_scope {
-    pure fn anon_region(&self, span: span) -> Result<ty::Region, ~str>;
-    pure fn self_region(&self, span: span) -> Result<ty::Region, ~str>;
-    pure fn named_region(&self, span: span, id: ast::ident)
+    fn anon_region(&self, span: span) -> Result<ty::Region, ~str>;
+    fn self_region(&self, span: span) -> Result<ty::Region, ~str>;
+    fn named_region(&self, span: span, id: ast::ident)
                       -> Result<ty::Region, ~str>;
 }
 
 pub enum empty_rscope { empty_rscope }
-
 impl region_scope for empty_rscope {
-    pure fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
-        result::Ok(ty::re_static)
+    fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
+        Ok(ty::re_static)
     }
-    pure fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
+    fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
         result::Err(~"only the static region is allowed here")
     }
-    pure fn named_region(&self, _span: span, _id: ast::ident)
+    fn named_region(&self, _span: span, _id: ast::ident)
         -> Result<ty::Region, ~str> {
         result::Err(~"only the static region is allowed here")
     }
 }
 
-pub enum type_rscope = Option<ty::region_variance>;
+pub struct MethodRscope {
+    self_ty: ast::self_ty_,
+    region_parameterization: Option<ty::region_variance>
+}
+impl region_scope for MethodRscope {
+    fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
+        result::Err(~"anonymous region types are not permitted here")
+    }
+    fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
+        assert self.region_parameterization.is_some() ||
+            self.self_ty.is_borrowed();
+        result::Ok(ty::re_bound(ty::br_self))
+    }
+    fn named_region(&self, span: span, id: ast::ident)
+                      -> Result<ty::Region, ~str> {
+        do empty_rscope.named_region(span, id).chain_err |_e| {
+            result::Err(~"region is not in scope here")
+        }
+    }
+}
 
+pub enum type_rscope = Option<ty::region_variance>;
 impl region_scope for type_rscope {
-    pure fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
-        match **self {
-          Some(_) => result::Ok(ty::re_bound(ty::br_self)),
-          None => result::Err(~"to use region types here, the containing \
-                                type must be declared with a region bound")
-        }
+    fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
+        // if the anon or self region is used, region parameterization should
+        // have inferred that this type is RP
+        assert self.is_some();
+        result::Ok(ty::re_bound(ty::br_self))
     }
-    pure fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
+    fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
         self.anon_region(span)
     }
-    pure fn named_region(&self, span: span, id: ast::ident)
+    fn named_region(&self, span: span, id: ast::ident)
                       -> Result<ty::Region, ~str> {
         do empty_rscope.named_region(span, id).chain_err |_e| {
             result::Err(~"named regions other than `self` are not \
@@ -70,50 +88,55 @@ pub fn bound_self_region(rp: Option<ty::region_variance>)
 }
 
 pub struct anon_rscope { anon: ty::Region, base: @region_scope }
-pub fn in_anon_rscope<RS:region_scope + Copy + Durable>(self: RS,
-                                                        r: ty::Region)
-                                                     -> @anon_rscope {
-    @anon_rscope {anon: r, base: @self as @region_scope}
+pub fn in_anon_rscope<RS:region_scope + Copy + Durable>(
+    self: &RS,
+    r: ty::Region) -> anon_rscope
+{
+    let base = @(copy *self) as @region_scope;
+    anon_rscope {anon: r, base: base}
 }
-
-impl region_scope for @anon_rscope {
-    pure fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
+impl region_scope for anon_rscope {
+    fn anon_region(&self,
+                   _span: span) -> Result<ty::Region, ~str>
+    {
         result::Ok(self.anon)
     }
-    pure fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
+    fn self_region(&self,
+                   span: span) -> Result<ty::Region, ~str>
+    {
         self.base.self_region(span)
     }
-    pure fn named_region(&self, span: span, id: ast::ident)
-                      -> Result<ty::Region, ~str> {
+    fn named_region(&self,
+                    span: span,
+                    id: ast::ident) -> Result<ty::Region, ~str>
+    {
         self.base.named_region(span, id)
     }
 }
 
 pub struct binding_rscope {
-    base: region_scope,
-    anon_bindings: uint,
+    base: @region_scope,
+    anon_bindings: @mut uint,
 }
 
-pub fn in_binding_rscope<RS:region_scope + Copy + Durable>(self: RS)
-    -> @mut binding_rscope {
-    let base = @self as @region_scope;
-    @mut binding_rscope { base: base, anon_bindings: 0 }
+pub fn in_binding_rscope<RS:region_scope + Copy + Durable>(self: &RS)
+    -> binding_rscope {
+    let base = @(copy *self) as @region_scope;
+    binding_rscope { base: base, anon_bindings: @mut 0 }
 }
-
-impl region_scope for @mut binding_rscope {
-    pure fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
-        // XXX: Unsafe to work around purity
-        unsafe {
-            let idx = self.anon_bindings;
-            self.anon_bindings += 1;
-            result::Ok(ty::re_bound(ty::br_anon(idx)))
-        }
+impl region_scope for binding_rscope {
+    fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
+        let idx = *self.anon_bindings;
+        *self.anon_bindings += 1;
+        result::Ok(ty::re_bound(ty::br_anon(idx)))
     }
-    pure fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
+    fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
         self.base.self_region(span)
     }
-    pure fn named_region(&self, span: span, id: ast::ident)
-                      -> Result<ty::Region, ~str> {
+    fn named_region(&self,
+                    span: span,
+                    id: ast::ident) -> Result<ty::Region, ~str>
+    {
         do self.base.named_region(span, id).chain_err |_e| {
             result::Ok(ty::re_bound(ty::br_named(id)))
         }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 47948cc3ead..484fff1f9de 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1017,6 +1017,15 @@ pub enum self_ty_ {
     sty_uniq(mutability)                // by-unique-pointer self: `~self`
 }
 
+impl self_ty_ {
+    fn is_borrowed(&self) -> bool {
+        match *self {
+            sty_region(_) => true,
+            _ => false
+        }
+    }
+}
+
 pub type self_ty = spanned<self_ty_>;
 
 #[auto_encode]
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 24110125262..735344e43be 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -30,7 +30,6 @@ use print::pprust;
 use core::char;
 use core::dvec::DVec;
 use core::io;
-use core::option;
 use core::str;
 use core::u64;
 use core::vec;
diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs
index 8512e8d13dc..c8384c18831 100644
--- a/src/test/compile-fail/map-types.rs
+++ b/src/test/compile-fail/map-types.rs
@@ -17,5 +17,5 @@ fn main() {
     let x: @Map<~str, ~str> = @LinearMap::new::<~str, ~str>() as
         Map::<~str, ~str>;
     let y: @Map<uint, ~str> = @x;
-    //~^ ERROR mismatched types: expected `@core::container::Map/&<uint,~str>`
+    //~^ ERROR mismatched types: expected `@core::container::Map<uint,~str>`
 }
diff --git a/src/test/run-pass/regions-parameterization-self-types-issue-5224.rs b/src/test/run-pass/regions-parameterization-self-types-issue-5224.rs
new file mode 100644
index 00000000000..588db79a6c5
--- /dev/null
+++ b/src/test/run-pass/regions-parameterization-self-types-issue-5224.rs
@@ -0,0 +1,28 @@
+// Test how region-parameterization inference
+// interacts with explicit self types.
+//
+// Issue #5224.
+
+trait Getter {
+    // This trait does not need to be
+    // region-parameterized, because 'self
+    // is bound in the self type:
+    fn get(&self) -> &'self int;
+}
+
+struct Foo {
+    field: int
+}
+
+impl Getter for Foo {
+    fn get(&self) -> &'self int { &self.field }
+}
+
+fn get_int<G: Getter>(g: &G) -> int {
+    *g.get()
+}
+
+fn main() {
+    let foo = Foo { field: 22 };
+    assert get_int(&foo) == 22;
+}