Skip to content

Commit 03c8e2d

Browse files
Fixed methods with self: &Self consuming the object (#4178)
1 parent 61f1d96 commit 03c8e2d

File tree

6 files changed

+164
-8
lines changed

6 files changed

+164
-8
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
# `wasm-bindgen` Change Log
22
--------------------------------------------------------------------------------
33

4+
## Unreleased
5+
6+
### Fixed
7+
8+
* Fixed methods with `self: &Self` consuming the object
9+
[#4178](https://github.com/rustwasm/wasm-bindgen/pull/4178)
10+
11+
--------------------------------------------------------------------------------
12+
413
## [0.2.95](https://github.com/rustwasm/wasm-bindgen/compare/0.2.94...0.2.95)
514

615
Released 2024-10-10
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* tslint:disable */
2+
/* eslint-disable */
3+
export class Test {
4+
free(): void;
5+
constructor();
6+
consume_self(): void;
7+
ref_self(): void;
8+
ref_mut_self(): void;
9+
self_Self(): void;
10+
self_ref_Self(): void;
11+
self_ref_mut_Self(): void;
12+
}
+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
let wasm;
2+
export function __wbg_set_wasm(val) {
3+
wasm = val;
4+
}
5+
6+
7+
const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;
8+
9+
let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });
10+
11+
cachedTextDecoder.decode();
12+
13+
let cachedUint8ArrayMemory0 = null;
14+
15+
function getUint8ArrayMemory0() {
16+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
17+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
18+
}
19+
return cachedUint8ArrayMemory0;
20+
}
21+
22+
function getStringFromWasm0(ptr, len) {
23+
ptr = ptr >>> 0;
24+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
25+
}
26+
27+
const TestFinalization = (typeof FinalizationRegistry === 'undefined')
28+
? { register: () => {}, unregister: () => {} }
29+
: new FinalizationRegistry(ptr => wasm.__wbg_test_free(ptr >>> 0, 1));
30+
31+
export class Test {
32+
33+
__destroy_into_raw() {
34+
const ptr = this.__wbg_ptr;
35+
this.__wbg_ptr = 0;
36+
TestFinalization.unregister(this);
37+
return ptr;
38+
}
39+
40+
free() {
41+
const ptr = this.__destroy_into_raw();
42+
wasm.__wbg_test_free(ptr, 0);
43+
}
44+
constructor() {
45+
const ret = wasm.test_new();
46+
this.__wbg_ptr = ret >>> 0;
47+
TestFinalization.register(this, this.__wbg_ptr, this);
48+
return this;
49+
}
50+
consume_self() {
51+
const ptr = this.__destroy_into_raw();
52+
wasm.test_consume_self(ptr);
53+
}
54+
ref_self() {
55+
wasm.test_ref_self(this.__wbg_ptr);
56+
}
57+
ref_mut_self() {
58+
wasm.test_ref_mut_self(this.__wbg_ptr);
59+
}
60+
self_Self() {
61+
const ptr = this.__destroy_into_raw();
62+
wasm.test_self_Self(ptr);
63+
}
64+
self_ref_Self() {
65+
wasm.test_self_ref_Self(this.__wbg_ptr);
66+
}
67+
self_ref_mut_Self() {
68+
wasm.test_self_ref_mut_Self(this.__wbg_ptr);
69+
}
70+
}
71+
72+
export function __wbindgen_throw(arg0, arg1) {
73+
throw new Error(getStringFromWasm0(arg0, arg1));
74+
};
75+
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen]
4+
pub struct Test;
5+
6+
#[wasm_bindgen]
7+
impl Test {
8+
#[wasm_bindgen(constructor)]
9+
pub fn new() -> Test {
10+
Test
11+
}
12+
13+
pub fn consume_self(self) {}
14+
pub fn ref_self(&self) {}
15+
pub fn ref_mut_self(&mut self) {}
16+
17+
pub fn self_Self(self: Self) {}
18+
pub fn self_ref_Self(self: &Self) {}
19+
pub fn self_ref_mut_Self(self: &mut Self) {}
20+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
(module $reference_test.wasm
2+
(type (;0;) (func (result i32)))
3+
(type (;1;) (func (param i32)))
4+
(type (;2;) (func (param i32 i32)))
5+
(func $test_ref_self (;0;) (type 1) (param i32))
6+
(func $test_ref_mut_self (;1;) (type 1) (param i32))
7+
(func $test_self_ref_Self (;2;) (type 1) (param i32))
8+
(func $test_self_ref_mut_Self (;3;) (type 1) (param i32))
9+
(func $__wbg_test_free (;4;) (type 2) (param i32 i32))
10+
(func $test_new (;5;) (type 0) (result i32))
11+
(func $test_consume_self (;6;) (type 1) (param i32))
12+
(func $test_self_Self (;7;) (type 1) (param i32))
13+
(memory (;0;) 17)
14+
(export "memory" (memory 0))
15+
(export "__wbg_test_free" (func $__wbg_test_free))
16+
(export "test_new" (func $test_new))
17+
(export "test_consume_self" (func $test_consume_self))
18+
(export "test_ref_self" (func $test_ref_self))
19+
(export "test_ref_mut_self" (func $test_ref_mut_self))
20+
(export "test_self_Self" (func $test_self_Self))
21+
(export "test_self_ref_Self" (func $test_self_ref_Self))
22+
(export "test_self_ref_mut_Self" (func $test_self_ref_mut_Self))
23+
(@custom "target_features" (after code) "\02+\0fmutable-globals+\08sign-ext")
24+
)
25+

crates/macro-support/src/parser.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,26 @@ pub(crate) fn is_js_keyword(keyword: &str, skip: Option<&[&str]>) -> bool {
886886
.any(|this| *this == keyword)
887887
}
888888

889+
/// Returns whether `self` is passed by reference or by value.
890+
fn get_self_method(r: syn::Receiver) -> ast::MethodSelf {
891+
// The tricky part here is that `r` can have many forms. E.g. `self`,
892+
// `&self`, `&mut self`, `self: Self`, `self: &Self`, `self: &mut Self`,
893+
// `self: Box<Self>`, `self: Rc<Self>`, etc.
894+
// Luckily, syn always populates the `ty` field with the type of `self`, so
895+
// e.g. `&self` gets the type `&Self`. So we only have check whether the
896+
// type is a reference or not.
897+
match &*r.ty {
898+
syn::Type::Reference(ty) => {
899+
if ty.mutability.is_some() {
900+
ast::MethodSelf::RefMutable
901+
} else {
902+
ast::MethodSelf::RefShared
903+
}
904+
}
905+
_ => ast::MethodSelf::ByValue,
906+
}
907+
}
908+
889909
/// Construct a function (and gets the self type if appropriate) for our AST from a syn function.
890910
#[allow(clippy::too_many_arguments)]
891911
fn function_from_decl(
@@ -965,15 +985,10 @@ fn function_from_decl(
965985
panic!("arguments cannot be `self`")
966986
}
967987

968-
// write down the way in which `self` is passed for later
988+
// We need to know *how* `self` is passed to the method (by
989+
// value or by reference) to generate the correct JS shim.
969990
assert!(method_self.is_none());
970-
if r.reference.is_none() {
971-
method_self = Some(ast::MethodSelf::ByValue);
972-
} else if r.mutability.is_some() {
973-
method_self = Some(ast::MethodSelf::RefMutable);
974-
} else {
975-
method_self = Some(ast::MethodSelf::RefShared);
976-
}
991+
method_self = Some(get_self_method(r));
977992

978993
None
979994
}

0 commit comments

Comments
 (0)