Fixed bug in tail calls of __call chains
A tail call of a __call chain (a __call metamethod that itself is
also not a function) was being perfomed as a regular call.
diff --git a/lvm.c b/lvm.c
index 5407d14..2c96c58 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1549,9 +1549,10 @@
luaF_close(L, base, NOCLOSINGMETH);
lua_assert(base == ci->func + 1);
}
- if (!ttisfunction(s2v(ra))) { /* not a function? */
+ while (!ttisfunction(s2v(ra))) { /* not a function? */
luaD_tryfuncTM(L, ra); /* try '__call' metamethod */
b++; /* there is now one extra argument */
+ checkstackp(L, 1, ra);
}
if (!ttisLclosure(s2v(ra))) { /* C function? */
luaD_call(L, ra, LUA_MULTRET); /* call it */
diff --git a/testes/calls.lua b/testes/calls.lua
index 739a624..0141ffa 100644
--- a/testes/calls.lua
+++ b/testes/calls.lua
@@ -107,7 +107,9 @@
deep(10)
deep(180)
--- testing tail calls
+
+print"testing tail calls"
+
function deep (n) if n>0 then return deep(n-1) else return 101 end end
assert(deep(30000) == 101)
a = {}
@@ -148,6 +150,27 @@
assert(X == 10 and Y == 20 and #A == 1 and A[1] == 30)
end
+
+
+do -- tail calls x chain of __call
+ local n = 10000 -- depth
+
+ local function foo ()
+ if n == 0 then return 1023
+ else n = n - 1; return foo()
+ end
+ end
+
+ -- build a chain of __call metamethods ending in function 'foo'
+ for i = 1, 100 do
+ foo = setmetatable({}, {__call = foo})
+ end
+
+ -- call the first one as a tail call in a new coroutine
+ -- (to ensure stack is not preallocated)
+ assert(coroutine.wrap(function() return foo() end)() == 1023)
+end
+
print('+')