1
Fork 0

Add AsyncArgument to AST.

This commit adds an `AsyncArgument` struct to the AST that contains the
generated argument and statement that will be used in HIR lowering, name
resolution and def collection.
This commit is contained in:
David Wood 2019-03-12 17:00:20 +01:00
parent 41c6bb1096
commit 879abb1641
No known key found for this signature in database
GPG key ID: 01760B4F9F53F154
12 changed files with 171 additions and 53 deletions

View file

@ -1,4 +1,4 @@
use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy};
use crate::ast::{AngleBracketedArgs, AsyncArgument, ParenthesizedArgs, AttrStyle, BareFnTy};
use crate::ast::{GenericBound, TraitBoundModifier};
use crate::ast::Unsafety;
use crate::ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind};
@ -1517,6 +1517,7 @@ impl<'a> Parser<'a> {
IsAsync::Async {
closure_id: ast::DUMMY_NODE_ID,
return_impl_trait_id: ast::DUMMY_NODE_ID,
arguments: Vec::new(),
}
} else {
IsAsync::NotAsync
@ -1575,7 +1576,7 @@ impl<'a> Parser<'a> {
// trait item macro.
(keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
} else {
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?;
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
@ -1589,6 +1590,7 @@ impl<'a> Parser<'a> {
p.parse_arg_general(p.span.rust_2018(), true, false)
})?;
generics.where_clause = self.parse_where_clause()?;
self.construct_async_arguments(&mut asyncness, &d);
let sig = ast::MethodSig {
header: FnHeader {
@ -6567,7 +6569,7 @@ impl<'a> Parser<'a> {
/// Parses an item-position function declaration.
fn parse_item_fn(&mut self,
unsafety: Unsafety,
asyncness: Spanned<IsAsync>,
mut asyncness: Spanned<IsAsync>,
constness: Spanned<Constness>,
abi: Abi)
-> PResult<'a, ItemInfo> {
@ -6576,6 +6578,7 @@ impl<'a> Parser<'a> {
let decl = self.parse_fn_decl(allow_c_variadic)?;
generics.where_clause = self.parse_where_clause()?;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
self.construct_async_arguments(&mut asyncness, &decl);
let header = FnHeader { unsafety, asyncness, constness, abi };
Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs)))
}
@ -6751,11 +6754,12 @@ impl<'a> Parser<'a> {
Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
ast::ImplItemKind::Macro(mac)))
} else {
let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
let (constness, unsafety, mut 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()?;
self.construct_async_arguments(&mut asyncness, &decl);
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let header = ast::FnHeader { abi, unsafety, constness, asyncness };
@ -8177,6 +8181,7 @@ impl<'a> Parser<'a> {
respan(async_span, IsAsync::Async {
closure_id: ast::DUMMY_NODE_ID,
return_impl_trait_id: ast::DUMMY_NODE_ID,
arguments: Vec::new(),
}),
respan(fn_span, Constness::NotConst),
Abi::Rust)?;
@ -8822,6 +8827,66 @@ impl<'a> Parser<'a> {
}
}
}
/// When lowering a `async fn` to the HIR, we need to move all of the arguments of the function
/// into the generated closure so that they are dropped when the future is polled and not when
/// it is created.
///
/// The arguments of the function are replaced in HIR lowering with the arguments created by
/// this function and the statements created here are inserted at the top of the closure body.
fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl: &FnDecl) {
if let IsAsync::Async { ref mut arguments, .. } = asyncness.node {
for (index, input) in decl.inputs.iter().enumerate() {
let id = ast::DUMMY_NODE_ID;
let span = input.pat.span;
// Construct a name for our temporary argument.
let name = format!("__arg{}", index);
let ident = Ident::from_str(&name);
// Construct an argument representing `__argN: <ty>` to replace the argument of the
// async function.
let arg = Arg {
ty: input.ty.clone(),
id,
pat: P(Pat {
id,
node: PatKind::Ident(
BindingMode::ByValue(Mutability::Immutable), ident, None,
),
span,
}),
};
// Construct a `let <pat>: <ty> = __argN;` statement to insert at the top of the
// async closure.
let local = P(Local {
pat: input.pat.clone(),
ty: Some(P(Ty {
id,
node: input.ty.node.clone(),
span: input.ty.span,
})),
init: Some(P(Expr {
id,
node: ExprKind::Path(None, ast::Path {
span,
segments: vec![PathSegment { ident, id, args: None }],
}),
span,
attrs: ThinVec::new(),
})),
id,
span,
attrs: ThinVec::new(),
source: LocalSource::AsyncFn,
});
let stmt = Stmt { id, node: StmtKind::Local(local), span, };
arguments.push(AsyncArgument { ident, arg, stmt });
}
}
}
}
pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, handler: &errors::Handler) {