Skip to content

Commit

Permalink
issue #163 Couple of more tests for coroutines and deferred functions…
Browse files Browse the repository at this point in the history
…, plus some changes in ldo.c back-ported from Lua 5.4
  • Loading branch information
dibyendumajumdar committed Jul 5, 2020
1 parent e832dcc commit b63005f
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 13 deletions.
25 changes: 12 additions & 13 deletions src/ldo.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
}
else { /* thread has no error handler */
global_State *g = G(L);
errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */
L->status = cast_byte(errcode); /* mark it as dead */
if (g->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
Expand Down Expand Up @@ -767,19 +768,17 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, &nargs);
if (status == -1) /* error calling 'lua_resume'? */
status = LUA_ERRRUN;
else { /* continue running after recoverable errors */
while (errorstatus(status) && recover(L, status)) {
/* unroll continuation */
status = luaD_rawrunprotected(L, unroll, &status);
}
if (errorstatus(status)) { /* unrecoverable error? */
L->status = cast_byte(status); /* mark thread as 'dead' */
luaD_seterrorobj(L, status, L->top); /* push error message */
L->ci->top = L->top;
}
else lua_assert(status == L->status); /* normal end or yield */
/* continue running after recoverable errors */
while (errorstatus(status) && recover(L, status)) {
/* unroll continuation */
status = luaD_rawrunprotected(L, unroll, &status);
}
if (likely(!errorstatus(status)))
lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */
luaD_seterrorobj(L, status, L->top); /* push error message */
L->ci->top = L->top;
}
L->nny = oldnny; /* restore 'nny' */
L->nCcalls--;
Expand Down
58 changes: 58 additions & 0 deletions tests/language/defer_tests.ravi
Original file line number Diff line number Diff line change
Expand Up @@ -424,4 +424,62 @@ do
print 'Test 10 OK'
end

-- a suspended coroutine should not close its variables when collected
do
function t()
local co
co = coroutine.wrap(function()
-- should not run
local x = func2close(function () os.exit(false) end)
defer getmetatable(x).__close(x) end
co = nil
coroutine.yield()
end)
co() -- start coroutine
assert(co == nil) -- eventually it will be collected
collectgarbage()
end
t()
compile(t)
t()
print 'Test 11 OK'
end

do
local function t()
-- error in a wrapped coroutine raising errors when closing a variable
local x = 0
local co = coroutine.wrap(function ()
local xx = func2close(function () x = x + 1; error("@YYY") end)
defer getmetatable(xx).__close(xx) end
local xv = func2close(function () x = x + 1; error("@XXX") end)
defer getmetatable(xv).__close(xv) end
coroutine.yield(100)
error(200)
end)
assert(co() == 100); assert(x == 0)
local st, msg = pcall(co); assert(x == 2)
assert(not st and msg == 200) -- should get first error raised

local x = 0
local y = 0
co = coroutine.wrap(function ()
local xx = func2close(function () y = y + 1; error("YYY") end)
defer getmetatable(xx).__close(xx) end
local xv = func2close(function () x = x + 1; error("XXX") end)
defer getmetatable(xv).__close(xv) end
coroutine.yield(100)
return 200
end)
assert(co() == 100); assert(x == 0)
local st, msg = pcall(co)
assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
assert(x == 1 and y == 1)
end
t()
compile(t)
t()
print 'Test 12 OK'
end

print 'OK'

0 comments on commit b63005f

Please sign in to comment.