Skip to content

Method-call obj:method(unpack(args)) drops all but first unpacked value #247

@davydog187

Description

@davydog187

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:

direct:     n=3
method:     n=1

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions