From bd96330d037660d9a1769c6c0d989f017e5f0278 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 17 Oct 2018 10:44:42 -0300 Subject: First "complete" implementation of to-be-closed variables Still missing: - handling of memory errors when creating upvalue (must run closing method all the same) - interaction with coroutines --- testes/api.lua | 14 +++++++++++- testes/locals.lua | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 6 deletions(-) (limited to 'testes') diff --git a/testes/api.lua b/testes/api.lua index bebb6d2d..925a80c1 100644 --- a/testes/api.lua +++ b/testes/api.lua @@ -1,4 +1,4 @@ --- $Id: testes/api.lua $ +-- $Id: testes/api.lua 2018-07-25 15:31:04 -0300 $ -- See Copyright Notice in file all.lua if T==nil then @@ -1027,6 +1027,18 @@ testamem("coroutine creation", function() end) +-- testing to-be-closed variables +testamem("to-be-closed variables", function() + local flag + do + local scoped x = function () flag = true end + flag = false + local x = {} + end + return flag +end) + + -- testing threads -- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1) diff --git a/testes/locals.lua b/testes/locals.lua index 20ecae4b..8d55e9f5 100644 --- a/testes/locals.lua +++ b/testes/locals.lua @@ -173,15 +173,69 @@ end assert(x==20) --- tests for to-be-closed variables +print"testing to-be-closed variables" + +do + local a = {} + do + local scoped x = setmetatable({"x"}, {__close = function (self) + a[#a + 1] = self[1] end}) + local scoped y = function () a[#a + 1] = "y" end + a[#a + 1] = "in" + end + a[#a + 1] = "out" + assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out") +end + + +do -- errors in __close + local log = {} + local function foo (err) + local scoped x = function (msg) log[#log + 1] = msg; error(1) end + local scoped x1 = function (msg) log[#log + 1] = msg; end + local scoped gc = function () collectgarbage() end + local scoped y = function (msg) log[#log + 1] = msg; error(2) end + local scoped z = function (msg) log[#log + 1] = msg or 10; error(3) end + if err then error(4) end + end + local stat, msg = pcall(foo, false) + assert(msg == 1) + assert(log[1] == 10 and log[2] == 3 and log[3] == 2 and log[4] == 2 + and #log == 4) + + log = {} + local stat, msg = pcall(foo, true) + assert(msg == 1) + assert(log[1] == 4 and log[2] == 3 and log[3] == 2 and log[4] == 2 + and #log == 4) +end + do - local scoped x = 3 - local a - local scoped y = 5 - assert(x == 3 and y == 5) + -- memory error inside closing function + local function foo () + local scoped y = function () io.write(2); T.alloccount() end + local scoped x = setmetatable({}, {__close = function () + T.alloccount(0); local x = {} -- force a memory error + end}) + io.write("1\n") + error("a") -- common error inside the function's body + end + + local _, msg = pcall(foo) +T.alloccount() + assert(msg == "not enough memory") + end +-- a suspended coroutine should not close its variables when collected +local co = coroutine.wrap(function() + local scoped x = function () os.exit(1) end -- should not run + coroutine.yield() +end) +co() +co = nil + print('OK') return 5,f -- cgit v1.2.3-55-g6feb