Fix #708, #574, #565: boxed-primitive wrapper coercion#800
Merged
Conversation
#708: new Number/String/Boolean wrappers coerce to their primitive. Register valueOf/toString on the Number and String built-ins; add an interpreter ToPrimitive (OrdinaryToPrimitive) wired into +, arithmetic/comparison/bitwise (via CoerceToNumber), loose ==, template literals, and String.fromCharCode/ fromCodePoint, so a wrapper reduces to its [[PrimitiveValue]] instead of "[object Object]"/NaN, and `String.fromCharCode(new Number(1))` no longer crashes. #574: JSON.stringify honors a user-overridden valueOf/toString on a wrapper — Number->ToNumber, String->ToString (both through ToPrimitive), Boolean->the [[BooleanData]] slot. JSON's value and space unwrap route through the interpreter. #565: compiled JSON.stringify gates the boxed-primitive unwrap on a string __primitiveType tag, matching the interpreter — a plain object that merely has a __primitiveValue field is no longer unwrapped. #475 (enumeration) is intentionally not included here: making Object.keys/values/ entries respect enumerability exposed two pre-existing gaps (for-in not filtering internal slots, and Object.defineProperty resetting an existing property's enumerable flag) that need their own fix. Tracked separately. Full test suite green (13419).
Boxed-primitive coercion (#708) and JSON valueOf/toString dispatch (#574) flip 29 interpreted Test262 tests to Pass: JSON/stringify value/space-{number,string}-object, String fromCharCode/fromCodePoint/concat/toString/valueOf, Number valueOf, new-expression wrapper coercion (S11.2.2), and Array.prototype.*.call over a number/boolean primitive. fromCharCode/S9.7_A3.1_T4 moves RuntimeError->Fail (object-with-valueOf arg, still unsupported — no longer crashes). Isolated by regenerating interpreted.txt on main vs this branch; only these lines changed. Compiled baseline unchanged (#565 has no Test262 case).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of the Batch-1 "boxed-primitive value semantics" cluster. Ships three tightly-coupled, regression-free fixes; the two remaining Batch-1 issues (#475, #449/#474) are split off (see below).
Fixes
new Number(x)/new String(x)wrapper objects don't coerce (valueOf returns the object; String.fromCharCode(new Number(1)) crashes) #708 —new Number/String/Booleanwrappers now coerce to their primitive. RegisteredvalueOf/toStringon the Number and String built-ins, and added an interpreterToPrimitive(OrdinaryToPrimitive, honoring an ownvalueOf/toString) wired into+, arithmetic/comparison/bitwise (viaCoerceToNumber), loose==, template literals, andString.fromCharCode/fromCodePoint. A wrapper now reduces to its[[PrimitiveValue]]instead of"[object Object]"/NaN, andString.fromCharCode(new Number(1))no longer hard-crashes.JSON.stringifyhonors a user-overriddenvalueOf/toStringon a wrapper (Number→ToNumber, String→ToString throughToPrimitive; Boolean→the[[BooleanData]]slot). Both the value andspaceunwrap route through the interpreter.__primitiveValuefield (boxed-primitive check too loose) #565 — compiledJSON.stringifygates the boxed-primitive unwrap on a string__primitiveTypetag, matching the interpreter, so a plain object that merely has a__primitiveValuefield is no longer unwrapped.Verification
interpreted.txtonmainvs this branch — only those lines changed): JSONvalue/space-{number,string}-object, StringfromCharCode/fromCodePoint/concat/toString/valueOf, NumbervalueOf,new-expression wrapper coercion (S11.2.2), andArray.prototype.*.callover a number/boolean primitive. NoPass→Failregressions. (fromCharCode/S9.7_A3.1_T4movesRuntimeError→Fail: an object-with-valueOfarg, still unsupported but no longer crashing.) Compiled baseline unchanged (Compiled JSON.stringify unwraps a plain object that has a__primitiveValuefield (boxed-primitive check too loose) #565 has no Test262 case).Deferred (kept open)
for-indoesn't filter internal slots, andObject.definePropertyresets an existing property'senumerableflag when redefining with a partial descriptor. Needs those companion fixes; pulled out to keep this PR clean.Symbol() instanceof Symbolreturns true (should be false); boxedObject(sym) instanceof Symbolreturns false (should be true) #449 / interp: Array.prototype.*.call(<number/boolean primitive>) — primitive prototypes aren't mutable and boxed wrappers don't read array-like state through the prototype chain #474 (Symbolinstanceof; mutable primitive prototypes) — separate sub-areas (Symbol-global plumbing +Object(sym)boxing; prototype mutability), to be tackled next.