Wasm-bindgen: Handling undefined arguments

Created on 18 Feb 2019  路  5Comments  路  Source: rustwasm/wasm-bindgen

I debugged a weird error message (TypeError: getObject(...) is undefined) for a while...

img

...until I realized that the signature of the get_caret_position function requires an &Element argument and that I didn't pass in any arguments.

When debug-printing the element argument, it shows Element { obj: JsValue(undefined) }.

Is there a clean way to handle the case of JS code not passing in sufficient arguments? Could wasm-bindgen generate a better error message for this case?

And as an intermediate solution, is there a way to check if an &Element value is backed by an undefined JsValue?

Most helpful comment

Ok sure! In any case I'll try to write some more details about how this would be handled.

Currently one aspect of wasm-bindgen is that it communicates the actual types of all arguments of exports/imports to the CLI tool. It does this via a pretty roundabound method, but the general idea is that:

  • In the crate itself (code generated by the macro) a type implement the WasmDescribe trait. This trait has one method that simply calls inform a number of times in succession. That basically produces a Vec<u32> which we then decode in the CLI later on.
  • The list of available descriptors are all associated implicitly with an encoding, but the one we're interested in here is ANYREF. That represents "any JS value", and so we'll want to add another, JSOBJECT, which represents "any non-null JS object".
  • We'll want to change the the WasmDescribe implementation for imported types to manually use JSOBJECT instead of delegating to JsValue.
  • The CLI definitions of descriptors then needs an update to stay in sync with src/describe.rs as well as the enum Descriptor needs a new variant for JsObject.
  • Next up the support for that needs to be plumbed around. You'll probably want to update the existing is_anyref method which is largely used to case on anyref, and then in a few locations, if necessary, you'd add an is_jsobject() check and emit necessary debug glue guards.

And in theory that's most of it!

All 5 comments

This seems reasonable to me! We don't provide a ton of guard rails in debug mode, but we do provide some. I think the best way to handle this would be to generate more type guard glue whenever --debug is passed to the CLI, sort of like we do for strings today.

I would like to take this as my first contribution. Where is a good place to start looking at this?

@pfernandom awesome! All the invocations which go from JS to Rust are located in a js2rust.rs file. That file has a number of "guard rails" already like so which are gated to only get emitted in debug mode.

As I look more into this though... this may be a bit more involved than I originally thought. The problem here is that the wasm-bindgen-facing-type for Element is JsValue, which can assume any arbitrary value. What we really want though is for Element to have type NonNullObject or something like that which would allow us to add guard rails that the object we get isn't null, undefined, or something that isn't an instance of Object in JS.

That does mean that this is actually significantly more complicated than I originally thought, but if you're still interested I can try to help guide through an implementation!

I'm more than happy to take this bug, but If you think that this is too complicated and might require too much hand-holding, I can find another issue to work on.

Maybe I can time box it and see if I can do some significant advance, and if I do, I can take it.

Ok sure! In any case I'll try to write some more details about how this would be handled.

Currently one aspect of wasm-bindgen is that it communicates the actual types of all arguments of exports/imports to the CLI tool. It does this via a pretty roundabound method, but the general idea is that:

  • In the crate itself (code generated by the macro) a type implement the WasmDescribe trait. This trait has one method that simply calls inform a number of times in succession. That basically produces a Vec<u32> which we then decode in the CLI later on.
  • The list of available descriptors are all associated implicitly with an encoding, but the one we're interested in here is ANYREF. That represents "any JS value", and so we'll want to add another, JSOBJECT, which represents "any non-null JS object".
  • We'll want to change the the WasmDescribe implementation for imported types to manually use JSOBJECT instead of delegating to JsValue.
  • The CLI definitions of descriptors then needs an update to stay in sync with src/describe.rs as well as the enum Descriptor needs a new variant for JsObject.
  • Next up the support for that needs to be plumbed around. You'll probably want to update the existing is_anyref method which is largely used to case on anyref, and then in a few locations, if necessary, you'd add an is_jsobject() check and emit necessary debug glue guards.

And in theory that's most of it!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pauldorehill picture pauldorehill  路  3Comments

bantic picture bantic  路  4Comments

expobrain picture expobrain  路  4Comments

fitzgen picture fitzgen  路  4Comments

poccariswet picture poccariswet  路  3Comments