Skip to content

Commit 271cf3e

Browse files
In async closures, make the returned async blocks the bindings owner of the bindings inside
Previously it was the closure, which is incorrect.
1 parent 993b436 commit 271cf3e

1 file changed

Lines changed: 23 additions & 7 deletions

File tree

crates/hir-def/src/expr_store/lower.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,9 +1407,11 @@ impl<'db> ExprCollector<'db> {
14071407
}
14081408
}
14091409
ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {
1410-
this.with_binding_owner(|this| {
1410+
this.with_binding_owner_and_return(|this| {
14111411
let mut args = Vec::new();
14121412
let mut arg_types = Vec::new();
1413+
// For coroutine closures, the body, aka. the coroutine is the bindings owner, and not the closure.
1414+
let mut body_is_bindings_owner = false;
14131415
if let Some(pl) = e.param_list() {
14141416
let num_params = pl.params().count();
14151417
args.reserve_exact(num_params);
@@ -1460,6 +1462,7 @@ impl<'db> ExprCollector<'db> {
14601462
// It will be fixed in capture analysis.
14611463
capture_by: CaptureBy::Ref,
14621464
});
1465+
body_is_bindings_owner = true;
14631466

14641467
ClosureKind::AsyncClosure
14651468
} else {
@@ -1469,7 +1472,7 @@ impl<'db> ExprCollector<'db> {
14691472
if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
14701473
this.is_lowering_coroutine = prev_is_lowering_coroutine;
14711474
this.current_try_block = prev_try_block;
1472-
this.alloc_expr(
1475+
let closure = this.alloc_expr(
14731476
Expr::Closure {
14741477
args: args.into(),
14751478
arg_types: arg_types.into(),
@@ -1479,7 +1482,9 @@ impl<'db> ExprCollector<'db> {
14791482
capture_by,
14801483
},
14811484
syntax_ptr,
1482-
)
1485+
);
1486+
1487+
(if body_is_bindings_owner { body } else { closure }, closure)
14831488
})
14841489
}),
14851490
ast::Expr::BinExpr(e) => {
@@ -1781,13 +1786,24 @@ impl<'db> ExprCollector<'db> {
17811786
}
17821787
}
17831788

1784-
fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId {
1789+
/// The callback should return two exprs: the first is the bindings owner, the second is the expr to return.
1790+
fn with_binding_owner_and_return(
1791+
&mut self,
1792+
create_expr: impl FnOnce(&mut Self) -> (ExprId, ExprId),
1793+
) -> ExprId {
17851794
let prev_unowned_bindings_len = self.unowned_bindings.len();
1786-
let expr_id = create_expr(self);
1795+
let (bindings_owner, expr_to_return) = create_expr(self);
17871796
for binding in self.unowned_bindings.drain(prev_unowned_bindings_len..) {
1788-
self.store.binding_owners.insert(binding, expr_id);
1797+
self.store.binding_owners.insert(binding, bindings_owner);
17891798
}
1790-
expr_id
1799+
expr_to_return
1800+
}
1801+
1802+
fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId {
1803+
self.with_binding_owner_and_return(move |this| {
1804+
let expr = create_expr(this);
1805+
(expr, expr)
1806+
})
17911807
}
17921808

17931809
/// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,

0 commit comments

Comments
 (0)