Skip to content

Commit 83a2ff4

Browse files
Make getters, setters, and constructors compiler errors for enums (#4278)
1 parent af7c106 commit 83a2ff4

16 files changed

+406
-15
lines changed

.github/workflows/main.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ jobs:
342342
runs-on: ubuntu-latest
343343
steps:
344344
- uses: actions/checkout@v4
345-
- run: rustup update --no-self-update 1.76.0 && rustup default 1.76.0
345+
- run: rustup update --no-self-update 1.78.0 && rustup default 1.78.0
346346
- run: cargo test -p wasm-bindgen-macro
347347
- run: cargo test -p wasm-bindgen-test-macro
348348

@@ -569,6 +569,8 @@ jobs:
569569
- wasm32-unknown-unknown
570570
features:
571571
- --no-default-features
572+
- --no-default-features --features std
573+
- --no-default-features --features msrv
572574
- ""
573575
defaults:
574576
run:
@@ -594,6 +596,8 @@ jobs:
594596
- wasm32-unknown-unknown
595597
features:
596598
- --no-default-features
599+
- --no-default-features --features std
600+
- --no-default-features --features msrv
597601
- ""
598602
defaults:
599603
run:

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
* Optional parameters are now typed as `T | undefined | null` to reflect the actual JS behavior.
1414
[#4188](https://github.com/rustwasm/wasm-bindgen/pull/4188)
1515

16+
* Adding `getter`, `setter`, and `constructor` methods to enums now results in a compiler error. This was previously erroneously allowed and resulted in invalid JS code gen.
17+
[#4278](https://github.com/rustwasm/wasm-bindgen/pull/4278)
18+
1619
### Fixed
1720

1821
- Fixed using [JavaScript keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords) as identifiers not being handled correctly.

Cargo.toml

+9-1
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@ features = ["serde-serialize"]
2222
test = false
2323

2424
[features]
25-
default = ["std"]
25+
default = ["std", "msrv"]
2626
enable-interning = ["std"]
2727
serde-serialize = ["serde", "serde_json", "std"]
2828
spans = []
2929
std = ["wasm-bindgen-macro/std", "once_cell/std"]
3030

31+
# Opt-in for Rust language features that require a higher MSRV.
32+
#
33+
# The current rustc version is detected at compile-time, so enabling this
34+
# feature for older compilers will NOT result in a compilation error. Instead,
35+
# any unsupported language feature will not be used.
36+
msrv = ["rustversion"]
37+
3138
# Whether or not the `#[wasm_bindgen]` macro is strict and generates an error on
3239
# all unused attributes
3340
strict-macro = ["wasm-bindgen-macro/strict-macro"]
@@ -43,6 +50,7 @@ xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_
4350
[dependencies]
4451
cfg-if = "1.0.0"
4552
once_cell = { version = "1.12", default-features = false }
53+
rustversion = { version = "1.0", optional = true }
4654
serde = { version = "1.0", optional = true }
4755
serde_json = { version = "1.0", optional = true }
4856
wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.99", default-features = false }

crates/backend/src/codegen.rs

+43-5
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,13 @@ impl ToTokens for ast::Struct {
224224
let unwrap_fn = Ident::new(&shared::unwrap_function(&name_str), Span::call_site());
225225
let wasm_bindgen = &self.wasm_bindgen;
226226
(quote! {
227+
#[automatically_derived]
228+
impl #wasm_bindgen::__rt::marker::SupportsConstructor for #name {}
229+
#[automatically_derived]
230+
impl #wasm_bindgen::__rt::marker::SupportsInstanceProperty for #name {}
231+
#[automatically_derived]
232+
impl #wasm_bindgen::__rt::marker::SupportsStaticProperty for #name {}
233+
227234
#[automatically_derived]
228235
impl #wasm_bindgen::describe::WasmDescribe for #name {
229236
fn describe() {
@@ -782,12 +789,41 @@ impl TryToTokens for ast::Export {
782789
let nargs = self.function.arguments.len() as u32;
783790
let attrs = &self.function.rust_attrs;
784791

785-
let start_check = if self.start {
786-
quote! { const _ASSERT: fn() = || -> #projection::Abi { loop {} }; }
787-
} else {
788-
quote! {}
792+
let mut checks = Vec::new();
793+
if self.start {
794+
checks.push(quote! { const _ASSERT: fn() = || -> #projection::Abi { loop {} }; });
789795
};
790796

797+
if let Some(class) = self.rust_class.as_ref() {
798+
// little helper function to make sure the check points to the
799+
// location of the function causing the assert to fail
800+
let mut add_check = |token_stream| {
801+
checks.push(respan(token_stream, &self.rust_name));
802+
};
803+
804+
match &self.method_kind {
805+
ast::MethodKind::Constructor => {
806+
add_check(quote! {
807+
let _: #wasm_bindgen::__rt::marker::CheckSupportsConstructor<#class>;
808+
});
809+
}
810+
ast::MethodKind::Operation(operation) => match operation.kind {
811+
ast::OperationKind::Getter(_) | ast::OperationKind::Setter(_) => {
812+
if operation.is_static {
813+
add_check(quote! {
814+
let _: #wasm_bindgen::__rt::marker::CheckSupportsStaticProperty<#class>;
815+
});
816+
} else {
817+
add_check(quote! {
818+
let _: #wasm_bindgen::__rt::marker::CheckSupportsInstanceProperty<#class>;
819+
});
820+
}
821+
}
822+
_ => {}
823+
},
824+
}
825+
}
826+
791827
(quote! {
792828
#[automatically_derived]
793829
const _: () = {
@@ -798,7 +834,9 @@ impl TryToTokens for ast::Export {
798834
export_name = #export_name,
799835
)]
800836
pub unsafe extern "C" fn #generated_name(#(#args),*) -> #wasm_bindgen::convert::WasmRet<#projection::Abi> {
801-
#start_check
837+
const _: () = {
838+
#(#checks)*
839+
};
802840

803841
let #ret = #call;
804842
#convert_ret

crates/macro/ui-tests/async-errors.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ error[E0277]: the trait bound `wasm_bindgen::JsValue: From<BadType>` is not sati
2222
--> ui-tests/async-errors.rs:35:24
2323
|
2424
35 | pub async fn bad3() -> BadType { loop {} }
25-
| ^^^^^^^ the trait `From<BadType>` is not implemented for `wasm_bindgen::JsValue`
25+
| ^^^^^^^ the trait `From<BadType>` is not implemented for `wasm_bindgen::JsValue`, which is required by `BadType: IntoJsResult`
2626
|
2727
= help: the following other types implement trait `From<T>`:
2828
<wasm_bindgen::JsValue as From<bool>>

crates/macro/ui-tests/main-debug.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ fn main() -> Result<(), Test> {
99
struct Test;
1010

1111
impl fmt::Debug for Test {
12-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
1313
unimplemented!()
1414
}
1515
}

crates/macro/ui-tests/main-infallible.stderr

+17
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,20 @@ error: the main function has to be called main
33
|
44
10 | fn fail() {}
55
| ^^^^
6+
7+
warning: unreachable expression
8+
--> ui-tests/main-infallible.rs:4:1
9+
|
10+
4 | #[wasm_bindgen(main)]
11+
| ^^^^^^^^^^^^^^^^^^^^^
12+
| |
13+
| unreachable expression
14+
| any code following this expression is unreachable
15+
|
16+
note: this expression has type `Infallible`, which is uninhabited
17+
--> ui-tests/main-infallible.rs:4:1
18+
|
19+
4 | #[wasm_bindgen(main)]
20+
| ^^^^^^^^^^^^^^^^^^^^^
21+
= note: `#[warn(unreachable_code)]` on by default
22+
= note: this warning originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)

crates/macro/ui-tests/missing-catch.stderr

+35
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,38 @@ error[E0277]: the trait bound `Result<wasm_bindgen::JsValue, wasm_bindgen::JsVal
1818
i128
1919
and $N others
2020
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
21+
22+
error[E0277]: the trait bound `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: FromWasmAbi` is not satisfied
23+
--> ui-tests/missing-catch.rs:3:1
24+
|
25+
3 | #[wasm_bindgen]
26+
| ^^^^^^^^^^^^^^^ the trait `FromWasmAbi` is not implemented for `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
27+
|
28+
= help: the following other types implement trait `FromWasmAbi`:
29+
bool
30+
char
31+
isize
32+
i8
33+
i16
34+
i32
35+
i64
36+
i128
37+
and $N others
38+
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
39+
40+
error[E0277]: the trait bound `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: FromWasmAbi` is not satisfied
41+
--> ui-tests/missing-catch.rs:6:18
42+
|
43+
6 | pub fn foo() -> Result<JsValue, JsValue>;
44+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromWasmAbi` is not implemented for `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
45+
|
46+
= help: the following other types implement trait `FromWasmAbi`:
47+
bool
48+
char
49+
isize
50+
i8
51+
i16
52+
i32
53+
i64
54+
i128
55+
and $N others

crates/macro/ui-tests/traits-not-implemented.stderr

+38
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,41 @@ error[E0277]: the trait bound `A: IntoWasmAbi` is not satisfied
1515
i128
1616
and $N others
1717
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
18+
19+
error[E0277]: the trait bound `A: IntoWasmAbi` is not satisfied
20+
--> ui-tests/traits-not-implemented.rs:8:19
21+
|
22+
8 | pub fn foo(a: A);
23+
| ^ the trait `IntoWasmAbi` is not implemented for `A`
24+
|
25+
= help: the following other types implement trait `IntoWasmAbi`:
26+
bool
27+
char
28+
isize
29+
i8
30+
i16
31+
i32
32+
i64
33+
i128
34+
and $N others
35+
36+
error[E0277]: the trait bound `A: IntoWasmAbi` is not satisfied
37+
--> ui-tests/traits-not-implemented.rs:8:12
38+
|
39+
5 | #[wasm_bindgen]
40+
| --------------- in this procedural macro expansion
41+
...
42+
8 | pub fn foo(a: A);
43+
| ^^^ the trait `IntoWasmAbi` is not implemented for `A`
44+
|
45+
= help: the following other types implement trait `IntoWasmAbi`:
46+
bool
47+
char
48+
isize
49+
i8
50+
i16
51+
i32
52+
i64
53+
i128
54+
and $N others
55+
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen]
4+
pub struct RustStruct {
5+
data: u32,
6+
}
7+
8+
#[wasm_bindgen]
9+
impl RustStruct {
10+
pub fn instance_method(&self) {}
11+
fn priv_instance_method(&self) {}
12+
pub fn static_method() {}
13+
14+
#[wasm_bindgen(constructor)]
15+
pub fn new() -> Self {
16+
Self { data: 0 }
17+
}
18+
19+
#[wasm_bindgen(getter)]
20+
pub fn prop(self) -> u32 {
21+
32
22+
}
23+
#[wasm_bindgen(setter)]
24+
pub fn set_prop(self, _value: u32) {}
25+
26+
#[wasm_bindgen(getter)]
27+
pub fn static_prop() -> u32 {
28+
32
29+
}
30+
#[wasm_bindgen(setter)]
31+
pub fn set_static_prop(_value: u32) {}
32+
33+
#[wasm_bindgen(indexing_getter)]
34+
pub fn indexing_getter(self) -> u32 {
35+
32
36+
}
37+
#[wasm_bindgen(indexing_setter)]
38+
pub fn indexing_setter(self, _value: u32) {}
39+
#[wasm_bindgen(indexing_deleter)]
40+
pub fn indexing_deleter(self, _value: u32) {}
41+
}
42+
43+
#[wasm_bindgen]
44+
pub enum RustEnum {
45+
A = 0,
46+
B = 1,
47+
}
48+
49+
#[wasm_bindgen]
50+
impl RustEnum {
51+
pub fn instance_method(self) {}
52+
fn priv_instance_method(self) {}
53+
pub fn static_method() {}
54+
55+
#[wasm_bindgen(constructor)]
56+
pub fn new() -> Self {
57+
Self::A
58+
}
59+
60+
#[wasm_bindgen(getter)]
61+
pub fn prop(self) -> u32 {
62+
32
63+
}
64+
#[wasm_bindgen(setter)]
65+
pub fn set_prop(self, _value: u32) {}
66+
67+
#[wasm_bindgen(getter)]
68+
pub fn static_prop() -> u32 {
69+
32
70+
}
71+
#[wasm_bindgen(setter)]
72+
pub fn set_static_prop(_value: u32) {}
73+
}
74+
75+
pub struct NonWasmType;
76+
77+
#[wasm_bindgen]
78+
impl NonWasmType {
79+
pub fn static_method() {}
80+
}
81+
82+
fn main() {}

0 commit comments

Comments
 (0)