Skip to content
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

Incorrect minification with a bigint value created by a binary operator inside conditions #4065

Closed
sapphi-red opened this issue Feb 7, 2025 · 2 comments

Comments

@sapphi-red
Copy link
Contributor

For input

export function foo(a, b) {
  if ((a | b) === 0) {
    throw new Error()
  }
}

esbuild outputs

export function foo(o,r){if(!(o|r))throw new Error}

But this changes the behavior when foo(0n, 0n) is called.
No error happens before minification, but an error happens after minification.

@evanw
Copy link
Owner

evanw commented Feb 7, 2025

Thanks for the report. I assume this assumption was left over from before the introduction of bigints. Will fix.

@evanw
Copy link
Owner

evanw commented Feb 7, 2025

Looks like this affects Terser too (which you also discovered): terser/terser#1587. This currently happens for all bitwise operators in esbuild:

Before (esbuild) After (esbuild)
if ((a | b) === 0) throw '|' if (!(a | b)) throw "|"
if ((a & b) === 0) throw '&' if (!(a & b)) throw "&"
if ((a ^ b) === 0) throw '^' if (!(a ^ b)) throw "^"
if ((a << b) === 0) throw '<<' if (!(a << b)) throw "<<"
if ((a >> b) === 0) throw '>>' if (!(a >> b)) throw ">>"
if ((a >>> b) === 0) throw '>>>' if (!(a >>> b)) throw ">>>"
if (~a === 0) throw '~' if (!~a) throw "~"

It's mostly the same for Terser except Terser doesn't do it for the >>> operator, which is funnily enough the only operator for which this is actually safe to do (because >>> throws when used with bigints):

Before (Terser) After (Terser)
if ((a | b) === 0) throw '|' if (!(a | b)) throw "|"
if ((a & b) === 0) throw '&' if (!(a & b)) throw "&"
if ((a ^ b) === 0) throw '^' if (!(a ^ b)) throw "^"
if ((a << b) === 0) throw '<<' if (!(a << b)) throw "<<"
if ((a >> b) === 0) throw '>>' if (!(a >> b)) throw ">>"
if ((a >>> b) === 0) throw '>>>' if (a >>> b == 0) throw ">>>"
if (~a === 0) throw '~' if (0 == ~a) throw "~"

Edit: Although the conversion of ~a === 0 to ~a == 0 that Terser does here is also problematic: ~-1n === 0 is false but ~-1n == 0 is true.

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

No branches or pull requests

2 participants