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;
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;
err.span_label(self.span, format!("expected identifier, found {}", token_descr));
} else {
err.span_label(self.span, "expected identifier");
+ if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
+ err.span_suggestion(self.span, "remove this comma", "".into());
+ }
}
err
}
/// Parse a sequence, not including the closing delimiter. The function
/// f must consume tokens until reaching the next separator or
/// closing bracket.
- fn parse_seq_to_before_end<T, F>(&mut self,
+ pub fn parse_seq_to_before_end<T, F>(&mut self,
ket: &token::Token,
sep: SeqSep,
f: F)
})))
}
+ /// 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) {
// 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()?;
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 {
ExprKind::AssignOp(binop, lhs, rhs)
}
- fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> {
+ pub fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> {
P(Expr {
id: ast::DUMMY_NODE_ID,
node: ExprKind::Mac(codemap::Spanned {node: m, span: span}),
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);
}
Err(mut e) => {
e.span_label(struct_sp, "while parsing this struct");
e.emit();
- self.recover_stmt();
- break;
+
+ // If the next token is a comma, then try to parse
+ // what comes next as additional fields, rather than
+ // bailing out until next `}`.
+ if self.token != token::Comma {
+ self.recover_stmt();
+ break;
+ }
}
}
} 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 {
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))
}
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>>
})
}
+ 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)) &&
if macro_legacy_warnings && self.token != token::Semi {
self.warn_missing_semicolon();
} else {
- self.expect_one_of(&[token::Semi], &[])?;
+ self.expect_one_of(&[], &[token::Semi])?;
}
}
_ => {}
/// Parse an item-position function declaration.
fn parse_item_fn(&mut self,
unsafety: Unsafety,
+ asyncness: IsAsync,
constness: Spanned<Constness>,
abi: Abi)
-> PResult<'a, ItemInfo> {
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
/// - `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 {
(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.
- crate fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> {
+ pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> {
maybe_whole!(self, NtImplItem, |x| x);
let attrs = self.parse_outer_attributes()?;
let (mut item, tokens) = self.collect_tokens(|this| {
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
+ )))
}
}
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;
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;
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)))
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;
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;
})
}
- fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option<ast::Name>)> {
+ pub fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option<ast::Name>)> {
let ret = match self.token {
token::Literal(token::Str_(s), suf) => (s, ast::StrStyle::Cooked, suf),
token::Literal(token::StrRaw(s, n), suf) => (s, ast::StrStyle::Raw(n), suf),