Skip to content

Commit

Permalink
Fix generated shims if APIs don't exist
Browse files Browse the repository at this point in the history
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 rustwasm#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.
  • Loading branch information
alexcrichton committed Oct 11, 2018
1 parent e03e404 commit 13cac2d
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 33 deletions.
59 changes: 26 additions & 33 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
}
",
);
Expand Down Expand Up @@ -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")
Expand All @@ -1989,24 +1986,20 @@ impl<'a, 'b> SubContext<'a, 'b> {
shared::OperationKind::IndexingDeleter => {
panic!("indexing deleter should be structural")
}
}
};

let fallback = if import.structural {
"".to_string()
} else {
format!(
" || function() {{
throw new Error(`wasm-bindgen: {} does not exist`);
}}",
target
)
};
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
};

self.cx.global(&format!(
"const {}_target = {}{};",
import.shim, target, fallback
));
self.cx.global(&format!("const {}_target = {};", import.shim, target));
Ok(format!(
"{}_target{}",
import.shim,
Expand Down
1 change: 1 addition & 0 deletions tests/wasm/imports.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
28 changes: 28 additions & 0 deletions tests/wasm/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ extern "C" {

fn unused_import();
fn assert_dead_import_not_generated();
fn should_call_undefined_functions() -> bool;
}

#[wasm_bindgen]
Expand Down Expand Up @@ -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());
}

0 comments on commit 13cac2d

Please sign in to comment.