diff --git a/crates/backend/Cargo.toml b/crates/backend/Cargo.toml index dda50e44..a2dfc7ee 100644 --- a/crates/backend/Cargo.toml +++ b/crates/backend/Cargo.toml @@ -14,5 +14,5 @@ Backend code generation of the wasm-bindgen tool quote = '0.5' proc-macro2 = { version = "0.3", features = ["nightly"] } wasm-bindgen-shared = { path = "../shared", version = "=0.2.4" } -syn = { version = '0.13', features = ['full', 'visit'] } +syn = { version = '0.13', features = ['full', 'visit-mut'] } serde_json = "1.0" diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 8313a18c..f5afd575 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -179,12 +179,13 @@ impl Program { }, _ => panic!("unsupported self type in impl"), }; - for mut item in item.items.iter_mut() { - self.push_impl_item(name, &mut item); + for item in item.items.iter_mut() { + self.push_impl_item(name, item); } } fn push_impl_item(&mut self, class: syn::Ident, item: &mut syn::ImplItem) { + replace_self(class, item); let method = match item { syn::ImplItem::Const(_) => panic!("const definitions aren't supported"), syn::ImplItem::Type(_) => panic!("type definitions in impls aren't supported"), @@ -458,7 +459,7 @@ impl Function { pub fn from_decl( name: syn::Ident, - decl: Box, + mut decl: Box, attrs: Vec, opts: BindgenAttrs, vis: syn::Visibility, @@ -471,7 +472,7 @@ impl Function { panic!("can't bindgen functions with lifetime or type parameters") } - assert_no_lifetimes(&decl); + assert_no_lifetimes(&mut decl); let mut mutable = None; let arguments = decl.inputs @@ -928,15 +929,29 @@ fn term<'a>(cursor: syn::buffer::Cursor<'a>, name: &str) -> syn::synom::PResult< syn::parse_error() } -fn assert_no_lifetimes(decl: &syn::FnDecl) { +fn assert_no_lifetimes(decl: &mut syn::FnDecl) { struct Walk; - impl<'ast> syn::visit::Visit<'ast> for Walk { - fn visit_lifetime(&mut self, _i: &'ast syn::Lifetime) { + impl<'ast> syn::visit_mut::VisitMut for Walk { + fn visit_lifetime_mut(&mut self, _i: &mut syn::Lifetime) { panic!("it is currently not sound to use lifetimes in function \ signatures"); } } - syn::visit::Visit::visit_fn_decl(&mut Walk, decl); + syn::visit_mut::VisitMut::visit_fn_decl_mut(&mut Walk, decl); +} + +fn replace_self(name: syn::Ident, item: &mut syn::ImplItem) { + struct Walk(syn::Ident); + + impl syn::visit_mut::VisitMut for Walk { + fn visit_ident_mut(&mut self, i: &mut syn::Ident) { + if i.as_ref() == "Self" { + *i = self.0; + } + } + } + + syn::visit_mut::VisitMut::visit_impl_item_mut(&mut Walk(name), item); } diff --git a/tests/all/classes.rs b/tests/all/classes.rs index 5de557a2..45b652b5 100644 --- a/tests/all/classes.rs +++ b/tests/all/classes.rs @@ -526,3 +526,35 @@ fn public_fields() { "#) .test(); } + +#[test] +fn using_self() { + project() + .debug(false) + .file("src/lib.rs", r#" + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + #[wasm_bindgen] + pub struct Foo { + } + + #[wasm_bindgen] + impl Foo { + pub fn new() -> Self { + Foo {} + } + } + "#) + .file("test.ts", r#" + import { Foo } from "./out"; + + export function test() { + Foo.new().free(); + } + "#) + .test(); +}