fix(lua): index assignment-style function definitions (#1650) (#1778)

Apply upstream PR #1623 by danusha2345 (fix commit aa777063),
which also addresses #1616, to the current main base. Preserve the
upstream WASM and Rust implementations and regression coverage.

Index assigned locals, table members, static string keys and nested
callback tables as callable symbols, with calls owned by those symbols.
Keep dynamic keys unguessed. Add #1650 to the Unreleased changelog and
retain the existing re-index guidance without an extraction-version bump.

Verified on Linux x64 with Node 22.19.0:
- native kernel build, tsc, asset copy, executable CLI
- issue repro: 3 nodes / 2 edges -> 4 nodes / 4 edges
- EPR.PowerController::SyncHydroPower is indexed; its caller is client.lua
- syncHydroPower depth-2 impact reaches client.lua
- extraction/resolution/Lua parity: 844 tests passed (kernel expected)
- forced-WASM Lua/Luau extraction/resolution: 20 tests passed

Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
This commit is contained in:
Colby Mchenry
2026-09-08 10:50:09 -05:00
committed by GitHub
co-authored by Colby McHenry
parent 195888d71f
commit 8c047342cd
8 changed files with 332 additions and 19 deletions
+16
View File
@@ -127,6 +127,22 @@ describe.skipIf(!kernelBuilt)('kernel Lua/Luau extraction parity', () => {
// lua functions carry NO isExported (undefined — not false).
const fn = result.nodes.find((n) => n.kind === 'function' && n.name === 'topFn');
expect(fn?.isExported).toBeUndefined();
expect(result.nodes.some((n) => n.kind === 'function' && n.name === 'anonAssigned')).toBe(true);
expect(result.nodes.some((n) => n.kind === 'method' && n.qualifiedName === 'M::assigned')).toBe(true);
expect(
result.nodes.some((n) => n.kind === 'method' && n.qualifiedName === 'M.callbacks::on_start')
).toBe(true);
expect(
result.nodes.some((n) => n.kind === 'method' && n.qualifiedName === 'M.callbacks::on_stop')
).toBe(true);
for (const qualifiedName of ['M::assigned', 'M.callbacks::on_start', 'M.callbacks::on_stop']) {
const callable = result.nodes.find((n) => n.qualifiedName === qualifiedName)!;
expect(
refs.some(
(r) => r.fromNodeId === callable.id && r.referenceKind === 'calls' && r.referenceName === 'topFn'
)
).toBe(true);
}
// variables DO carry isExported === false.
const v = result.nodes.find((n) => n.kind === 'variable' && n.name === 'core');
expect(v?.isExported).toBe(false);