Importing and scoping in proc macros


#1

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?