Skip to content

Extract shared resolve_relative_index helper for slice/copyWithin/fill clamping#188

Open
pmatos wants to merge 1 commit into
mainfrom
claude/loving-mccarthy-sju4nh
Open

Extract shared resolve_relative_index helper for slice/copyWithin/fill clamping#188
pmatos wants to merge 1 commit into
mainfrom
claude/loving-mccarthy-sju4nh

Conversation

@pmatos

@pmatos pmatos commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

This is a targeted architecture refactor from a codebase audit (using the codebase-design/improve-codebase-architecture deep-module vocabulary), aimed at eliminating duplicated, drift-prone logic rather than adding new features.

The audit surfaced several duplication hotspots (receiver-validation boilerplate in collections.rs, repeated Date getter wrappers, RegExp Symbol.match/replace/split loop duplication, a fragmented property-access interface in eval.rs/mod.rs). This PR tackles the highest-payoff, lowest-risk candidate: the relative-index clamping algorithm — "if n < 0, clamp to max(0, len+n), else min(len, n)" — used by the spec algorithms behind Array.prototype.slice/splice/toSpliced/fill/copyWithin, String.prototype.slice, and the %TypedArray%.prototype equivalents.

This algorithm was hand-rolled independently at 9 call sites across array.rs, string.rs, and typedarray.rs. typedarray.rs alone reimplemented it 4 different ways, including one genuine inconsistency between < and <= at the lower boundary (copyWithin vs. slice/subarray) that happened to still produce the same clamped result — a latent correctness risk that would only need one future edit to diverge for real.

Deletion test: deleting all 9 inline implementations and factoring them into one helper makes 9 call sites shrink to one-liners; the arithmetic (a real correctness risk given NaN/Infinity/overflow edge cases) collapses into one place instead of drifting independently in 3 files.

Changes

  • Added resolve_relative_index(n: f64, len: usize) -> usize to src/interpreter/helpers.rs, a pure function with no interpreter/JS dependency, directly unit-testable in Rust.
  • Swept all 9 duplicated inline implementations in array.rs (slice, splice, toSpliced, fill, copyWithin), string.rs (slice), and typedarray.rs (subarray, slice, copyWithin, fill) over to the shared helper.
  • Net diff: +81/-114 lines, despite adding 8 new unit tests — pure duplication removal.

Tests

Built test-first (TDD): 8 unit tests in src/interpreter/helpers.rs pin the helper's boundary behavior directly against the Rust function — no JS parsing or interpreter execution involved — added one vertical slice at a time before the call-site sweep:

  • in-range positive index unchanged
  • negative index counts back from length
  • positive index beyond length clamps to length
  • negative index beyond length clamps to zero
  • negative index exactly at the < vs <= boundary that previously diverged between implementations (both landed on 0; now pinned to prevent regression)
  • +Infinity/-Infinity clamp correctly
  • zero-length array clamps everything to zero

Test plan

  • cargo build --release — clean, no warnings
  • cargo test --bin jsse --release — 172/172 passing (including the 8 new unit tests)
  • ./scripts/lint.sh — clippy clean
  • uv run python scripts/run-custom-tests.py — 3/3 passing
  • uv run python scripts/run-test262.pynot run: this sandboxed environment's network access is scoped to the pmatos/jsse repo only, so the test262/spec git submodules (hosted at tc39/*) could not be fetched (git submodule update returns 403). Since this is a pure refactor preserving the exact clamping semantics (verified by the unit tests above, including the boundary case where prior implementations disagreed), a full test262 run on this branch is recommended before merge to confirm no regressions in built-ins/Array, built-ins/String, and built-ins/TypedArray*.

https://claude.ai/code/session_019oiTHXtesxw6uvcF31MU1p


Generated by Claude Code

…l clamping

The "if n < 0, clamp to max(0, len+n), else min(len, n)" relative-index
algorithm used by Array.prototype.slice/splice/toSpliced/fill/copyWithin,
String.prototype.slice, and the %TypedArray%.prototype equivalents was
hand-rolled independently at 9 call sites across array.rs, string.rs, and
typedarray.rs, with typedarray.rs alone reimplementing it 4 different ways
(including one inconsistency between `<` and `<=` at the lower boundary
that happened to still produce the same result). Consolidated into one
pure, directly unit-tested `resolve_relative_index` helper in helpers.rs.

Added via TDD: 8 unit tests pin the boundary/infinity/zero-length behavior
directly against the Rust function, with no JS parsing/interpreter
involved, before sweeping the call sites over to it.

🤖 Generated with Claude Code
Claude-Session: https://claude.ai/code/session_019oiTHXtesxw6uvcF31MU1p
@pmatos pmatos marked this pull request as ready for review July 1, 2026 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant