Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7d526e7

Browse files
committed
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.
1 parent c12983c commit 7d526e7

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

lvm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1549,9 +1549,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
15491549
luaF_close(L, base, NOCLOSINGMETH);
15501550
lua_assert(base == ci->func + 1);
15511551
}
1552-
if (!ttisfunction(s2v(ra))) { /* not a function? */
1552+
while (!ttisfunction(s2v(ra))) { /* not a function? */
15531553
luaD_tryfuncTM(L, ra); /* try '__call' metamethod */
15541554
b++; /* there is now one extra argument */
1555+
checkstackp(L, 1, ra);
15551556
}
15561557
if (!ttisLclosure(s2v(ra))) { /* C function? */
15571558
luaD_call(L, ra, LUA_MULTRET); /* call it */

testes/calls.lua

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ end
107107
deep(10)
108108
deep(180)
109109

110-
-- testing tail calls
110+
111+
print"testing tail calls"
112+
111113
function deep (n) if n>0 then return deep(n-1) else return 101 end end
112114
assert(deep(30000) == 101)
113115
a = {}
@@ -148,6 +150,27 @@ do -- tail calls x varargs
148150
assert(X == 10 and Y == 20 and #A == 1 and A[1] == 30)
149151
end
150152

153+
154+
155+
do -- tail calls x chain of __call
156+
local n = 10000 -- depth
157+
158+
local function foo ()
159+
if n == 0 then return 1023
160+
else n = n - 1; return foo()
161+
end
162+
end
163+
164+
-- build a chain of __call metamethods ending in function 'foo'
165+
for i = 1, 100 do
166+
foo = setmetatable({}, {__call = foo})
167+
end
168+
169+
-- call the first one as a tail call in a new coroutine
170+
-- (to ensure stack is not preallocated)
171+
assert(coroutine.wrap(function() return foo() end)() == 1023)
172+
end
173+
151174
print('+')
152175

153176

0 commit comments

Comments
 (0)