Fix #[wasm_bindgen] on structs with no exports

It should still be usable in other types!

Closes #27
This commit is contained in:
Alex Crichton 2018-02-16 13:49:53 -08:00
parent c148a3b6dc
commit 7802535948
3 changed files with 60 additions and 11 deletions

View File

@ -35,13 +35,11 @@ pub struct SubContext<'a, 'b: 'a> {
impl<'a> Context<'a> { impl<'a> Context<'a> {
pub fn add_custom_type_names(&mut self, program: &shared::Program) { pub fn add_custom_type_names(&mut self, program: &shared::Program) {
for custom in program.custom_type_names.iter() { for custom in program.custom_type_names.iter() {
assert!(self.custom_type_names.insert(custom.descriptor, let prev = self.custom_type_names.insert(custom.descriptor,
custom.name.clone()).is_none()); custom.name.clone());
let val = custom.descriptor as u32; if let Some(prev) = prev {
assert!(val & 1 == 0); assert_eq!(prev, custom.name);
let descriptor = char::from_u32(val | 1).unwrap(); }
assert!(self.custom_type_names.insert(descriptor,
custom.name.clone()).is_none());
} }
} }
@ -636,6 +634,12 @@ impl<'a> Context<'a> {
i.module() == "env" && i.field() == name i.module() == "env" && i.field() == name
}) })
} }
fn custom_type_name(&self, c: char) -> &str {
let c = (c as u32) & !shared::TYPE_CUSTOM_REF_FLAG;
let c = char::from_u32(c).unwrap();
&self.custom_type_names[&c]
}
} }
impl<'a, 'b> SubContext<'a, 'b> { impl<'a, 'b> SubContext<'a, 'b> {
@ -772,7 +776,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
pass(&format!("idx{}", i)); pass(&format!("idx{}", i));
} }
custom if (custom as u32) & shared::TYPE_CUSTOM_REF_FLAG != 0 => { custom if (custom as u32) & shared::TYPE_CUSTOM_REF_FLAG != 0 => {
let s = self.cx.custom_type_names[&custom].clone(); let s = self.cx.custom_type_name(custom).to_string();
dst_ts.push_str(&format!(": {}", s)); dst_ts.push_str(&format!(": {}", s));
if self.cx.config.debug { if self.cx.config.debug {
self.cx.expose_assert_class(); self.cx.expose_assert_class();
@ -783,7 +787,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
pass(&format!("{}.ptr", name)); pass(&format!("{}.ptr", name));
} }
custom => { custom => {
let s = self.cx.custom_type_names[&custom].clone(); let s = self.cx.custom_type_name(custom).to_string();
dst_ts.push_str(&format!(": {}", s)); dst_ts.push_str(&format!(": {}", s));
if self.cx.config.debug { if self.cx.config.debug {
self.cx.expose_assert_class(); self.cx.expose_assert_class();
@ -836,8 +840,8 @@ impl<'a, 'b> SubContext<'a, 'b> {
Some(shared::TYPE_JS_REF) | Some(shared::TYPE_JS_REF) |
Some(shared::TYPE_BORROWED_STR) => panic!(), Some(shared::TYPE_BORROWED_STR) => panic!(),
Some(t) if (t as u32) & shared::TYPE_CUSTOM_REF_FLAG != 0 => panic!(), Some(t) if (t as u32) & shared::TYPE_CUSTOM_REF_FLAG != 0 => panic!(),
Some(ref custom) => { Some(custom) => {
let name = &self.cx.custom_type_names[custom]; let name = self.cx.custom_type_name(custom);
dst_ts.push_str(": "); dst_ts.push_str(": ");
dst_ts.push_str(name); dst_ts.push_str(name);
if self.cx.config.debug { if self.cx.config.debug {

View File

@ -289,6 +289,7 @@ impl Program {
("custom_type_names", &|a| { ("custom_type_names", &|a| {
let names = self.exports.iter() let names = self.exports.iter()
.filter_map(|e| e.class) .filter_map(|e| e.class)
.chain(self.structs.iter().map(|s| s.name))
.collect::<BTreeSet<_>>(); .collect::<BTreeSet<_>>();
a.list(&names, |s, a| { a.list(&names, |s, a| {
let val = shared::name_to_descriptor(s.as_ref()); let val = shared::name_to_descriptor(s.as_ref());

View File

@ -224,3 +224,47 @@ fn pass_one_to_another() {
"#) "#)
.test(); .test();
} }
#[test]
fn issue_27() {
test_support::project()
.file("src/lib.rs", r#"
#![feature(proc_macro)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct Context {}
#[wasm_bindgen]
impl Context {
pub fn parse(&self, expr: &str) -> Expr {
panic!()
}
pub fn eval(&self, expr: &Expr) -> f64 {
panic!()
}
pub fn set(&mut self, var: &str, val: f64) {
panic!()
}
}
#[wasm_bindgen]
pub struct Expr {}
#[wasm_bindgen]
#[no_mangle]
pub extern fn context() -> Context {
Context {}
}
"#)
.file("test.ts", r#"
import { context } from "./out";
export function test() {
context();
}
"#)
.test();
}