The Lua optimizer rule reduceTableDefinitionAccessor (lib/Language/PureScript/Backend/Lua/Optimizer.hs) rewrites { foo = 1, bar = 2 }.foo to 1, but it searches only TableRowNV rows and takes the first match via listToMaybe, falling back to Nil.
Two latent hazards follow. If codegen ever emits a string key in KV form (["foo"] = 1) for a field that is later accessed with VarField, the rule folds the access to Nil instead of the value. And on duplicate field names Lua's table constructor keeps the last occurrence while the rule returns the first.
Neither shape is currently produced by the codegen, so this is hardening rather than a live miscompile: the rule should refuse to match when the constructor contains any TableRowKV row or duplicate field names.
Found during the 2026-07-02 backend audit.
The Lua optimizer rule
reduceTableDefinitionAccessor(lib/Language/PureScript/Backend/Lua/Optimizer.hs) rewrites{ foo = 1, bar = 2 }.footo1, but it searches onlyTableRowNVrows and takes the first match vialistToMaybe, falling back toNil.Two latent hazards follow. If codegen ever emits a string key in KV form (
["foo"] = 1) for a field that is later accessed withVarField, the rule folds the access toNilinstead of the value. And on duplicate field names Lua's table constructor keeps the last occurrence while the rule returns the first.Neither shape is currently produced by the codegen, so this is hardening rather than a live miscompile: the rule should refuse to match when the constructor contains any
TableRowKVrow or duplicate field names.Found during the 2026-07-02 backend audit.