I'm having a weird problem with proc macros, imports and scoping: What I'm trying to implement is a crate wrapping wasm-bindgen (though the problem is not limited to wasm-bindgen, it also occurs with pyo3). For example the code below should simply generate the same code as wasm-bindgen would:
#![feature(proc_macro, specialization, wasm_import_module, wasm_custom_section, concat_idents)]
#[macro_use]
extern crate capybara;
use capybara::capybara_bindgen;
#[capybara_bindgen]
pub struct ExportedClass {}
Since wasm-bindgen generates those use wasm_bindgen::[..]
statements as seen below, I somehow have to get wasm_bindgen in scope.
impl ::wasm_bindgen::convert::FromWasmAbi for ExportedClass {
type Abi = u32;
unsafe fn from_abi(js: u32, _extra: &mut ::wasm_bindgen::convert::Stack) -> Self {
use wasm_bindgen::__rt::std::boxed::Box;
use wasm_bindgen::__rt::{assert_not_null, WasmRefCell};
let ptr = js as *mut WasmRefCell<ExportedClass>;
assert_not_null(ptr);
let js = Box::from_raw(ptr);
js.borrow_mut();
js.into_inner()
}
}
Since importing in the top level of a proc macro output is not allowed, a dummy const should do the trick:
let original_tokens = derive_with_wasm_bindgen(input);
let tokens: TokenStream = quote!(
const #dummy_const: () = {
use capybara::wasm_bindgen;
#original_tokens
};
).into();
Now the following code is generated, where it looks like wasm_bindgen
is in scope:
const _CAPYBARA_CLS_STRUCT_EXPORTEDCLASS: () = {
use capybara::wasm_bindgen;
pub struct ExportedClass {}
// [elided]
impl ::wasm_bindgen::convert::IntoWasmAbi for ExportedClass {
type Abi = u32;
fn into_abi(self, _extra: &mut ::wasm_bindgen::convert::Stack) -> u32 {
use wasm_bindgen::__rt::std::boxed::Box;
use wasm_bindgen::__rt::WasmRefCell;
Box::into_raw(Box::new(WasmRefCell::new(self))) as u32
}
}
// [elided]
};
Nevertheless, I get errors like the following:
error[E0433]: failed to resolve. Use of undeclared type or module `WasmRefCell`
--> tests/src/lib.rs:8:1
|
8 | #[capybara_bindgen]
| ^^^^^^^^^^^^^^^^^^^ Use of undeclared type or module `WasmRefCell`
This is even weirder since adding the exact same import to the level of the macro invocation works perfectly fine:
use capybara::wasm_bindgen;
#[capybara_bindgen]
pub struct ExportedClass {}
I've also tried replacing use wasm_bindgen::
with use ::wasm_bindgen::
in wasm-bindgen, but the two colons were removed in the generated code, which seems pretty strange to me.
I can provide a repo with the complete code for reproducing this. Building a minimal example is kinda difficult since there are 5 different crates involved.
So in summary, how do I get a crate (or a module in general) into the scope in a proc macro? And why is my current approach failing?