about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2023-08-07 02:12:35 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2023-08-07 02:12:35 +0330
commitb96e4f2f4a209d2dd1fa3c87c26d370258003f1b (patch)
treeec393b64f8e19646b7485a41c4aaec2e9ce717a5
parent9b636e23265705f5ca4f5965a0e207fefd869990 (diff)
downloadrust-b96e4f2f4a209d2dd1fa3c87c26d370258003f1b.tar.gz
rust-b96e4f2f4a209d2dd1fa3c87c26d370258003f1b.zip
Add mir lower support for tuple destructing assignment
-rw-r--r--crates/hir-ty/src/consteval/tests.rs21
-rw-r--r--crates/hir-ty/src/mir/lower.rs44
2 files changed, 65 insertions, 0 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 666955fa1c3..666a7e81e31 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1203,6 +1203,27 @@ fn destructing_assignment() {
         "#,
         5,
     );
+    check_number(
+        r#"
+    const GOAL: u8 = {
+        let (mut a, mut b) = (2, 5);
+        (a, b) = (b, a);
+        a * 10 + b
+    };
+        "#,
+        52,
+    );
+    check_number(
+        r#"
+    struct Point { x: i32, y: i32 }
+    const GOAL: i32 = {
+        let mut p = Point { x: 5, y: 6 };
+        (p.x, _) = (p.y, p.x);
+        p.x * 10 + p.y
+    };
+        "#,
+        66,
+    );
 }
 
 #[test]
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 718df8331e2..9eaa9e1c2f5 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -1244,6 +1244,41 @@ impl<'ctx> MirLowerCtx<'ctx> {
         }
     }
 
+    fn lower_destructing_assignment(
+        &mut self,
+        mut current: BasicBlockId,
+        lhs: ExprId,
+        rhs: Place,
+        span: MirSpan,
+    ) -> Result<Option<BasicBlockId>> {
+        match &self.body.exprs[lhs] {
+            Expr::Tuple { exprs, is_assignee_expr: _ } => {
+                for (i, expr) in exprs.iter().enumerate() {
+                    let Some(c) = self.lower_destructing_assignment(
+                        current,
+                        *expr,
+                        rhs.project(ProjectionElem::TupleOrClosureField(i)),
+                        span,
+                    )? else {
+                        return Ok(None);
+                    };
+                    current = c;
+                }
+                Ok(Some(current))
+            }
+            Expr::Underscore => Ok(Some(current)),
+            _ => {
+                let Some((lhs_place, current)) =
+                    self.lower_expr_as_place(current, lhs, false)?
+                else {
+                    return Ok(None);
+                };
+                self.push_assignment(current, lhs_place, Operand::Copy(rhs).into(), span);
+                Ok(Some(current))
+            }
+        }
+    }
+
     fn lower_assignment(
         &mut self,
         current: BasicBlockId,
@@ -1259,6 +1294,15 @@ impl<'ctx> MirLowerCtx<'ctx> {
         if matches!(&self.body.exprs[lhs], Expr::Underscore) {
             return Ok(Some(current));
         }
+        if matches!(
+            &self.body.exprs[lhs],
+            Expr::Tuple { .. } | Expr::RecordLit { .. } | Expr::Call { .. }
+        ) {
+            let temp = self.temp(self.expr_ty_after_adjustments(rhs), current, rhs.into())?;
+            let temp = Place::from(temp);
+            self.push_assignment(current, temp.clone(), rhs_op.into(), span);
+            return self.lower_destructing_assignment(current, lhs, temp, span);
+        }
         let Some((lhs_place, current)) =
             self.lower_expr_as_place(current, lhs, false)?
         else {