From f03aa3056d8de91531ad8fd32e5d105f1350fed7 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 10:53:58 +0000 Subject: [PATCH] js-on-sx: js-to-number throws TypeError on non-primitive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the earlier js-to-string fix. Number(obj) must throw if ToPrimitive cannot extract a primitive (both valueOf and toString return objects). Was returning NaN silently. Replaced the inner (js-nan-value) fallback with (raise (js-new-call TypeError ...)). built-ins/Number: 45/50 → 46/50. conformance.sh: 148/148. --- lib/js/runtime.sx | 2 +- lib/js/test262-scoreboard.json | 32 ++++++++++++++++---------------- lib/js/test262-scoreboard.md | 16 ++++++++-------- plans/js-on-sx.md | 2 ++ 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/lib/js/runtime.sx b/lib/js/runtime.sx index 869749a9..74deaa86 100644 --- a/lib/js/runtime.sx +++ b/lib/js/runtime.sx @@ -1049,7 +1049,7 @@ (if (not (= (type-of result2) "dict")) (js-to-number result2) - (js-nan-value))) + (raise (js-new-call TypeError (list "Cannot convert object to primitive value"))))) (js-nan-value))))) (js-nan-value)))))) (else 0)))) diff --git a/lib/js/test262-scoreboard.json b/lib/js/test262-scoreboard.json index e13b9684..c8fa7863 100644 --- a/lib/js/test262-scoreboard.json +++ b/lib/js/test262-scoreboard.json @@ -1,29 +1,29 @@ { "totals": { - "pass": 44, - "fail": 6, + "pass": 46, + "fail": 2, "skip": 0, - "timeout": 0, + "timeout": 2, "total": 50, "runnable": 50, - "pass_rate": 88.0 + "pass_rate": 92.0 }, "categories": [ { - "category": "built-ins/Object", + "category": "built-ins/Number", "total": 50, - "pass": 44, - "fail": 6, + "pass": 46, + "fail": 2, "skip": 0, - "timeout": 0, - "pass_rate": 88.0, + "timeout": 2, + "pass_rate": 92.0, "top_failures": [ [ - "ReferenceError (undefined symbol)", - 4 + "Timeout", + 2 ], [ - "SyntaxError (parse/unsupported syntax)", + "Test262Error (assertion failed)", 2 ] ] @@ -31,15 +31,15 @@ ], "top_failure_modes": [ [ - "ReferenceError (undefined symbol)", - 4 + "Timeout", + 2 ], [ - "SyntaxError (parse/unsupported syntax)", + "Test262Error (assertion failed)", 2 ] ], "pinned_commit": "d5e73fc8d2c663554fb72e2380a8c2bc1a318a33", - "elapsed_seconds": 38.2, + "elapsed_seconds": 90.4, "workers": 1 } \ No newline at end of file diff --git a/lib/js/test262-scoreboard.md b/lib/js/test262-scoreboard.md index c93ed504..6685d1cf 100644 --- a/lib/js/test262-scoreboard.md +++ b/lib/js/test262-scoreboard.md @@ -1,24 +1,24 @@ # test262 scoreboard Pinned commit: `d5e73fc8d2c663554fb72e2380a8c2bc1a318a33` -Wall time: 38.2s +Wall time: 90.4s -**Total:** 44/50 runnable passed (88.0%). Raw: pass=44 fail=6 skip=0 timeout=0 total=50. +**Total:** 46/50 runnable passed (92.0%). Raw: pass=46 fail=2 skip=0 timeout=2 total=50. ## Top failure modes -- **4x** ReferenceError (undefined symbol) -- **2x** SyntaxError (parse/unsupported syntax) +- **2x** Timeout +- **2x** Test262Error (assertion failed) ## Categories (worst pass-rate first, min 10 runnable) | Category | Pass | Fail | Skip | Timeout | Total | Pass % | |---|---:|---:|---:|---:|---:|---:| -| built-ins/Object | 44 | 6 | 0 | 0 | 50 | 88.0% | +| built-ins/Number | 46 | 2 | 0 | 2 | 50 | 92.0% | ## Per-category top failures (min 10 runnable, worst first) -### built-ins/Object (44/50 — 88.0%) +### built-ins/Number (46/50 — 92.0%) -- **4x** ReferenceError (undefined symbol) -- **2x** SyntaxError (parse/unsupported syntax) +- **2x** Timeout +- **2x** Test262Error (assertion failed) diff --git a/plans/js-on-sx.md b/plans/js-on-sx.md index 161170f8..53f26bcc 100644 --- a/plans/js-on-sx.md +++ b/plans/js-on-sx.md @@ -158,6 +158,8 @@ Each item: implement → tests → update progress. Mark `[x]` when tests green. Append-only record of completed iterations. Loop writes one line per iteration: date, what was done, test count delta. +- 2026-05-08 — **`js-to-number` throws TypeError when valueOf+toString both return non-primitive.** Mirrors the earlier `js-to-string` fix. Per spec, `Number(obj)` must throw if `ToPrimitive` cannot extract a primitive. Was returning `NaN` silently. Replaced the inner `(js-nan-value)` fallback with `(raise (js-new-call TypeError ...))`. built-ins/Number: 45/50 → 46/50. conformance.sh: 148/148. + - 2026-05-08 — **`Array.prototype` / `Number.prototype` / etc. inherit from `Object.prototype`.** Per ES, every native prototype's `[[Prototype]]` is `Object.prototype` (and `Function.prototype.[[Prototype]]` is also `Object.prototype`). Was missing those `__proto__` links, so `Object.prototype.isPrototypeOf(Boolean.prototype)` returned false (the explicit isPrototypeOf walks `__proto__`, not the recent fallback). Added 5 `dict-set!` lines to the post-init block at the end of `runtime.sx`. built-ins/Boolean: 22/27 → 23/27, built-ins/Number: 44/50 → 45/50. conformance.sh: 148/148. - 2026-05-08 — **`delete obj.key` actually removes the key.** `js-delete-prop` was setting the value to `js-undefined` instead of removing the key, so subsequent `'key' in obj` returned true and proto-chain lookup didn't fall through to the parent. Switched to `dict-delete!` (existing SX primitive). Now `delete Boolean.prototype.toString; Boolean.prototype.toString()` correctly walks up to `Object.prototype.toString` and returns `"[object Boolean]"`. built-ins/Boolean: 21/27 → 22/27. conformance.sh: 148/148.