Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make getters, setters, and constructors compiler errors for enums #4278

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- run: rustup update --no-self-update stable && rustup default stable
- run: rustup component add rustfmt
- run: cargo fmt --all -- --check

# Check TOML style by using Taplo.
taplo:
name: Taplo
Expand Down Expand Up @@ -325,7 +325,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: rustup update --no-self-update 1.76.0 && rustup default 1.76.0
- run: rustup update --no-self-update 1.78.0 && rustup default 1.78.0
- run: cargo test -p wasm-bindgen-macro
- run: cargo test -p wasm-bindgen-test-macro

Expand Down
11 changes: 10 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,20 @@ features = ["serde-serialize"]
test = false

[features]
default = ["spans", "std"]
default = ["spans", "std", "diagnostic"]
enable-interning = ["std"]
serde-serialize = ["serde", "serde_json", "std"]
spans = ["wasm-bindgen-macro/spans"]
std = ["wasm-bindgen-macro/std", "once_cell/std"]

# Enables the use of Rust's `diagnostic` macro for several traits to provide
# better error messages when those traits are not implemented.
#
# Diagnostic messages are only available since Rust 1.78. Enabling this feature
# for older compilers will NOT improve error message and will NOT result in a
# compilation error.
diagnostic = ["rustversion"]

# Whether or not the `#[wasm_bindgen]` macro is strict and generates an error on
# all unused attributes
strict-macro = ["wasm-bindgen-macro/strict-macro"]
Expand All @@ -43,6 +51,7 @@ xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_
[dependencies]
cfg-if = "1.0.0"
once_cell = { version = "1.12", default-features = false }
rustversion = { version = "1.0", optional = true }
serde = { version = "1.0", optional = true }
serde_json = { version = "1.0", optional = true }
wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.95", default-features = false }
Expand Down
52 changes: 47 additions & 5 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ impl ToTokens for ast::Struct {
let wasm_bindgen = &self.wasm_bindgen;
let maybe_no_coverage = coverage();
(quote! {
#[automatically_derived]
impl #wasm_bindgen::__rt::marker::SupportsConstructor for #name {}
#[automatically_derived]
impl #wasm_bindgen::__rt::marker::SupportsInstanceProperty for #name {}
#[automatically_derived]
impl #wasm_bindgen::__rt::marker::SupportsStaticProperty for #name {}

#[automatically_derived]
impl #wasm_bindgen::describe::WasmDescribe for #name {
fn describe() {
Expand Down Expand Up @@ -783,12 +790,44 @@ impl TryToTokens for ast::Export {
let nargs = self.function.arguments.len() as u32;
let attrs = &self.function.rust_attrs;

let start_check = if self.start {
quote! { const _ASSERT: fn() = || -> #projection::Abi { loop {} }; }
} else {
quote! {}
let mut checks = Vec::new();
if self.start {
checks.push(quote! { const _ASSERT: fn() = || -> #projection::Abi { loop {} }; });
};

if let Some(class) = self.rust_class.as_ref() {
// little helper function to make sure the check points to the
// location of the function causing the assert to fail
let mut add_check = |token_stream| {
checks.push(respan(token_stream, &self.rust_name));
};

match &self.method_kind {
ast::MethodKind::Constructor => {
add_check(quote! {
struct CheckSupportsConstructor<T: #wasm_bindgen::__rt::marker::SupportsConstructor>(T);
let _: CheckSupportsConstructor<#class>;
});
}
ast::MethodKind::Operation(operation) => match operation.kind {
ast::OperationKind::Getter(_) | ast::OperationKind::Setter(_) => {
if operation.is_static {
add_check(quote! {
struct CheckSupportsStaticProperty<T: #wasm_bindgen::__rt::marker::SupportsStaticProperty>(T);
let _: CheckSupportsStaticProperty<#class>;
});
} else {
add_check(quote! {
struct CheckSupportsInstanceProperty<T: #wasm_bindgen::__rt::marker::SupportsInstanceProperty>(T);
let _: CheckSupportsInstanceProperty<#class>;
});
}
}
_ => {}
},
}
}

let maybe_no_coverage = coverage();

(quote! {
Expand All @@ -801,7 +840,10 @@ impl TryToTokens for ast::Export {
)]
#maybe_no_coverage
pub unsafe extern "C" fn #generated_name(#(#args),*) -> #wasm_bindgen::convert::WasmRet<#projection::Abi> {
#start_check
#[automatically_derived]
const _: () = {
#(#checks)*
};

let #ret = #call;
#convert_ret
Expand Down
2 changes: 1 addition & 1 deletion crates/macro/ui-tests/async-errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ error[E0277]: the trait bound `wasm_bindgen::JsValue: From<BadType>` is not sati
--> ui-tests/async-errors.rs:35:24
|
35 | pub async fn bad3() -> BadType { loop {} }
| ^^^^^^^ the trait `From<BadType>` is not implemented for `wasm_bindgen::JsValue`
| ^^^^^^^ the trait `From<BadType>` is not implemented for `wasm_bindgen::JsValue`, which is required by `BadType: IntoJsResult`
|
= help: the following other types implement trait `From<T>`:
<wasm_bindgen::JsValue as From<bool>>
Expand Down
8 changes: 8 additions & 0 deletions crates/macro/ui-tests/main-debug.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,11 @@ error: the main function has to be called main
|
18 | fn fail() {}
| ^^^^

warning: unused variable: `f`
--> ui-tests/main-debug.rs:12:19
|
12 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
| ^ help: if this is intentional, prefix it with an underscore: `_f`
|
= note: `#[warn(unused_variables)]` on by default
17 changes: 17 additions & 0 deletions crates/macro/ui-tests/main-infallible.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,20 @@ error: the main function has to be called main
|
10 | fn fail() {}
| ^^^^

warning: unreachable expression
--> ui-tests/main-infallible.rs:4:1
|
4 | #[wasm_bindgen(main)]
| ^^^^^^^^^^^^^^^^^^^^^
| |
| unreachable expression
| any code following this expression is unreachable
|
note: this expression has type `Infallible`, which is uninhabited
--> ui-tests/main-infallible.rs:4:1
|
4 | #[wasm_bindgen(main)]
| ^^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(unreachable_code)]` on by default
= note: this warning originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
35 changes: 35 additions & 0 deletions crates/macro/ui-tests/missing-catch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,38 @@ error[E0277]: the trait bound `Result<wasm_bindgen::JsValue, wasm_bindgen::JsVal
i128
and $N others
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: FromWasmAbi` is not satisfied
--> ui-tests/missing-catch.rs:3:1
|
3 | #[wasm_bindgen]
| ^^^^^^^^^^^^^^^ the trait `FromWasmAbi` is not implemented for `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
|
= help: the following other types implement trait `FromWasmAbi`:
bool
char
isize
i8
i16
i32
i64
i128
and $N others
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: FromWasmAbi` is not satisfied
--> ui-tests/missing-catch.rs:6:18
|
6 | pub fn foo() -> Result<JsValue, JsValue>;
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromWasmAbi` is not implemented for `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
|
= help: the following other types implement trait `FromWasmAbi`:
bool
char
isize
i8
i16
i32
i64
i128
and $N others
38 changes: 38 additions & 0 deletions crates/macro/ui-tests/traits-not-implemented.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,41 @@ error[E0277]: the trait bound `A: IntoWasmAbi` is not satisfied
i128
and $N others
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `A: IntoWasmAbi` is not satisfied
--> ui-tests/traits-not-implemented.rs:8:19
|
8 | pub fn foo(a: A);
| ^ the trait `IntoWasmAbi` is not implemented for `A`
|
= help: the following other types implement trait `IntoWasmAbi`:
bool
char
isize
i8
i16
i32
i64
i128
and $N others

error[E0277]: the trait bound `A: IntoWasmAbi` is not satisfied
--> ui-tests/traits-not-implemented.rs:8:12
|
5 | #[wasm_bindgen]
| --------------- in this procedural macro expansion
...
8 | pub fn foo(a: A);
| ^^^ the trait `IntoWasmAbi` is not implemented for `A`
|
= help: the following other types implement trait `IntoWasmAbi`:
bool
char
isize
i8
i16
i32
i64
i128
and $N others
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
82 changes: 82 additions & 0 deletions crates/macro/ui-tests/unsupported-options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct RustStruct {
data: u32,
}

#[wasm_bindgen]
impl RustStruct {
pub fn instance_method(&self) {}
fn priv_instance_method(&self) {}
pub fn static_method() {}

#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self { data: 0 }
}

#[wasm_bindgen(getter)]
pub fn prop(self) -> u32 {
32
}
#[wasm_bindgen(setter)]
pub fn set_prop(self, _value: u32) {}

#[wasm_bindgen(getter)]
pub fn static_prop() -> u32 {
32
}
#[wasm_bindgen(setter)]
pub fn set_static_prop(_value: u32) {}

#[wasm_bindgen(indexing_getter)]
pub fn indexing_getter(self) -> u32 {
32
}
#[wasm_bindgen(indexing_setter)]
pub fn indexing_setter(self, _value: u32) {}
#[wasm_bindgen(indexing_deleter)]
pub fn indexing_deleter(self, _value: u32) {}
}

#[wasm_bindgen]
pub enum RustEnum {
A = 0,
B = 1,
}

#[wasm_bindgen]
impl RustEnum {
pub fn instance_method(self) {}
fn priv_instance_method(self) {}
pub fn static_method() {}

#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self::A
}

#[wasm_bindgen(getter)]
pub fn prop(self) -> u32 {
32
}
#[wasm_bindgen(setter)]
pub fn set_prop(self, _value: u32) {}

#[wasm_bindgen(getter)]
pub fn static_prop() -> u32 {
32
}
#[wasm_bindgen(setter)]
pub fn set_static_prop(_value: u32) {}
}

pub struct NonWasmType;

#[wasm_bindgen]
impl NonWasmType {
pub fn static_method() {}
}

fn main() {}
Loading
Loading