diff --git a/crates/cli-support/src/js/rust2js.rs b/crates/cli-support/src/js/rust2js.rs index 3687c948..1b672602 100644 --- a/crates/cli-support/src/js/rust2js.rs +++ b/crates/cli-support/src/js/rust2js.rs @@ -298,6 +298,26 @@ impl<'a, 'b> Rust2Js<'a, 'b> { ); return Ok(()); } + + if let Some(class) = ty.rust_struct() { + if ty.is_by_ref() { + bail!("cannot invoke JS functions returning custom ref types yet") + } + // Insert an assertion to the type of the returned value as + // otherwise this will cause memory unsafety on the Rust side of + // things. + self.ret_expr = format!("\ + const val = JS; + if (!(val instanceof {0})) {{ + throw new Error('expected value of type {0}'); + }} + const ret = val.ptr; + val.ptr = 0; + return ret;\ + ", class); + return Ok(()) + } + self.ret_expr = match *ty { Descriptor::Boolean => "return JS ? 1 : 0;".to_string(), Descriptor::Char => "return JS.codePointAt(0);".to_string(), @@ -337,9 +357,9 @@ impl<'a, 'b> Rust2Js<'a, 'b> { invoc = format!( "\ try {{\n\ - {} + {} }} catch (e) {{\n\ - {} + {} }}\ ", &invoc, catch @@ -350,9 +370,9 @@ impl<'a, 'b> Rust2Js<'a, 'b> { invoc = format!( "\ try {{\n\ - {} + {} }} finally {{\n\ - {} + {} }}\ ", &invoc, &self.finally diff --git a/tests/all/imports.rs b/tests/all/imports.rs index f4a3e881..bc09154b 100644 --- a/tests/all/imports.rs +++ b/tests/all/imports.rs @@ -607,3 +607,64 @@ fn rust_keyword2() { ) .test(); } + +#[test] +fn custom_type() { + project() + .debug(false) + .file("src/lib.rs", r#" + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + #[wasm_bindgen(module = "./test")] + extern { + fn foo(f: Foo) -> Foo; + fn bad2() -> Foo; + } + + #[wasm_bindgen] + pub struct Foo(()); + + #[wasm_bindgen] + impl Foo { + pub fn touch(&self) { + panic!() + } + } + + #[wasm_bindgen] + pub fn run() { + foo(Foo(())); + } + + #[wasm_bindgen] + pub fn bad() { + bad2(); + } + "#) + .file("test.ts", r#" + import * as assert from "assert"; + import { run, Foo, bad } from "./out"; + + let VAL: any = null; + + export function foo(f: Foo): Foo { + VAL = f; + return f; + } + + export function bad2(): number { + return 2; + } + + export function test() { + run(); + assert.throws(() => VAL.touch(), /Attempt to use a moved value/); + assert.throws(bad, /expected value of type Foo/); + } + "#) + .test(); +}