Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/expr_store/lower.rs')
| -rw-r--r-- | crates/hir-def/src/expr_store/lower.rs | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 2a1ed0afa9..5352991d7b 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -1407,9 +1407,11 @@ impl<'db> ExprCollector<'db> { } } ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| { - this.with_binding_owner(|this| { + this.with_binding_owner_and_return(|this| { let mut args = Vec::new(); let mut arg_types = Vec::new(); + // For coroutine closures, the body, aka. the coroutine is the bindings owner, and not the closure. + let mut body_is_bindings_owner = false; if let Some(pl) = e.param_list() { let num_params = pl.params().count(); args.reserve_exact(num_params); @@ -1460,6 +1462,7 @@ impl<'db> ExprCollector<'db> { // It will be fixed in capture analysis. capture_by: CaptureBy::Ref, }); + body_is_bindings_owner = true; ClosureKind::AsyncClosure } else { @@ -1469,7 +1472,7 @@ impl<'db> ExprCollector<'db> { if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref }; this.is_lowering_coroutine = prev_is_lowering_coroutine; this.current_try_block = prev_try_block; - this.alloc_expr( + let closure = this.alloc_expr( Expr::Closure { args: args.into(), arg_types: arg_types.into(), @@ -1479,7 +1482,9 @@ impl<'db> ExprCollector<'db> { capture_by, }, syntax_ptr, - ) + ); + + (if body_is_bindings_owner { body } else { closure }, closure) }) }), ast::Expr::BinExpr(e) => { @@ -1781,13 +1786,24 @@ impl<'db> ExprCollector<'db> { } } - fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId { + /// The callback should return two exprs: the first is the bindings owner, the second is the expr to return. + fn with_binding_owner_and_return( + &mut self, + create_expr: impl FnOnce(&mut Self) -> (ExprId, ExprId), + ) -> ExprId { let prev_unowned_bindings_len = self.unowned_bindings.len(); - let expr_id = create_expr(self); + let (bindings_owner, expr_to_return) = create_expr(self); for binding in self.unowned_bindings.drain(prev_unowned_bindings_len..) { - self.store.binding_owners.insert(binding, expr_id); + self.store.binding_owners.insert(binding, bindings_owner); } - expr_id + expr_to_return + } + + fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId { + self.with_binding_owner_and_return(move |this| { + let expr = create_expr(this); + (expr, expr) + }) } /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`, |