From 050bb5cd6bf377d660dbe28e6f3e3a6a44152c4b Mon Sep 17 00:00:00 2001 From: daxpedda Date: Thu, 5 Dec 2024 23:43:51 +0100 Subject: [PATCH] Handle potentially throwing getters --- crates/cli-support/src/js/mod.rs | 51 +++++++++++++++--------- crates/cli/tests/reference/static.js | 24 ++--------- guide/src/reference/static-js-objects.md | 5 +-- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 1a4f904bf76..fdeda766cb9 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -2578,6 +2578,38 @@ __wbg_set_wasm(wasm);" Ok(name) } + fn import_static(&mut self, import: &JsImport, optional: bool) -> Result { + let mut name = if let Some(name) = self.imported_names.get(&import.name) { + name.to_owned() + } else { + let JsImportName::Global { name } = &import.name else { + unreachable!("invalid static import") + }; + let unique_name = self.generate_identifier(name); + if unique_name != *name { + bail!("cannot import `{}` from two locations", name); + } + unique_name + }; + + // After we've got an actual name handle field projections + if optional { + name = format!("typeof {name} === 'undefined' ? null: {name}"); + + for field in import.fields.iter() { + name.push_str("?."); + name.push_str(field); + } + } else { + for field in import.fields.iter() { + name.push('.'); + name.push_str(field); + } + } + + Ok(name) + } + /// If a start function is present, it removes it from the `start` section /// of the Wasm module and then moves it to an exported function, named /// `__wbindgen_start`. @@ -3269,24 +3301,7 @@ __wbg_set_wasm(wasm);" assert!(kind == AdapterJsImportKind::Normal); assert!(!variadic); assert_eq!(args.len(), 0); - let js = self.import_name(js)?; - - if *optional { - writeln!( - prelude, - "\ - let result; - try {{ - result = {js}; - }} catch (_) {{ - result = null; - }}", - ) - .unwrap(); - Ok("result".to_owned()) - } else { - Ok(js) - } + self.import_static(js, *optional) } AuxImport::String(string) => { diff --git a/crates/cli/tests/reference/static.js b/crates/cli/tests/reference/static.js index 86549f8bb6d..fcf7e92fa19 100644 --- a/crates/cli/tests/reference/static.js +++ b/crates/cli/tests/reference/static.js @@ -39,13 +39,7 @@ export function exported() { } export function __wbg_static_accessor_NAMESPACE_OPTIONAL_c9a4344c544120f4() { - let result; - try { - result = test.NAMESPACE_OPTIONAL; - } catch (_) { - result = null; - } - const ret = result; + const ret = typeof test === 'undefined' ? null: test?.NAMESPACE_OPTIONAL; return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); }; @@ -55,13 +49,7 @@ export function __wbg_static_accessor_NAMESPACE_PLAIN_784c8d7f5bbac62a() { }; export function __wbg_static_accessor_NESTED_NAMESPACE_OPTIONAL_a414abbeb018a35a() { - let result; - try { - result = test1.test2.NESTED_NAMESPACE_OPTIONAL; - } catch (_) { - result = null; - } - const ret = result; + const ret = typeof test1 === 'undefined' ? null: test1?.test2?.NESTED_NAMESPACE_OPTIONAL; return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); }; @@ -71,13 +59,7 @@ export function __wbg_static_accessor_NESTED_NAMESPACE_PLAIN_1121b285cb8479df() }; export function __wbg_static_accessor_OPTIONAL_ade71b6402851d0c() { - let result; - try { - result = OPTIONAL; - } catch (_) { - result = null; - } - const ret = result; + const ret = typeof OPTIONAL === 'undefined' ? null: OPTIONAL; return isLikeNone(ret) ? 0 : addToExternrefTable0(ret); }; diff --git a/guide/src/reference/static-js-objects.md b/guide/src/reference/static-js-objects.md index ab96c0708af..6604eee8994 100644 --- a/guide/src/reference/static-js-objects.md +++ b/guide/src/reference/static-js-objects.md @@ -7,9 +7,8 @@ a named `static` in the `extern` block with an `JsThreadLocal` for these objects, which can be cloned into a `JsValue`. These values are cached in a thread-local and are meant to bind static values -or objects only. Binding getters or expecting a new value or object when -changed in JS is not supported. For these use -[getters](attributes/on-js-imports/getter-and-setter.md). +or objects only. For getters which can change their return value or throw see +[how to import getters](attributes/on-js-imports/getter-and-setter.md). For example, given the following JavaScript: