diff options
| author | Taylor Cramer <cramertj@google.com> | 2018-06-06 15:50:59 -0700 |
|---|---|---|
| committer | Taylor Cramer <cramertj@google.com> | 2018-06-21 22:36:36 -0700 |
| commit | cf844b547dbec1f23982fca8e07ec65800ed5d6d (patch) | |
| tree | a5420599dea5829f105d2a12bb14a3102141a749 /src/libsyntax | |
| parent | 589446e19cbf7a2c7eddf80b490992d31134015c (diff) | |
| download | rust-cf844b547dbec1f23982fca8e07ec65800ed5d6d.tar.gz rust-cf844b547dbec1f23982fca8e07ec65800ed5d6d.zip | |
async await desugaring and tests
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 24 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 25 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 58 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 24 | ||||
| -rw-r--r-- | src/libsyntax/ptr.rs | 10 | ||||
| -rw-r--r-- | src/libsyntax/test.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/util/parser.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 7 |
10 files changed, 154 insertions, 22 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 55c21c64c83..a57a9b95e5f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -987,6 +987,7 @@ impl Expr { ExprKind::Closure(..) => ExprPrecedence::Closure, ExprKind::Block(..) => ExprPrecedence::Block, ExprKind::Catch(..) => ExprPrecedence::Catch, + ExprKind::Async(..) => ExprPrecedence::Async, ExprKind::Assign(..) => ExprPrecedence::Assign, ExprKind::AssignOp(..) => ExprPrecedence::AssignOp, ExprKind::Field(..) => ExprPrecedence::Field, @@ -1094,9 +1095,18 @@ pub enum ExprKind { /// A closure (for example, `move |a, b, c| a + b + c`) /// /// The final span is the span of the argument block `|...|` - Closure(CaptureBy, Movability, P<FnDecl>, P<Expr>, Span), + Closure(CaptureBy, IsAsync, Movability, P<FnDecl>, P<Expr>, Span), /// A block (`'label: { ... }`) Block(P<Block>, Option<Label>), + /// An async block (`async move { ... }`) + /// + /// The `NodeId` is the `NodeId` for the closure that results from + /// desugaring an async block, just like the NodeId field in the + /// `IsAsync` enum. This is necessary in order to create a def for the + /// closure which can be used as a parent of any child defs. Defs + /// created during lowering cannot be made the parent of any other + /// preexisting defs. + Async(CaptureBy, NodeId, P<Block>), /// A catch block (`catch { ... }`) Catch(P<Block>), @@ -1708,10 +1718,20 @@ pub enum Unsafety { #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum IsAsync { - Async, + Async(NodeId), NotAsync, } +impl IsAsync { + pub fn is_async(self) -> bool { + if let IsAsync::Async(_) = self { + true + } else { + false + } + } +} + #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Constness { Const, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 6bb7535544b..61356507665 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -915,6 +915,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn_decl_span: Span) // span of the `|...|` part -> P<ast::Expr> { self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, + ast::IsAsync::NotAsync, ast::Movability::Movable, fn_decl, body, @@ -935,6 +936,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { // the entire lambda body. Probably we should extend the API // here, but that's not entirely clear. self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, + ast::IsAsync::NotAsync, ast::Movability::Movable, fn_decl, body, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a9679f86ddb..ccb2f51f964 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -308,7 +308,7 @@ declare_features! ( // Declarative macros 2.0 (`macro`). (active, decl_macro, "1.17.0", Some(39412), None), - // Allows #[link(kind="static-nobundle"...] + // Allows #[link(kind="static-nobundle"...)] (active, static_nobundle, "1.16.0", Some(37403), None), // `extern "msp430-interrupt" fn()` @@ -474,7 +474,7 @@ declare_features! ( (active, doc_keyword, "1.28.0", Some(51315), None), // Allows async and await syntax - (active, async_await, "1.28.0", Some(0), Some(Edition::Edition2018)), + (active, async_await, "1.28.0", Some(50547), None), ); declare_features! ( @@ -1722,6 +1722,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "labels on blocks are unstable"); } } + ast::ExprKind::Closure(_, ast::IsAsync::Async(_), ..) => { + gate_feature_post!(&self, async_await, e.span, "async closures are unstable"); + } + ast::ExprKind::Async(..) => { + gate_feature_post!(&self, async_await, e.span, "async blocks are unstable"); + } _ => {} } visit::walk_expr(self, e); @@ -1764,7 +1770,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match fn_kind { FnKind::ItemFn(_, header, _, _) => { // check for const fn and async fn declarations - if header.asyncness == ast::IsAsync::Async { + if header.asyncness.is_async() { gate_feature_post!(&self, async_await, span, "async fn is unstable"); } if header.constness.node == ast::Constness::Const { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 941d2180fd1..ffea713f4ec 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -76,6 +76,10 @@ pub trait Folder : Sized { noop_fold_item_simple(i, self) } + fn fold_fn_header(&mut self, header: FnHeader) -> FnHeader { + noop_fold_fn_header(header, self) + } + fn fold_struct_field(&mut self, sf: StructField) -> StructField { noop_fold_struct_field(sf, self) } @@ -883,6 +887,7 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind { } ItemKind::Fn(decl, header, generics, body) => { let generics = folder.fold_generics(generics); + let header = folder.fold_fn_header(header); let decl = folder.fold_fn_decl(decl); let body = folder.fold_block(body); ItemKind::Fn(decl, header, generics, body) @@ -990,6 +995,14 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T) }) } +pub fn noop_fold_fn_header<T: Folder>(mut header: FnHeader, folder: &mut T) -> FnHeader { + header.asyncness = match header.asyncness { + IsAsync::Async(node_id) => IsAsync::Async(folder.new_id(node_id)), + IsAsync::NotAsync => IsAsync::NotAsync, + }; + header +} + pub fn noop_fold_mod<T: Folder>(Mod {inner, items}: Mod, folder: &mut T) -> Mod { Mod { inner: folder.new_span(inner), @@ -1082,7 +1095,7 @@ pub fn noop_fold_foreign_item_simple<T: Folder>(ni: ForeignItem, folder: &mut T) pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig { MethodSig { - header: sig.header, + header: folder.fold_fn_header(sig.header), decl: folder.fold_fn_decl(sig.decl) } } @@ -1235,8 +1248,13 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Match(folder.fold_expr(expr), arms.move_map(|x| folder.fold_arm(x))) } - ExprKind::Closure(capture_clause, movability, decl, body, span) => { + ExprKind::Closure(capture_clause, asyncness, movability, decl, body, span) => { + let asyncness = match asyncness { + IsAsync::Async(node_id) => IsAsync::Async(folder.new_id(node_id)), + IsAsync::NotAsync => IsAsync::NotAsync, + }; ExprKind::Closure(capture_clause, + asyncness, movability, folder.fold_fn_decl(decl), folder.fold_expr(body), @@ -1246,6 +1264,9 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Block(folder.fold_block(blk), opt_label.map(|label| folder.fold_label(label))) } + ExprKind::Async(capture_clause, node_id, body) => { + ExprKind::Async(capture_clause, folder.new_id(node_id), folder.fold_block(body)) + } ExprKind::Assign(el, er) => { ExprKind::Assign(folder.fold_expr(el), folder.fold_expr(er)) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d897aaadf43..e5ac0b8ed7c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,7 +43,7 @@ use ast::{BinOpKind, UnOp}; use ast::{RangeEnd, RangeSyntax}; use {ast, attr}; use codemap::{self, CodeMap, Spanned, respan}; -use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, DUMMY_SP}; +use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, DUMMY_SP, edition::Edition}; use errors::{self, Applicability, DiagnosticBuilder}; use parse::{self, SeqSep, classify, token}; use parse::lexer::TokenAndSpan; @@ -2258,6 +2258,15 @@ impl<'a> Parser<'a> { hi = path.span; return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } + if syntax_pos::hygiene::default_edition() >= Edition::Edition2018 && + self.check_keyword(keywords::Async) + { + if self.is_async_block() { // check for `async {` and `async move {` + return self.parse_async_block(attrs); + } else { + return self.parse_lambda_expr(attrs); + } + } if self.check_keyword(keywords::Move) || self.check_keyword(keywords::Static) { return self.parse_lambda_expr(attrs); } @@ -3252,6 +3261,13 @@ impl<'a> Parser<'a> { } else { Movability::Movable }; + let asyncness = if syntax_pos::hygiene::default_edition() >= Edition::Edition2018 + && self.eat_keyword(keywords::Async) + { + IsAsync::Async(ast::DUMMY_NODE_ID) + } else { + IsAsync::NotAsync + }; let capture_clause = if self.eat_keyword(keywords::Move) { CaptureBy::Value } else { @@ -3274,7 +3290,7 @@ impl<'a> Parser<'a> { Ok(self.mk_expr( lo.to(body.span), - ExprKind::Closure(capture_clause, movability, decl, body, lo.to(decl_hi)), + ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)), attrs)) } @@ -3352,6 +3368,24 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs)) } + /// Parse an `async move {...}` expression + pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>) + -> PResult<'a, P<Expr>> + { + let span_lo = self.span; + self.expect_keyword(keywords::Async)?; + let capture_clause = if self.eat_keyword(keywords::Move) { + CaptureBy::Value + } else { + CaptureBy::Ref + }; + let (iattrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(iattrs); + Ok(self.mk_expr( + span_lo.to(body.span), + ExprKind::Async(capture_clause, ast::DUMMY_NODE_ID, body), attrs)) + } + /// Parse a `do catch {...}` expression (`do catch` token already eaten) fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> @@ -4286,6 +4320,18 @@ impl<'a> Parser<'a> { }) } + fn is_async_block(&mut self) -> bool { + self.token.is_keyword(keywords::Async) && + ( + ( // `async move {` + self.look_ahead(1, |t| t.is_keyword(keywords::Move)) && + self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) + ) || ( // `async {` + self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) + ) + ) + } + fn is_catch_expr(&mut self) -> bool { self.token.is_keyword(keywords::Do) && self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && @@ -6698,14 +6744,18 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.eat_keyword(keywords::Async) { + if self.check_keyword(keywords::Async) && + (self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) || + self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe))) + { // ASYNC FUNCTION ITEM + self.expect_keyword(keywords::Async)?; let unsafety = self.parse_unsafety(); self.expect_keyword(keywords::Fn)?; let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(unsafety, - IsAsync::Async, + IsAsync::Async(ast::DUMMY_NODE_ID), respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 210742c55a5..743d36d8db5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2171,8 +2171,10 @@ impl<'a> State<'a> { } self.bclose_(expr.span, INDENT_UNIT)?; } - ast::ExprKind::Closure(capture_clause, movability, ref decl, ref body, _) => { + ast::ExprKind::Closure( + capture_clause, asyncness, movability, ref decl, ref body, _) => { self.print_movability(movability)?; + self.print_asyncness(asyncness)?; self.print_capture_clause(capture_clause)?; self.print_fn_block_args(decl)?; @@ -2196,6 +2198,12 @@ impl<'a> State<'a> { self.ibox(0)?; self.print_block_with_attrs(blk, attrs)?; } + ast::ExprKind::Async(capture_clause, _, ref blk) => { + self.word_nbsp("async")?; + self.print_capture_clause(capture_clause)?; + self.s.space()?; + self.print_block_with_attrs(blk, attrs)?; + } ast::ExprKind::Assign(ref lhs, ref rhs) => { let prec = AssocOp::Assign.precedence() as i8; self.print_expr_maybe_paren(lhs, prec + 1)?; @@ -2792,6 +2800,14 @@ impl<'a> State<'a> { } } + pub fn print_asyncness(&mut self, asyncness: ast::IsAsync) + -> io::Result<()> { + if asyncness.is_async() { + self.word_nbsp("async")?; + } + Ok(()) + } + pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) -> io::Result<()> { match capture_clause { @@ -3122,11 +3138,7 @@ impl<'a> State<'a> { ast::Constness::Const => self.word_nbsp("const")? } - match header.asyncness { - ast::IsAsync::NotAsync => {} - ast::IsAsync::Async => self.word_nbsp("async")? - } - + self.print_asyncness(header.asyncness)?; self.print_unsafety(header.unsafety)?; if header.abi != Abi::Rust { diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 25d916af77d..ed10857e4c5 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -95,6 +95,16 @@ impl<T: 'static> P<T> { } } +impl<T: 'static> P<[T]> { + pub fn map_slice<F>(self, f: F) -> P<[T]> where + F: FnOnce(Vec<T>) -> Vec<T> + { + P { + ptr: f(self.ptr.into()).into(), + } + } +} + impl<T: ?Sized> Deref for P<T> { type Target = T; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index cfb29f562d7..77225585141 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -127,11 +127,17 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { ast::ItemKind::Fn(_, header, _, _) => { if header.unsafety == ast::Unsafety::Unsafe { let diag = self.cx.span_diagnostic; - diag.span_fatal(i.span, "unsafe functions cannot be used for tests").raise(); + diag.span_fatal( + i.span, + "unsafe functions cannot be used for tests" + ).raise(); } - if header.asyncness == ast::IsAsync::Async { + if header.asyncness.is_async() { let diag = self.cx.span_diagnostic; - diag.span_fatal(i.span, "async functions cannot be used for tests").raise(); + diag.span_fatal( + i.span, + "async functions cannot be used for tests" + ).raise(); } } _ => {}, diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 51b535275d6..15d910b33b0 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -277,6 +277,7 @@ pub enum ExprPrecedence { Block, Catch, Struct, + Async, } impl PartialOrd for ExprPrecedence { @@ -346,6 +347,7 @@ impl ExprPrecedence { ExprPrecedence::Match | ExprPrecedence::Block | ExprPrecedence::Catch | + ExprPrecedence::Async | ExprPrecedence::Struct => PREC_PAREN, } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3df96ff07c5..41e3ad9d4f4 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -235,7 +235,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { } ItemKind::Fn(ref declaration, header, ref generics, ref body) => { visitor.visit_generics(generics); - visitor.visit_fn(FnKind::ItemFn(item.ident, header, + visitor.visit_fn(FnKind::ItemFn(item.ident, header, &item.vis, body), declaration, item.span, @@ -735,7 +735,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); walk_list!(visitor, visit_arm, arms); } - ExprKind::Closure(_, _, ref function_declaration, ref body, _decl_span) => { + ExprKind::Closure(_, _, _, ref function_declaration, ref body, _decl_span) => { visitor.visit_fn(FnKind::Closure(body), function_declaration, expression.span, @@ -745,6 +745,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { walk_list!(visitor, visit_label, opt_label); visitor.visit_block(block); } + ExprKind::Async(_, _, ref body) => { + visitor.visit_block(body); + } ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => { visitor.visit_expr(left_hand_expression); visitor.visit_expr(right_hand_expression); |
