about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2013-03-25 13:15:03 -0700
committerPatrick Walton <pcwalton@mimiga.net>2013-03-26 21:29:35 -0700
commit15688eaf284b54d29e42b4ec415c23c94e567b23 (patch)
treee171e163bbeab4085101612136e74bb443b0c740
parent3b2fcf9f5991effa96c0102adc155bad0b5a4feb (diff)
downloadrust-15688eaf284b54d29e42b4ec415c23c94e567b23.tar.gz
rust-15688eaf284b54d29e42b4ec415c23c94e567b23.zip
librustc: Require explicit lifetime binders
-rw-r--r--src/librustc/middle/typeck/astconv.rs49
-rw-r--r--src/librustc/middle/typeck/check/mod.rs29
-rw-r--r--src/librustc/middle/typeck/collect.rs112
-rw-r--r--src/librustc/middle/typeck/rscope.rs195
4 files changed, 322 insertions, 63 deletions
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 4f8f600485e..dad660e8c70 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -58,13 +58,15 @@ use middle::const_eval;
 use middle::ty::{arg, field, substs};
 use middle::ty::{ty_param_substs_and_ty};
 use middle::ty;
-use middle::typeck::rscope::{in_binding_rscope};
+use middle::typeck::rscope::{in_binding_rscope, in_binding_rscope_ext};
 use middle::typeck::rscope::{region_scope, type_rscope, RegionError};
+use middle::typeck::rscope::{RegionParamNames};
 
 use core::result;
 use core::vec;
 use syntax::{ast, ast_util};
 use syntax::codemap::span;
+use syntax::opt_vec::OptVec;
 use syntax::print::pprust::{lifetime_to_str, path_to_str};
 use syntax::parse::token::special_idents;
 use util::common::indenter;
@@ -348,9 +350,15 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + Durable>(
                                             bf.abi, &bf.decl))
       }
       ast::ty_closure(ref f) => {
-          let fn_decl = ty_of_closure(self, rscope, f.sigil,
-                                      f.purity, f.onceness,
-                                      f.region, &f.decl, None,
+          let fn_decl = ty_of_closure(self,
+                                      rscope,
+                                      f.sigil,
+                                      f.purity,
+                                      f.onceness,
+                                      f.region,
+                                      &f.decl,
+                                      None,
+                                      &f.lifetimes,
                                       ast_ty.span);
           ty::mk_closure(tcx, fn_decl)
       }
@@ -507,7 +515,7 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
         abi: ast::Abi,
         decl: &ast::fn_decl)
      -> ty::BareFnTy {
-    debug!("ty_of_fn_decl");
+    debug!("ty_of_bare_fn");
 
     // new region names that appear inside of the fn decl are bound to
     // that function type
@@ -526,6 +534,33 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
     }
 }
 
+pub fn ty_of_bare_fn_ext<AC:AstConv,RS:region_scope + Copy + Durable>(
+        self: &AC,
+        rscope: &RS,
+        purity: ast::purity,
+        abi: ast::Abi,
+        decl: &ast::fn_decl,
+        +region_param_names: RegionParamNames)
+     -> ty::BareFnTy {
+    debug!("ty_of_bare_fn_ext");
+
+    // new region names that appear inside of the fn decl are bound to
+    // that function type
+    let rb = in_binding_rscope_ext(rscope, region_param_names);
+
+    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)
+    };
+
+    ty::BareFnTy {
+        purity: purity,
+        abi: abi,
+        sig: ty::FnSig {inputs: input_tys, output: output_ty}
+    }
+}
+
 pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
         self: &AC,
         rscope: &RS,
@@ -535,6 +570,7 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
         opt_lifetime: Option<@ast::Lifetime>,
         decl: &ast::fn_decl,
         expected_tys: Option<ty::FnSig>,
+        lifetimes: &OptVec<ast::Lifetime>,
         span: span)
      -> ty::ClosureTy {
     debug!("ty_of_fn_decl");
@@ -563,7 +599,8 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
 
     // new region names that appear inside of the fn decl are bound to
     // that function type
-    let rb = in_binding_rscope(rscope);
+    let region_param_names = RegionParamNames::from_lifetimes(lifetimes);
+    let rb = in_binding_rscope_ext(rscope, region_param_names);
 
     let input_tys = do decl.inputs.mapi |i, a| {
         let expected_arg_ty = do expected_tys.chain_ref |e| {
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 17a67838bbe..75c6bfd5d64 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -100,7 +100,7 @@ use middle::typeck::CrateCtxt;
 use middle::typeck::infer::{resolve_type, force_tvar, mk_eqty};
 use middle::typeck::infer;
 use middle::typeck::rscope::{binding_rscope, bound_self_region};
-use middle::typeck::rscope::{RegionError};
+use middle::typeck::rscope::{RegionError, RegionParameterization};
 use middle::typeck::rscope::{in_binding_rscope, region_scope, type_rscope};
 use middle::typeck::rscope;
 use middle::typeck::{isr_alist, lookup_def_ccx, method_map_entry};
@@ -126,10 +126,11 @@ use syntax::ast_util::{Private, Public, is_local, local_def};
 use syntax::ast_util;
 use syntax::codemap::{span, spanned, respan};
 use syntax::codemap;
+use syntax::opt_vec::OptVec;
+use syntax::opt_vec;
 use syntax::parse::token::special_idents;
 use syntax::print::pprust;
 use syntax::visit;
-use syntax::opt_vec::OptVec;
 use syntax;
 
 pub mod _match;
@@ -570,10 +571,12 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
       ast::item_fn(ref decl, _, _, ref body) => {
         check_bare_fn(ccx, decl, body, it.id, None);
       }
-      ast::item_impl(_, _, ty, ref ms) => {
+      ast::item_impl(ref generics, _, ty, ref ms) => {
         let rp = ccx.tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
         debug!("item_impl %s with id %d rp %?",
                *ccx.tcx.sess.str_of(it.ident), it.id, rp);
+        let rp = RegionParameterization::from_variance_and_generics(
+            rp, generics);
         let self_ty = ccx.to_ty(&rscope::type_rscope(rp), ty);
         for ms.each |m| {
             check_method(ccx, *m, self_ty);
@@ -1069,9 +1072,13 @@ pub fn impl_self_ty(vcx: &VtableContext,
                   node: ast::item_impl(ref ts, _, st, _),
                   _
               }, _)) => {
+            let region_parameterization =
+                RegionParameterization::from_variance_and_generics(
+                    region_param,
+                    ts);
             (ts.ty_params.len(),
              region_param,
-             vcx.ccx.to_ty(&rscope::type_rscope(region_param), st))
+             vcx.ccx.to_ty(&rscope::type_rscope(region_parameterization), st))
           }
           Some(&ast_map::node_item(@ast::item {
                   node: ast::item_struct(_, ref ts),
@@ -1654,10 +1661,16 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
         };
 
         // construct the function type
-        let mut fn_ty = astconv::ty_of_closure(
-            fcx, fcx,
-            sigil, purity, expected_onceness,
-            None, decl, expected_tys, expr.span);
+        let mut fn_ty = astconv::ty_of_closure(fcx,
+                                               fcx,
+                                               sigil,
+                                               purity,
+                                               expected_onceness,
+                                               None,
+                                               decl,
+                                               expected_tys,
+                                               &opt_vec::Empty,
+                                               expr.span);
 
         let mut fty_sig;
         let fty = if error_happened {
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index a1fcf102988..6d304247c5d 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -166,12 +166,15 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
 
     // Create a set of parameter types shared among all the variants.
     for variants.each |variant| {
+        let region_parameterization =
+            RegionParameterization::from_variance_and_generics(rp, generics);
+
         // Nullary enum constructors get turned into constants; n-ary enum
         // constructors get turned into functions.
         let result_ty;
         match variant.node.kind {
             ast::tuple_variant_kind(ref args) if args.len() > 0 => {
-                let rs = type_rscope(rp);
+                let rs = type_rscope(region_parameterization);
                 let input_tys = args.map(|va| ccx.to_ty(&rs, va.ty));
                 result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty));
             }
@@ -301,7 +304,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
                 ccx,
                 &ty_m,
                 region_paramd,
-                def_id
+                def_id,
+                generics
             );
             if ty_m.self_ty.node == ast::sty_static {
                 make_static_method_ty(ccx, &ty_m, region_paramd,
@@ -319,13 +323,14 @@ pub fn ensure_supertraits(ccx: &CrateCtxt,
                           id: ast::node_id,
                           sp: codemap::span,
                           rp: Option<ty::region_variance>,
-                          trait_refs: &[@ast::trait_ref]) {
+                          trait_refs: &[@ast::trait_ref],
+                          generics: &ast::Generics) {
     let tcx = ccx.tcx;
     if tcx.supertraits.contains_key(&local_def(id)) { return; }
 
     let mut instantiated = ~[];
     for trait_refs.each |trait_ref| {
-        let (did, tpt) = instantiate_trait_ref(ccx, *trait_ref, rp);
+        let (did, tpt) = instantiate_trait_ref(ccx, *trait_ref, rp, generics);
         if instantiated.any(|other_trait: &InstantiatedTraitRef|
                             { other_trait.def_id == did }) {
             // This means a trait inherited from the same supertrait more
@@ -506,7 +511,7 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt,
                                    impl_ms: &[ConvertedMethod]) {
 
     let tcx = ccx.tcx;
-    let (did, tpt) = instantiate_trait_ref(ccx, a_trait_ty, rp);
+    let (did, tpt) = instantiate_trait_ref(ccx, a_trait_ty, rp, generics);
 
     if did.crate == ast::local_crate {
         // NB: This is subtle. We need to do this on the type of the trait
@@ -553,8 +558,11 @@ pub fn check_methods_against_trait(ccx: &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);
+                     v: @ast::struct_field,
+                     generics: &ast::Generics) {
+    let region_parameterization =
+        RegionParameterization::from_variance_and_generics(rp, generics);
+    let tt = ccx.to_ty(&type_rscope(region_parameterization), 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),
@@ -575,13 +583,14 @@ pub struct ConvertedMethod {
 pub fn convert_methods(ccx: &CrateCtxt,
                        ms: &[@ast::method],
                        rp: Option<ty::region_variance>,
-                       rcvr_bounds: @~[ty::param_bounds])
+                       rcvr_bounds: @~[ty::param_bounds],
+                       rcvr_generics: &ast::Generics)
                     -> ~[ConvertedMethod] {
 
     let tcx = ccx.tcx;
     do vec::map(ms) |m| {
         let bounds = ty_param_bounds(ccx, &m.generics);
-        let mty = ty_of_method(ccx, *m, rp);
+        let mty = ty_of_method(ccx, *m, rp, rcvr_generics, &m.generics);
         let fty = ty::mk_bare_fn(tcx, copy mty.fty);
         tcx.tcache.insert(
             local_def(m.id),
@@ -633,7 +642,9 @@ pub fn convert(ccx: &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 region_parameterization =
+            RegionParameterization::from_variance_and_generics(rp, generics);
+        let selfty = ccx.to_ty(&type_rscope(region_parameterization), selfty);
         write_ty_to_tcx(tcx, it.id, selfty);
         tcx.tcache.insert(local_def(it.id),
                           ty_param_bounds_and_ty {
@@ -642,7 +653,7 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) {
                             ty: selfty});
 
         // XXX: Bad copy of `ms` below.
-        let cms = convert_methods(ccx, *ms, rp, i_bounds);
+        let cms = convert_methods(ccx, *ms, rp, i_bounds, generics);
         for trait_ref.each |t| {
             check_methods_against_trait(ccx, generics, rp, selfty, *t, cms);
         }
@@ -653,12 +664,12 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) {
                it.id, ppaux::ty_to_str(tcx, tpt.ty));
         write_ty_to_tcx(tcx, it.id, tpt.ty);
         ensure_trait_methods(ccx, it.id, tpt.ty);
-        ensure_supertraits(ccx, it.id, it.span, rp, *supertraits);
+        ensure_supertraits(ccx, it.id, it.span, rp, *supertraits, generics);
 
         let (_, provided_methods) =
             split_trait_methods(*trait_methods);
         let (bounds, _) = mk_substs(ccx, generics, rp);
-        let _ = convert_methods(ccx, provided_methods, rp, bounds);
+        let _ = convert_methods(ccx, provided_methods, rp, bounds, generics);
       }
       ast::item_struct(struct_def, ref generics) => {
         ensure_no_ty_param_bounds(ccx, it.span, generics, "structure");
@@ -694,12 +705,17 @@ pub fn convert_struct(ccx: &CrateCtxt,
     let tcx = ccx.tcx;
 
     for struct_def.dtor.each |dtor| {
+        let region_parameterization =
+            RegionParameterization::from_variance_and_generics(rp, generics);
+
         // Write the dtor type
         let t_dtor = ty::mk_bare_fn(
             tcx,
             astconv::ty_of_bare_fn(
-                ccx, &type_rscope(rp),
-                ast::impure_fn, ast::RustAbi,
+                ccx,
+                &type_rscope(region_parameterization),
+                ast::impure_fn,
+                ast::RustAbi,
                 &ast_util::dtor_dec()));
         write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
         tcx.tcache.insert(local_def(dtor.node.id),
@@ -711,7 +727,7 @@ pub fn convert_struct(ccx: &CrateCtxt,
 
     // Write the type of each of the members
     for struct_def.fields.each |f| {
-       convert_field(ccx, rp, tpt.bounds, *f);
+       convert_field(ccx, rp, tpt.bounds, *f, generics);
     }
     let (_, substs) = mk_substs(ccx, generics, rp);
     let selfty = ty::mk_struct(tcx, local_def(id), substs);
@@ -754,17 +770,23 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) {
 
 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
-    };
-
+                    rp: Option<ty::region_variance>,
+                    rcvr_generics: &ast::Generics,
+                    method_generics: &ast::Generics)
+                 -> ty::method {
+    let rscope = MethodRscope::new(m.self_ty.node,
+                                   rp,
+                                   rcvr_generics,
+                                   method_generics);
     ty::method {
         ident: m.ident,
         tps: ty_param_bounds(ccx, &m.generics),
-        fty: astconv::ty_of_bare_fn(ccx, &rscope, m.purity,
-                                    ast::RustAbi, &m.decl),
+        fty: astconv::ty_of_bare_fn_ext(ccx,
+                                        &rscope,
+                                        m.purity,
+                                        ast::RustAbi,
+                                        &m.decl,
+                                        rscope.region_param_names()),
         self_ty: m.self_ty.node,
         vis: m.vis,
         def_id: local_def(m.id)
@@ -774,17 +796,19 @@ pub fn ty_of_method(ccx: &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
-    };
-
+                       id: ast::def_id,
+                       generics: &ast::Generics)
+                    -> ty::method {
+    let rscope = MethodRscope::new(m.self_ty.node, rp, generics, &m.generics);
     ty::method {
         ident: m.ident,
         tps: ty_param_bounds(self, &m.generics),
-        fty: astconv::ty_of_bare_fn(self, &rscope, m.purity,
-                                    ast::RustAbi, &m.decl),
+        fty: astconv::ty_of_bare_fn_ext(self,
+                                        &rscope,
+                                        m.purity,
+                                        ast::RustAbi,
+                                        &m.decl,
+                                        rscope.region_param_names()),
         // assume public, because this is only invoked on trait methods
         self_ty: m.self_ty.node,
         vis: ast::public,
@@ -797,13 +821,17 @@ pub fn ty_of_ty_method(self: &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: &CrateCtxt, t: @ast::trait_ref,
-                             rp: Option<ty::region_variance>)
+pub fn instantiate_trait_ref(ccx: &CrateCtxt,
+                             t: @ast::trait_ref,
+                             rp: Option<ty::region_variance>,
+                             generics: &ast::Generics)
     -> (ast::def_id, ty_param_substs_and_ty) {
 
     let sp = t.path.span, err = ~"can only implement trait types",
         sess = ccx.tcx.sess;
 
+    let rp = RegionParameterization::from_variance_and_generics(rp, generics);
+
     let rscope = type_rscope(rp);
 
     match lookup_def_tcx(ccx.tcx, t.path.span, t.ref_id) {
@@ -841,8 +869,13 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item)
       }
       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,
-                                          ast::RustAbi, decl);
+        let region_param_names = RegionParamNames::from_generics(generics);
+        let tofd = astconv::ty_of_bare_fn_ext(ccx,
+                                              &empty_rscope,
+                                              purity,
+                                              ast::RustAbi,
+                                              decl,
+                                              region_param_names);
         let tpt = ty_param_bounds_and_ty {
             bounds: bounds,
             region_param: None,
@@ -862,9 +895,11 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item)
         }
 
         let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
+        let region_parameterization =
+            RegionParameterization::from_variance_and_generics(rp, generics);
         let tpt = {
             let ty = {
-                let t0 = ccx.to_ty(&type_rscope(rp), t);
+                let t0 = ccx.to_ty(&type_rscope(region_parameterization), 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
@@ -1007,7 +1042,8 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
                              generics: &ast::Generics)
                           -> ty::ty_param_bounds_and_ty {
     let bounds = ty_param_bounds(ccx, generics);
-    let rb = in_binding_rscope(&empty_rscope);
+    let region_param_names = RegionParamNames::from_generics(generics);
+    let rb = in_binding_rscope_ext(&empty_rscope, region_param_names);
     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);
 
diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs
index e29e63c41ec..135993e18a2 100644
--- a/src/librustc/middle/typeck/rscope.rs
+++ b/src/librustc/middle/typeck/rscope.rs
@@ -16,6 +16,9 @@ use core::result::Result;
 use core::result;
 use syntax::ast;
 use syntax::codemap::span;
+use syntax::opt_vec::OptVec;
+use syntax::opt_vec;
+use syntax::parse::token::special_idents;
 
 pub struct RegionError {
     msg: ~str,
@@ -47,10 +50,130 @@ impl region_scope for empty_rscope {
     }
 }
 
+pub struct RegionParamNames(OptVec<ast::ident>);
+
+impl RegionParamNames {
+    fn has_self(&self) -> bool {
+        self.has_ident(special_idents::self_)
+    }
+
+    fn has_ident(&self, ident: ast::ident) -> bool {
+        for self.each |region_param_name| {
+            if *region_param_name == ident {
+                return true;
+            }
+        }
+        false
+    }
+
+    pub fn add_generics(&mut self, generics: &ast::Generics) {
+        match generics.lifetimes {
+            opt_vec::Empty => {}
+            opt_vec::Vec(ref new_lifetimes) => {
+                match **self {
+                    opt_vec::Empty => {
+                        *self = RegionParamNames(
+                            opt_vec::Vec(new_lifetimes.map(|lt| lt.ident)));
+                    }
+                    opt_vec::Vec(ref mut existing_lifetimes) => {
+                        for new_lifetimes.each |new_lifetime| {
+                            existing_lifetimes.push(new_lifetime.ident);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // Convenience function to produce the error for an unresolved name. The
+    // optional argument specifies a custom replacement.
+    pub fn undeclared_name(custom_replacement: Option<ty::Region>)
+                        -> Result<ty::Region, RegionError> {
+        let replacement = match custom_replacement {
+            None => ty::re_bound(ty::br_self),
+            Some(custom_replacement) => custom_replacement
+        };
+        Err(RegionError {
+            msg: ~"this lifetime must be declared",
+            replacement: replacement
+        })
+    }
+
+    pub fn from_generics(generics: &ast::Generics) -> RegionParamNames {
+        match generics.lifetimes {
+            opt_vec::Empty => RegionParamNames(opt_vec::Empty),
+            opt_vec::Vec(ref lifetimes) => {
+                RegionParamNames(opt_vec::Vec(lifetimes.map(|lt| lt.ident)))
+            }
+        }
+    }
+
+    pub fn from_lifetimes(lifetimes: &opt_vec::OptVec<ast::Lifetime>)
+                       -> RegionParamNames {
+        match *lifetimes {
+            opt_vec::Empty => RegionParamNames::new(),
+            opt_vec::Vec(ref v) => {
+                RegionParamNames(opt_vec::Vec(v.map(|lt| lt.ident)))
+            }
+        }
+    }
+
+    fn new() -> RegionParamNames {
+        RegionParamNames(opt_vec::Empty)
+    }
+}
+
+struct RegionParameterization {
+    variance: ty::region_variance,
+    region_param_names: RegionParamNames,
+}
+
+impl RegionParameterization {
+    pub fn from_variance_and_generics(variance: Option<ty::region_variance>,
+                                      generics: &ast::Generics)
+                                   -> Option<RegionParameterization> {
+        match variance {
+            None => None,
+            Some(variance) => {
+                Some(RegionParameterization {
+                    variance: variance,
+                    region_param_names:
+                        RegionParamNames::from_generics(generics),
+                })
+            }
+        }
+    }
+}
+
 pub struct MethodRscope {
     self_ty: ast::self_ty_,
-    region_parameterization: Option<ty::region_variance>
+    variance: Option<ty::region_variance>,
+    region_param_names: RegionParamNames,
+}
+
+impl MethodRscope {
+    // `generics` here refers to the generics of the outer item (impl or
+    // trait).
+    pub fn new(self_ty: ast::self_ty_,
+               variance: Option<ty::region_variance>,
+               rcvr_generics: &ast::Generics,
+               method_generics: &ast::Generics)
+            -> MethodRscope {
+        let mut region_param_names =
+            RegionParamNames::from_generics(rcvr_generics);
+        region_param_names.add_generics(method_generics);
+        MethodRscope {
+            self_ty: self_ty,
+            variance: variance,
+            region_param_names: region_param_names
+        }
+    }
+
+    pub fn region_param_names(&self) -> RegionParamNames {
+        copy self.region_param_names
+    }
 }
+
 impl region_scope for MethodRscope {
     fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
         result::Err(RegionError {
@@ -59,12 +182,26 @@ impl region_scope for MethodRscope {
         })
     }
     fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
-        fail_unless!(self.region_parameterization.is_some() ||
-            self.self_ty.is_borrowed());
+        fail_unless!(self.variance.is_some() || self.self_ty.is_borrowed());
+        match self.variance {
+            None => {}  // must be borrowed self, so this is OK
+            Some(_) => {
+                if !self.self_ty.is_borrowed() &&
+                        !self.region_param_names.has_self() {
+                    return Err(RegionError {
+                        msg: ~"the `self` lifetime must be declared",
+                        replacement: ty::re_bound(ty::br_self)
+                    })
+                }
+            }
+        }
         result::Ok(ty::re_bound(ty::br_self))
     }
     fn named_region(&self, span: span, id: ast::ident)
                       -> Result<ty::Region, RegionError> {
+        if !self.region_param_names.has_ident(id) {
+            return RegionParamNames::undeclared_name(None);
+        }
         do empty_rscope.named_region(span, id).chain_err |_e| {
             result::Err(RegionError {
                 msg: ~"lifetime is not in scope",
@@ -74,7 +211,7 @@ impl region_scope for MethodRscope {
     }
 }
 
-pub struct type_rscope(Option<ty::region_variance>);
+pub struct type_rscope(Option<RegionParameterization>);
 
 impl type_rscope {
     priv fn replacement(&self) -> ty::Region {
@@ -93,17 +230,29 @@ impl region_scope for type_rscope {
         })
     }
     fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
-        // if the self region is used, region parameterization should
-        // have inferred that this type is RP
-        fail_unless!(self.is_some());
+        match **self {
+            None => {
+                // if the self region is used, region parameterization should
+                // have inferred that this type is RP
+                fail!(~"region parameterization should have inferred that \
+                        this type is RP");
+            }
+            Some(ref region_parameterization) => {
+                if !region_parameterization.region_param_names.has_self() {
+                    return Err(RegionError {
+                        msg: ~"the `self` lifetime must be declared",
+                        replacement: ty::re_bound(ty::br_self)
+                    })
+                }
+            }
+        }
         result::Ok(ty::re_bound(ty::br_self))
     }
     fn named_region(&self, span: span, id: ast::ident)
                       -> Result<ty::Region, RegionError> {
         do empty_rscope.named_region(span, id).chain_err |_e| {
             result::Err(RegionError {
-                msg: ~"only 'self is allowed allowed as \
-                       part of a type declaration",
+                msg: ~"only 'self is allowed as part of a type declaration",
                 replacement: self.replacement()
             })
         }
@@ -121,14 +270,33 @@ pub fn bound_self_region(rp: Option<ty::region_variance>)
 pub struct binding_rscope {
     base: @region_scope,
     anon_bindings: @mut uint,
+    region_param_names: RegionParamNames,
 }
 
 pub fn in_binding_rscope<RS:region_scope + Copy + Durable>(self: &RS)
     -> binding_rscope {
     let base = @copy *self;
     let base = base as @region_scope;
-    binding_rscope { base: base, anon_bindings: @mut 0 }
+    binding_rscope {
+        base: base,
+        anon_bindings: @mut 0,
+        region_param_names: RegionParamNames::new()
+    }
 }
+
+pub fn in_binding_rscope_ext<RS:region_scope + Copy + Durable>(
+        self: &RS,
+        +region_param_names: RegionParamNames)
+     -> binding_rscope {
+    let base = @copy *self;
+    let base = base as @region_scope;
+    binding_rscope {
+        base: base,
+        anon_bindings: @mut 0,
+        region_param_names: region_param_names,
+    }
+}
+
 impl region_scope for binding_rscope {
     fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
         let idx = *self.anon_bindings;
@@ -143,7 +311,12 @@ impl region_scope for binding_rscope {
                     id: ast::ident) -> Result<ty::Region, RegionError>
     {
         do self.base.named_region(span, id).chain_err |_e| {
-            result::Ok(ty::re_bound(ty::br_named(id)))
+            let result = ty::re_bound(ty::br_named(id));
+            if self.region_param_names.has_ident(id) {
+                result::Ok(result)
+            } else {
+                RegionParamNames::undeclared_name(Some(result))
+            }
         }
     }
 }