Fix generated shims if APIs don't exist

This commit fixes instantiation of the wasm module even if some of the
improted APIs don't exist. This extends the functionality initially
added in #409 to attempt to gracefully allow importing values from the
environment which don't actually exist in all contexts. In addition to
nonexistent methods being handled now entire nonexistent types are now
also handled.

I suspect that eventually we'll add a CLI flag to `wasm-bindgen` to say
"I assert everything exists, don't check it" to trim out the extra JS
glue generated here. In the meantime though this'll pave the way for a
wasm-bindgen shim to be instantiated in both a web worker and the main
thread, while using DOM-like APIs only on the main thread.
This commit is contained in:
Alex Crichton 2018-10-10 16:10:24 -07:00
parent e03e40451e
commit 13cac2d0c4
3 changed files with 54 additions and 32 deletions

View File

@ -1542,7 +1542,7 @@ impl<'a> Context<'a> {
if (desc) return desc;
obj = Object.getPrototypeOf(obj);
}
throw new Error(`descriptor for id='${id}' not found`);
return {}
}
",
);
@ -1956,29 +1956,26 @@ impl<'a, 'b> SubContext<'a, 'b> {
),
}
} else {
let (location, binding) = if op.is_static {
("", format!(".bind({})", class))
} else {
(".prototype", "".into())
};
match &op.kind {
let target = format!("typeof {0} === 'undefined' ? null : {}{}",
class,
if op.is_static { "" } else { ".prototype" });
let (mut target, name) = match &op.kind {
shared::OperationKind::Regular => {
format!("{}{}.{}{}", class, location, import.function.name, binding)
(format!("{}.{}", target, import.function.name), &import.function.name)
}
shared::OperationKind::Getter(g) => {
self.cx.expose_get_inherited_descriptor();
format!(
"GetOwnOrInheritedPropertyDescriptor({}{}, '{}').get{}",
class, location, g, binding,
)
(format!(
"GetOwnOrInheritedPropertyDescriptor({}, '{}').get",
target, g,
), g)
}
shared::OperationKind::Setter(s) => {
self.cx.expose_get_inherited_descriptor();
format!(
"GetOwnOrInheritedPropertyDescriptor({}{}, '{}').set{}",
class, location, s, binding,
)
(format!(
"GetOwnOrInheritedPropertyDescriptor({}, '{}').set",
target, s,
), s)
}
shared::OperationKind::IndexingGetter => {
panic!("indexing getter should be structural")
@ -1989,24 +1986,20 @@ impl<'a, 'b> SubContext<'a, 'b> {
shared::OperationKind::IndexingDeleter => {
panic!("indexing deleter should be structural")
}
};
target.push_str(&format!(" || function() {{
throw new Error(`wasm-bindgen: {}.{} does not exist`);
}}", class, name));
if op.is_static {
target.insert(0, '(');
target.push_str(").bind(");
target.push_str(&class);
target.push_str(")");
}
target
};
let fallback = if import.structural {
"".to_string()
} else {
format!(
" || function() {{
throw new Error(`wasm-bindgen: {} does not exist`);
}}",
target
)
};
self.cx.global(&format!(
"const {}_target = {}{};",
import.shim, target, fallback
));
self.cx.global(&format!("const {}_target = {};", import.shim, target));
Ok(format!(
"{}_target{}",
import.shim,

View File

@ -104,3 +104,4 @@ exports.assert_dead_import_not_generated = function() {
exports.import_inside_function_works = function() {};
exports.import_inside_private_module = function() {};
exports.should_call_undefined_functions = () => false;

View File

@ -50,6 +50,7 @@ extern "C" {
fn unused_import();
fn assert_dead_import_not_generated();
fn should_call_undefined_functions() -> bool;
}
#[wasm_bindgen]
@ -204,3 +205,30 @@ mod private {
import_inside_private_module();
}
}
#[wasm_bindgen]
extern {
fn something_not_defined_in_the_environment();
type TypeThatIsNotDefined;
#[wasm_bindgen(constructor)]
fn new() -> TypeThatIsNotDefined;
#[wasm_bindgen(method)]
fn method(this: &TypeThatIsNotDefined);
#[wasm_bindgen(method, getter)]
fn property(this: &TypeThatIsNotDefined) -> u32;
#[wasm_bindgen(method, setter)]
fn set_property(this: &TypeThatIsNotDefined, val: u32);
}
#[wasm_bindgen_test]
fn undefined_function_is_ok() {
if !should_call_undefined_functions() {
return
}
something_not_defined_in_the_environment();
let x = TypeThatIsNotDefined::new();
x.method();
x.set_property(x.property());
}