overlookmotel/livepack

`++` and `--` prefix operators not serialized correctly with "soft" constant

overlookmotel opened this issue · 1 comments

Input:

// Sloppy mode
const f = function x() {
  return ++x;
};
f.valueOf = () => 100;
module.exports = f;

Output:

const x = (x$0 => x$0 = function x() {
  return +x$0;
})();
Object.assign(x, {
  valueOf: (0, () => 100)
});
module.exports = x;

x here is a constant, but a "soft" const which doesn't throw an error when assigned to in sloppy mode code.

The original function returns 101, whereas the serialized function returns 100.

The output would be correct if it was x++, but for ++x the function's body should be return +x$0 + 1;.

NB x$0 + 1 (without the preceding +) is insufficient. ++x coerces x to a number, whereas x + 1 may instead coerce 1 to a string, so +x$0 is required to ensure x is coerced to a number before + 1.

Same problem with --x.

Actually, even that doesn't cover where value is a BigInt.

const x = 100n;
export default () => x++;

or:

// Sloppy mode
const f = function x() {
  return ++x;
};
f.valueOf = () => 100n;
module.exports = f;

If x is a BigInt, +x throws error TypeError: Cannot convert a BigInt value to a number.

Only way to cover this is:

++x -> (n=>++n)(x)
x++ -> (n=>n++)(x)
--x -> (n=>--n)(x)
x-- -> (n=>n--)(x)

i.e. Perform the original operation, but just don't assign the result to the constant var.