Skip to content

Commit adcf286

Browse files
committed
Implement #[wasm_bindgen(main)]
1 parent d090e94 commit adcf286

24 files changed

+336
-116
lines changed

.github/workflows/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ jobs:
219219
runs-on: ubuntu-latest
220220
steps:
221221
- uses: actions/checkout@v3
222-
- run: rustup update --no-self-update 1.56.0 && rustup default 1.56.0
222+
- run: rustup update --no-self-update 1.61.0 && rustup default 1.61.0
223223
- run: cargo test -p wasm-bindgen-macro
224224

225225
build_examples:

crates/macro-support/src/parser.rs

+62-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
1010
use quote::ToTokens;
1111
use syn::parse::{Parse, ParseStream, Result as SynResult};
1212
use syn::spanned::Spanned;
13-
use syn::Lit;
13+
use syn::{ItemFn, Lit, ReturnType};
1414

1515
thread_local!(static ATTRS: AttributeParseState = Default::default());
1616

@@ -80,6 +80,7 @@ macro_rules! attrgen {
8080
(variadic, Variadic(Span)),
8181
(typescript_custom_section, TypescriptCustomSection(Span)),
8282
(skip_typescript, SkipTypescript(Span)),
83+
(main, Main(Span)),
8384
(start, Start(Span)),
8485
(skip, Skip(Span)),
8586
(typescript_type, TypeScriptType(Span, String, Span)),
@@ -933,6 +934,13 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
933934
) -> Result<(), Diagnostic> {
934935
match self {
935936
syn::Item::Fn(mut f) => {
937+
let opts = opts.unwrap_or_default();
938+
939+
if opts.main().is_some() {
940+
opts.check_used();
941+
return main(f, tokens);
942+
}
943+
936944
let no_mangle = f
937945
.attrs
938946
.iter()
@@ -951,7 +959,6 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
951959
// `dead_code` warning. So, add `#[allow(dead_code)]` before it to avoid that.
952960
tokens.extend(quote::quote! { #[allow(dead_code)] });
953961
f.to_tokens(tokens);
954-
let opts = opts.unwrap_or_default();
955962
if opts.start().is_some() {
956963
if f.sig.generics.params.len() > 0 {
957964
bail_span!(&f.sig.generics, "the start function cannot have generics",);
@@ -1689,6 +1696,59 @@ pub fn link_to(opts: BindgenAttrs) -> Result<ast::LinkToModule, Diagnostic> {
16891696
Ok(ast::LinkToModule(program))
16901697
}
16911698

1699+
fn main(mut f: ItemFn, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
1700+
if f.sig.ident != "main" {
1701+
bail_span!(&f.sig.ident, "the main function has to be called main");
1702+
}
1703+
if let Some(constness) = f.sig.constness {
1704+
bail_span!(&constness, "the main function cannot be const");
1705+
}
1706+
if !f.sig.generics.params.is_empty() {
1707+
bail_span!(&f.sig.generics, "the main function cannot have generics");
1708+
}
1709+
if !f.sig.inputs.is_empty() {
1710+
bail_span!(&f.sig.inputs, "the main function cannot have arguments");
1711+
}
1712+
1713+
let r#return = f.sig.output;
1714+
f.sig.output = ReturnType::Default;
1715+
let body = f.block;
1716+
1717+
if f.sig.asyncness.take().is_some() {
1718+
f.block = Box::new(
1719+
syn::parse2(quote::quote! {
1720+
{
1721+
async fn __wasm_bindgen_generated_main() #r#return #body
1722+
wasm_bindgen_futures::spawn_local(
1723+
async move {
1724+
use wasm_bindgen::__rt::Main;
1725+
let __ret = __wasm_bindgen_generated_main();
1726+
(&mut wasm_bindgen::__rt::MainWrapper(Some(__ret.await))).__wasm_bindgen_main()
1727+
},
1728+
)
1729+
}
1730+
})
1731+
.unwrap(),
1732+
);
1733+
} else {
1734+
f.block = Box::new(
1735+
syn::parse2(quote::quote! {
1736+
{
1737+
fn __wasm_bindgen_generated_main() #r#return #body
1738+
use wasm_bindgen::__rt::Main;
1739+
let __ret = __wasm_bindgen_generated_main();
1740+
(&mut wasm_bindgen::__rt::MainWrapper(Some(__ret))).__wasm_bindgen_main()
1741+
}
1742+
})
1743+
.unwrap(),
1744+
);
1745+
}
1746+
1747+
f.to_tokens(tokens);
1748+
1749+
Ok(())
1750+
}
1751+
16921752
#[cfg(test)]
16931753
mod tests {
16941754
#[test]

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

-20
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ error[E0277]: the trait bound `Result<(), ()>: IntoJsResult` is not satisfied
77
= help: the following implementations were found:
88
<Result<(), E> as IntoJsResult>
99
<Result<T, E> as IntoJsResult>
10-
note: required by `into_js_result`
11-
--> $WORKSPACE/src/lib.rs
12-
|
13-
| fn into_js_result(self) -> Result<JsValue, JsValue>;
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1510
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
1611

1712
error[E0277]: the trait bound `Result<(), BadType>: IntoJsResult` is not satisfied
@@ -23,11 +18,6 @@ error[E0277]: the trait bound `Result<(), BadType>: IntoJsResult` is not satisfi
2318
= help: the following implementations were found:
2419
<Result<(), E> as IntoJsResult>
2520
<Result<T, E> as IntoJsResult>
26-
note: required by `into_js_result`
27-
--> $WORKSPACE/src/lib.rs
28-
|
29-
| fn into_js_result(self) -> Result<JsValue, JsValue>;
30-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3121
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
3222

3323
error[E0277]: the trait bound `wasm_bindgen::JsValue: From<BadType>` is not satisfied
@@ -44,11 +34,6 @@ error[E0277]: the trait bound `wasm_bindgen::JsValue: From<BadType>` is not sati
4434
and $N others
4535
= note: required because of the requirements on the impl of `Into<wasm_bindgen::JsValue>` for `BadType`
4636
= note: required because of the requirements on the impl of `IntoJsResult` for `BadType`
47-
note: required by `into_js_result`
48-
--> $WORKSPACE/src/lib.rs
49-
|
50-
| fn into_js_result(self) -> Result<JsValue, JsValue>;
51-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5237
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
5338

5439
error[E0277]: the trait bound `Result<BadType, wasm_bindgen::JsValue>: IntoJsResult` is not satisfied
@@ -60,9 +45,4 @@ error[E0277]: the trait bound `Result<BadType, wasm_bindgen::JsValue>: IntoJsRes
6045
= help: the following implementations were found:
6146
<Result<(), E> as IntoJsResult>
6247
<Result<T, E> as IntoJsResult>
63-
note: required by `into_js_result`
64-
--> $WORKSPACE/src/lib.rs
65-
|
66-
| fn into_js_result(self) -> Result<JsValue, JsValue>;
67-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6848
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
+12-12
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,61 @@
11
error: #[wasm_bindgen] default impls are not supported
2-
--> $DIR/invalid-methods.rs:7:1
2+
--> ui-tests/invalid-methods.rs:7:1
33
|
44
7 | default impl A {
55
| ^^^^^^^
66

77
error: #[wasm_bindgen] unsafe impls are not supported
8-
--> $DIR/invalid-methods.rs:11:1
8+
--> ui-tests/invalid-methods.rs:11:1
99
|
1010
11 | unsafe impl A {
1111
| ^^^^^^
1212

1313
error: #[wasm_bindgen] trait impls are not supported
14-
--> $DIR/invalid-methods.rs:15:6
14+
--> ui-tests/invalid-methods.rs:15:6
1515
|
1616
15 | impl Clone for A {
1717
| ^^^^^
1818

1919
error: #[wasm_bindgen] generic impls aren't supported
20-
--> $DIR/invalid-methods.rs:19:5
20+
--> ui-tests/invalid-methods.rs:19:5
2121
|
2222
19 | impl<T> A {
2323
| ^^^
2424

2525
error: unsupported self type in #[wasm_bindgen] impl
26-
--> $DIR/invalid-methods.rs:23:6
26+
--> ui-tests/invalid-methods.rs:23:6
2727
|
2828
23 | impl &'static A {
2929
| ^^^^^^^^^^
3030

3131
error: const definitions aren't supported with #[wasm_bindgen]
32-
--> $DIR/invalid-methods.rs:30:5
32+
--> ui-tests/invalid-methods.rs:30:5
3333
|
3434
30 | const X: u32 = 3;
3535
| ^^^^^^^^^^^^^^^^^
3636

3737
error: type definitions in impls aren't supported with #[wasm_bindgen]
38-
--> $DIR/invalid-methods.rs:31:5
38+
--> ui-tests/invalid-methods.rs:31:5
3939
|
4040
31 | type Y = u32;
4141
| ^^^^^^^^^^^^^
4242

4343
error: macros in impls aren't supported
44-
--> $DIR/invalid-methods.rs:32:5
44+
--> ui-tests/invalid-methods.rs:32:5
4545
|
4646
32 | x!();
4747
| ^^^^^
4848

4949
error: can only #[wasm_bindgen] non-const functions
50-
--> $DIR/invalid-methods.rs:39:9
50+
--> ui-tests/invalid-methods.rs:39:9
5151
|
5252
39 | pub const fn foo() {}
5353
| ^^^^^
5454

55-
warning: unused macro definition
56-
--> $DIR/invalid-methods.rs:26:1
55+
warning: unused macro definition: `x`
56+
--> ui-tests/invalid-methods.rs:26:14
5757
|
5858
26 | macro_rules! x { () => () }
59-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
59+
| ^
6060
|
6161
= note: `#[warn(unused_macros)]` on by default

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

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen(main)]
4+
async fn main() {}
5+
6+
#[wasm_bindgen(main)]
7+
fn fail() {}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: the main function has to be called main
2+
--> ui-tests/main-async.rs:7:4
3+
|
4+
7 | fn fail() {}
5+
| ^^^^

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

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use std::fmt;
2+
use wasm_bindgen::prelude::*;
3+
4+
#[wasm_bindgen(main)]
5+
fn main() -> Result<(), Test> {
6+
unimplemented!()
7+
}
8+
9+
struct Test;
10+
11+
impl fmt::Debug for Test {
12+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13+
unimplemented!()
14+
}
15+
}
16+
17+
#[wasm_bindgen(main)]
18+
fn fail() {}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: the main function has to be called main
2+
--> ui-tests/main-debug.rs:18:4
3+
|
4+
18 | fn fail() {}
5+
| ^^^^
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use std::convert::Infallible;
2+
use wasm_bindgen::prelude::*;
3+
4+
#[wasm_bindgen(main)]
5+
fn main() -> Infallible {
6+
unimplemented!()
7+
}
8+
9+
#[wasm_bindgen(main)]
10+
fn fail() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: the main function has to be called main
2+
--> ui-tests/main-infallible.rs:10:4
3+
|
4+
10 | fn fail() {}
5+
| ^^^^

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

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen(main)]
4+
fn main() -> Result<(), JsValue> {
5+
unimplemented!()
6+
}
7+
8+
#[wasm_bindgen(main)]
9+
fn fail() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: the main function has to be called main
2+
--> ui-tests/main-jsvalue.rs:9:4
3+
|
4+
9 | fn fail() {}
5+
| ^^^^
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use std::process;
2+
use wasm_bindgen::prelude::*;
3+
4+
#[wasm_bindgen(main)]
5+
fn main() -> Result<(), Test> {
6+
unimplemented!()
7+
}
8+
9+
struct Test;
10+
11+
impl process::Termination for Test {
12+
fn report(self) -> process::ExitCode {
13+
unimplemented!()
14+
}
15+
}
16+
17+
#[wasm_bindgen(main)]
18+
fn fail() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
error: the main function has to be called main
2+
--> ui-tests/main-termination.rs:18:4
3+
|
4+
18 | fn fail() {}
5+
| ^^^^
6+
7+
error[E0599]: the method `__wasm_bindgen_main` exists for mutable reference `&mut MainWrapper<Result<(), Test>>`, but its trait bounds were not satisfied
8+
--> ui-tests/main-termination.rs:4:1
9+
|
10+
4 | #[wasm_bindgen(main)]
11+
| ^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `&mut MainWrapper<Result<(), Test>>` due to unsatisfied trait bounds
12+
...
13+
9 | struct Test;
14+
| ------------
15+
| |
16+
| doesn't satisfy `Test: Debug`
17+
| doesn't satisfy `Test: Into<JsValue>`
18+
|
19+
::: $WORKSPACE/src/lib.rs
20+
|
21+
| pub struct MainWrapper<T>(pub Option<T>);
22+
| ----------------------------------------- doesn't satisfy `MainWrapper<Result<(), Test>>: Main`
23+
|
24+
= note: the following trait bounds were not satisfied:
25+
`Test: Debug`
26+
which is required by `&mut MainWrapper<Result<(), Test>>: Main`
27+
`Result<(), Test>: Termination`
28+
which is required by `&mut &mut MainWrapper<Result<(), Test>>: Main`
29+
`Test: Into<JsValue>`
30+
which is required by `MainWrapper<Result<(), Test>>: Main`
31+
note: the following trait must be implemented
32+
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
33+
help: consider annotating `Test` with `#[derive(Debug)]`
34+
|
35+
9 | #[derive(Debug)]
36+
|

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

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen(main)]
4+
fn main() -> () {}
5+
6+
#[wasm_bindgen(main)]
7+
fn fail() {}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: the main function has to be called main
2+
--> ui-tests/main-unit.rs:7:4
3+
|
4+
7 | fn fail() {}
5+
| ^^^^

crates/macro/ui-tests/main.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen(main)]
4+
fn main() {}
5+
6+
#[wasm_bindgen(main)]
7+
fn fail() {}

crates/macro/ui-tests/main.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: the main function has to be called main
2+
--> ui-tests/main.rs:7:4
3+
|
4+
7 | fn fail() {}
5+
| ^^^^

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

-12
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,3 @@ error[E0277]: the trait bound `Result<wasm_bindgen::JsValue, wasm_bindgen::JsVal
33
|
44
6 | pub fn foo() -> Result<JsValue, JsValue>;
55
| ^^^ the trait `FromWasmAbi` is not implemented for `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
6-
|
7-
note: required by a bound in `FromWasmAbi`
8-
--> $WORKSPACE/src/convert/traits.rs
9-
|
10-
| / pub trait FromWasmAbi: WasmDescribe {
11-
| | /// The wasm ABI type that this converts from when coming back out from the
12-
| | /// ABI boundary.
13-
| | type Abi: WasmAbi;
14-
... |
15-
| | unsafe fn from_abi(js: Self::Abi) -> Self;
16-
| | }
17-
| |_^ required by this bound in `FromWasmAbi`

0 commit comments

Comments
 (0)