Skip to content

[wg-async-await] Drop async fn arguments in async block #59823

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 23, 2019
Prev Previous commit
Next Next commit
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.
  • Loading branch information
davidtwco committed Apr 21, 2019
commit 879abb1641d97be798010f52a875b9fc83881323
6 changes: 3 additions & 3 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ impl<'a> FnKind<'a> {
}
}

pub fn header(&self) -> Option<FnHeader> {
pub fn header(&self) -> Option<&FnHeader> {
match *self {
FnKind::ItemFn(_, _, header, _, _) => Some(header),
FnKind::Method(_, sig, _, _) => Some(sig.header),
FnKind::ItemFn(_, _, ref header, _, _) => Some(header),
FnKind::Method(_, ref sig, _, _) => Some(&sig.header),
FnKind::Closure(_) => None,
}
}
Expand Down
22 changes: 11 additions & 11 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3000,13 +3000,13 @@ impl<'a> LoweringContext<'a> {
fn lower_async_body(
&mut self,
decl: &FnDecl,
asyncness: IsAsync,
asyncness: &IsAsync,
body: &Block,
) -> hir::BodyId {
self.lower_body(Some(decl), |this| {
if let IsAsync::Async { closure_id, .. } = asyncness {
let async_expr = this.make_async_expr(
CaptureBy::Value, closure_id, None,
CaptureBy::Value, *closure_id, None,
|this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
Expand Down Expand Up @@ -3067,14 +3067,14 @@ impl<'a> LoweringContext<'a> {
value
)
}
ItemKind::Fn(ref decl, header, ref generics, ref body) => {
ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
let fn_def_id = self.resolver.definitions().local_def_id(id);
self.with_new_scopes(|this| {
// Note: we don't need to change the return type from `T` to
// `impl Future<Output = T>` here because lower_body
// only cares about the input argument patterns in the function
// declaration (decl), not the return types.
let body_id = this.lower_async_body(decl, header.asyncness.node, body);
let body_id = this.lower_async_body(decl, &header.asyncness.node, body);

let (generics, fn_decl) = this.add_in_band_defs(
generics,
Expand Down Expand Up @@ -3565,7 +3565,7 @@ impl<'a> LoweringContext<'a> {
)
}
ImplItemKind::Method(ref sig, ref body) => {
let body_id = self.lower_async_body(&sig.decl, sig.header.asyncness.node, body);
let body_id = self.lower_async_body(&sig.decl, &sig.header.asyncness.node, body);
let impl_trait_return_allow = !self.is_in_trait_impl;
let (generics, sig) = self.lower_method_sig(
&i.generics,
Expand Down Expand Up @@ -3767,7 +3767,7 @@ impl<'a> LoweringContext<'a> {
impl_trait_return_allow: bool,
is_async: Option<NodeId>,
) -> (hir::Generics, hir::MethodSig) {
let header = self.lower_fn_header(sig.header);
let header = self.lower_fn_header(&sig.header);
let (generics, decl) = self.add_in_band_defs(
generics,
fn_def_id,
Expand All @@ -3789,10 +3789,10 @@ impl<'a> LoweringContext<'a> {
}
}

fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
fn lower_fn_header(&mut self, h: &FnHeader) -> hir::FnHeader {
hir::FnHeader {
unsafety: self.lower_unsafety(h.unsafety),
asyncness: self.lower_asyncness(h.asyncness.node),
asyncness: self.lower_asyncness(&h.asyncness.node),
constness: self.lower_constness(h.constness),
abi: h.abi,
}
Expand All @@ -3812,7 +3812,7 @@ impl<'a> LoweringContext<'a> {
}
}

fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
fn lower_asyncness(&mut self, a: &IsAsync) -> hir::IsAsync {
match a {
IsAsync::Async { .. } => hir::IsAsync::Async,
IsAsync::NotAsync => hir::IsAsync::NotAsync,
Expand Down Expand Up @@ -4125,7 +4125,7 @@ impl<'a> LoweringContext<'a> {
})
}
ExprKind::Closure(
capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span
) => {
if let IsAsync::Async { closure_id, .. } = asyncness {
let outer_decl = FnDecl {
Expand Down Expand Up @@ -4163,7 +4163,7 @@ impl<'a> LoweringContext<'a> {
Some(&**ty)
} else { None };
let async_body = this.make_async_expr(
capture_clause, closure_id, async_ret_ty,
capture_clause, *closure_id, async_ret_ty,
|this| {
this.with_new_scopes(|this| this.lower_expr(body))
});
Expand Down
7 changes: 4 additions & 3 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl<'a> DefCollector<'a> {
id: NodeId,
name: Name,
span: Span,
header: &FnHeader,
header: &'a FnHeader,
generics: &'a Generics,
decl: &'a FnDecl,
body: &'a Block,
Expand All @@ -77,6 +77,7 @@ impl<'a> DefCollector<'a> {
IsAsync::Async {
closure_id,
return_impl_trait_id,
..
} => (closure_id, return_impl_trait_id),
_ => unreachable!(),
};
Expand Down Expand Up @@ -290,7 +291,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {

match expr.node {
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
ExprKind::Closure(_, asyncness, ..) => {
ExprKind::Closure(_, ref asyncness, ..) => {
let closure_def = self.create_def(expr.id,
DefPathData::ClosureExpr,
REGULAR_SPACE,
Expand All @@ -300,7 +301,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
// Async closures desugar to closures inside of closures, so
// we must create two defs.
if let IsAsync::Async { closure_id, .. } = asyncness {
let async_def = self.create_def(closure_id,
let async_def = self.create_def(*closure_id,
DefPathData::ClosureExpr,
REGULAR_SPACE,
expr.span);
Expand Down
16 changes: 16 additions & 0 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,22 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>

run_early_pass!(self, check_mac, mac);
}

fn visit_fn_header(&mut self, header: &'a ast::FnHeader) {
// Unlike in HIR lowering and name resolution, the `AsyncArgument` statements are not added
// to the function body and the arguments do not replace those in the declaration. They are
// still visited manually here so that buffered lints can be emitted.
if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node {
for a in arguments {
// Visit the argument..
self.visit_pat(&a.arg.pat);
self.visit_ty(&a.arg.ty);

// ..and the statement.
self.visit_stmt(&a.stmt);
}
}
}
}

struct LateLintPassObjects<'a> {
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl<'a> AstValidator<'a> {
}
}

fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
fn check_trait_fn_not_async(&self, span: Span, asyncness: &IsAsync) {
if asyncness.is_async() {
struct_span_err!(self.session, span, E0706,
"trait fns cannot be declared `async`").emit()
Expand Down Expand Up @@ -570,7 +570,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.invalid_visibility(&impl_item.vis, None);
if let ImplItemKind::Method(ref sig, _) = impl_item.node {
self.check_trait_fn_not_const(sig.header.constness);
self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
self.check_trait_fn_not_async(impl_item.span, &sig.header.asyncness.node);
}
}
}
Expand Down Expand Up @@ -642,7 +642,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.no_questions_in_bounds(bounds, "supertraits", true);
for trait_item in trait_items {
if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node);
self.check_trait_fn_not_async(trait_item.span, &sig.header.asyncness.node);
self.check_trait_fn_not_const(sig.header.constness);
if block.is_none() {
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
Expand Down
10 changes: 4 additions & 6 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,13 +817,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
debug!("(resolving function) entering function");
let (rib_kind, asyncness) = match function_kind {
FnKind::ItemFn(_, ref header, ..) =>
(FnItemRibKind, header.asyncness.node),
(FnItemRibKind, &header.asyncness.node),
FnKind::Method(_, ref sig, _, _) =>
(TraitOrImplItemRibKind, sig.header.asyncness.node),
(TraitOrImplItemRibKind, &sig.header.asyncness.node),
FnKind::Closure(_) =>
// Async closures aren't resolved through `visit_fn`-- they're
// processed separately
(ClosureRibKind(node_id), IsAsync::NotAsync),
(ClosureRibKind(node_id), &IsAsync::NotAsync),
};

// Create a value rib for the function.
Expand All @@ -836,16 +836,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
let mut bindings_list = FxHashMap::default();
for argument in &declaration.inputs {
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);

self.visit_ty(&argument.ty);

debug!("(resolving function) recorded argument");
}
visit::walk_fn_ret_ty(self, &declaration.output);

// Resolve the function body, potentially inside the body of an async closure
if let IsAsync::Async { closure_id, .. } = asyncness {
let rib_kind = ClosureRibKind(closure_id);
let rib_kind = ClosureRibKind(*closure_id);
self.ribs[ValueNS].push(Rib::new(rib_kind));
self.label_ribs.push(Rib::new(rib_kind));
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_save_analysis/sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ impl Sig for ast::Item {

Ok(extend_sig(ty, text, defs, vec![]))
}
ast::ItemKind::Fn(ref decl, header, ref generics, _) => {
ast::ItemKind::Fn(ref decl, ref header, ref generics, _) => {
let mut text = String::new();
if header.constness.node == ast::Constness::Const {
text.push_str("const ");
Expand Down
29 changes: 23 additions & 6 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1849,31 +1849,48 @@ pub enum Unsafety {
Normal,
}

#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct AsyncArgument {
/// `__arg0`
pub ident: Ident,
/// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`.
pub arg: Arg,
/// `let <pat>: <ty> = __arg0;` statement to be inserted at the start of the block.
pub stmt: Stmt,
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum IsAsync {
Async {
closure_id: NodeId,
return_impl_trait_id: NodeId,
/// This field stores the arguments and statements that are used in HIR lowering to
/// ensure that `async fn` arguments are dropped at the correct time.
///
/// The argument and statements here are generated at parse time as they are required in
/// both the hir lowering, def collection and name resolution and this stops them needing
/// to be created in each place.
arguments: Vec<AsyncArgument>,
},
NotAsync,
}

impl IsAsync {
pub fn is_async(self) -> bool {
if let IsAsync::Async { .. } = self {
pub fn is_async(&self) -> bool {
if let IsAsync::Async { .. } = *self {
true
} else {
false
}
}

/// In ths case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
pub fn opt_return_id(self) -> Option<NodeId> {
pub fn opt_return_id(&self) -> Option<NodeId> {
match self {
IsAsync::Async {
return_impl_trait_id,
..
} => Some(return_impl_trait_id),
} => Some(*return_impl_trait_id),
IsAsync::NotAsync => None,
}
}
Expand Down Expand Up @@ -2213,7 +2230,7 @@ impl Item {
///
/// All the information between the visibility and the name of the function is
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct FnHeader {
pub unsafety: Unsafety,
pub asyncness: Spanned<IsAsync>,
Expand Down
20 changes: 17 additions & 3 deletions src/libsyntax/ext/placeholders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
fn remove(&mut self, id: ast::NodeId) -> AstFragment {
self.expanded_fragments.remove(&id).unwrap()
}

fn next_id(&mut self, id: &mut ast::NodeId) {
if self.monotonic {
assert_eq!(*id, ast::DUMMY_NODE_ID);
*id = self.cx.resolver.next_node_id()
}
}
}

impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
Expand Down Expand Up @@ -183,9 +190,16 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
noop_visit_block(block, self);

for stmt in block.stmts.iter_mut() {
if self.monotonic {
assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
stmt.id = self.cx.resolver.next_node_id();
self.next_id(&mut stmt.id);
}
}

fn visit_asyncness(&mut self, a: &mut ast::IsAsync) {
noop_visit_asyncness(a, self);

if let ast::IsAsync::Async { ref mut arguments, .. } = a {
for argument in arguments.iter_mut() {
self.next_id(&mut argument.stmt.id);
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion src/libsyntax/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,9 +679,17 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:

pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T) {
match asyncness {
IsAsync::Async { closure_id, return_impl_trait_id } => {
IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => {
vis.visit_id(closure_id);
vis.visit_id(return_impl_trait_id);
for AsyncArgument { ident, arg, stmt } in arguments.iter_mut() {
vis.visit_ident(ident);
vis.visit_arg(arg);
visit_clobber(stmt, |stmt| {
vis.flat_map_stmt(stmt)
.expect_one("expected visitor to produce exactly one item")
});
}
}
IsAsync::NotAsync => {}
}
Expand Down
Loading