Wasm-bindgen: wasm_bindgen(constructor) doesn't compile with cfg_attr

Created on 17 Jan 2019  路  5Comments  路  Source: rustwasm/wasm-bindgen

Hi, it seems that constructors can't be conditionally tagged when using cfg_attr in combination with wasm_bindgen(constructor), for example:

#[cfg_attr(feature = "bindings", wasm_bindgen(constructor))]

The error message I get from attempting this is:

error: expected one of `(`, `async`, `const`, `default`, `existential`, `extern`, `fn`, `type`, or `unsafe`, found `static`
  --> src/lib.rs:19:38
   |
19 |     #[cfg_attr(feature = "bindings", wasm_bindgen(constructor))]
   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^

Most helpful comment

All 5 comments

Oh dear this looks bad! It looks like we're possibly generating bad code and this may not be related to #[cfg_attr] though. Can you gist the code in question to help us reproduce?

Sorry for the delay, I made a repo if you'd like to clone and try it out:
https://github.com/attente/wasm-bindgen-1191

I built it with cargo build --release --target wasm32-unknown-unknown --features bindings.

Hm ok thanks for the reproduction! Something is happening here with procedural macros we weren't expecting which is causing the issue. Regardless though this is a use case we want to support! I'll work on getting this fixed hopefully

Ok I think I know how we can solve this. I'm gonna jot some thoughts down so I don't forget!

The problem is that in this code:

#[foo]
impl Foo {
    #[cfg_attr(a, foo)]
    pub fn new() {}
}

the expansion of the impl doesn't actually see the #[foo] on new because the #[cfg] expansion is deferred until later. In wasm-bindgen we try to do all the expansions immediately, but they don't work out in this case because we can't expand the sub-methods as we don't know whether they'll be included or not.

To solve this I think what we should do is expand the above to:

impl Foo {
    #[cfg_attr(a, foo)]
    #[wasm_bindgen_method_of = Foo]
    pub fn new() {}
}

// other goop generated by `impl Foo { ... }`

basically we rely on recursive macro expansion. We added a synthetic attribute on all methods (at the end). This synthetic attribute will simply return its input if #[wasm_bindgen] isn't present, but otherwise #[wasm_bindgen] will remove the internal attribute.

That way when expanding a method we still know whether it's part of a struct or not, and we should properly handle #[cfg]!

This will be a somewhat involved fix, so it may take some time to implement

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fitzgen picture fitzgen  路  3Comments

MarcAntoine-Arnaud picture MarcAntoine-Arnaud  路  3Comments

kurbaniec picture kurbaniec  路  3Comments

arilotter picture arilotter  路  3Comments

aschampion picture aschampion  路  4Comments