about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2023-08-08 01:49:34 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2023-08-08 01:49:34 +0330
commit31c30933cf0a94929d533078a402f15a1d350055 (patch)
tree9d9bb0eec0e1a9d2d2cac7da546db38e3ffff114
parentb96e4f2f4a209d2dd1fa3c87c26d370258003f1b (diff)
downloadrust-31c30933cf0a94929d533078a402f15a1d350055.tar.gz
rust-31c30933cf0a94929d533078a402f15a1d350055.zip
Support closure in clone shim
-rw-r--r--crates/hir-ty/src/consteval/tests.rs24
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs70
2 files changed, 73 insertions, 21 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 666a7e81e31..74c62a08a2b 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1454,6 +1454,30 @@ fn from_trait() {
 }
 
 #[test]
+fn closure_clone() {
+    check_number(
+        r#"
+//- minicore: clone, fn
+struct S(u8);
+
+impl Clone for S(u8) {
+    fn clone(&self) -> S {
+        S(self.0 + 5)
+    }
+}
+
+const GOAL: u8 = {
+    let s = S(3);
+    let cl = move || s;
+    let cl = cl.clone();
+    cl().0
+}
+    "#,
+        8,
+    );
+}
+
+#[test]
 fn builtin_derive_macro() {
     check_number(
         r#"
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index bfd7d7c1f2c..52943e97ac0 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -136,7 +136,10 @@ impl Evaluator<'_> {
                     not_supported!("wrong generic arg kind for clone");
                 };
                 // Clone has special impls for tuples and function pointers
-                if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) {
+                if matches!(
+                    self_ty.kind(Interner),
+                    TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..)
+                ) {
                     self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
                     return Ok(true);
                 }
@@ -167,32 +170,26 @@ impl Evaluator<'_> {
                 return destination
                     .write_from_interval(self, Interval { addr, size: destination.size });
             }
+            TyKind::Closure(id, subst) => {
+                let [arg] = args else {
+                    not_supported!("wrong arg count for clone");
+                };
+                let addr = Address::from_bytes(arg.get(self)?)?;
+                let (closure_owner, _) = self.db.lookup_intern_closure((*id).into());
+                let infer = self.db.infer(closure_owner);
+                let (captures, _) = infer.closure_info(id);
+                let layout = self.layout(&self_ty)?;
+                let ty_iter = captures.iter().map(|c| c.ty(subst));
+                self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
+            }
             TyKind::Tuple(_, subst) => {
                 let [arg] = args else {
                     not_supported!("wrong arg count for clone");
                 };
                 let addr = Address::from_bytes(arg.get(self)?)?;
                 let layout = self.layout(&self_ty)?;
-                for (i, ty) in subst.iter(Interner).enumerate() {
-                    let ty = ty.assert_ty_ref(Interner);
-                    let size = self.layout(ty)?.size.bytes_usize();
-                    let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
-                    let arg = IntervalAndTy {
-                        interval: Interval { addr: tmp, size: self.ptr_size() },
-                        ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone())
-                            .intern(Interner),
-                    };
-                    let offset = layout.fields.offset(i).bytes_usize();
-                    self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
-                    self.exec_clone(
-                        def,
-                        &[arg],
-                        ty.clone(),
-                        locals,
-                        destination.slice(offset..offset + size),
-                        span,
-                    )?;
-                }
+                let ty_iter = subst.iter(Interner).map(|ga| ga.assert_ty_ref(Interner).clone());
+                self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
             }
             _ => {
                 self.exec_fn_with_args(
@@ -209,6 +206,37 @@ impl Evaluator<'_> {
         Ok(())
     }
 
+    fn exec_clone_for_fields(
+        &mut self,
+        ty_iter: impl Iterator<Item = Ty>,
+        layout: Arc<Layout>,
+        addr: Address,
+        def: FunctionId,
+        locals: &Locals,
+        destination: Interval,
+        span: MirSpan,
+    ) -> Result<()> {
+        for (i, ty) in ty_iter.enumerate() {
+            let size = self.layout(&ty)?.size.bytes_usize();
+            let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
+            let arg = IntervalAndTy {
+                interval: Interval { addr: tmp, size: self.ptr_size() },
+                ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone()).intern(Interner),
+            };
+            let offset = layout.fields.offset(i).bytes_usize();
+            self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
+            self.exec_clone(
+                def,
+                &[arg],
+                ty,
+                locals,
+                destination.slice(offset..offset + size),
+                span,
+            )?;
+        }
+        Ok(())
+    }
+
     fn exec_alloc_fn(
         &mut self,
         alloc_fn: &str,