Repository: gluon-lang/gluon
Pull request #780 (2019-08-30 05:53:07)

fix: Add tests and fix the regression with clone_userdata
cc #779
cc @Etherian


Patch:
diff --git a/codegen/src/userdata.rs b/codegen/src/userdata.rs
index 5a2ef9f2..e370998b 100644
--- a/codegen/src/userdata.rs
+++ b/codegen/src/userdata.rs
@@ -55,10 +55,10 @@ fn gen_impl(container: &Container, ident: Ident, generics: Generics) -> TokenStr
 
     let deep_clone = if container.clone {
         quote! {
-            fn deep_clone(
+            fn deep_clone<'gc>(
                 &self,
-                deep_cloner: &mut _gluon_api::Cloner
-            ) -> _gluon_Result<_gluon_gc::GcPtr<Box<dyn _gluon_api::Userdata>>> {
+                deep_cloner: &'gc mut _gluon_api::Cloner
+            ) -> _gluon_Result<_gluon_gc::GcRef<'gc, Box<dyn _gluon_api::Userdata>>> {
                 let data: Box<dyn _gluon_api::Userdata> = Box::new(self.clone());
                 deep_cloner.gc().alloc(_gluon_gc::Move(data))
             }
diff --git a/examples/marshalling.rs b/examples/marshalling.rs
index 2222fa5d..9319150a 100644
--- a/examples/marshalling.rs
+++ b/examples/marshalling.rs
@@ -334,7 +334,9 @@ fn marshal_wrapper() -> Result<()> {
     Ok(())
 }
 
-#[derive(Userdata, Trace, Debug, Clone, VmType)]
+#[derive(Userdata, Trace, Clone, Debug, VmType)]
+#[gluon_userdata(clone)]
+// Lets gluon know that the value can be cloned which can be needed when transferring the value between threads
 #[gluon(vm_type = "WindowHandle")]
 struct WindowHandle {
     id: Arc<u64>,
@@ -348,6 +350,7 @@ fn load_mod(vm: &gluon::Thread) -> vm::Result<ExternModule> {
         create_hwnd => primitive!(2, create_hwnd),
         id => primitive!(1, id),
         metadata => primitive!(1, metadata),
+        default_hwnd => create_hwnd(0, "default".into()),
     };
 
     ExternModule::new(vm, module)
diff --git a/parser/src/grammar.lalrpop b/parser/src/grammar.lalrpop
index df277f01..a60fc1b2 100644
--- a/parser/src/grammar.lalrpop
+++ b/parser/src/grammar.lalrpop
@@ -806,7 +806,7 @@ Expr: Expr<Id> = {
     },
 
     <metadata: Metadata?> "rec" <bindings: RecursiveValueBinding+> <body: InExpr> => {
-        let mut bindings = bindings.into_iter().map(|x| *x).collect::<Vec<_>>();;
+        let mut bindings = bindings.into_iter().map(|x| *x).collect::<Vec<_>>();
         if let Some(metadata) = metadata {
             bindings[0].metadata = metadata;
         }
@@ -814,7 +814,7 @@ Expr: Expr<Id> = {
     },
 
     <metadata: Metadata?> "rec" <bindings: TypeBinding+> <body: InExpr> => {
-        let mut bindings = bindings.into_iter().map(|x| *x).collect::<Vec<_>>();;
+        let mut bindings = bindings.into_iter().map(|x| *x).collect::<Vec<_>>();
         if let Some(metadata) = metadata {
             bindings[0].metadata = metadata;
         }


Test patch:
diff --git a/tests/api.rs b/tests/api.rs
index d90c2544..2a999373 100644
--- a/tests/api.rs
+++ b/tests/api.rs
@@ -705,3 +705,28 @@ fn child_vm_do_not_cause_undroppable_cycle_reverse_drop_order() {
         "The virtual machine and its values were not dropped"
     );
 }
+
+#[test]
+fn clone_userdata() {
+    let _ = ::env_logger::try_init();
+
+    let expr = r#"
+        import! test
+    "#;
+
+    #[derive(Debug, Userdata, Trace, VmType, Clone, PartialEq)]
+    #[gluon(vm_type = "Test")]
+    #[gluon_userdata(clone)]
+    struct Test(VmInt);
+
+    let vm = make_vm();
+    vm.register_type::<Test>("Test", &[])
+        .unwrap_or_else(|_| panic!("Could not add type"));
+    add_extern_module(&vm, "test", |thread| ExternModule::new(thread, Test(123)));
+
+    let (result, _) = Compiler::new()
+        .run_expr::<OpaqueValue<RootedThread, Test>>(&vm, "<top>", expr)
+        .unwrap_or_else(|err| panic!("{}", err));
+
+    assert_eq!(*result, Test(123));
+}