about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorTaylor Cramer <cramertj@google.com>2018-06-06 15:50:59 -0700
committerTaylor Cramer <cramertj@google.com>2018-06-21 22:36:36 -0700
commitcf844b547dbec1f23982fca8e07ec65800ed5d6d (patch)
treea5420599dea5829f105d2a12bb14a3102141a749 /src/libsyntax
parent589446e19cbf7a2c7eddf80b490992d31134015c (diff)
downloadrust-cf844b547dbec1f23982fca8e07ec65800ed5d6d.tar.gz
rust-cf844b547dbec1f23982fca8e07ec65800ed5d6d.zip
async await desugaring and tests
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs24
-rw-r--r--src/libsyntax/ext/build.rs2
-rw-r--r--src/libsyntax/feature_gate.rs12
-rw-r--r--src/libsyntax/fold.rs25
-rw-r--r--src/libsyntax/parse/parser.rs58
-rw-r--r--src/libsyntax/print/pprust.rs24
-rw-r--r--src/libsyntax/ptr.rs10
-rw-r--r--src/libsyntax/test.rs12
-rw-r--r--src/libsyntax/util/parser.rs2
-rw-r--r--src/libsyntax/visit.rs7
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);