diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 33ee39984ae..4829ef65eeb 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -2269,6 +2269,11 @@ impl<'a> Context<'a> { } }, + AuxImport::ValueWithThis(class, name) => { + let class = self.import_name(class)?; + Ok(format!("{}.{}({})", class, name, variadic_args(&args)?)) + } + AuxImport::Instanceof(js) => { assert!(webidl_ty.kind == ast::WebidlFunctionKind::Static); assert!(!variadic); diff --git a/crates/cli-support/src/webidl/mod.rs b/crates/cli-support/src/webidl/mod.rs index c81ddbd8fdd..f780f73edd7 100644 --- a/crates/cli-support/src/webidl/mod.rs +++ b/crates/cli-support/src/webidl/mod.rs @@ -278,6 +278,10 @@ pub enum AuxImport { /// imported Value(AuxValue), + /// A static method on a class is being imported, and the `this` of the + /// function call is expected to always be the class. + ValueWithThis(JsImport, String), + /// This import is expected to be a function that takes an `anyref` and /// returns a `bool`. It's expected that it tests if the argument is an /// instance of (using `instanceof`) the name specified. @@ -950,8 +954,7 @@ impl<'a> Context<'a> { match op.kind { decode::OperationKind::Regular => { if op.is_static { - class.fields.push(function.name.to_string()); - Ok((AuxImport::Value(AuxValue::Bare(class)), false)) + Ok((AuxImport::ValueWithThis(class, function.name.to_string()), false)) } else if structural { Ok(( AuxImport::StructuralMethod(function.name.to_string()), diff --git a/crates/cli-support/src/webidl/standard.rs b/crates/cli-support/src/webidl/standard.rs index 105fc9a479f..ae48c9eae6b 100644 --- a/crates/cli-support/src/webidl/standard.rs +++ b/crates/cli-support/src/webidl/standard.rs @@ -574,6 +574,9 @@ fn check_standard_import(import: &AuxImport) -> Result<(), Error> { | AuxImport::Value(AuxValue::ClassSetter(js, name)) => { format!("field access of `{}` for {}", name, desc_js(js)) } + AuxImport::ValueWithThis(js, method) => { + format!("method `{}.{}`", desc_js(js), method) + } AuxImport::Instanceof(js) => format!("instance of check of {}", desc_js(js)), AuxImport::Static(js) => format!("static js value {}", desc_js(js)), AuxImport::StructuralMethod(name) => format!("structural method `{}`", name), diff --git a/guide/src/reference/attributes/on-js-imports/static_method_of.md b/guide/src/reference/attributes/on-js-imports/static_method_of.md index b9faeec5952..cd654f38c70 100644 --- a/guide/src/reference/attributes/on-js-imports/static_method_of.md +++ b/guide/src/reference/attributes/on-js-imports/static_method_of.md @@ -23,3 +23,6 @@ let instant = Date::now(); This is similar to the `js_namespace` attribute, but the usage from within Rust is different since the method also becomes a static method of the imported type. +Additionally this attribute also specifies that the `this` parameter when +invoking the method is expected to be the JS class, e.g. always invoked as +`Date.now()` instead of `const x = Date.now; x()`. diff --git a/tests/wasm/imports.js b/tests/wasm/imports.js index 2628c9400ba..6d11ccb5de5 100644 --- a/tests/wasm/imports.js +++ b/tests/wasm/imports.js @@ -107,3 +107,11 @@ exports.import_inside_private_module = function() {}; exports.should_call_undefined_functions = () => false; exports.STATIC_STRING = 'x'; + +class StaticMethodCheck { + static static_method_of_right_this() { + assert.ok(this === StaticMethodCheck); + } +} + +exports.StaticMethodCheck = StaticMethodCheck; diff --git a/tests/wasm/imports.rs b/tests/wasm/imports.rs index 5d596b5af09..4dc2b4011bd 100644 --- a/tests/wasm/imports.rs +++ b/tests/wasm/imports.rs @@ -52,6 +52,9 @@ extern "C" { fn assert_dead_import_not_generated(); fn should_call_undefined_functions() -> bool; + type StaticMethodCheck; + #[wasm_bindgen(static_method_of = StaticMethodCheck)] + fn static_method_of_right_this(); static STATIC_STRING: String; } @@ -240,3 +243,8 @@ fn undefined_function_is_ok() { fn static_string_ok() { assert_eq!(*STATIC_STRING, "x"); } + +#[wasm_bindgen_test] +fn static_method_of_has_right_this() { + StaticMethodCheck::static_method_of_right_this(); +}