Skip to content

Commit c7f8500

Browse files
committed
Permit lifetimes to appear in type parameter lists and after &. Lifetimes in
type parameter lists are currently ignored, but `&'a T` is equivalent to `&a/T`.
1 parent 9ad8a1f commit c7f8500

File tree

7 files changed

+120
-21
lines changed

7 files changed

+120
-21
lines changed

src/libsyntax/ast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ pub impl to_bytes::IterBytes for ident {
6767
// Functions may or may not have names.
6868
pub type fn_ident = Option<ident>;
6969
70+
pub struct Lifetime {
71+
id: node_id,
72+
span: span,
73+
ident: ident
74+
}
75+
7076
#[auto_encode]
7177
#[auto_decode]
7278
#[deriving_eq]

src/libsyntax/parse/parser.rs

Lines changed: 99 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -624,8 +624,13 @@ pub impl Parser {
624624
sigil: ast::Sigil,
625625
ctor: &fn(+v: mt) -> ty_) -> ty_
626626
{
627-
// @foo/fn() or @fn() are parsed directly as fn types:
627+
// @'foo fn() or @foo/fn() or @fn() are parsed directly as fn types:
628628
match copy self.token {
629+
token::LIFETIME(rname) => {
630+
self.bump();
631+
return self.parse_ty_closure(Some(sigil), Some(rname));
632+
}
633+
629634
token::IDENT(rname, _) => {
630635
if self.look_ahead(1u) == token::BINOP(token::SLASH) &&
631636
self.token_is_closure_keyword(self.look_ahead(2u))
@@ -648,8 +653,13 @@ pub impl Parser {
648653
}
649654

650655
fn parse_borrowed_pointee() -> ty_ {
651-
// look for `&foo/` and interpret `foo` as the region name:
652-
let rname = match copy self.token {
656+
// look for `&'lt` or `&foo/` and interpret `foo` as the region name:
657+
let rname = match self.token {
658+
token::LIFETIME(sid) => {
659+
self.bump();
660+
Some(sid)
661+
}
662+
653663
token::IDENT(sid, _) => {
654664
if self.look_ahead(1u) == token::BINOP(token::SLASH) {
655665
self.bump(); self.bump();
@@ -658,6 +668,7 @@ pub impl Parser {
658668
None
659669
}
660670
}
671+
661672
_ => { None }
662673
};
663674

@@ -890,22 +901,95 @@ pub impl Parser {
890901
}
891902
};
892903

893-
// Parse any type parameters which may appear:
904+
// Parse any lifetime or type parameters which may appear:
894905
let tps = {
895-
if self.token == token::LT {
896-
self.parse_seq_lt_gt(Some(token::COMMA),
897-
|p| p.parse_ty(false))
906+
if !self.eat(token::LT) {
907+
~[]
898908
} else {
899-
codemap::spanned {node: ~[], span: path.span}
909+
// First consume lifetimes.
910+
let _lifetimes = self.parse_lifetimes();
911+
let result = self.parse_seq_to_gt(
912+
Some(token::COMMA),
913+
|p| p.parse_ty(false));
914+
result
900915
}
901916
};
902917

903-
@ast::path { span: mk_sp(lo, tps.span.hi),
918+
let hi = self.span.lo;
919+
920+
@ast::path { span: mk_sp(lo, hi),
904921
rp: rp,
905-
types: tps.node,
922+
types: tps,
906923
.. *path }
907924
}
908925

926+
fn parse_opt_lifetime() -> Option<ast::Lifetime> {
927+
/*!
928+
*
929+
* Parses 0 or 1 lifetime.
930+
*/
931+
932+
match self.token {
933+
token::LIFETIME(_) => {
934+
Some(self.parse_lifetime())
935+
}
936+
_ => {
937+
None
938+
}
939+
}
940+
}
941+
942+
fn parse_lifetime() -> ast::Lifetime {
943+
/*!
944+
*
945+
* Parses a single lifetime.
946+
*/
947+
948+
match self.token {
949+
token::LIFETIME(i) => {
950+
self.bump();
951+
return ast::Lifetime {
952+
id: self.get_id(),
953+
span: self.span,
954+
ident: i
955+
};
956+
}
957+
_ => {
958+
self.fatal(fmt!("Expected a lifetime name"));
959+
}
960+
}
961+
}
962+
963+
fn parse_lifetimes() -> ~[ast::Lifetime] {
964+
/*!
965+
*
966+
* Parses zero or more comma separated lifetimes.
967+
* Expects each lifetime to be followed by either
968+
* a comma or `>`. Used when parsing type parameter
969+
* lists, where we expect something like `<'a, 'b, T>`.
970+
*/
971+
972+
let mut res = ~[];
973+
loop {
974+
match self.token {
975+
token::LIFETIME(_) => {
976+
res.push(self.parse_lifetime());
977+
}
978+
_ => {
979+
return res;
980+
}
981+
}
982+
983+
match self.token {
984+
token::COMMA => { self.bump();}
985+
token::GT => { return res; }
986+
_ => {
987+
self.fatal(~"expected `,` or `>` after lifetime name");
988+
}
989+
}
990+
}
991+
}
992+
909993
fn parse_mutability() -> mutability {
910994
if self.eat_keyword(~"mut") {
911995
m_mutbl
@@ -1424,6 +1508,7 @@ pub impl Parser {
14241508
}
14251509
token::AND => {
14261510
self.bump();
1511+
let _lt = self.parse_opt_lifetime();
14271512
let m = self.parse_mutability();
14281513
let e = self.parse_prefix_expr();
14291514
hi = e.span.hi;
@@ -2574,7 +2659,10 @@ pub impl Parser {
25742659

25752660
fn parse_ty_params() -> ~[ty_param] {
25762661
if self.eat(token::LT) {
2577-
self.parse_seq_to_gt(Some(token::COMMA), |p| p.parse_ty_param())
2662+
let _lifetimes = self.parse_lifetimes();
2663+
self.parse_seq_to_gt(
2664+
Some(token::COMMA),
2665+
|p| p.parse_ty_param())
25782666
} else { ~[] }
25792667
}
25802668

src/test/compile-fail/regions-addr-of-arg.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
// except according to those terms.
1010

1111
fn foo(a: int) {
12-
let _p: &static/int = &a; //~ ERROR illegal borrow
12+
let _p: &'static int = &a; //~ ERROR illegal borrow
1313
}
1414

1515
fn bar(a: int) {
16-
let _q: &blk/int = &a;
16+
let _q: &'blk int = &a;
1717
}
1818

1919
fn main() {

src/test/compile-fail/regions-addr-of-upvar-self.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct dog {
1515
impl dog {
1616
fn chase_cat() {
1717
for uint::range(0u, 10u) |_i| {
18-
let p: &static/mut uint = &mut self.food; //~ ERROR illegal borrow
18+
let p: &'static mut uint = &mut self.food; //~ ERROR illegal borrow
1919
*p = 3u;
2020
}
2121
}

src/test/compile-fail/regions-bounds.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
// checked.
1414

1515
enum an_enum = &int;
16-
trait a_trait { fn foo() -> &self/int; }
17-
struct a_class { x:&self/int }
16+
trait a_trait {
17+
fn foo() -> &'self int;
18+
}
19+
struct a_class { x:&'self int }
1820

1921
fn a_fn1(e: an_enum/&a) -> an_enum/&b {
2022
return e; //~ ERROR mismatched types: expected `an_enum/&b` but found `an_enum/&a`

src/test/compile-fail/regions-in-enums.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
enum yes0 {
12-
x3(&uint)
11+
enum yes0<'lt> {
12+
// This will eventually be legal (and in fact the only way):
13+
x3(&'lt uint) //~ ERROR named regions other than `self` are not allowed as part of a type declaration
1314
}
1415

1516
enum yes1 {
16-
x4(&self/uint)
17+
x4(&'self uint)
1718
}
1819

1920
enum yes2 {
20-
x5(&foo/uint) //~ ERROR named regions other than `self` are not allowed as part of a type declaration
21+
x5(&'foo uint) //~ ERROR named regions other than `self` are not allowed as part of a type declaration
2122
}
2223

2324
fn main() {}

src/test/run-pass/regions-self-impls.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
struct Clam { chowder: &int }
11+
struct Clam<'self> {
12+
chowder: &'self int
13+
}
1214

1315
trait get_chowder {
1416
fn get_chowder() -> &self/int;

0 commit comments

Comments
 (0)