Skip to content

Array.prototype.toLocaleString returns "[object Array]" for every receiver; Uint8Array.prototype.toString decodes bytes as text #8139

Closed

Description

@proggeramlug

Two stringification gaps measured while sweeping Array.prototype receivers
(#8135). Neither is a receiver-routing bug — toLocaleString is wrong for a
plain array too — so they are filed separately rather than folded into that
family.

Measured against node v26.5.1 on main @ 0a1e78e5f.

1. toLocaleString returns Object.prototype.toString for every receiver

[3, 1, 2].toLocaleString()                 // node "3,1,2"  perry "[object Array]"
new Int32Array([3, 1, 2]).toLocaleString() // node "3,1,2"  perry "[object Int32Array]"
new Uint8Array([3, 1, 2]).toLocaleString() // node "3,1,2"  perry "[object Uint8Array]"
new Float64Array([3,1,2]).toLocaleString() // node "3,1,2"  perry "[object Float64Array]"

The plain-array row is the tell: whatever resolves .toLocaleString() is
falling through to the generic object stringifier before
js_array_to_locale_string (array/iter_methods.rs:1110) is ever reached.
That helper looks broadly right — it reads length off
normalize_array_receiver and formats per element — so this is a dispatch
miss, not a helper bug.

lower_array_method.rs:1113 routes toLocaleString to the dynamic
js_native_call_method tower with no HIR fold at all, which is the place to
start looking.

2. Uint8Array.prototype.toString decodes bytes as text

new Uint8Array([3, 1, 2]).toString()
// node:  "3,1,2"      (Array-style element join)
// perry: the three raw bytes decoded as UTF-8 (Buffer.prototype.toString)

Perry backs new Uint8Array([…]) with a BufferHeader
(buffer::js_uint8array_new) and dispatch_buffer_method serves toString
from node's Buffer semantics. But Buffer.prototype.toString is an own
override on Buffer; a plain Uint8Array inherits
%TypedArray%.prototype.toString, which is the Array-style join. Perry
conflates the two because the backing store is the same object.

An Int32Array receiver is correct ("3,1,2"), so this is specific to the
Buffer-backed shape.

Same underlying identity conflation as the findLast / reduceRight /
splice holes catalogued in #8137 — a Uint8Array that is not a Buffer
needs to be distinguishable at dispatch — but the fix here is a toString
arm, not a receiver reroute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions