Skip to content

[TS] Support array growth and sparse slots #388

Description

@CaelmBleidd

Goal

Support growth of ordinary TypeScript arrays through array.length = n and writes beyond the current last element, with correct sparse-slot (hole) semantics.

Follow-up to #366 / PR #380. Existing push and unshift approximations already grow arrays; this issue covers direct length and indexed writes.

Current limitation

At PR #380 head 41961f7b, length assignment restricts the new length to the current length. Indexed writes also require an existing index.

Simply removing these bounds is incorrect: shrinking currently changes the length without removing the old payloads from symbolic memory. Growing again could expose deleted values. Numeric and Boolean storage also cannot represent a hole by writing their default value.

const values = [10, 20];
values.length = 1;
values.length = 2;

values[1] === undefined; // true; the old 20 must not reappear
1 in values;            // false

A hole must remain distinct from an existing element whose value is undefined:

const values: any[] = [];
values.length = 3;
values[2] = undefined;

0 in values; // false
2 in values; // true

Scope

  • Support nonnegative integral numeric length assignments within the configured maxArraySize, including symbolic lengths.
  • Shrinking deletes elements at and beyond the new length. Growing creates holes without reviving deleted payloads.
  • Support dense append via array[array.length] = value and writes to larger valid indices. Set the new length to max(oldLength, index + 1); intervening indices remain holes.
  • Reading a hole yields undefined for ordinary arrays in the supported domain, including arrays stored as number[] or boolean[].
  • Distinguish holes from explicit undefined for array-index membership with in. The current symbolic-Boolean approximation of in cannot establish this behavior.
  • Preserve hole information across aliases, repeated resizing, and existing supported array operations such as push, pop, shift, unshift, slice, concat, reverse, and fill. Audit other array approximations that read or copy elements; unsupported sparse cases must be handled explicitly.
  • Extend test-value reconstruction and JavaScript replay so holes are not materialized as ordinary undefined elements and mutations do not corrupt reconstructed input arrays.

Implementation direction

Prefer a TS-layer representation of element presence using the existing symbolic-memory regions, for example a Boolean region indexed by array reference and element index. Reads, writes, deletion, and array copying must agree on that representation.

Retain the storage-type normalization from #377 and the unresolved-value payload/kind representation. Current symbolic memory remains authoritative; allocation history is reconstruction metadata.

Dense append can be the first implementation step, but it alone does not complete this issue. Avoid a generic sparse-container framework or unrelated core redesign.

Acceptance criteria

  • Fresh growth, shrink-then-grow, repeated resize, dense append, and writes leaving gaps agree with native JavaScript.
  • Deleted values and reference aliases never reappear after growth.
  • Holes read as undefined, while in distinguishes holes from explicit undefined elements.
  • Cases cover concrete and symbolic lengths/indices, numeric and Boolean arrays, reference arrays, any[]/unknown[], and widened/wrapped aliases.
  • Affected array operations preserve their observable sparse-array behavior; regressions include pop on a trailing hole and shift with holes.
  • Generated inputs, return values, and before/after heap states replay correctly in JavaScript without filling holes accidentally.
  • Existing array/model regressions, TypeScript checks, and Detekt pass.

Boundaries

Keep existing numeric-length validation and explicit size bounds. Full coercion of nonnumeric lengths, exotic arrays, proxies, inherited indexed properties, and complete ECMAScript array semantics are outside this issue. Unsupported behavior must not silently be reported as a successful exact model result.

Activity

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions