diff --git a/CHANGELOG.md b/CHANGELOG.md index f010e99fb8f..a0327e42a33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,9 @@ * Fixed calls to `JsCast::instanceof()` not respecting JavaScript namespaces. [#4241](https://github.com/rustwasm/wasm-bindgen/pull/4241) +* Fixed imports for functions using `this` and late binding. + [#4225](https://github.com/rustwasm/wasm-bindgen/pull/4225) + -------------------------------------------------------------------------------- ## [0.2.95](https://github.com/rustwasm/wasm-bindgen/compare/0.2.94...0.2.95) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 5ab61f3c4bc..aff91c6cfcc 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -3062,6 +3062,21 @@ __wbg_set_wasm(wasm);" } } + if let JsImportName::Global { .. } | JsImportName::VendorPrefixed { .. } = js.name { + // We generally cannot import globals directly, because users can + // change most globals at runtime. + // + // An obvious example of this when the object literally changes + // (e.g. binding `foo.bar`), but polyfills can also change the + // object or fundtion. + // + // Late binding is another issue. The function might not even be + // defined when the Wasm module is instantiated. In such cases, + // there is an observable difference between a direct import and a + // JS shim calling the function. + return Ok(false); + } + self.expose_not_defined(); let name = self.import_name(js)?; let js = format!( diff --git a/crates/cli/tests/reference/import-catch.js b/crates/cli/tests/reference/import-catch.js deleted file mode 100644 index 3f6f772e0ae..00000000000 --- a/crates/cli/tests/reference/import-catch.js +++ /dev/null @@ -1,54 +0,0 @@ -let wasm; -export function __wbg_set_wasm(val) { - wasm = val; -} - - -const heap = new Array(128).fill(undefined); - -heap.push(undefined, null, true, false); - -let heap_next = heap.length; - -function addHeapObject(obj) { - if (heap_next === heap.length) heap.push(heap.length + 1); - const idx = heap_next; - heap_next = heap[idx]; - - heap[idx] = obj; - return idx; -} - -function handleError(f, args) { - try { - return f.apply(this, args); - } catch (e) { - wasm.__wbindgen_exn_store(addHeapObject(e)); - } -} - -function getObject(idx) { return heap[idx]; } - -function dropObject(idx) { - if (idx < 132) return; - heap[idx] = heap_next; - heap_next = idx; -} - -function takeObject(idx) { - const ret = getObject(idx); - dropObject(idx); - return ret; -} - -export function exported() { - const ret = wasm.exported(); - if (ret[1]) { - throw takeObject(ret[0]); - } -} - -export function __wbg_foo_95fe1a04017077db() { return handleError(function () { - foo(); -}, arguments) }; - diff --git a/crates/cli/tests/reference/import-catch.rs b/crates/cli/tests/reference/import-catch.rs deleted file mode 100644 index b6a6e58fbf9..00000000000 --- a/crates/cli/tests/reference/import-catch.rs +++ /dev/null @@ -1,12 +0,0 @@ -use wasm_bindgen::prelude::*; - -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(catch)] - fn foo() -> Result<(), JsValue>; -} - -#[wasm_bindgen] -pub fn exported() -> Result<(), JsValue> { - foo() -} diff --git a/crates/cli/tests/reference/import-catch.d.ts b/crates/cli/tests/reference/import.d.ts similarity index 100% rename from crates/cli/tests/reference/import-catch.d.ts rename to crates/cli/tests/reference/import.d.ts diff --git a/crates/cli/tests/reference/import.js b/crates/cli/tests/reference/import.js new file mode 100644 index 00000000000..229dd246115 --- /dev/null +++ b/crates/cli/tests/reference/import.js @@ -0,0 +1,95 @@ +let wasm; +export function __wbg_set_wasm(val) { + wasm = val; +} + + +const heap = new Array(128).fill(undefined); + +heap.push(undefined, null, true, false); + +let heap_next = heap.length; + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } +} + +const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder; + +let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true }); + +cachedTextDecoder.decode(); + +let cachedUint8ArrayMemory0 = null; + +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8ArrayMemory0; +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); +} + +function getObject(idx) { return heap[idx]; } + +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +export function exported() { + const ret = wasm.exported(); + if (ret[1]) { + throw takeObject(ret[0]); + } +} + +export function __wbg_add_dd5307a7ca6818d5(arg0, arg1) { + const ret = add(arg0, arg1); + return ret; +}; + +export function __wbg_barfromfoo_d097f3ec35aab47c() { + bar_from_foo(); +}; + +export function __wbg_catchme_a7bca7f3d5a5f319() { return handleError(function () { + catch_me(); +}, arguments) }; + +export function __wbg_nocatch_62552fa42a58590b() { + no_catch(); +}; + +export function __wbg_reload_90d82b22b83c1d99() { + window.location.reload(); +}; + +export function __wbg_write_d258674ff6f0ea8d(arg0, arg1) { + window.document.write(getStringFromWasm0(arg0, arg1)); +}; + diff --git a/crates/cli/tests/reference/import.rs b/crates/cli/tests/reference/import.rs new file mode 100644 index 00000000000..a7bea1953ed --- /dev/null +++ b/crates/cli/tests/reference/import.rs @@ -0,0 +1,34 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern "C" { + // Both `catch_me` and `no_catch` should be defined in the JS and invoke + // their respective JS function inside a JS shim function. This is + // important, because these 2 function may not be defined when the WASM + // module is instantiated. + #[wasm_bindgen(catch)] + fn catch_me() -> Result<(), JsValue>; + fn no_catch(); + + // Reload needs to be passed the right `this` parameter in JS. + #[wasm_bindgen(js_namespace = ["window", "location"])] + fn reload(); + #[wasm_bindgen(js_namespace = ["window", "document"])] + fn write(s: &str); + + // module import + #[wasm_bindgen(module = "./foo.js")] + fn bar_from_foo(); + #[wasm_bindgen(inline_js = "export function add(a,b) { return a + b; }")] + fn add(a: f64, b: f64) -> f64; +} + +#[wasm_bindgen] +pub fn exported() -> Result<(), JsValue> { + bar_from_foo(); + let _ = add(1.0, 2.0); + reload(); + write(""); + no_catch(); + catch_me() +} diff --git a/crates/cli/tests/reference/import-catch.wat b/crates/cli/tests/reference/import.wat similarity index 100% rename from crates/cli/tests/reference/import-catch.wat rename to crates/cli/tests/reference/import.wat