diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-01-18 11:40:45 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-01-18 11:40:45 -0300 |
| commit | d0f34d91373fa265d4445e456e4a10ce206c1559 (patch) | |
| tree | 0389b97b7844634144158df06040ea89c63fda46 /testes | |
| parent | 825ac8eca8e384d6ad2538b5670088c31e08a9d7 (diff) | |
| download | lua-d0f34d91373fa265d4445e456e4a10ce206c1559.tar.gz lua-d0f34d91373fa265d4445e456e4a10ce206c1559.tar.bz2 lua-d0f34d91373fa265d4445e456e4a10ce206c1559.zip | |
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.
Diffstat (limited to 'testes')
| -rw-r--r-- | testes/locals.lua | 48 |
1 files changed, 40 insertions, 8 deletions
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 | |||
| 697 | 697 | ||
| 698 | 698 | ||
| 699 | do | 699 | do |
| 700 | -- yielding inside closing metamethods after an error: | 700 | -- yielding inside closing metamethods after an error |
| 701 | -- not yet implemented; raises an error | ||
| 702 | 701 | ||
| 703 | local co = coroutine.wrap(function () | 702 | local co = coroutine.wrap(function () |
| 704 | 703 | ||
| 705 | local function foo (err) | 704 | local function foo (err) |
| 706 | 705 | ||
| 706 | local z <close> = func2close(function(_, msg) | ||
| 707 | assert(msg == nil or msg == err + 20) | ||
| 708 | coroutine.yield("z") | ||
| 709 | return 100, 200 | ||
| 710 | end) | ||
| 711 | |||
| 712 | local y <close> = func2close(function(_, msg) | ||
| 713 | -- still gets the original error (if any) | ||
| 714 | assert(msg == err or (msg == nil and err == 1)) | ||
| 715 | coroutine.yield("y") | ||
| 716 | if err then error(err + 20) end -- creates or changes the error | ||
| 717 | end) | ||
| 718 | |||
| 707 | local x <close> = func2close(function(_, msg) | 719 | local x <close> = func2close(function(_, msg) |
| 708 | assert(msg == err) | 720 | assert(msg == err or (msg == nil and err == 1)) |
| 709 | coroutine.yield("x") | 721 | coroutine.yield("x") |
| 710 | return 100, 200 | 722 | return 100, 200 |
| 711 | end) | 723 | end) |
| 712 | 724 | ||
| 713 | if err then error(err) else return 10, 20 end | 725 | if err == 10 then error(err) else return 10, 20 end |
| 714 | end | 726 | end |
| 715 | 727 | ||
| 716 | coroutine.yield(pcall(foo, nil)) -- no error | 728 | coroutine.yield(pcall(foo, nil)) -- no error |
| 729 | coroutine.yield(pcall(foo, 1)) -- error in __close | ||
| 717 | return pcall(foo, 10) -- 'foo' will raise an error | 730 | return pcall(foo, 10) -- 'foo' will raise an error |
| 718 | end) | 731 | end) |
| 719 | 732 | ||
| 720 | local a, b = co() | 733 | local a, b = co() -- first foo: no error |
| 721 | assert(a == "x" and b == nil) -- yields inside 'x'; Ok | 734 | assert(a == "x" and b == nil) -- yields inside 'x'; Ok |
| 722 | 735 | a, b = co() | |
| 736 | assert(a == "y" and b == nil) -- yields inside 'y'; Ok | ||
| 737 | a, b = co() | ||
| 738 | assert(a == "z" and b == nil) -- yields inside 'z'; Ok | ||
| 723 | local a, b, c = co() | 739 | local a, b, c = co() |
| 724 | assert(a and b == 10 and c == 20) -- returns from 'pcall(foo, nil)' | 740 | assert(a and b == 10 and c == 20) -- returns from 'pcall(foo, nil)' |
| 725 | 741 | ||
| 726 | local st, msg = co() -- error yielding after an error | 742 | local a, b = co() -- second foo: error in __close |
| 727 | assert(not st and string.find(msg, "attempt to yield")) | 743 | assert(a == "x" and b == nil) -- yields inside 'x'; Ok |
| 744 | a, b = co() | ||
| 745 | assert(a == "y" and b == nil) -- yields inside 'y'; Ok | ||
| 746 | a, b = co() | ||
| 747 | assert(a == "z" and b == nil) -- yields inside 'z'; Ok | ||
| 748 | local st, msg = co() -- reports the error in 'y' | ||
| 749 | assert(not st and msg == 21) | ||
| 750 | |||
| 751 | local a, b = co() -- third foo: error in function body | ||
| 752 | assert(a == "x" and b == nil) -- yields inside 'x'; Ok | ||
| 753 | a, b = co() | ||
| 754 | assert(a == "y" and b == nil) -- yields inside 'y'; Ok | ||
| 755 | a, b = co() | ||
| 756 | assert(a == "z" and b == nil) -- yields inside 'z'; Ok | ||
| 757 | local st, msg = co() -- gets final error | ||
| 758 | assert(not st and msg == 10 + 20) | ||
| 759 | |||
| 728 | end | 760 | end |
| 729 | 761 | ||
| 730 | 762 | ||
