You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
++ and -- on a BigInt-valued binding throw TypeError: Cannot convert a BigInt value to a number instead of producing a BigInt result. ES2026 §13.4.4.1 (PostfixIncrement) and §13.4.5.1 (PostfixDecrement) call Type(oldValue)::add(oldValue, Type(oldValue)::unit) where unit is 1n for BigInt and 1 for Number; Goccia's compiler hard-codes OP_LOAD_INT 1 so the runtime hits BigInt-vs-Int in OP_ADD / OP_SUB and rejects.
./build/GocciaScriptLoaderBare --compat-all --mode=bytecode -
let i = 10n; i++; print(i);
^D
# Error: TypeError: Cannot convert a BigInt value to a number
Affected sites
source/units/Goccia.Compiler.Expressions.pas:2906-2916 — CompileIncrement non-global-backed local branch loads OP_LOAD_INT 1 regardless of operand type.
Symmetric branches at lines 2887-2904 (global-backed local), 2929-2946 (upvalue), and 2791-2845 (member / computed-member targets) have the same issue.
Likely fix
Two options:
Compiler-level: detect operand type at runtime — compile ++ as if value is BigInt then value + 1n else value + 1. Either via a new OP_INC / OP_DEC opcode that picks the unit based on the operand's runtime type, or via existing branches.
VM-level: have OP_ADD / OP_SUB widen the Int operand to BigInt automatically when the other is BigInt. Less spec-pure (5n + 1 should still throw) but localized.
Recommend (1).
Why this surfaced now
#531 enables --compat-traditional-for-loop via --compat-all, which test262 already uses. Several test262 tests (e.g., built-ins/BigInt/prototype/toString/a-z.js) use for (let i = 10n; i < radix; i++) ... to iterate over BigInt indices; previously the loop body warn-and-skipped, hiding this bug.
Summary
++and--on aBigInt-valued binding throwTypeError: Cannot convert a BigInt value to a numberinstead of producing a BigInt result. ES2026 §13.4.4.1 (PostfixIncrement) and §13.4.5.1 (PostfixDecrement) callType(oldValue)::add(oldValue, Type(oldValue)::unit)whereunitis1nfor BigInt and1for Number; Goccia's compiler hard-codesOP_LOAD_INT 1so the runtime hits BigInt-vs-Int inOP_ADD/OP_SUBand rejects.Reproducer
Affected sites
source/units/Goccia.Compiler.Expressions.pas:2906-2916—CompileIncrementnon-global-backed local branch loadsOP_LOAD_INT 1regardless of operand type.Likely fix
Two options:
++asif value is BigInt then value + 1n else value + 1. Either via a newOP_INC/OP_DECopcode that picks the unit based on the operand's runtime type, or via existing branches.OP_ADD/OP_SUBwiden the Int operand to BigInt automatically when the other is BigInt. Less spec-pure (5n + 1should still throw) but localized.Recommend (1).
Why this surfaced now
#531 enables
--compat-traditional-for-loopvia--compat-all, which test262 already uses. Several test262 tests (e.g.,built-ins/BigInt/prototype/toString/a-z.js) usefor (let i = 10n; i < radix; i++) ...to iterate over BigInt indices; previously the loop body warn-and-skipped, hiding this bug.Scope notes
bytecode-mode test262 run on PR Add --compat-traditional-for-loop opt-in flag #531.EvaluateIncrementcallsPerformIncrement(OldValue, true)which uses Number(1).+= 1nandi = i + 1nwork correctly today; only the prefix/postfix++/--are broken.