Skip to content

Commit

Permalink
Implement #[wasm_bindgen(main)]
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Feb 12, 2023
1 parent d090e94 commit adcf286
Show file tree
Hide file tree
Showing 24 changed files with 336 additions and 116 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: rustup update --no-self-update 1.56.0 && rustup default 1.56.0
- run: rustup update --no-self-update 1.61.0 && rustup default 1.61.0
- run: cargo test -p wasm-bindgen-macro

build_examples:
Expand Down
64 changes: 62 additions & 2 deletions crates/macro-support/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
use quote::ToTokens;
use syn::parse::{Parse, ParseStream, Result as SynResult};
use syn::spanned::Spanned;
use syn::Lit;
use syn::{ItemFn, Lit, ReturnType};

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

Expand Down Expand Up @@ -80,6 +80,7 @@ macro_rules! attrgen {
(variadic, Variadic(Span)),
(typescript_custom_section, TypescriptCustomSection(Span)),
(skip_typescript, SkipTypescript(Span)),
(main, Main(Span)),
(start, Start(Span)),
(skip, Skip(Span)),
(typescript_type, TypeScriptType(Span, String, Span)),
Expand Down Expand Up @@ -933,6 +934,13 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
) -> Result<(), Diagnostic> {
match self {
syn::Item::Fn(mut f) => {
let opts = opts.unwrap_or_default();

if opts.main().is_some() {
opts.check_used();
return main(f, tokens);
}

let no_mangle = f
.attrs
.iter()
Expand All @@ -951,7 +959,6 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
// `dead_code` warning. So, add `#[allow(dead_code)]` before it to avoid that.
tokens.extend(quote::quote! { #[allow(dead_code)] });
f.to_tokens(tokens);
let opts = opts.unwrap_or_default();
if opts.start().is_some() {
if f.sig.generics.params.len() > 0 {
bail_span!(&f.sig.generics, "the start function cannot have generics",);
Expand Down Expand Up @@ -1689,6 +1696,59 @@ pub fn link_to(opts: BindgenAttrs) -> Result<ast::LinkToModule, Diagnostic> {
Ok(ast::LinkToModule(program))
}

fn main(mut f: ItemFn, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
if f.sig.ident != "main" {
bail_span!(&f.sig.ident, "the main function has to be called main");
}
if let Some(constness) = f.sig.constness {
bail_span!(&constness, "the main function cannot be const");
}
if !f.sig.generics.params.is_empty() {
bail_span!(&f.sig.generics, "the main function cannot have generics");
}
if !f.sig.inputs.is_empty() {
bail_span!(&f.sig.inputs, "the main function cannot have arguments");
}

let r#return = f.sig.output;
f.sig.output = ReturnType::Default;
let body = f.block;

if f.sig.asyncness.take().is_some() {
f.block = Box::new(
syn::parse2(quote::quote! {
{
async fn __wasm_bindgen_generated_main() #r#return #body
wasm_bindgen_futures::spawn_local(
async move {
use wasm_bindgen::__rt::Main;
let __ret = __wasm_bindgen_generated_main();
(&mut wasm_bindgen::__rt::MainWrapper(Some(__ret.await))).__wasm_bindgen_main()
},
)
}
})
.unwrap(),
);
} else {
f.block = Box::new(
syn::parse2(quote::quote! {
{
fn __wasm_bindgen_generated_main() #r#return #body
use wasm_bindgen::__rt::Main;
let __ret = __wasm_bindgen_generated_main();
(&mut wasm_bindgen::__rt::MainWrapper(Some(__ret))).__wasm_bindgen_main()
}
})
.unwrap(),
);
}

f.to_tokens(tokens);

Ok(())
}

#[cfg(test)]
mod tests {
#[test]
Expand Down
20 changes: 0 additions & 20 deletions crates/macro/ui-tests/async-errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ error[E0277]: the trait bound `Result<(), ()>: IntoJsResult` is not satisfied
= help: the following implementations were found:
<Result<(), E> as IntoJsResult>
<Result<T, E> as IntoJsResult>
note: required by `into_js_result`
--> $WORKSPACE/src/lib.rs
|
| fn into_js_result(self) -> Result<JsValue, JsValue>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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<(), BadType>: IntoJsResult` is not satisfied
Expand All @@ -23,11 +18,6 @@ error[E0277]: the trait bound `Result<(), BadType>: IntoJsResult` is not satisfi
= help: the following implementations were found:
<Result<(), E> as IntoJsResult>
<Result<T, E> as IntoJsResult>
note: required by `into_js_result`
--> $WORKSPACE/src/lib.rs
|
| fn into_js_result(self) -> Result<JsValue, JsValue>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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 `wasm_bindgen::JsValue: From<BadType>` is not satisfied
Expand All @@ -44,11 +34,6 @@ error[E0277]: the trait bound `wasm_bindgen::JsValue: From<BadType>` is not sati
and $N others
= note: required because of the requirements on the impl of `Into<wasm_bindgen::JsValue>` for `BadType`
= note: required because of the requirements on the impl of `IntoJsResult` for `BadType`
note: required by `into_js_result`
--> $WORKSPACE/src/lib.rs
|
| fn into_js_result(self) -> Result<JsValue, JsValue>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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<BadType, wasm_bindgen::JsValue>: IntoJsResult` is not satisfied
Expand All @@ -60,9 +45,4 @@ error[E0277]: the trait bound `Result<BadType, wasm_bindgen::JsValue>: IntoJsRes
= help: the following implementations were found:
<Result<(), E> as IntoJsResult>
<Result<T, E> as IntoJsResult>
note: required by `into_js_result`
--> $WORKSPACE/src/lib.rs
|
| fn into_js_result(self) -> Result<JsValue, JsValue>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
24 changes: 12 additions & 12 deletions crates/macro/ui-tests/invalid-methods.stderr
Original file line number Diff line number Diff line change
@@ -1,61 +1,61 @@
error: #[wasm_bindgen] default impls are not supported
--> $DIR/invalid-methods.rs:7:1
--> ui-tests/invalid-methods.rs:7:1
|
7 | default impl A {
| ^^^^^^^

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

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

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

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

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

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

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

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

warning: unused macro definition
--> $DIR/invalid-methods.rs:26:1
warning: unused macro definition: `x`
--> ui-tests/invalid-methods.rs:26:14
|
26 | macro_rules! x { () => () }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^
|
= note: `#[warn(unused_macros)]` on by default
7 changes: 7 additions & 0 deletions crates/macro/ui-tests/main-async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use wasm_bindgen::prelude::*;

#[wasm_bindgen(main)]
async fn main() {}

#[wasm_bindgen(main)]
fn fail() {}
5 changes: 5 additions & 0 deletions crates/macro/ui-tests/main-async.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: the main function has to be called main
--> ui-tests/main-async.rs:7:4
|
7 | fn fail() {}
| ^^^^
18 changes: 18 additions & 0 deletions crates/macro/ui-tests/main-debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::fmt;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(main)]
fn main() -> Result<(), Test> {
unimplemented!()
}

struct Test;

impl fmt::Debug for Test {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unimplemented!()
}
}

#[wasm_bindgen(main)]
fn fail() {}
5 changes: 5 additions & 0 deletions crates/macro/ui-tests/main-debug.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: the main function has to be called main
--> ui-tests/main-debug.rs:18:4
|
18 | fn fail() {}
| ^^^^
10 changes: 10 additions & 0 deletions crates/macro/ui-tests/main-infallible.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use std::convert::Infallible;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(main)]
fn main() -> Infallible {
unimplemented!()
}

#[wasm_bindgen(main)]
fn fail() {}
5 changes: 5 additions & 0 deletions crates/macro/ui-tests/main-infallible.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: the main function has to be called main
--> ui-tests/main-infallible.rs:10:4
|
10 | fn fail() {}
| ^^^^
9 changes: 9 additions & 0 deletions crates/macro/ui-tests/main-jsvalue.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use wasm_bindgen::prelude::*;

#[wasm_bindgen(main)]
fn main() -> Result<(), JsValue> {
unimplemented!()
}

#[wasm_bindgen(main)]
fn fail() {}
5 changes: 5 additions & 0 deletions crates/macro/ui-tests/main-jsvalue.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: the main function has to be called main
--> ui-tests/main-jsvalue.rs:9:4
|
9 | fn fail() {}
| ^^^^
18 changes: 18 additions & 0 deletions crates/macro/ui-tests/main-termination.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::process;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(main)]
fn main() -> Result<(), Test> {
unimplemented!()
}

struct Test;

impl process::Termination for Test {
fn report(self) -> process::ExitCode {
unimplemented!()
}
}

#[wasm_bindgen(main)]
fn fail() {}
36 changes: 36 additions & 0 deletions crates/macro/ui-tests/main-termination.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
error: the main function has to be called main
--> ui-tests/main-termination.rs:18:4
|
18 | fn fail() {}
| ^^^^

error[E0599]: the method `__wasm_bindgen_main` exists for mutable reference `&mut MainWrapper<Result<(), Test>>`, but its trait bounds were not satisfied
--> ui-tests/main-termination.rs:4:1
|
4 | #[wasm_bindgen(main)]
| ^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `&mut MainWrapper<Result<(), Test>>` due to unsatisfied trait bounds
...
9 | struct Test;
| ------------
| |
| doesn't satisfy `Test: Debug`
| doesn't satisfy `Test: Into<JsValue>`
|
::: $WORKSPACE/src/lib.rs
|
| pub struct MainWrapper<T>(pub Option<T>);
| ----------------------------------------- doesn't satisfy `MainWrapper<Result<(), Test>>: Main`
|
= note: the following trait bounds were not satisfied:
`Test: Debug`
which is required by `&mut MainWrapper<Result<(), Test>>: Main`
`Result<(), Test>: Termination`
which is required by `&mut &mut MainWrapper<Result<(), Test>>: Main`
`Test: Into<JsValue>`
which is required by `MainWrapper<Result<(), Test>>: Main`
note: the following trait must be implemented
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Test` with `#[derive(Debug)]`
|
9 | #[derive(Debug)]
|
7 changes: 7 additions & 0 deletions crates/macro/ui-tests/main-unit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use wasm_bindgen::prelude::*;

#[wasm_bindgen(main)]
fn main() -> () {}

#[wasm_bindgen(main)]
fn fail() {}
5 changes: 5 additions & 0 deletions crates/macro/ui-tests/main-unit.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: the main function has to be called main
--> ui-tests/main-unit.rs:7:4
|
7 | fn fail() {}
| ^^^^
7 changes: 7 additions & 0 deletions crates/macro/ui-tests/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use wasm_bindgen::prelude::*;

#[wasm_bindgen(main)]
fn main() {}

#[wasm_bindgen(main)]
fn fail() {}
5 changes: 5 additions & 0 deletions crates/macro/ui-tests/main.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: the main function has to be called main
--> ui-tests/main.rs:7:4
|
7 | fn fail() {}
| ^^^^
12 changes: 0 additions & 12 deletions crates/macro/ui-tests/missing-catch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,3 @@ error[E0277]: the trait bound `Result<wasm_bindgen::JsValue, wasm_bindgen::JsVal
|
6 | pub fn foo() -> Result<JsValue, JsValue>;
| ^^^ the trait `FromWasmAbi` is not implemented for `Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
|
note: required by a bound in `FromWasmAbi`
--> $WORKSPACE/src/convert/traits.rs
|
| / pub trait FromWasmAbi: WasmDescribe {
| | /// The wasm ABI type that this converts from when coming back out from the
| | /// ABI boundary.
| | type Abi: WasmAbi;
... |
| | unsafe fn from_abi(js: Self::Abi) -> Self;
| | }
| |_^ required by this bound in `FromWasmAbi`
Loading

0 comments on commit adcf286

Please sign in to comment.