diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-31 10:43:51 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-31 10:43:51 -0300 |
commit | f645d3157372c73573dff221c5b26691cb0e7d56 (patch) | |
tree | 61adb1f332bbd8c0c0365b81cef8de47fa2ea06a /testes | |
parent | 35b4efc270db2418bc2cac6671575a45028061c3 (diff) | |
download | lua-f645d3157372c73573dff221c5b26691cb0e7d56.tar.gz lua-f645d3157372c73573dff221c5b26691cb0e7d56.tar.bz2 lua-f645d3157372c73573dff221c5b26691cb0e7d56.zip |
To-be-closed variables must be closed on initialization
When initializing a to-be-closed variable, check whether it has a
'__close' metamethod (or is a false value) and raise an error if
if it hasn't. This produces more accurate error messages. (The
check before closing still need to be done: in the C API, the value
is not constant; and the object may lose its '__close' metamethod
during the block.)
Diffstat (limited to 'testes')
-rw-r--r-- | testes/api.lua | 11 | ||||
-rw-r--r-- | testes/locals.lua | 23 |
2 files changed, 22 insertions, 12 deletions
diff --git a/testes/api.lua b/testes/api.lua index 3f7f7596..f6915c3e 100644 --- a/testes/api.lua +++ b/testes/api.lua | |||
@@ -1096,7 +1096,7 @@ do | |||
1096 | assert(type(a[1]) == "string" and a[2][1] == 11) | 1096 | assert(type(a[1]) == "string" and a[2][1] == 11) |
1097 | assert(#openresource == 0) -- was closed | 1097 | assert(#openresource == 0) -- was closed |
1098 | 1098 | ||
1099 | -- error | 1099 | -- closing by error |
1100 | local a, b = pcall(T.makeCfunc[[ | 1100 | local a, b = pcall(T.makeCfunc[[ |
1101 | call 0 1 # create resource | 1101 | call 0 1 # create resource |
1102 | toclose -1 # mark it to be closed | 1102 | toclose -1 # mark it to be closed |
@@ -1105,6 +1105,15 @@ do | |||
1105 | assert(a == false and b[1] == 11) | 1105 | assert(a == false and b[1] == 11) |
1106 | assert(#openresource == 0) -- was closed | 1106 | assert(#openresource == 0) -- was closed |
1107 | 1107 | ||
1108 | -- non-closable value | ||
1109 | local a, b = pcall(T.makeCfunc[[ | ||
1110 | newtable # create non-closable object | ||
1111 | toclose -1 # mark it to be closed (shoud raise an error) | ||
1112 | abort # will not be executed | ||
1113 | ]]) | ||
1114 | assert(a == false and | ||
1115 | string.find(b, "non%-closable value")) | ||
1116 | |||
1108 | local function check (n) | 1117 | local function check (n) |
1109 | assert(#openresource == n) | 1118 | assert(#openresource == n) |
1110 | end | 1119 | end |
diff --git a/testes/locals.lua b/testes/locals.lua index 3b145ca3..6eb1ba0e 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -215,11 +215,13 @@ end | |||
215 | do | 215 | do |
216 | local a = {} | 216 | local a = {} |
217 | do | 217 | do |
218 | local b <close> = false -- not to be closed | ||
218 | local x <close> = setmetatable({"x"}, {__close = function (self) | 219 | local x <close> = setmetatable({"x"}, {__close = function (self) |
219 | a[#a + 1] = self[1] end}) | 220 | a[#a + 1] = self[1] end}) |
220 | local w, y <close>, z = func2close(function (self, err) | 221 | local w, y <close>, z = func2close(function (self, err) |
221 | assert(err == nil); a[#a + 1] = "y" | 222 | assert(err == nil); a[#a + 1] = "y" |
222 | end, 10, 20) | 223 | end, 10, 20) |
224 | local c <close> = nil -- not to be closed | ||
223 | a[#a + 1] = "in" | 225 | a[#a + 1] = "in" |
224 | assert(w == 10 and z == 20) | 226 | assert(w == 10 and z == 20) |
225 | end | 227 | end |
@@ -325,24 +327,22 @@ do -- errors in __close | |||
325 | end | 327 | end |
326 | 328 | ||
327 | 329 | ||
328 | do | 330 | do -- errors due to non-closable values |
329 | |||
330 | -- errors due to non-closable values | ||
331 | local function foo () | 331 | local function foo () |
332 | local x <close> = {} | 332 | local x <close> = {} |
333 | os.exit(false) -- should not run | ||
333 | end | 334 | end |
334 | local stat, msg = pcall(foo) | 335 | local stat, msg = pcall(foo) |
335 | assert(not stat and string.find(msg, "variable 'x'")) | 336 | assert(not stat and |
337 | string.find(msg, "variable 'x' got a non%-closable value")) | ||
336 | 338 | ||
337 | |||
338 | -- with other errors, non-closable values are ignored | ||
339 | local function foo () | 339 | local function foo () |
340 | local x <close> = 34 | 340 | local xyz <close> = setmetatable({}, {__close = print}) |
341 | local y <close> = func2close(function () error(32) end) | 341 | getmetatable(xyz).__close = nil -- remove metamethod |
342 | end | 342 | end |
343 | local stat, msg = pcall(foo) | 343 | local stat, msg = pcall(foo) |
344 | assert(not stat and msg == 32) | 344 | assert(not stat and |
345 | 345 | string.find(msg, "attempt to close non%-closable variable 'xyz'")) | |
346 | end | 346 | end |
347 | 347 | ||
348 | 348 | ||
@@ -519,7 +519,8 @@ end | |||
519 | -- a suspended coroutine should not close its variables when collected | 519 | -- a suspended coroutine should not close its variables when collected |
520 | local co | 520 | local co |
521 | co = coroutine.wrap(function() | 521 | co = coroutine.wrap(function() |
522 | local x <close> = function () os.exit(false) end -- should not run | 522 | -- should not run |
523 | local x <close> = func2close(function () os.exit(false) end) | ||
523 | co = nil | 524 | co = nil |
524 | coroutine.yield() | 525 | coroutine.yield() |
525 | end) | 526 | end) |