Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22266 from ChayimFriedman2/closure-analysis
fix: Fix handling of `self` in `lower_coroutine_body_with_moved_arguments()`
Chayim Refael Friedman 11 days ago
parent a936884 · parent ac53ab9 · commit a28bec8
-rw-r--r--crates/hir-def/src/expr_store/lower.rs25
-rw-r--r--crates/hir-def/src/expr_store/tests/body.rs1
2 files changed, 26 insertions, 0 deletions
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index a82046149a..93f8304230 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -165,6 +165,7 @@ pub(super) fn lower_body(
};
let body_expr = collector.collect(
+ self_param,
&mut params,
body,
if is_async_fn {
@@ -963,6 +964,7 @@ impl<'db> ExprCollector<'db> {
/// drop order are stable.
fn lower_coroutine_body_with_moved_arguments(
&mut self,
+ self_param: Option<BindingId>,
params: &mut [PatId],
body: ExprId,
kind: CoroutineKind,
@@ -995,6 +997,26 @@ impl<'db> ExprCollector<'db> {
// `let <pattern> = <pattern>;` statement as an optimization.
let mut statements = Vec::new();
+
+ if let Some(self_param) = self_param {
+ let Binding { ref name, mode, hygiene, .. } = self.store.bindings[self_param];
+ let name = name.clone();
+ let child_binding_id = self.alloc_binding(name.clone(), mode, hygiene);
+ let child_pat_id =
+ self.alloc_pat_desugared(Pat::Bind { id: child_binding_id, subpat: None });
+ self.add_definition_to_binding(child_binding_id, child_pat_id);
+ let expr = self.alloc_expr_desugared(Expr::Path(name.into()));
+ if !hygiene.is_root() {
+ self.store.ident_hygiene.insert(expr.into(), hygiene);
+ }
+ statements.push(Statement::Let {
+ pat: child_pat_id,
+ type_ref: None,
+ initializer: Some(expr),
+ else_branch: None,
+ });
+ }
+
for param in params {
let (name, hygiene, is_simple_parameter) = match self.store.pats[*param] {
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
@@ -1094,6 +1116,7 @@ impl<'db> ExprCollector<'db> {
fn collect(
&mut self,
+ self_param: Option<BindingId>,
params: &mut [PatId],
expr: Option<ast::Expr>,
awaitable: Awaitable,
@@ -1111,6 +1134,7 @@ impl<'db> ExprCollector<'db> {
(false, false) => unreachable!(),
};
this.lower_coroutine_body_with_moved_arguments(
+ self_param,
params,
body,
kind,
@@ -1587,6 +1611,7 @@ impl<'db> ExprCollector<'db> {
// It's important that this expr is allocated immediately before the closure.
// We rely on it for `coroutine_for_closure()`.
body = this.lower_coroutine_body_with_moved_arguments(
+ None,
&mut args,
body,
kind,
diff --git a/crates/hir-def/src/expr_store/tests/body.rs b/crates/hir-def/src/expr_store/tests/body.rs
index 9727d87cf0..e97718ca22 100644
--- a/crates/hir-def/src/expr_store/tests/body.rs
+++ b/crates/hir-def/src/expr_store/tests/body.rs
@@ -653,6 +653,7 @@ async fn main(&self, param1: i32, ref mut param2: i32, _: i32, param4 @ _: i32,
"#,
expect![[r#"
fn main(self, param1, mut param2, mut <ra@gennew>0, mut param4, mut <ra@gennew>1) async {
+ let self = self;
let mut param1 = param1;
let mut param2 = param2;
let ref mut param2 = param2;