From a6187c62e93ba96dce8f19849fb7016f4f941f8c Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Sat, 9 Mar 2013 19:43:53 -0500
Subject: [PATCH] Make &self permit explicit lifetimes, but don't really use
 them (this will be needed for snapshotting at some point).

---
 src/librustc/metadata/decoder.rs              |  5 +-
 src/librustc/metadata/encoder.rs              | 53 ++++++++++------
 src/librustc/middle/liveness.rs               |  2 +-
 src/librustc/middle/trans/meth.rs             |  4 +-
 src/librustc/middle/trans/reflect.rs          |  1 +
 src/librustc/middle/typeck/check/method.rs    |  9 ++-
 .../middle/typeck/check/regionmanip.rs        | 12 ++--
 src/libsyntax/ast.rs                          | 14 ++---
 src/libsyntax/ext/auto_encode.rs              |  6 +-
 src/libsyntax/ext/deriving.rs                 |  6 +-
 src/libsyntax/parse/parser.rs                 | 63 ++++++++++++++++++-
 src/libsyntax/print/pprust.rs                 | 25 ++++----
 src/test/run-pass/regions-expl-self.rs        | 21 +++++++
 13 files changed, 166 insertions(+), 55 deletions(-)
 create mode 100644 src/test/run-pass/regions-expl-self.rs

diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 658b32edf21..2e8b536e44d 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -631,7 +631,10 @@ fn get_self_ty(item: ebml::Doc) -> ast::self_ty_ {
         'v' => { return ast::sty_value; }
         '@' => { return ast::sty_box(get_mutability(string[1])); }
         '~' => { return ast::sty_uniq(get_mutability(string[1])); }
-        '&' => { return ast::sty_region(get_mutability(string[1])); }
+        '&' => {
+            // FIXME(#4846) expl. region
+            return ast::sty_region(None, get_mutability(string[1]));
+        }
         _ => {
             fail!(fmt!("unknown self type code: `%c`", self_ty_kind as char));
         }
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 4b1260e76d0..83550289a4f 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -406,32 +406,47 @@ fn encode_self_type(ebml_w: writer::Encoder, self_type: ast::self_ty_) {
     ebml_w.start_tag(tag_item_trait_method_self_ty);
 
     // Encode the base self type.
-    let ch;
     match self_type {
-        sty_static =>       { ch = 's' as u8; }
-        sty_by_ref =>       { ch = 'r' as u8; }
-        sty_value =>        { ch = 'v' as u8; }
-        sty_region(_) =>    { ch = '&' as u8; }
-        sty_box(_) =>       { ch = '@' as u8; }
-        sty_uniq(_) =>      { ch = '~' as u8; }
-    }
-    ebml_w.writer.write(&[ ch ]);
-
-    // Encode mutability.
-    match self_type {
-        sty_static | sty_by_ref | sty_value => { /* No-op. */ }
-        sty_region(m_imm) | sty_box(m_imm) | sty_uniq(m_imm) => {
-            ebml_w.writer.write(&[ 'i' as u8 ]);
+        sty_static => {
+            ebml_w.writer.write(&[ 's' as u8 ]);
         }
-        sty_region(m_mutbl) | sty_box(m_mutbl) | sty_uniq(m_mutbl) => {
-            ebml_w.writer.write(&[ 'm' as u8 ]);
+        sty_by_ref => {
+            ebml_w.writer.write(&[ 'r' as u8 ]);
         }
-        sty_region(m_const) | sty_box(m_const) | sty_uniq(m_const) => {
-            ebml_w.writer.write(&[ 'c' as u8 ]);
+        sty_value => {
+            ebml_w.writer.write(&[ 'v' as u8 ]);
+        }
+        sty_region(_, m) => {
+            // FIXME(#4846) encode custom lifetime
+            ebml_w.writer.write(&[ '&' as u8 ]);
+            encode_mutability(ebml_w, m);
+        }
+        sty_box(m) => {
+            ebml_w.writer.write(&[ '@' as u8 ]);
+            encode_mutability(ebml_w, m);
+        }
+        sty_uniq(m) => {
+            ebml_w.writer.write(&[ '~' as u8 ]);
+            encode_mutability(ebml_w, m);
         }
     }
 
     ebml_w.end_tag();
+
+    fn encode_mutability(ebml_w: writer::Encoder,
+                         m: ast::mutability) {
+        match m {
+            m_imm => {
+                ebml_w.writer.write(&[ 'i' as u8 ]);
+            }
+            m_mutbl => {
+                ebml_w.writer.write(&[ 'm' as u8 ]);
+            }
+            m_const => {
+                ebml_w.writer.write(&[ 'c' as u8 ]);
+            }
+        }
+    }
 }
 
 fn encode_method_sort(ebml_w: writer::Encoder, sort: char) {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 2afe9564b20..34fe7af8f1c 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -472,7 +472,7 @@ fn visit_fn(fk: &visit::fn_kind,
                                              special_idents::self_,
                                              by_ref));
                 }
-                sty_value | sty_region(_) | sty_box(_) | sty_uniq(_) => {
+                sty_value | sty_region(*) | sty_box(_) | sty_uniq(_) => {
                     fn_maps.add_variable(Arg(method.self_id,
                                              special_idents::self_,
                                              by_copy));
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index 5a46c24b939..51e26d3cfef 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -589,7 +589,7 @@ pub fn trans_trait_callee(bcx: block,
     let llpair = self_datum.to_ref_llval(bcx);
 
     let llpair = match explicit_self {
-        ast::sty_region(_) => Load(bcx, llpair),
+        ast::sty_region(*) => Load(bcx, llpair),
         ast::sty_static | ast::sty_by_ref | ast::sty_value |
         ast::sty_box(_) | ast::sty_uniq(_) => llpair
     };
@@ -658,7 +658,7 @@ pub fn trans_trait_callee_from_llval(bcx: block,
             bcx.tcx().sess.bug(~"methods with by-value self should not be \
                                called on objects");
         }
-        ast::sty_region(_) => {
+        ast::sty_region(*) => {
             // As before, we need to pass a pointer to a pointer to the
             // payload.
             match store {
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index a4a7d958e69..955bc563107 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -105,6 +105,7 @@ pub impl Reflector {
                                                       v,
                                                       ty::BoxTraitStore,
                                                       ast::sty_region(
+                                                        None,
                                                         ast::m_imm)),
             ArgVals(args), SaveIn(scratch.val), DontAutorefArg);
         let result = scratch.to_value_llval(bcx);
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index d673cf6a39a..39c0948ec67 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -743,10 +743,12 @@ pub impl LookupContext/&self {
                 sty_box(_) | sty_uniq(_) => {
                     self_substs
                 }
-                sty_region(_) if self_substs.self_r.is_some() => {
+                sty_region(*) if self_substs.self_r.is_some() => {
+                    // FIXME(#4846) ignoring expl lifetime here
                     self_substs
                 }
-                sty_region(_) => {
+                sty_region(*) => {
+                    // FIXME(#4846) ignoring expl lifetime here
                     substs {
                         self_r:
                              Some(self.infcx().next_region_var(
@@ -1326,7 +1328,8 @@ pub fn transform_self_type_for_method(tcx: ty::ctxt,
       sty_by_ref | sty_value => {
         impl_ty
       }
-      sty_region(mutability) => {
+      sty_region(_, mutability) => {
+        // FIXME(#4846) ignoring expl lifetime here
         mk_rptr(tcx,
                 self_region.expect(~"self region missing for &self param"),
                 ty::mt { ty: impl_ty, mutbl: mutability })
diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs
index 98f49e48c08..ffdd40c6cd8 100644
--- a/src/librustc/middle/typeck/check/regionmanip.rs
+++ b/src/librustc/middle/typeck/check/regionmanip.rs
@@ -30,8 +30,9 @@ pub fn replace_bound_regions_in_fn_sig(
     isr: isr_alist,
     self_info: Option<SelfInfo>,
     fn_sig: &ty::FnSig,
-    mapf: &fn(ty::bound_region) -> ty::Region) ->
-    (isr_alist, Option<SelfInfo>, ty::FnSig) {
+    mapf: &fn(ty::bound_region) -> ty::Region)
+    -> (isr_alist, Option<SelfInfo>, ty::FnSig)
+{
     // Take self_info apart; the self_ty part is the only one we want
     // to update here.
     let self_ty = self_info.map(|s| s.self_ty);
@@ -41,8 +42,10 @@ pub fn replace_bound_regions_in_fn_sig(
 
     match self_info {
       Some(SelfInfo {
-            explicit_self: codemap::spanned { node: ast::sty_region(m),
-                                          _}, _}) => {
+            explicit_self: codemap::spanned {
+                node: ast::sty_region(_, m),
+                // FIXME(#4846) ------^ Use this lifetime instead of self
+                _}, _}) => {
         let region = ty::re_bound(ty::br_self);
         let ty = ty::mk_rptr(tcx, region,
                              ty::mt { ty: ty::mk_self(tcx), mutbl: m });
@@ -51,7 +54,6 @@ pub fn replace_bound_regions_in_fn_sig(
       _ => {}
     }
 
-
     for self_ty.each |t| { all_tys.push(*t) }
 
     debug!("replace_bound_regions_in_fn_sig(self_info.self_ty=%?, fn_sig=%s, \
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index e5fb2ad153c..f603b86b58a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1002,18 +1002,18 @@ impl to_bytes::IterBytes for ret_style {
 #[auto_decode]
 #[deriving_eq]
 pub enum self_ty_ {
-    sty_static,                         // no self: static method
-    sty_by_ref,                         // old by-reference self: ``
-    sty_value,                          // by-value self: `self`
-    sty_region(mutability),             // by-region self: `&self`
-    sty_box(mutability),                // by-managed-pointer self: `@self`
-    sty_uniq(mutability)                // by-unique-pointer self: `~self`
+    sty_static,                                // no self
+    sty_by_ref,                                // ``
+    sty_value,                                 // `self`
+    sty_region(Option<@Lifetime>, mutability), // `&'lt self`
+    sty_box(mutability),                       // `@self`
+    sty_uniq(mutability)                       // `~self`
 }
 
 impl self_ty_ {
     fn is_borrowed(&self) -> bool {
         match *self {
-            sty_region(_) => true,
+            sty_region(*) => true,
             _ => false
         }
     }
diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs
index 8c02b432371..294174dc8f9 100644
--- a/src/libsyntax/ext/auto_encode.rs
+++ b/src/libsyntax/ext/auto_encode.rs
@@ -634,8 +634,10 @@ fn mk_ser_method(
         ident: cx.ident_of(~"encode"),
         attrs: ~[],
         generics: ast_util::empty_generics(),
-        self_ty: codemap::spanned { node: ast::sty_region(ast::m_imm),
-                                span: span },
+        self_ty: codemap::spanned {
+            node: ast::sty_region(None, ast::m_imm),
+            span: span
+        },
         purity: ast::impure_fn,
         decl: ser_decl,
         body: ser_body,
diff --git a/src/libsyntax/ext/deriving.rs b/src/libsyntax/ext/deriving.rs
index 26b5b4566b7..324c5289eb3 100644
--- a/src/libsyntax/ext/deriving.rs
+++ b/src/libsyntax/ext/deriving.rs
@@ -220,7 +220,7 @@ fn create_eq_method(cx: @ext_ctxt,
     let body_block = build::mk_simple_block(cx, span, body);
 
     // Create the method.
-    let self_ty = spanned { node: sty_region(m_imm), span: span };
+    let self_ty = spanned { node: sty_region(None, m_imm), span: span };
     @ast::method {
         ident: method_ident,
         attrs: ~[],
@@ -398,7 +398,7 @@ fn create_iter_bytes_method(cx: @ext_ctxt,
     let body_block = build::mk_block_(cx, span, statements);
 
     // Create the method.
-    let self_ty = spanned { node: sty_region(m_imm), span: span };
+    let self_ty = spanned { node: sty_region(None, m_imm), span: span };
     let method_ident = cx.ident_of(~"iter_bytes");
     @ast::method {
         ident: method_ident,
@@ -448,7 +448,7 @@ fn create_clone_method(cx: @ext_ctxt,
     let body_block = build::mk_simple_block(cx, span, expr);
 
     // Create the self type and method identifier.
-    let self_ty = spanned { node: sty_region(m_imm), span: span };
+    let self_ty = spanned { node: sty_region(None, m_imm), span: span };
     let method_ident = cx.ident_of(~"clone");
 
     // Create the method.
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a30b910b347..1881a2115d7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -975,6 +975,13 @@ pub impl Parser {
         }
     }
 
+    fn token_is_lifetime(&self, tok: &token::Token) -> bool {
+        match *tok {
+            token::LIFETIME(_) => true,
+            _ => false
+        }
+    }
+
     fn parse_lifetime(&self) -> ast::Lifetime {
         /*!
          *
@@ -1041,6 +1048,11 @@ pub impl Parser {
         }
     }
 
+    fn token_is_mutability(&self, tok: &token::Token) -> bool {
+        self.token_is_keyword(&~"mut", tok) ||
+        self.token_is_keyword(&~"const", tok)
+    }
+
     fn parse_mutability(&self) -> mutability {
         if self.eat_keyword(&~"mut") {
             m_mutbl
@@ -2844,6 +2856,55 @@ pub impl Parser {
             }
         }
 
+        fn maybe_parse_borrowed_self_ty(
+            self: &Parser
+        ) -> ast::self_ty_ {
+            // The following things are possible to see here:
+            //
+            //     fn(&self)
+            //     fn(&mut self)
+            //     fn(&'lt self)
+            //     fn(&'lt mut self)
+            //
+            // We already know that the current token is `&`.
+
+            if (
+                self.token_is_keyword(&~"self", &self.look_ahead(1)))
+            {
+                self.bump();
+                self.expect_self_ident();
+                sty_region(None, m_imm)
+            } else if (
+                self.token_is_mutability(&self.look_ahead(1)) &&
+                self.token_is_keyword(&~"self", &self.look_ahead(2)))
+            {
+                self.bump();
+                let mutability = self.parse_mutability();
+                self.expect_self_ident();
+                sty_region(None, mutability)
+            } else if (
+                self.token_is_lifetime(&self.look_ahead(1)) &&
+                self.token_is_keyword(&~"self", &self.look_ahead(2)))
+            {
+                self.bump();
+                let lifetime = @self.parse_lifetime();
+                self.expect_self_ident();
+                sty_region(Some(lifetime), m_imm)
+            } else if (
+                self.token_is_lifetime(&self.look_ahead(1)) &&
+                self.token_is_mutability(&self.look_ahead(2)) &&
+                self.token_is_keyword(&~"self", &self.look_ahead(3)))
+            {
+                self.bump();
+                let lifetime = @self.parse_lifetime();
+                let mutability = self.parse_mutability();
+                self.expect_self_ident();
+                sty_region(Some(lifetime), mutability)
+            } else {
+                sty_by_ref
+            }
+        }
+
         self.expect(&token::LPAREN);
 
         // A bit of complexity and lookahead is needed here in order to to be
@@ -2851,7 +2912,7 @@ pub impl Parser {
         let lo = self.span.lo;
         let self_ty = match *self.token {
           token::BINOP(token::AND) => {
-            maybe_parse_self_ty(sty_region, self)
+            maybe_parse_borrowed_self_ty(self)
           }
           token::AT => {
             maybe_parse_self_ty(sty_box, self)
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 5aae5570dbf..dcd57e12329 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1646,17 +1646,20 @@ pub fn print_pat(s: @ps, &&pat: @ast::pat, refutable: bool) {
 // Returns whether it printed anything
 pub fn print_self_ty(s: @ps, self_ty: ast::self_ty_) -> bool {
     match self_ty {
-      ast::sty_static | ast::sty_by_ref => { return false; }
-      ast::sty_value => { word(s.s, ~"self"); }
-      ast::sty_region(m) => {
-        word(s.s, ~"&"); print_mutability(s, m); word(s.s, ~"self");
-      }
-      ast::sty_box(m) => {
-        word(s.s, ~"@"); print_mutability(s, m); word(s.s, ~"self");
-      }
-      ast::sty_uniq(m) => {
-        word(s.s, ~"~"); print_mutability(s, m); word(s.s, ~"self");
-      }
+        ast::sty_static | ast::sty_by_ref => { return false; }
+        ast::sty_value => { word(s.s, ~"self"); }
+        ast::sty_region(lt, m) => {
+            word(s.s, ~"&");
+            print_opt_lifetime(s, lt);
+            print_mutability(s, m);
+            word(s.s, ~"self");
+        }
+        ast::sty_box(m) => {
+            word(s.s, ~"@"); print_mutability(s, m); word(s.s, ~"self");
+        }
+        ast::sty_uniq(m) => {
+            word(s.s, ~"~"); print_mutability(s, m); word(s.s, ~"self");
+        }
     }
     return true;
 }
diff --git a/src/test/run-pass/regions-expl-self.rs b/src/test/run-pass/regions-expl-self.rs
new file mode 100644
index 00000000000..736ed24097c
--- /dev/null
+++ b/src/test/run-pass/regions-expl-self.rs
@@ -0,0 +1,21 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that you can insert an explicit lifetime in explicit self.
+
+struct Foo {
+    f: uint
+}
+
+pub impl Foo {
+    fn foo(&'a self) {}
+}
+
+fn main() {}
\ No newline at end of file