Skip to content

Commit f566e98

Browse files
committed
Move async fn arguments into closure.
This commit takes advantage of `AsyncArgument` type that was added in a previous commit to replace the arguments of the `async fn` in the HIR and add statements to move the bindings from the new arguments to the pattern from the old argument. For example, the async function `foo` below: async fn foo((x, _y): (T, V)) { async move { } } becomes: async fn foo(__arg0: (T, V)) { async move { let (x, _y) = __arg0; } }
1 parent 70b7b78 commit f566e98

File tree

3 files changed

+86
-31
lines changed

3 files changed

+86
-31
lines changed

src/librustc/hir/lowering.rs

+41-19
Original file line numberDiff line numberDiff line change
@@ -2819,12 +2819,18 @@ impl<'a> LoweringContext<'a> {
28192819
asyncness: &IsAsync,
28202820
body: &Block,
28212821
) -> hir::BodyId {
2822-
self.lower_body(Some(decl), |this| {
2823-
if let IsAsync::Async { closure_id, .. } = asyncness {
2822+
self.lower_body(Some(&decl), |this| {
2823+
if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness {
2824+
let mut body = body.clone();
2825+
2826+
for a in arguments.iter().rev() {
2827+
body.stmts.insert(0, a.stmt.clone());
2828+
}
2829+
28242830
let async_expr = this.make_async_expr(
28252831
CaptureBy::Value, *closure_id, None,
28262832
|this| {
2827-
let body = this.lower_block(body, false);
2833+
let body = this.lower_block(&body, false);
28282834
this.expr_block(body, ThinVec::new())
28292835
});
28302836
this.expr(body.span, async_expr, ThinVec::new())
@@ -2886,23 +2892,39 @@ impl<'a> LoweringContext<'a> {
28862892
ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
28872893
let fn_def_id = self.resolver.definitions().local_def_id(id);
28882894
self.with_new_scopes(|this| {
2889-
// Note: we don't need to change the return type from `T` to
2890-
// `impl Future<Output = T>` here because lower_body
2891-
// only cares about the input argument patterns in the function
2892-
// declaration (decl), not the return types.
2893-
let body_id = this.lower_async_body(decl, &header.asyncness.node, body);
2895+
let mut lower_fn = |decl: &FnDecl| {
2896+
// Note: we don't need to change the return type from `T` to
2897+
// `impl Future<Output = T>` here because lower_body
2898+
// only cares about the input argument patterns in the function
2899+
// declaration (decl), not the return types.
2900+
let body_id = this.lower_async_body(&decl, &header.asyncness.node, body);
2901+
2902+
let (generics, fn_decl) = this.add_in_band_defs(
2903+
generics,
2904+
fn_def_id,
2905+
AnonymousLifetimeMode::PassThrough,
2906+
|this, idty| this.lower_fn_decl(
2907+
&decl,
2908+
Some((fn_def_id, idty)),
2909+
true,
2910+
header.asyncness.node.opt_return_id()
2911+
),
2912+
);
28942913

2895-
let (generics, fn_decl) = this.add_in_band_defs(
2896-
generics,
2897-
fn_def_id,
2898-
AnonymousLifetimeMode::PassThrough,
2899-
|this, idty| this.lower_fn_decl(
2900-
decl,
2901-
Some((fn_def_id, idty)),
2902-
true,
2903-
header.asyncness.node.opt_return_id()
2904-
),
2905-
);
2914+
(body_id, generics, fn_decl)
2915+
};
2916+
2917+
let (body_id, generics, fn_decl) = if let IsAsync::Async {
2918+
arguments, ..
2919+
} = &header.asyncness.node {
2920+
let mut decl = decl.clone();
2921+
// Replace the arguments of this async function with the generated
2922+
// arguments that will be moved into the closure.
2923+
decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
2924+
lower_fn(&decl)
2925+
} else {
2926+
lower_fn(decl)
2927+
};
29062928

29072929
hir::ItemKind::Fn(
29082930
fn_decl,

src/librustc/hir/map/def_collector.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,12 @@ impl<'a> DefCollector<'a> {
7373
decl: &'a FnDecl,
7474
body: &'a Block,
7575
) {
76-
let (closure_id, return_impl_trait_id) = match header.asyncness.node {
76+
let (closure_id, return_impl_trait_id, arguments) = match &header.asyncness.node {
7777
IsAsync::Async {
7878
closure_id,
7979
return_impl_trait_id,
80-
} => (closure_id, return_impl_trait_id),
80+
arguments,
81+
} => (closure_id, return_impl_trait_id, arguments),
8182
_ => unreachable!(),
8283
};
8384

@@ -89,14 +90,28 @@ impl<'a> DefCollector<'a> {
8990
this.create_def(*return_impl_trait_id, DefPathData::ImplTrait, REGULAR_SPACE, span);
9091

9192
visit::walk_generics(this, generics);
92-
visit::walk_fn_decl(this, decl);
9393

94-
let closure_def = this.create_def(*closure_id,
95-
DefPathData::ClosureExpr,
96-
REGULAR_SPACE,
97-
span);
94+
// Walk the generated arguments for the `async fn`.
95+
for a in arguments {
96+
use visit::Visitor;
97+
this.visit_ty(&a.arg.ty);
98+
}
99+
100+
// We do not invoke `walk_fn_decl` as this will walk the arguments that are being
101+
// replaced.
102+
visit::walk_fn_ret_ty(this, &decl.output);
103+
104+
let closure_def = this.create_def(
105+
*closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span,
106+
);
98107
this.with_parent(closure_def, |this| {
99-
visit::walk_block(this, body);
108+
for a in arguments {
109+
use visit::Visitor;
110+
// Walk each of the generated statements before the regular block body.
111+
this.visit_stmt(&a.stmt);
112+
}
113+
114+
visit::walk_block(this, &body);
100115
})
101116
})
102117
}

src/librustc_resolve/lib.rs

+22-4
Original file line numberDiff line numberDiff line change
@@ -831,11 +831,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
831831

832832
// Add each argument to the rib.
833833
let mut bindings_list = FxHashMap::default();
834-
for argument in &declaration.inputs {
834+
let mut add_argument = |argument: &ast::Arg| {
835835
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
836836
self.visit_ty(&argument.ty);
837837
debug!("(resolving function) recorded argument");
838+
};
839+
840+
// Walk the generated async arguments if this is an `async fn`, otherwise walk the
841+
// normal arguments.
842+
if let IsAsync::Async { ref arguments, .. } = asyncness {
843+
for a in arguments { add_argument(&a.arg); }
844+
} else {
845+
for a in &declaration.inputs { add_argument(a); }
838846
}
847+
839848
visit::walk_fn_ret_ty(self, &declaration.output);
840849

841850
// Resolve the function body, potentially inside the body of an async closure
@@ -846,9 +855,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
846855
}
847856

848857
match function_kind {
849-
FnKind::ItemFn(.., body) |
850-
FnKind::Method(.., body) => {
851-
self.visit_block(body);
858+
FnKind::ItemFn(.., body) | FnKind::Method(.., body) => {
859+
if let IsAsync::Async { ref arguments, .. } = asyncness {
860+
let mut body = body.clone();
861+
// Insert the generated statements into the body before attempting to
862+
// resolve names.
863+
for a in arguments {
864+
body.stmts.insert(0, a.stmt.clone());
865+
}
866+
self.visit_block(&body);
867+
} else {
868+
self.visit_block(body);
869+
}
852870
}
853871
FnKind::Closure(body) => {
854872
self.visit_expr(body);

0 commit comments

Comments
 (0)