diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 4f58190a1..0f75b4272 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -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, diff --git a/tests/wasm/imports.js b/tests/wasm/imports.js index a97c8be6f..a2aef2e1b 100644 --- a/tests/wasm/imports.js +++ b/tests/wasm/imports.js @@ -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; diff --git a/tests/wasm/imports.rs b/tests/wasm/imports.rs index 463aa5aba..15a6c4c20 100644 --- a/tests/wasm/imports.rs +++ b/tests/wasm/imports.rs @@ -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()); +}