fix(assert): deepStrictEqual — don't treat object-literal shape ids as prototypes (#4937)#5051
Merged
Merged
Conversation
…s prototypes (#4937) deepStrictEqual's prototype gate (#2934) tokenized an object's prototype as CLASS_PROTO_NAMESPACE | class_id. Codegen stores an unregistered layout-shape id in class_id for object literals, while a {}-born object mutated afterwards keeps class_id 0 — so 'd = {}; d.simple = v' never compared equal to '{ simple: v }' despite identical keys, values, and real [[Prototype]] (both Object.prototype). Normalize class_ids with no CLASS_NAMES entry (the registry's own constructor test, per class_decl_prototype_value) to 0 before building the token. Registered class instances, null-prototype objects, and recorded setPrototypeOf values keep their distinct tokens.
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.
Fixes #4937.
Root cause
Not in the deep-equality body walk at all — the prototype-sensitivity gate from #2934.
prototype_token(builtins/formatting/prototype_equality.rs) tokenizes a heap object's prototype asCLASS_PROTO_NAMESPACE | class_id. Codegen stores an unregistered layout-shape id inclass_idfor object literals (e.g. 4), while a{}-born object populated afterwards keepsclass_id0. Both haveObject.prototypeas their real[[Prototype]], but the tokens differed (…0000vs…0004), soprototypes_differshort-circuited every mutated-vs-literal comparison to not equal before the body compare ran.Fix
Normalize any
class_idwith noCLASS_NAMESentry to 0 before building the token — the registry's own constructor test (class_decl_prototype_valueuses exactly this predicate). Registered class instances, null-prototype objects, and recordedsetPrototypeOfvalues keep their distinct tokens.Validation
All of these now match Node (
node --experimental-strip-types) exactly:unregistered_shape_id_normalizes_to_plain_object_prototypepins the token normalization + end-to-endjs_util_is_deep_strict_equalbehavior.cargo test -p perry-runtime prototype: thetest_array_exotic_descriptors_and_global_prototype_identityflake in that group reproduces on pristineorigin/main(parallel-run snapshot flake, passes in isolation) — pre-existing, unrelated.Code-only PR — version bump + changelog left for merge time.