Fix object literals silently corrupting data with interleaved field/method type annotations#265
Merged
ASDAlexander77 merged 1 commit intoJul 20, 2026
Conversation
…ethod type annotations An object literal's own storage always lays out as "all fields, then all methods" (two separate codegen passes over the properties, by design - a method may reference sibling fields that must already be registered). A type-literal annotation on the receiving var/let, however, preserves verbatim interleaved source declaration order. When these orderings diverge - any annotation with 2+ fields and 2+ methods not grouped field-first - method bodies get compiled against the WRONG byte offsets for the annotated variable's actual memory layout: a `this.field` write can silently land on a neighboring method's function-pointer slot instead, corrupting data with no compile error and no crash. Fix: after all fields/methods/captures are processed but before method bodies are generated, if the receiver type's field order differs from the literal's own accumulated order, permute the literal's field list (and parallel value list) to match it. Field access inside method bodies resolves by name against the storage type's live field list, so this reordering alone is sufficient - no per-method index patching needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ASDAlexander77
deleted the
fix/object-literal-interleaved-field-method-layout
branch
July 20, 2026 16:49
3 tasks
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.
Summary
mlirGenObjectLiteralFields/mlirGenObjectLiteralMethodPrototypesrun as two separate passes over the literal's properties, by design (a method may reference sibling fields that must already be registered).var/let, however, preserves verbatim interleaved source declaration order.this.fieldwrite can silently land on a neighboring method's function-pointer slot instead of the intended field. No compile error, no crash — just silently corrupted data.Fix
After all fields/methods/captures are processed but before method bodies are generated, if the receiver type's field order differs from the literal's own accumulated order, permute the literal's field list (and the parallel value list) to match it. Field access inside method bodies resolves by name against the storage type's live field list at codegen time, so this reordering alone is sufficient — no per-method index patching needed.
Test plan
00object_annotated_method_interleaved.ts(compile + JIT)export/import_object_literal_structural_typed_interleaved.ts(compile + JIT), combining this fix with the recent decl-text printer fix (Fix cross-module multi-method vtable corruption via decl-text object-vs-tuple printing #263)Known follow-up (not in scope here)
An
extends-based variant of the cross-module scenario (interface Base {...} interface Accumulator extends Base {...}, cast in the importer) still fails to compile at all with a bareerror: failed statement— confirmed unrelated to this bug (the flat, non-extendsversion with identical members now compiles and runs correctly). Looks related to a separately-documented discovery-pass issue; not investigated further here.🤖 Generated with Claude Code