Found while triaging test262 regressions exposed by #112 (built-ins/BigInt/wrapper-object-ordinary-toprimitive.js and the analogous built-ins/Symbol/prototype/Symbol.toPrimitive/redefined-symbol-wrapper-ordinary-toprimitive.js). Pre-existing bug, unrelated to #65/#112's mechanism - just uncovered by it (the test previously died silently before reaching the failing assertion).
Repro
const BigIntValueOf = BigInt.prototype.valueOf;
Object.defineProperty(BigInt.prototype, "valueOf", {
get: () => {
console.log("valueOf getter called");
return function () {
console.log("valueOf() called");
return BigIntValueOf.call(this) * 2n;
};
},
});
console.log(Object(1n) == 2n); // expected: true (via the overridden valueOf); actual: false, no logging at all
Nothing is logged - the overridden valueOf getter is never invoked. Abstract equality between an Object(1n) wrapper and a BigInt primitive isn't going through ToPrimitive/GetMethod(@@toPrimitive)/OrdinaryToPrimitive at all; it's using some internal fast path that unwraps the BigInt value directly, bypassing user-overridden valueOf/toString entirely.
Scope
The test262 file this surfaced from exercises this across ==, +, string-template interpolation, and property-key coercion, with both toString and valueOf overridden at different points - the failure is at the very first assertion (hint: default via ==), so the rest of the file's coverage is unverified against our implementation. The sibling Symbol.toPrimitive test suggests the same gap likely applies to Object(Symbol()) wrapper comparisons too, though not independently confirmed.
Needs tracing through wherever abstract equality (==) special-cases BigInt-vs-Object comparisons in the VM to find where it skips the ToPrimitive protocol.
Found while triaging test262 regressions exposed by #112 (
built-ins/BigInt/wrapper-object-ordinary-toprimitive.jsand the analogousbuilt-ins/Symbol/prototype/Symbol.toPrimitive/redefined-symbol-wrapper-ordinary-toprimitive.js). Pre-existing bug, unrelated to #65/#112's mechanism - just uncovered by it (the test previously died silently before reaching the failing assertion).Repro
Nothing is logged - the overridden
valueOfgetter is never invoked. Abstract equality between anObject(1n)wrapper and aBigIntprimitive isn't going throughToPrimitive/GetMethod(@@toPrimitive)/OrdinaryToPrimitiveat all; it's using some internal fast path that unwraps the BigInt value directly, bypassing user-overriddenvalueOf/toStringentirely.Scope
The test262 file this surfaced from exercises this across
==,+, string-template interpolation, and property-key coercion, with bothtoStringandvalueOfoverridden at different points - the failure is at the very first assertion (hint: defaultvia==), so the rest of the file's coverage is unverified against our implementation. The siblingSymbol.toPrimitivetest suggests the same gap likely applies toObject(Symbol())wrapper comparisons too, though not independently confirmed.Needs tracing through wherever abstract equality (
==) special-cases BigInt-vs-Object comparisons in the VM to find where it skips the ToPrimitive protocol.