Summary
The method-call syntax obj:method(unpack(args)) drops all but the first
unpacked value. The implicit self argument appears to consume the
multi-value slot that the unpack expansion was supposed to fill, leaving
the rest of the unpacked tail unreachable to the callee.
Reference Lua treats t:m(unpack(vals)) as sugar for
t.m(t, vals[1], vals[2], ...). Lua-elixir only forwards t.m(t, vals[1]).
Reproduction
Tested against lua at commit
7a498b7
(also reproduces on 1.0.0-rc.0).
Lua.eval!(Lua.new(), """
local t = {}
function t:m(...)
return select('#', ...), ...
end
local vals = {"a", "b", "c"}
-- Positional form — desugared by hand:
local n1 = t.m(t, table.unpack(vals))
print("direct: n=" .. n1) -- prints: direct: n=3
-- Method-call form — should be equivalent:
local n2 = t:m(table.unpack(vals))
print("method: n=" .. n2) -- prints: method: n=1 ← bug
return n1, n2
""")
Output:
A user-visible knock-on is that ("%s,%s,%s"):format(table.unpack(args))
crashes with a MatchError because string.format receives an empty
varargs and tries to consume an argument for each %s:
Lua.eval!(Lua.new(), """
local args = {"a", "b", "c"}
return ("[%s,%s,%s]"):format(table.unpack(args))
""")
** (Lua.RuntimeException) Lua runtime error: no match of right hand side value:
[]
(lua 1.0.0-rc.0) lib/lua/vm/stdlib/string.ex:342: Lua.VM.Stdlib.String.format_string/3
(lua 1.0.0-rc.0) lib/lua/vm/stdlib/string.ex:317: Lua.VM.Stdlib.String.string_format/2
(The positional form string.format("[%s,%s,%s]", table.unpack(args))
works correctly.)
Expected
t:m(unpack(vals)) should pass t, vals[1], vals[2], …, vals[#vals] to
m, matching reference Lua 5.3 semantics.
Workaround
Use the positional call form (obj.method(obj, unpack(args)) or
string.format(fmt, unpack(args))) until this is fixed.
Related
Surfaces in luassert / say via this line in
say/init.lua:
return #strings > 0 and str:format(unpack(strings)) or str
Summary
The method-call syntax
obj:method(unpack(args))drops all but the firstunpacked value. The implicit
selfargument appears to consume themulti-value slot that the unpack expansion was supposed to fill, leaving
the rest of the unpacked tail unreachable to the callee.
Reference Lua treats
t:m(unpack(vals))as sugar fort.m(t, vals[1], vals[2], ...). Lua-elixir only forwardst.m(t, vals[1]).Reproduction
Tested against
luaat commit7a498b7(also reproduces on
1.0.0-rc.0).Output:
A user-visible knock-on is that
("%s,%s,%s"):format(table.unpack(args))crashes with a MatchError because
string.formatreceives an emptyvarargs and tries to consume an argument for each
%s:(The positional form
string.format("[%s,%s,%s]", table.unpack(args))works correctly.)
Expected
t:m(unpack(vals))should passt, vals[1], vals[2], …, vals[#vals]tom, matching reference Lua 5.3 semantics.Workaround
Use the positional call form (
obj.method(obj, unpack(args))orstring.format(fmt, unpack(args))) until this is fixed.Related
Surfaces in
luassert/sayvia this line insay/init.lua: