Skip to content

Properly implement From<usize/isize> and PartialEq<usize/isize> for JsValue #2978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 5, 2022

Conversation

Liamolucko
Copy link
Collaborator

Fixes #2977

Previously, usize and isize were converted to bigints when converting to JS values, when they should be converted to regular JS numbers due to being 32-bit. PartialEq was then implemented on top of that, checking whether self == JsValue::from(n).

It could be argued that they should be bigints to try and be forwards-compatible with 64-bit WebAssembly; however, they're already represented as regular numbers everywhere else.

One major issue here is that this is a breaking change. You can't just use a number where a bigint is expected (or vice versa), so this will break any code that used From to convert from a usize/isize to JsValue. That happens most commonly indirectly, through the return type of async functions, which are internally converted using Into<JsValue>.

…or `JsValue`

Fixes rustwasm#2977

Previously, `usize` and `isize` were converted to bigints when converting to JS values, when they should be converted to regular JS numbers due to being 32-bit. `PartialEq` was then implemented on top of that, checking whether `self == JsValue::from(n)`.

It could be argued that they should be bigints to try and be forwards-compatible with 64-bit WebAssembly; however, they're already represented as regular numbers everywhere else.

One major issue here is that this is a breaking change. You can't just use a number where a bigint is expected (or vice versa), so this will break any code that used `From` to convert from `usize`/`isize` to `JsValue`. That happens most commonly indirectly, through the return type of async functions, which are internally converted using `Into<JsValue>`.
Copy link
Collaborator

@ranile ranile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix!

@ranile ranile merged commit 1060d69 into rustwasm:main Jul 5, 2022
@Liamolucko
Copy link
Collaborator Author

Just in case I wasn't clear enough (it was sorta buried at the bottom of the PR description), this will almost certainly break anything which relies on the previous behaviour. I doubt that there are many things that do, and this isn't actually a breaking change to the API (so the code will still compile), but I want to double-check that you're okay with that.

@ranile
Copy link
Collaborator

ranile commented Jul 8, 2022

It should be fine. I assume the equality works as it's supposed to, right?

let one: JsValue = JsValue::from(10usize);
assert!(one == 10usize)

How the comparison happens was (and still is) an implementation detail so I don't see how this breaking change effects much.

@Liamolucko
Copy link
Collaborator Author

I assume the equality works as it's supposed to, right?

let one: JsValue = JsValue::from(10usize);
assert!(one == 10usize)

Yes, that works; it's this kind of thing that breaks:

// previously returned true, now returns false:
assert_eq!(JsValue::bigint_from_str("10"), 10usize);
// previously returned false, now returns true:
assert_ne!(JsValue::from_f64(10.0), 10usize);

@ranile
Copy link
Collaborator

ranile commented Jul 8, 2022

I'd argue that the previous behavior was incorrect and has been fixed now

bigint should be i/u128 and number should equal to i/usize

@Liamolucko Liamolucko deleted the usize-non-bigint branch July 10, 2022 05:15
@RReverser
Copy link
Member

This definitely broke serde-wasm-bindgen tests and took a bit to narrow down, but, luckily, it's only the tests that got broken, because Serde itself always serializes usize/isize as u64/i64, regardless of platform size, so our runtime behaviour didn't change.

RReverser added a commit to RReverser/serde-wasm-bindgen that referenced this pull request Sep 2, 2022
Update deps and fix tests after rustwasm/wasm-bindgen#2978.
Liamolucko added a commit to Liamolucko/wasm-bindgen that referenced this pull request Sep 2, 2022
Fixes rustwasm#3055

This changes `isize` and `usize` to be converted to `BigInt` in the same way as `i32`/`u32`, `BigInt(JsValue::from(n))`, rather than `JsValue::from(n).unchecked_into()`. The latter is now wrong since as of rustwasm#2978 that `JsValue::from` returns a `Number`, not a `BigInt`.
alexcrichton pushed a commit that referenced this pull request Sep 2, 2022
* js-sys: Fix `BigInt::from(usize)` and `BigInt::from(isize)`

Fixes #3055

This changes `isize` and `usize` to be converted to `BigInt` in the same way as `i32`/`u32`, `BigInt(JsValue::from(n))`, rather than `JsValue::from(n).unchecked_into()`. The latter is now wrong since as of #2978 that `JsValue::from` returns a `Number`, not a `BigInt`.

* Add a regression test

* fmt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

usize and isize are converted into BigInt in some situations
3 participants