Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@

### Fixed

* Fixed `ReferenceError` when using Rust struct names that conflict with JS builtins (e.g., `Array`).
The constructor now correctly uses the aliased `FinalizationRegistry` identifier.
[#4932](https://github.com/wasm-bindgen/wasm-bindgen/pull/4932)

### Removed

## [0.2.108](https://github.com/wasm-bindgen/wasm-bindgen/compare/0.2.107...0.2.108)
Expand Down
5 changes: 4 additions & 1 deletion crates/cli-support/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,9 @@ fn instruction(
let val = js.pop();
match constructor {
Some(name) if name == class => {
// Get the JS identifier for the class, which may be aliased
// if the name conflicts with a JS builtin (e.g., `Array` -> `Array2`)
let identifier = js.cx.require_class_identifier(class);
let (ptr_assignment, register_data) = if js.cx.config.generate_reset_state {
(
format!(
Expand All @@ -1346,7 +1349,7 @@ fn instruction(
js.prelude(&format!(
"
{ptr_assignment}
{name}Finalization.register(this, {register_data}, this);
{identifier}Finalization.register(this, {register_data}, this);
"
));
js.push(String::from("this"));
Expand Down
6 changes: 6 additions & 0 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2934,6 +2934,12 @@ if (require('worker_threads').isMainThread) {{
self.globals.push('\n');
}

/// Gets the JS identifier for a class, which may be aliased if the original
/// name conflicts with a JS builtin (e.g., `Array` -> `Array2`).
pub fn require_class_identifier(&mut self, name: &str) -> String {
self.require_class(name).identifier.clone()
}

fn require_class_wrap(&mut self, name: &str) -> String {
let cls = self.require_class(name);
cls.wrap_needed = true;
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/tests/reference/default-class.bg.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class _default {
constructor(value) {
const ret = wasm.default_new(value);
this.__wbg_ptr = ret >>> 0;
defaultFinalization.register(this, this.__wbg_ptr, this);
_defaultFinalization.register(this, this.__wbg_ptr, this);
return this;
}
}
Expand Down
87 changes: 87 additions & 0 deletions crates/cli/tests/reference/reserved-class-name.bg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
class Array2 {
__destroy_into_raw() {
const ptr = this.__wbg_ptr;
this.__wbg_ptr = 0;
Array2Finalization.unregister(this);
return ptr;
}
free() {
const ptr = this.__destroy_into_raw();
wasm.__wbg_array_free(ptr, 0);
}
/**
* @returns {number}
*/
get() {
const ret = wasm.array_get(this.__wbg_ptr);
return ret >>> 0;
}
constructor() {
const ret = wasm.array_new();
this.__wbg_ptr = ret >>> 0;
Array2Finalization.register(this, this.__wbg_ptr, this);
return this;
}
}
if (Symbol.dispose) Array2.prototype[Symbol.dispose] = Array2.prototype.free;
export { Array2 as Array }

/**
* @returns {any}
*/
export function use_js_array() {
const ret = wasm.use_js_array();
return ret;
}
export function __wbg___wbindgen_throw_be289d5034ed271b(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
}
export function __wbg_new_843f65aabd37d2db() {
const ret = new Array();
return ret;
}
export function __wbindgen_init_externref_table() {
const table = wasm.__wbindgen_externrefs;
const offset = table.grow(4);
table.set(0, undefined);
table.set(offset + 0, undefined);
table.set(offset + 1, null);
table.set(offset + 2, true);
table.set(offset + 3, false);
}
const Array2Finalization = (typeof FinalizationRegistry === 'undefined')
? { register: () => {}, unregister: () => {} }
: new FinalizationRegistry(ptr => wasm.__wbg_array_free(ptr >>> 0, 1));

function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return decodeText(ptr, len);
}

let cachedUint8ArrayMemory0 = null;
function getUint8ArrayMemory0() {
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8ArrayMemory0;
}

let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
const MAX_SAFARI_DECODE_BYTES = 2146435072;
let numBytesDecoded = 0;
function decodeText(ptr, len) {
numBytesDecoded += len;
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
numBytesDecoded = len;
}
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
}


let wasm;
export function __wbg_set_wasm(val) {
wasm = val;
}
12 changes: 12 additions & 0 deletions crates/cli/tests/reference/reserved-class-name.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* tslint:disable */
/* eslint-disable */

declare class Array2 {
free(): void;
[Symbol.dispose](): void;
get(): number;
constructor();
}
export { Array2 as Array }

export function use_js_array(): any;
9 changes: 9 additions & 0 deletions crates/cli/tests/reference/reserved-class-name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* @ts-self-types="./reference_test.d.ts" */

import * as wasm from "./reference_test_bg.wasm";
import { __wbg_set_wasm } from "./reference_test_bg.js";
__wbg_set_wasm(wasm);
wasm.__wbindgen_start();
export {
Array, use_js_array
} from "./reference_test_bg.js";
38 changes: 38 additions & 0 deletions crates/cli/tests/reference/reserved-class-name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Test for issue #4885: class names that conflict with JS builtins
// should be properly aliased in all generated code, including the
// FinalizationRegistry reference in constructors.
//
// This test imports the global Array type which will register "Array" as an
// identifier, causing our custom Array struct to be aliased to "Array2".

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
// Import the global Array constructor to cause a naming conflict
#[wasm_bindgen(js_name = Array)]
type JsArray;

#[wasm_bindgen(constructor, js_class = "Array")]
fn new() -> JsArray;
}

#[wasm_bindgen]
pub struct Array(u32);

#[wasm_bindgen]
impl Array {
#[wasm_bindgen(constructor)]
pub fn new() -> Array {
Array(0)
}

pub fn get(&self) -> u32 {
self.0
}
}

#[wasm_bindgen]
pub fn use_js_array() -> JsArray {
JsArray::new()
}
24 changes: 24 additions & 0 deletions crates/cli/tests/reference/reserved-class-name.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(module $reserved_class_name_reftest.wasm
(type (;0;) (func))
(type (;1;) (func (result i32)))
(type (;2;) (func (result externref)))
(type (;3;) (func (param i32) (result i32)))
(type (;4;) (func (param i32 i32)))
(import "./reference_test_bg.js" "__wbg___wbindgen_throw_be289d5034ed271b" (func (;0;) (type 4)))
(import "./reference_test_bg.js" "__wbg_new_843f65aabd37d2db" (func (;1;) (type 2)))
(import "./reference_test_bg.js" "__wbindgen_init_externref_table" (func (;2;) (type 0)))
(table $__wbindgen_externrefs (;0;) 128 externref)
(memory (;0;) 17)
(export "memory" (memory 0))
(export "__wbg_array_free" (func $__wbg_array_free))
(export "array_get" (func $array_get))
(export "array_new" (func $array_new))
(export "use_js_array" (func $"use_js_array externref shim"))
(export "__wbindgen_externrefs" (table $__wbindgen_externrefs))
(export "__wbindgen_start" (func 2))
(func $__wbg_array_free (;3;) (type 4) (param i32 i32))
(func $array_get (;4;) (type 3) (param i32) (result i32))
(func $array_new (;5;) (type 1) (result i32))
(func $"use_js_array externref shim" (;6;) (type 2) (result externref))
(@custom "target_features" (after code) "\08+\0bbulk-memory+\0fbulk-memory-opt+\16call-indirect-overlong+\0amultivalue+\0fmutable-globals+\13nontrapping-fptoint+\0freference-types+\08sign-ext")
)