Repository navigation
fix(codemode): honor thisArg, program toString in computed keys, and ToPrimitive in String and Number arguments - #51264
Merged
Merged
Conversation
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.
Three small gaps where an argument the interpreter already receives was ignored or rejected. One commit each, in review order.
1.
thisArgon iteration callbacksconst c = { n: 0 } [1, 2].forEach(function () { this.n++ }, c) c.n -// TypeError: Cannot read properties of undefined (reading 'n') +2Array
forEach/map/filter/find/findIndex/findLast/findLastIndex/some/every/flatMap, the Uint8Array equivalents,Array.from(items, mapFn, thisArg), andMap/Set/URLSearchParams/HeadersforEachpass it asthis.reduce/reduceRightkeep their initial-value slot. Arrows ignore it, as before.2. Computed property keys use the object's own
toStringconst key = { toString() { return "id" } } const o = {} o[key] = 1; o[key] += 1 [o.id, key in o, (({ [key]: v }) => v)(o)] -// [undefined, false, undefined] (key was "[object Object]") +[2, true, 2]One conversion per access (compound assignment and
++calltoStringonce), in reads, writes,delete,in, object literals, and destructuring. Primitives keep the synchronous path. Opaque values (functions, promises, tool references) keep their built-in string form and are never invoked. A nullish base throws before the key converts (ToObjectprecedesToPropertyKey).3. String and Number method arguments convert through ToPrimitive
"abc".indexOf({ toString() { return "b" } }) -// TypeError: String.indexOf expects argument 1 to be a data value. +1 (255).toString({ valueOf() { return 16 } }) -// RangeError (radix became NaN) +"ff" String.prototype.trim.call({ toString() { return " a " } }) -"[object Object]" +"a"Receiver first, then each consumed argument in spec order; string positions (search strings, separators, fills, replacements,
normalizeform,localeCompare) use the string hint, numeric positions (indexes, counts, digits, radix) the number hint. Extra arguments are not converted. A RegExp pattern tosplit/replace/match/matchAll/searchis used as is;includes/startsWith/endsWithreject a RegExp before converting. Top-level opaque values and un-awaited promises still reject as data errors.Leakage probes
Tool calls counted by a host tool handler; every conversion path made zero calls.
toStringthrowsRangeError: bad keytoStringrecurses (key.toString = () => o[key])RangeError: Maximum call stack size exceededtoString/valueOfreturn objectsTypeError: Cannot convert object to primitive value.tools.x"[object Object]"(unchanged){ toString: tools.x }TypeError: Cannot convert object to primitive value.toStringreturnstools.xTypeError: Cannot convert object to primitive value.toStringreturns 8M charsrepeatcap; no separate key check)toStringreturns 2^24+1 charsRangeError: Invalid string lengthfromrepeat"[object Promise]"(unchanged)thisArgistools.xthis,typeof this === "function", not dispatchedthisArgis a promisethistoStringreturnstools.xTypeError: Cannot convert object to primitive value.toStringthrows a stringvalueOfrecursesRangeError: Maximum call stack size exceededVerification
bun test(packages/codemode)skipped.txtlines removedbun run check(root)Decisions
Headers.prototype.forEachgotthisArgtoo: same one-line pattern as URLSearchParams, WebIDL-specified.String.prototype.trim.call(obj)): it is the samewithPrimitivescall, spec order requires receiver first, and it recovered ~25 test262 files. Say if this should be split out."abc".indexOf([tools.x])) now converts through the array'stoStringinstead of rejecting, matching the documented "operators inspect only their direct operands" rule. Top-leveltools.x/ promise arguments still reject.Error.prototype.toStringon an objectmessageis not done:errorToStringis also used synchronously at the result boundary, so it would need splitting rather than a one-line change. Left unchecked ininterpreter-support.md.Noticed, not fixed
compound-assignment/S11.13.2_A7.*recoveries are blocked bynew DummyError()(user-defined constructors), not by key conversion; 3assignment/target-member-computed-reference*.jsfiles likewise.tools.x === tools.xisfalse(each member read creates a newToolReference); pre-existing.Number.prototype.toPrecision(p)style calls on the prototype itself still throw (no boxedNumber.prototype);s.at(function () {})still rejects the function argument by design.String.prototype[Symbol.iterator]still uses the built-in string form of an object receiver.