Skip to content

ES module output: destructure #js [] arrays by index - #16

Merged
k7d merged 1 commit into
mainfrom
esm-destructure-arrays
Oct 30, 2026
Merged

k7d merged 1 commit into
mainfrom
esm-destructure-arrays

Conversation

@k7d

@k7d k7d commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Based on main.

In ES module output, sequential destructuring of a let local that certainly holds a JavaScript array reads it by index, (v?.[i] ?? null), instead of calling nth. The result is the same as nth's: the element within the array's bounds, nil past its end.

(let [[x y] #js [1 2]] ...)
const vec__1 = [1, 2];
const x = (vec__1?.[0] ?? null);
const y = (vec__1?.[1] ?? null);

What counts as an array: only a let local bound to a #js [] literal (cljs.analyzer/js-array-init?). Everything else goes through nth as before:

  • loop locals and params, which recur can rebind to other values;
  • values merely hinted ^array (a hinted param that gets a vector would break);
  • other JS calls.

React's array-returning hooks (useState and the like) are added to js-array-init? in #17, with the rest of the React Compiler logic.

Performance

Micro-benchmark (release build, rolldown-minified, Node 26, 3 runs):

Benchmark before this branch
destructure a JS array, 10M times ~113 ms ~45 ms (2.5× faster)
destructure a vector, 10M times (unchanged path) ~66 ms ~63 ms

Tests

  • script/test-esm: 0 failures, 0 errors. A new build test checks that #js [] literals are read by index (nil past their end), that vectors, other JS calls, loop locals and ^array hints go through nth, and that the output runs correctly.
  • Compiler tests: 0 failures, 0 errors.

@k7d

k7d commented Oct 29, 2026

Copy link
Copy Markdown
Member Author

Fixes from review (fdba401):

  • Past the end, v?.[i] was undefined, not nil. It now emits (v?.[i] ?? null), as nth returns.
  • Loop locals were trusted to stay arrays. Only let locals qualify now; recur can't assign those.
  • An ^array hint changed runtime semantics. A hinted param that received a vector got nil. Hints no longer qualify; only values certain to be arrays do.
  • React hook names were matched by name in the compiler. cljs.analyzer/js-array-init? now decides, by module and fn: react's (and preact/hooks', preact/compat's) useState, useReducer, useTransition, useActionState, useOptimistic and useFormState, or a #js [] literal. Another module's useState goes through nth.

The test now covers each case. script/test-esm and the compiler tests pass.

@k7d

k7d commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

Restacked on main with #21 merged (312dfa40), force-pushed:

The review-fix merges are folded into the branches' own commits. The code is unchanged apart from #21's changes. Only CHANGELOG.md and the build tests needed conflicts resolved, and each branch's [Next] section now has main's entries plus its own.

On every branch, script/test-esm and the compiler tests pass, including #21's new test-locals-munged-to-the-same-name. On #17 the Node tests pass too, and the react-compiler template works in the dev server (memoized rows).

@k7d
k7d changed the base branch from esm-for-self-ref to main October 30, 2026 12:40
@k7d
k7d force-pushed the esm-destructure-arrays branch from 2316608 to 458872c Compare October 30, 2026 12:40
… array reads it by index in ES module output
@k7d
k7d force-pushed the esm-destructure-arrays branch from 458872c to c97bad1 Compare October 30, 2026 13:05
@k7d k7d changed the title ES module output: destructure JavaScript arrays (React hooks' values) by index ES module output: destructure #js [] arrays by index Oct 30, 2026
@k7d
k7d marked this pull request as ready for review October 30, 2026 13:31
@k7d
k7d merged commit 97a2c4c into main Oct 30, 2026
9 checks passed
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