diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 59 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 11 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 49 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 31 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 13 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 135 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 79 | ||||
| -rw-r--r-- | src/libsyntax/test.rs | 52 | ||||
| -rw-r--r-- | src/libsyntax/util/parser.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 17 |
10 files changed, 330 insertions, 118 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c6de2c4da39..a57a9b95e5f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -17,7 +17,7 @@ pub use util::ThinVec; pub use util::parser::ExprPrecedence; use syntax_pos::{Span, DUMMY_SP}; -use codemap::{respan, Spanned}; +use codemap::{dummy_spanned, respan, Spanned}; use rustc_target::spec::abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; use print::pprust; @@ -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>), @@ -1325,9 +1335,7 @@ pub struct MutTy { /// or in an implementation. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct MethodSig { - pub unsafety: Unsafety, - pub constness: Spanned<Constness>, - pub abi: Abi, + pub header: FnHeader, pub decl: P<FnDecl>, } @@ -1709,6 +1717,22 @@ pub enum Unsafety { } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum IsAsync { + 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, NotConst, @@ -2009,6 +2033,29 @@ pub struct Item { pub tokens: Option<TokenStream>, } +/// A function header +/// +/// All the information between the visibility & the name of the function is +/// included in this struct (e.g. `async unsafe fn` or `const extern "C" fn`) +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct FnHeader { + pub unsafety: Unsafety, + pub asyncness: IsAsync, + pub constness: Spanned<Constness>, + pub abi: Abi, +} + +impl Default for FnHeader { + fn default() -> FnHeader { + FnHeader { + unsafety: Unsafety::Normal, + asyncness: IsAsync::NotAsync, + constness: dummy_spanned(Constness::NotConst), + abi: Abi::Rust, + } + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum ItemKind { /// An `extern crate` item, with optional *original* crate name if the crate was renamed. @@ -2030,7 +2077,7 @@ pub enum ItemKind { /// A function declaration (`fn` or `pub fn`). /// /// E.g. `fn foo(bar: usize) -> usize { .. }` - Fn(P<FnDecl>, Unsafety, Spanned<Constness>, Abi, Generics, P<Block>), + Fn(P<FnDecl>, FnHeader, Generics, P<Block>), /// A module declaration (`mod` or `pub mod`). /// /// E.g. `mod foo;` or `mod foo { .. }` diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 9044cab05d6..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, @@ -1008,9 +1010,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> { name, Vec::new(), ast::ItemKind::Fn(self.fn_decl(inputs, ast::FunctionRetTy::Ty(output)), - ast::Unsafety::Normal, - dummy_spanned(ast::Constness::NotConst), - Abi::Rust, + ast::FnHeader { + unsafety: ast::Unsafety::Normal, + asyncness: ast::IsAsync::NotAsync, + constness: dummy_spanned(ast::Constness::NotConst), + abi: Abi::Rust, + }, generics, body)) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index be4cf197be4..ccb2f51f964 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -29,7 +29,6 @@ use rustc_target::spec::abi::Abi; use ast::{self, NodeId, PatKind, RangeEnd}; use attr; use edition::{ALL_EDITIONS, Edition}; -use codemap::Spanned; use syntax_pos::{Span, DUMMY_SP}; use errors::{DiagnosticBuilder, Handler, FatalError}; use visit::{self, FnKind, Visitor}; @@ -309,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()` @@ -468,12 +467,14 @@ declare_features! ( // 'a: { break 'a; } (active, label_break_value, "1.28.0", Some(48594), None), - // #[panic_implementation] (active, panic_implementation, "1.28.0", Some(44489), None), // #[doc(keyword = "...")] (active, doc_keyword, "1.28.0", Some(51315), None), + + // Allows async and await syntax + (active, async_await, "1.28.0", Some(50547), None), ); declare_features! ( @@ -1721,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); @@ -1760,20 +1767,24 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn_decl: &'a ast::FnDecl, span: Span, _node_id: NodeId) { - // check for const fn declarations - if let FnKind::ItemFn(_, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) = - fn_kind { - gate_feature_post!(&self, const_fn, span, "const fn is unstable"); - } - // stability of const fn methods are covered in - // visit_trait_item and visit_impl_item below; this is - // because default methods don't pass through this - // point. - match fn_kind { - FnKind::ItemFn(_, _, _, abi, _, _) | - FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => { - self.check_abi(abi, span); + FnKind::ItemFn(_, header, _, _) => { + // check for const fn and async fn declarations + if header.asyncness.is_async() { + gate_feature_post!(&self, async_await, span, "async fn is unstable"); + } + if header.constness.node == ast::Constness::Const { + gate_feature_post!(&self, const_fn, span, "const fn is unstable"); + } + // stability of const fn methods are covered in + // visit_trait_item and visit_impl_item below; this is + // because default methods don't pass through this + // point. + + self.check_abi(header.abi, span); + } + FnKind::Method(_, sig, _, _) => { + self.check_abi(sig.header.abi, span); } _ => {} } @@ -1784,9 +1795,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match ti.node { ast::TraitItemKind::Method(ref sig, ref block) => { if block.is_none() { - self.check_abi(sig.abi, ti.span); + self.check_abi(sig.header.abi, ti.span); } - if sig.constness.node == ast::Constness::Const { + if sig.header.constness.node == ast::Constness::Const { gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); } } @@ -1820,7 +1831,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match ii.node { ast::ImplItemKind::Method(ref sig, _) => { - if sig.constness.node == ast::Constness::Const { + if sig.header.constness.node == ast::Constness::Const { gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable"); } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 93248fe3bfa..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) } @@ -881,11 +885,12 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::Const(t, e) => { ItemKind::Const(folder.fold_ty(t), folder.fold_expr(e)) } - ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => { + 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, unsafety, constness, abi, generics, body) + ItemKind::Fn(decl, header, generics, body) } ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)), ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)), @@ -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,9 +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 { - abi: sig.abi, - unsafety: sig.unsafety, - constness: sig.constness, + header: folder.fold_fn_header(sig.header), decl: folder.fold_fn_decl(sig.decl) } } @@ -1237,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), @@ -1248,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/mod.rs b/src/libsyntax/parse/mod.rs index 1cb127bdcc9..cce8da1dcbd 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -928,12 +928,15 @@ mod tests { output: ast::FunctionRetTy::Default(sp(15, 15)), variadic: false }), - ast::Unsafety::Normal, - Spanned { - span: sp(0,2), - node: ast::Constness::NotConst, + ast::FnHeader { + unsafety: ast::Unsafety::Normal, + asyncness: ast::IsAsync::NotAsync, + constness: Spanned { + span: sp(0,2), + node: ast::Constness::NotConst, + }, + abi: Abi::Rust, }, - Abi::Rust, ast::Generics{ params: Vec::new(), where_clause: ast::WhereClause { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 69521c17a25..5970f94b97d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -19,11 +19,11 @@ use ast::{Constness, Crate}; use ast::Defaultness; use ast::EnumDef; use ast::{Expr, ExprKind, RangeLimits}; -use ast::{Field, FnDecl}; +use ast::{Field, FnDecl, FnHeader}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use ast::{GenericParam, GenericParamKind}; use ast::GenericArg; -use ast::{Ident, ImplItem, IsAuto, Item, ItemKind}; +use ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; use ast::{Label, Lifetime, Lit, LitKind}; use ast::Local; use ast::MacStmtStyle; @@ -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; @@ -1296,6 +1296,15 @@ impl<'a> Parser<'a> { }))) } + /// Parse asyncness: `async` or nothing + fn parse_asyncness(&mut self) -> IsAsync { + if self.eat_keyword(keywords::Async) { + IsAsync::Async(ast::DUMMY_NODE_ID) + } else { + IsAsync::NotAsync + } + } + /// Parse unsafety: `unsafe` or nothing. fn parse_unsafety(&mut self) -> Unsafety { if self.eat_keyword(keywords::Unsafe) { @@ -1345,7 +1354,7 @@ impl<'a> Parser<'a> { // trait item macro. (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) } else { - let (constness, unsafety, abi) = self.parse_fn_front_matter()?; + let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; @@ -1359,10 +1368,13 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; let sig = ast::MethodSig { - unsafety, - constness, + header: FnHeader { + unsafety, + constness, + abi, + asyncness, + }, decl: d, - abi, }; let body = match self.token { @@ -2258,6 +2270,15 @@ impl<'a> Parser<'a> { hi = path.span; return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } + if self.span.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); } @@ -3258,6 +3279,13 @@ impl<'a> Parser<'a> { } else { Movability::Movable }; + let asyncness = if self.span.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 { @@ -3280,7 +3308,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)) } @@ -3358,6 +3386,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>> @@ -4292,6 +4338,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)) && @@ -5358,6 +5416,7 @@ impl<'a> Parser<'a> { /// Parse an item-position function declaration. fn parse_item_fn(&mut self, unsafety: Unsafety, + asyncness: IsAsync, constness: Spanned<Constness>, abi: Abi) -> PResult<'a, ItemInfo> { @@ -5365,7 +5424,8 @@ impl<'a> Parser<'a> { let decl = self.parse_fn_decl(false)?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - Ok((ident, ItemKind::Fn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs))) + let header = FnHeader { unsafety, asyncness, constness, abi }; + Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) } /// true if we are looking at `const ID`, false for things like `const fn` etc @@ -5383,10 +5443,18 @@ impl<'a> Parser<'a> { /// - `const unsafe fn` /// - `extern fn` /// - etc - fn parse_fn_front_matter(&mut self) -> PResult<'a, (Spanned<Constness>, Unsafety, Abi)> { + fn parse_fn_front_matter(&mut self) + -> PResult<'a, ( + Spanned<Constness>, + Unsafety, + IsAsync, + Abi + )> + { let is_const_fn = self.eat_keyword(keywords::Const); let const_span = self.prev_span; let unsafety = self.parse_unsafety(); + let asyncness = self.parse_asyncness(); let (constness, unsafety, abi) = if is_const_fn { (respan(const_span, Constness::Const), unsafety, Abi::Rust) } else { @@ -5398,7 +5466,7 @@ impl<'a> Parser<'a> { (respan(self.prev_span, Constness::NotConst), unsafety, abi) }; self.expect_keyword(keywords::Fn)?; - Ok((constness, unsafety, abi)) + Ok((constness, unsafety, asyncness, abi)) } /// Parse an impl item. @@ -5533,19 +5601,18 @@ impl<'a> Parser<'a> { Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(), ast::ImplItemKind::Macro(mac))) } else { - let (constness, unsafety, abi) = self.parse_fn_front_matter()?; + let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?; generics.where_clause = self.parse_where_clause()?; *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(ast::MethodSig { - abi, - unsafety, - constness, - decl, - }, body))) + let header = ast::FnHeader { abi, unsafety, constness, asyncness }; + Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method( + ast::MethodSig { header, decl }, + body + ))) } } @@ -6631,6 +6698,7 @@ impl<'a> Parser<'a> { let abi = opt_abi.unwrap_or(Abi::C); let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Normal, + IsAsync::NotAsync, respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; @@ -6674,6 +6742,7 @@ impl<'a> Parser<'a> { self.bump(); let (ident, item_, extra_attrs) = self.parse_item_fn(unsafety, + IsAsync::NotAsync, respan(const_span, Constness::Const), Abi::Rust)?; let prev_span = self.prev_span; @@ -6701,6 +6770,34 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } + + // `unsafe async fn` or `async fn` + if ( + self.check_keyword(keywords::Unsafe) && + self.look_ahead(1, |t| t.is_keyword(keywords::Async)) + ) || ( + self.check_keyword(keywords::Async) && + self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) + ) + { + // ASYNC FUNCTION ITEM + let unsafety = self.parse_unsafety(); + self.expect_keyword(keywords::Async)?; + self.expect_keyword(keywords::Fn)?; + let fn_span = self.prev_span; + let (ident, item_, extra_attrs) = + self.parse_item_fn(unsafety, + IsAsync::Async(ast::DUMMY_NODE_ID), + respan(fn_span, Constness::NotConst), + Abi::Rust)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } if self.check_keyword(keywords::Unsafe) && (self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) || self.look_ahead(1, |t| t.is_keyword(keywords::Auto))) @@ -6746,6 +6843,7 @@ impl<'a> Parser<'a> { let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Normal, + IsAsync::NotAsync, respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; @@ -6771,6 +6869,7 @@ impl<'a> Parser<'a> { let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Unsafe, + IsAsync::NotAsync, respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 7a55919f422..ac8088507dd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -373,14 +373,13 @@ pub fn vis_to_string(v: &ast::Visibility) -> String { } pub fn fun_to_string(decl: &ast::FnDecl, - unsafety: ast::Unsafety, - constness: ast::Constness, + header: ast::FnHeader, name: ast::Ident, generics: &ast::Generics) -> String { to_string(|s| { s.head("")?; - s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name), + s.print_fn(decl, header, Some(name), generics, &codemap::dummy_spanned(ast::VisibilityKind::Inherited))?; s.end()?; // Close the head box s.end() // Close the outer box @@ -1118,9 +1117,8 @@ impl<'a> State<'a> { match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { self.head("")?; - self.print_fn(decl, ast::Unsafety::Normal, - ast::Constness::NotConst, - Abi::Rust, Some(item.ident), + self.print_fn(decl, ast::FnHeader::default(), + Some(item.ident), generics, &item.vis)?; self.end()?; // end head-ibox self.s.word(";")?; @@ -1249,13 +1247,11 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer cbox } - ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref typarams, ref body) => { + ast::ItemKind::Fn(ref decl, header, ref typarams, ref body) => { self.head("")?; self.print_fn( decl, - unsafety, - constness.node, - abi, + header, Some(item.ident), typarams, &item.vis @@ -1582,9 +1578,7 @@ impl<'a> State<'a> { vis: &ast::Visibility) -> io::Result<()> { self.print_fn(&m.decl, - m.unsafety, - m.constness.node, - m.abi, + m.header, Some(ident), &generics, vis) @@ -2177,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)?; @@ -2202,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)?; @@ -2740,13 +2742,11 @@ impl<'a> State<'a> { pub fn print_fn(&mut self, decl: &ast::FnDecl, - unsafety: ast::Unsafety, - constness: ast::Constness, - abi: abi::Abi, + header: ast::FnHeader, name: Option<ast::Ident>, generics: &ast::Generics, vis: &ast::Visibility) -> io::Result<()> { - self.print_fn_header_info(unsafety, constness, abi, vis)?; + self.print_fn_header_info(header, vis)?; if let Some(name) = name { self.nbsp()?; @@ -2800,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 { @@ -3058,9 +3066,7 @@ impl<'a> State<'a> { span: syntax_pos::DUMMY_SP, }; self.print_fn(decl, - unsafety, - ast::Constness::NotConst, - abi, + ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() }, name, &generics, &codemap::dummy_spanned(ast::VisibilityKind::Inherited))?; @@ -3123,22 +3129,21 @@ impl<'a> State<'a> { } pub fn print_fn_header_info(&mut self, - unsafety: ast::Unsafety, - constness: ast::Constness, - abi: Abi, + header: ast::FnHeader, vis: &ast::Visibility) -> io::Result<()> { self.s.word(&visibility_qualified(vis, ""))?; - match constness { + match header.constness.node { ast::Constness::NotConst => {} ast::Constness::Const => self.word_nbsp("const")? } - self.print_unsafety(unsafety)?; + self.print_asyncness(header.asyncness)?; + self.print_unsafety(header.unsafety)?; - if abi != Abi::Rust { + if header.abi != Abi::Rust { self.word_nbsp("extern")?; - self.word_nbsp(&abi.to_string())?; + self.word_nbsp(&header.abi.to_string())?; } self.s.word("fn") @@ -3181,10 +3186,20 @@ mod tests { variadic: false }; let generics = ast::Generics::default(); - assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal, - ast::Constness::NotConst, - abba_ident, &generics), - "fn abba()"); + assert_eq!( + fun_to_string( + &decl, + ast::FnHeader { + unsafety: ast::Unsafety::Normal, + constness: codemap::dummy_spanned(ast::Constness::NotConst), + asyncness: ast::IsAsync::NotAsync, + abi: Abi::Rust, + }, + abba_ident, + &generics + ), + "fn abba()" + ); }) } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index f896fa351b0..77225585141 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -124,24 +124,36 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) { match i.node { - ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => { - let diag = self.cx.span_diagnostic; - diag.span_fatal(i.span, "unsafe functions cannot be used for tests").raise(); - } - _ => { - debug!("this is a test function"); - let test = Test { - span: i.span, - path: self.cx.path.clone(), - bench: is_bench_fn(&self.cx, &i), - ignore: is_ignored(&i), - should_panic: should_panic(&i, &self.cx), - allow_fail: is_allowed_fail(&i), - }; - self.cx.testfns.push(test); - self.tests.push(i.ident); + 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(); + } + if header.asyncness.is_async() { + let diag = self.cx.span_diagnostic; + diag.span_fatal( + i.span, + "async functions cannot be used for tests" + ).raise(); + } } + _ => {}, } + + debug!("this is a test function"); + let test = Test { + span: i.span, + path: self.cx.path.clone(), + bench: is_bench_fn(&self.cx, &i), + ignore: is_ignored(&i), + should_panic: should_panic(&i, &self.cx), + allow_fail: is_allowed_fail(&i), + }; + self.cx.testfns.push(test); + self.tests.push(i.ident); } let mut item = i.into_inner(); @@ -338,7 +350,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { fn has_test_signature(_cx: &TestCtxt, i: &ast::Item) -> HasTestSignature { let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic"); match i.node { - ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { + ast::ItemKind::Fn(ref decl, _, ref generics, _) => { // If the termination trait is active, the compiler will check that the output // type implements the `Termination` trait as `libtest` enforces that. let has_output = match decl.output { @@ -396,7 +408,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { fn has_bench_signature(_cx: &TestCtxt, i: &ast::Item) -> bool { match i.node { - ast::ItemKind::Fn(ref decl, _, _, _, _, _) => { + ast::ItemKind::Fn(ref decl, _, _, _) => { // NB: inadequate check, but we're running // well before resolve, can't get too deep. decl.inputs.len() == 1 @@ -537,9 +549,7 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> { let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![])); let main_body = ecx.block(sp, vec![call_test_main]); let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)), - ast::Unsafety::Normal, - dummy_spanned(ast::Constness::NotConst), - ::rustc_target::spec::abi::Abi::Rust, + ast::FnHeader::default(), ast::Generics::default(), main_body); P(ast::Item { 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 613f1a4f113..41e3ad9d4f4 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -23,17 +23,15 @@ //! instance, a walker looking for item names in a module will miss all of //! those that are created by the expansion of a macro. -use rustc_target::spec::abi::Abi; use ast::*; use syntax_pos::Span; -use codemap::Spanned; use parse::token::Token; use tokenstream::{TokenTree, TokenStream}; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - ItemFn(Ident, Unsafety, Spanned<Constness>, Abi, &'a Visibility, &'a Block), + ItemFn(Ident, FnHeader, &'a Visibility, &'a Block), /// fn foo(&self) Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block), @@ -235,10 +233,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_ty(typ); visitor.visit_expr(expr); } - ItemKind::Fn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { + ItemKind::Fn(ref declaration, header, ref generics, ref body) => { visitor.visit_generics(generics); - visitor.visit_fn(FnKind::ItemFn(item.ident, unsafety, - constness, abi, &item.vis, body), + visitor.visit_fn(FnKind::ItemFn(item.ident, header, + &item.vis, body), declaration, item.span, item.id) @@ -544,7 +542,7 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl where V: Visitor<'a>, { match kind { - FnKind::ItemFn(_, _, _, _, _, body) => { + FnKind::ItemFn(_, _, _, body) => { walk_fn_decl(visitor, declaration); visitor.visit_block(body); } @@ -737,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, @@ -747,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); |
