From d0f34d91373fa265d4445e456e4a10ce206c1559 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 18 Jan 2021 11:40:45 -0300 Subject: Allow yields in '__close' metamethods ater errors Completes commit b07fc10e91a. '__close' metamethods can yield even when they are being called due to an error. '__close' metamethods from C functions are still not allowed to yield. --- testes/locals.lua | 48 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) (limited to 'testes') diff --git a/testes/locals.lua b/testes/locals.lua index c9c93ccf..8506195e 100644 --- a/testes/locals.lua +++ b/testes/locals.lua @@ -697,34 +697,66 @@ end do - -- yielding inside closing metamethods after an error: - -- not yet implemented; raises an error + -- yielding inside closing metamethods after an error local co = coroutine.wrap(function () local function foo (err) + local z = func2close(function(_, msg) + assert(msg == nil or msg == err + 20) + coroutine.yield("z") + return 100, 200 + end) + + local y = func2close(function(_, msg) + -- still gets the original error (if any) + assert(msg == err or (msg == nil and err == 1)) + coroutine.yield("y") + if err then error(err + 20) end -- creates or changes the error + end) + local x = func2close(function(_, msg) - assert(msg == err) + assert(msg == err or (msg == nil and err == 1)) coroutine.yield("x") return 100, 200 end) - if err then error(err) else return 10, 20 end + if err == 10 then error(err) else return 10, 20 end end coroutine.yield(pcall(foo, nil)) -- no error + coroutine.yield(pcall(foo, 1)) -- error in __close return pcall(foo, 10) -- 'foo' will raise an error end) - local a, b = co() + local a, b = co() -- first foo: no error assert(a == "x" and b == nil) -- yields inside 'x'; Ok - + a, b = co() + assert(a == "y" and b == nil) -- yields inside 'y'; Ok + a, b = co() + assert(a == "z" and b == nil) -- yields inside 'z'; Ok local a, b, c = co() assert(a and b == 10 and c == 20) -- returns from 'pcall(foo, nil)' - local st, msg = co() -- error yielding after an error - assert(not st and string.find(msg, "attempt to yield")) + local a, b = co() -- second foo: error in __close + assert(a == "x" and b == nil) -- yields inside 'x'; Ok + a, b = co() + assert(a == "y" and b == nil) -- yields inside 'y'; Ok + a, b = co() + assert(a == "z" and b == nil) -- yields inside 'z'; Ok + local st, msg = co() -- reports the error in 'y' + assert(not st and msg == 21) + + local a, b = co() -- third foo: error in function body + assert(a == "x" and b == nil) -- yields inside 'x'; Ok + a, b = co() + assert(a == "y" and b == nil) -- yields inside 'y'; Ok + a, b = co() + assert(a == "z" and b == nil) -- yields inside 'z'; Ok + local st, msg = co() -- gets final error + assert(not st and msg == 10 + 20) + end -- cgit v1.2.3-55-g6feb