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.
This commit is contained in:
3
lvm.c
3
lvm.c
@@ -1549,9 +1549,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
luaF_close(L, base, NOCLOSINGMETH);
|
luaF_close(L, base, NOCLOSINGMETH);
|
||||||
lua_assert(base == ci->func + 1);
|
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 */
|
luaD_tryfuncTM(L, ra); /* try '__call' metamethod */
|
||||||
b++; /* there is now one extra argument */
|
b++; /* there is now one extra argument */
|
||||||
|
checkstackp(L, 1, ra);
|
||||||
}
|
}
|
||||||
if (!ttisLclosure(s2v(ra))) { /* C function? */
|
if (!ttisLclosure(s2v(ra))) { /* C function? */
|
||||||
luaD_call(L, ra, LUA_MULTRET); /* call it */
|
luaD_call(L, ra, LUA_MULTRET); /* call it */
|
||||||
|
|||||||
@@ -107,7 +107,9 @@ end
|
|||||||
deep(10)
|
deep(10)
|
||||||
deep(180)
|
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
|
function deep (n) if n>0 then return deep(n-1) else return 101 end end
|
||||||
assert(deep(30000) == 101)
|
assert(deep(30000) == 101)
|
||||||
a = {}
|
a = {}
|
||||||
@@ -148,6 +150,27 @@ do -- tail calls x varargs
|
|||||||
assert(X == 10 and Y == 20 and #A == 1 and A[1] == 30)
|
assert(X == 10 and Y == 20 and #A == 1 and A[1] == 30)
|
||||||
end
|
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('+')
|
print('+')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user