diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2014-07-29 22:08:39 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2014-08-14 08:53:25 -0700 |
| commit | 8d272321417df3a954802e42a66adda87ade5a49 (patch) | |
| tree | bb73f130dbe32e8a4714319e5c793702a02a53e1 /src/libsyntax/parse/parser.rs | |
| parent | 9d45d63d0d18f21f74c8a2a4e5367a785932f64e (diff) | |
| download | rust-8d272321417df3a954802e42a66adda87ade5a49.tar.gz rust-8d272321417df3a954802e42a66adda87ade5a49.zip | |
librustc: Tie up loose ends in unboxed closures.
This patch primarily does two things: (1) it prevents lifetimes from
leaking out of unboxed closures; (2) it allows unboxed closure type
notation, call notation, and construction notation to construct closures
matching any of the three traits.
This breaks code that looked like:
let mut f;
{
let x = &5i;
f = |&mut:| *x + 10;
}
Change this code to avoid having a reference escape. For example:
{
let x = &5i;
let mut f; // <-- move here to avoid dangling reference
f = |&mut:| *x + 10;
}
I believe this is enough to consider unboxed closures essentially
implemented. Further issues (for example, higher-rank lifetimes) should
be filed as followups.
Closes #14449.
[breaking-change]
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 167 |
1 files changed, 96 insertions, 71 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f0920603ad1..f6db577a004 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -30,6 +30,8 @@ use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn}; use ast::{ExprVec, ExprVstore, ExprVstoreSlice}; use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl}; use ast::{ExprVstoreUniq, Once, Many}; +use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; +use ast::{FnOnceUnboxedClosureKind}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod}; use ast::{Ident, NormalFn, Inherited, Item, Item_, ItemStatic}; use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl}; @@ -53,7 +55,8 @@ use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; use ast::{TyTypeof, TyInfer, TypeMethod}; use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyRptr}; use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq}; -use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock}; +use ast::{UnboxedClosureKind, UnboxedFnTy, UnboxedFnTyParamBound}; +use ast::{UnnamedField, UnsafeBlock}; use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::Visibility; @@ -1087,6 +1090,34 @@ impl<'a> Parser<'a> { }) } + /// Parses an optional unboxed closure kind (`&:`, `&mut:`, or `:`). + pub fn parse_optional_unboxed_closure_kind(&mut self) + -> Option<UnboxedClosureKind> { + if self.token == token::BINOP(token::AND) && + self.look_ahead(1, |t| { + token::is_keyword(keywords::Mut, t) + }) && + self.look_ahead(2, |t| *t == token::COLON) { + self.bump(); + self.bump(); + self.bump(); + return Some(FnMutUnboxedClosureKind) + } + + if self.token == token::BINOP(token::AND) && + self.look_ahead(1, |t| *t == token::COLON) { + self.bump(); + self.bump(); + return Some(FnUnboxedClosureKind) + } + + if self.eat(&token::COLON) { + return Some(FnOnceUnboxedClosureKind) + } + + return None + } + /// Parse a TyClosure type pub fn parse_ty_closure(&mut self) -> Ty_ { /* @@ -1115,27 +1146,19 @@ impl<'a> Parser<'a> { Vec::new() }; - let (is_unboxed, inputs) = if self.eat(&token::OROR) { - (false, Vec::new()) + let (optional_unboxed_closure_kind, inputs) = if self.eat(&token::OROR) { + (None, Vec::new()) } else { self.expect_or(); - let is_unboxed = self.token == token::BINOP(token::AND) && - self.look_ahead(1, |t| { - token::is_keyword(keywords::Mut, t) - }) && - self.look_ahead(2, |t| *t == token::COLON); - if is_unboxed { - self.bump(); - self.bump(); - self.bump(); - } + let optional_unboxed_closure_kind = + self.parse_optional_unboxed_closure_kind(); let inputs = self.parse_seq_to_before_or( &token::COMMA, |p| p.parse_arg_general(false)); self.expect_or(); - (is_unboxed, inputs) + (optional_unboxed_closure_kind, inputs) }; let (region, bounds) = { @@ -1155,18 +1178,22 @@ impl<'a> Parser<'a> { variadic: false }); - if is_unboxed { - TyUnboxedFn(box(GC) UnboxedFnTy { - decl: decl, - }) - } else { - TyClosure(box(GC) ClosureTy { - fn_style: fn_style, - onceness: onceness, - bounds: bounds, - decl: decl, - lifetimes: lifetime_defs, - }, region) + match optional_unboxed_closure_kind { + Some(unboxed_closure_kind) => { + TyUnboxedFn(box(GC) UnboxedFnTy { + kind: unboxed_closure_kind, + decl: decl, + }) + } + None => { + TyClosure(box(GC) ClosureTy { + fn_style: fn_style, + onceness: onceness, + bounds: bounds, + decl: decl, + lifetimes: lifetime_defs, + }, region) + } } } @@ -2703,7 +2730,8 @@ impl<'a> Parser<'a> { pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause) -> Gc<Expr> { let lo = self.span.lo; - let (decl, is_unboxed) = self.parse_fn_block_decl(); + let (decl, optional_unboxed_closure_kind) = + self.parse_fn_block_decl(); let body = self.parse_expr(); let fakeblock = P(ast::Block { view_items: Vec::new(), @@ -2714,14 +2742,20 @@ impl<'a> Parser<'a> { span: body.span, }); - if is_unboxed { - self.mk_expr(lo, - body.span.hi, - ExprUnboxedFn(capture_clause, decl, fakeblock)) - } else { - self.mk_expr(lo, - body.span.hi, - ExprFnBlock(capture_clause, decl, fakeblock)) + match optional_unboxed_closure_kind { + Some(unboxed_closure_kind) => { + self.mk_expr(lo, + body.span.hi, + ExprUnboxedFn(capture_clause, + unboxed_closure_kind, + decl, + fakeblock)) + } + None => { + self.mk_expr(lo, + body.span.hi, + ExprFnBlock(capture_clause, decl, fakeblock)) + } } } @@ -3553,28 +3587,22 @@ impl<'a> Parser<'a> { } fn parse_unboxed_function_type(&mut self) -> UnboxedFnTy { - let inputs = if self.eat(&token::OROR) { - Vec::new() - } else { - self.expect_or(); + let (optional_unboxed_closure_kind, inputs) = + if self.eat(&token::OROR) { + (None, Vec::new()) + } else { + self.expect_or(); - if self.token == token::BINOP(token::AND) && - self.look_ahead(1, |t| { - token::is_keyword(keywords::Mut, t) - }) && - self.look_ahead(2, |t| *t == token::COLON) { - self.bump(); - self.bump(); - self.bump(); - } + let optional_unboxed_closure_kind = + self.parse_optional_unboxed_closure_kind(); - let inputs = self.parse_seq_to_before_or(&token::COMMA, - |p| { - p.parse_arg_general(false) - }); - self.expect_or(); - inputs - }; + let inputs = self.parse_seq_to_before_or(&token::COMMA, + |p| { + p.parse_arg_general(false) + }); + self.expect_or(); + (optional_unboxed_closure_kind, inputs) + }; let (return_style, output) = self.parse_ret_ty(); UnboxedFnTy { @@ -3583,7 +3611,11 @@ impl<'a> Parser<'a> { output: output, cf: return_style, variadic: false, - }) + }), + kind: match optional_unboxed_closure_kind { + Some(kind) => kind, + None => FnMutUnboxedClosureKind, + }, } } @@ -4026,29 +4058,22 @@ impl<'a> Parser<'a> { } // parse the |arg, arg| header on a lambda - fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, bool) { - let (is_unboxed, inputs_captures) = { + fn parse_fn_block_decl(&mut self) + -> (P<FnDecl>, Option<UnboxedClosureKind>) { + let (optional_unboxed_closure_kind, inputs_captures) = { if self.eat(&token::OROR) { - (false, Vec::new()) + (None, Vec::new()) } else { self.expect(&token::BINOP(token::OR)); - let is_unboxed = self.token == token::BINOP(token::AND) && - self.look_ahead(1, |t| { - token::is_keyword(keywords::Mut, t) - }) && - self.look_ahead(2, |t| *t == token::COLON); - if is_unboxed { - self.bump(); - self.bump(); - self.bump(); - } + let optional_unboxed_closure_kind = + self.parse_optional_unboxed_closure_kind(); let args = self.parse_seq_to_before_end( &token::BINOP(token::OR), seq_sep_trailing_disallowed(token::COMMA), |p| p.parse_fn_block_arg() ); self.bump(); - (is_unboxed, args) + (optional_unboxed_closure_kind, args) } }; let output = if self.eat(&token::RARROW) { @@ -4066,7 +4091,7 @@ impl<'a> Parser<'a> { output: output, cf: Return, variadic: false - }), is_unboxed) + }), optional_unboxed_closure_kind) } /// Parses the `(arg, arg) -> return_type` header on a procedure. |
