Skip to content

fix(api): tighten public surface before the 1.0 freeze#380

Merged
davydog187 merged 3 commits into
mainfrom
fix/api-pre-freeze
Jul 5, 2026
Merged

fix(api): tighten public surface before the 1.0 freeze#380
davydog187 merged 3 commits into
mainfrom
fix/api-pre-freeze

Conversation

@davydog187

Copy link
Copy Markdown
Contributor

API pre-freeze fixes: struct encoding, dead guard, option consistency

Plan: .agents/plans/A50-api-pre-freeze.md

These are the public-API sharp edges that would become breaking changes once 1.0 freezes the surface. Each must land before the freeze so the fix isn't a breaking change later.

Changes

  1. Bare-struct encoding now raises (lib/lua/vm/value.ex). Structs are maps, so Lua.encode!(lua, %MyStruct{}) (and Lua.set!/3) silently encoded a Lua table carrying a "__struct__" key. A new %mod{} clause (before the is_map clause) raises Lua.RuntimeException with a message pointing at Map.from_struct/1 and noting the planned Lua.Encoder protocol (Ergonomic encode/decode for deflua (Lua.Encoder protocol + auto-marshalling) #341). Why before freeze: if struct encoding "works" accidentally today, adding the protocol in 1.1 becomes breaking instead of additive. Audit found no struct legitimately encoded in lib/ or test/ today.
  2. Removed the dead is_mfa/1 guard (lib/lua/api.ex). A Luerl-era shim that always returned false, imported into every use Lua.API module. Removed the guard and the import entry; cleaned up the only other references (comments in a skipped test). Why before freeze: removing an exported guard after freeze is breaking.
  3. Documented closure/tag tuples as unstableis_lua_func/1, is_erl_func/1, and Lua.unwrap/1 now carry warnings that the :lua_closure / :compiled_closure / :native_func / :tref tuple internals are not stable API; use the guards. No tags were restructured.
  4. :max_string_bytes accepts :infinity (lib/lua.ex, lib/lua/vm/state.ex, lib/lua/vm/limits.ex), uniform with :max_call_depth and :max_instructions. Enforcement is already :infinity-safe via Erlang term ordering (every number sorts below every atom); documented at the check site.
  5. eval!/3 chunk clause accepts :source (lib/lua.ex). The string clause validated [decode:, source:] but the chunk clause only [decode:], so eval!(lua, chunk, source: "x") raised via Keyword.validate!. The chunk already carries its compiled-in source name, so :source is accepted but ignored (documented).
  6. Documented call_function/3's error shape — added doctests showing {:error, reason, lua} where reason is the raw Lua-facing pcall error value (non-string values pass through verbatim; strings carry the source:line: prefix), distinct from the terminal-formatted call_function!/3.
  7. Removed Lua.CompilerException's :state field — it was never populated (always nil). Moduledoc field list updated.
  8. Reworded Lua.VM moduledoc from "Public API" to internal (kept readable for source/IEx readers); noted :reset_instructions is require-reentrancy machinery, not user API.
  9. CHANGELOG Unreleased entries for items 1, 2, 4, 5, 7 in clearly-labeled subsections (breaking-before-freeze changes called out explicitly).

Verification

mix format --check-formatted   # clean
mix compile --warnings-as-errors  # clean (lua app, no warnings)
mix test                       # 2580 passed, 7 skipped, 30 excluded
mix test --only lua53          # 20 passed, 9 skipped
mix docs --warnings-as-errors  # generated, no warnings

Out of scope (intentional)

Plan: A50

Fix the API sharp edges that would become breaking changes once 1.0
freezes the surface: bare struct encoding now raises a helpful error
(keeping the planned Lua.Encoder protocol additive), the dead is_mfa/1
compat guard is removed, :max_string_bytes accepts :infinity uniform
with its siblings, eval!/3 accepts :source on the chunk clause, and the
never-populated CompilerException :state field is dropped. Also documents
closure/tag-tuple internals as unstable and reframes Lua.VM as internal.

Plan: A50
@davydog187 davydog187 merged commit 00df159 into main Jul 5, 2026
5 checks passed
@davydog187 davydog187 deleted the fix/api-pre-freeze branch July 5, 2026 20:20
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