Skip to content

fix(stdlib): route cache_module_result through Table.put so required modules appear in pairs(package.loaded)#356

Merged
davydog187 merged 1 commit into
mainfrom
fix/package-loaded-pairs-visibility
Jun 11, 2026
Merged

fix(stdlib): route cache_module_result through Table.put so required modules appear in pairs(package.loaded)#356
davydog187 merged 1 commit into
mainfrom
fix/package-loaded-pairs-visibility

Conversation

@davydog187

Copy link
Copy Markdown
Contributor

What

Route Lua.VM.Stdlib.cache_module_result/3 through Table.put/3 instead of writing Table.data directly, so a freshly require()d module is visible to for k in pairs(package.loaded).

Why this is a separate PR

This fix was developed on the perf/table-hash-iteration branch (#349) during review, but #349 was squash-merged from a stale head (128c73e) that predated the fix commit, so the correction never reached main. The bug is therefore live in main today:

lib/lua/vm/stdlib.ex:788:  %{loaded_table | data: Map.put(loaded_table.data, modname, result)}

cache_module_result/3 was the only writer of Table.data outside table.ex. The direct map write bypasses the order/order_tail and memoized iteration-order bookkeeping that #349 introduced, so the new module key is reachable by direct index (package.loaded.foo) but never enumerated by pairs.

The fix

One line — route the write through the single maintained mutation path:

# before
%{loaded_table | data: Map.put(loaded_table.data, modname, result)}
# after
Table.put(loaded_table, modname, result)

Coverage

  • test/lua/vm/stdlib/package_test.exs — load-bearing regression test: a newly required module is seen by a full pairs(package.loaded) walk (fails on the direct-write form, passes through Table.put).
  • test/lua/vm/table_iteration_test.exs — memo-invalidation / absorb-after-flush / replace_data reset coverage for the iteration-order machinery.
  • benchmarks/table_ops.exs — a pairs hash-arm benchmark exercising the O(1)-per-step advance path.

Scope is deliberately limited to the stranded fix; unrelated commits that were on the perf branch (and already in main) are excluded.

🤖 Surfaced by an adversarial multi-lens review pass.

… modules are visible to pairs

The package.loaded cache wrote the required module's key directly into
loaded_table.data via Map.put, bypassing Table.put and its iteration-order
bookkeeping. Key-access (package.loaded[name]) still worked, but the key
never entered the order/memo maps, so a freshly required module was
invisible to `for k in pairs(package.loaded)`.

This was fixed on the perf/table-hash-iteration branch but the PR (#349)
was squash-merged from a stale head that predated the fix, shipping the
bug to main. Re-applies the one-line stdlib fix plus the pairs-visibility
regression test, the table-iteration memo-invalidation/replace_data
coverage, and the pairs_hash benchmark, all of which were stranded on the
merged branch.

Co-authored-by: Dave Lucia <dave@tvlabs.ai>
@davydog187 davydog187 merged commit fde2576 into main Jun 11, 2026
5 checks passed
@davydog187 davydog187 deleted the fix/package-loaded-pairs-visibility branch June 11, 2026 13:36
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