locals.lua 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159
  1. -- $Id: testes/locals.lua $
  2. -- See Copyright Notice in file all.lua
  3. print('testing local variables and environments')
  4. local debug = require"debug"
  5. local tracegc = require"tracegc"
  6. -- bug in 5.1:
  7. local function f(x) x = nil; return x end
  8. assert(f(10) == nil)
  9. local function f() local x; return x end
  10. assert(f(10) == nil)
  11. local function f(x) x = nil; local y; return x, y end
  12. assert(f(10) == nil and select(2, f(20)) == nil)
  13. do
  14. local i = 10
  15. do local i = 100; assert(i==100) end
  16. do local i = 1000; assert(i==1000) end
  17. assert(i == 10)
  18. if i ~= 10 then
  19. local i = 20
  20. else
  21. local i = 30
  22. assert(i == 30)
  23. end
  24. end
  25. f = nil
  26. local f
  27. x = 1
  28. a = nil
  29. load('local a = {}')()
  30. assert(a == nil)
  31. function f (a)
  32. local _1, _2, _3, _4, _5
  33. local _6, _7, _8, _9, _10
  34. local x = 3
  35. local b = a
  36. local c,d = a,b
  37. if (d == b) then
  38. local x = 'q'
  39. x = b
  40. assert(x == 2)
  41. else
  42. assert(nil)
  43. end
  44. assert(x == 3)
  45. local f = 10
  46. end
  47. local b=10
  48. local a; repeat local b; a,b=1,2; assert(a+1==b); until a+b==3
  49. assert(x == 1)
  50. f(2)
  51. assert(type(f) == 'function')
  52. local function getenv (f)
  53. local a,b = debug.getupvalue(f, 1)
  54. assert(a == '_ENV')
  55. return b
  56. end
  57. -- test for global table of loaded chunks
  58. assert(getenv(load"a=3") == _G)
  59. local c = {}; local f = load("a = 3", nil, nil, c)
  60. assert(getenv(f) == c)
  61. assert(c.a == nil)
  62. f()
  63. assert(c.a == 3)
  64. -- old test for limits for special instructions
  65. do
  66. local i = 2
  67. local p = 4 -- p == 2^i
  68. repeat
  69. for j=-3,3 do
  70. assert(load(string.format([[local a=%s;
  71. a=a+%s;
  72. assert(a ==2^%s)]], j, p-j, i), '')) ()
  73. assert(load(string.format([[local a=%s;
  74. a=a-%s;
  75. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  76. assert(load(string.format([[local a,b=0,%s;
  77. a=b-%s;
  78. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  79. end
  80. p = 2 * p; i = i + 1
  81. until p <= 0
  82. end
  83. print'+'
  84. if rawget(_G, "T") then
  85. -- testing clearing of dead elements from tables
  86. collectgarbage("stop") -- stop GC
  87. local a = {[{}] = 4, [3] = 0, alo = 1,
  88. a1234567890123456789012345678901234567890 = 10}
  89. local t = T.querytab(a)
  90. for k,_ in pairs(a) do a[k] = undef end
  91. collectgarbage() -- restore GC and collect dead fields in 'a'
  92. for i=0,t-1 do
  93. local k = querytab(a, i)
  94. assert(k == nil or type(k) == 'number' or k == 'alo')
  95. end
  96. -- testing allocation errors during table insertions
  97. local a = {}
  98. local function additems ()
  99. a.x = true; a.y = true; a.z = true
  100. a[1] = true
  101. a[2] = true
  102. end
  103. for i = 1, math.huge do
  104. T.alloccount(i)
  105. local st, msg = pcall(additems)
  106. T.alloccount()
  107. local count = 0
  108. for k, v in pairs(a) do
  109. assert(a[k] == v)
  110. count = count + 1
  111. end
  112. if st then assert(count == 5); break end
  113. end
  114. end
  115. -- testing lexical environments
  116. assert(_ENV == _G)
  117. do
  118. local dummy
  119. local _ENV = (function (...) return ... end)(_G, dummy) -- {
  120. do local _ENV = {assert=assert}; assert(true) end
  121. mt = {_G = _G}
  122. local foo,x
  123. A = false -- "declare" A
  124. do local _ENV = mt
  125. function foo (x)
  126. A = x
  127. do local _ENV = _G; A = 1000 end
  128. return function (x) return A .. x end
  129. end
  130. end
  131. assert(getenv(foo) == mt)
  132. x = foo('hi'); assert(mt.A == 'hi' and A == 1000)
  133. assert(x('*') == mt.A .. '*')
  134. do local _ENV = {assert=assert, A=10};
  135. do local _ENV = {assert=assert, A=20};
  136. assert(A==20);x=A
  137. end
  138. assert(A==10 and x==20)
  139. end
  140. assert(x==20)
  141. do -- constants
  142. local a<const>, b, c<const> = 10, 20, 30
  143. b = a + c + b -- 'b' is not constant
  144. assert(a == 10 and b == 60 and c == 30)
  145. local function checkro (name, code)
  146. local st, msg = load(code)
  147. local gab = string.format("attempt to assign to const variable '%s'", name)
  148. assert(not st and string.find(msg, gab))
  149. end
  150. checkro("y", "local x, y <const>, z = 10, 20, 30; x = 11; y = 12")
  151. checkro("x", "local x <const>, y, z <const> = 10, 20, 30; x = 11")
  152. checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
  153. checkro("foo", "local foo <const> = 10; function foo() end")
  154. checkro("foo", "local foo <const> = {}; function foo() end")
  155. checkro("z", [[
  156. local a, z <const>, b = 10;
  157. function foo() a = 20; z = 32; end
  158. ]])
  159. checkro("var1", [[
  160. local a, var1 <const> = 10;
  161. function foo() a = 20; z = function () var1 = 12; end end
  162. ]])
  163. end
  164. print"testing to-be-closed variables"
  165. local function stack(n) n = ((n == 0) or stack(n - 1)) end
  166. local function func2close (f, x, y)
  167. local obj = setmetatable({}, {__close = f})
  168. if x then
  169. return x, obj, y
  170. else
  171. return obj
  172. end
  173. end
  174. do
  175. local a = {}
  176. do
  177. local b <close> = false -- not to be closed
  178. local x <close> = setmetatable({"x"}, {__close = function (self)
  179. a[#a + 1] = self[1] end})
  180. local w, y <close>, z = func2close(function (self, err)
  181. assert(err == nil); a[#a + 1] = "y"
  182. end, 10, 20)
  183. local c <close> = nil -- not to be closed
  184. a[#a + 1] = "in"
  185. assert(w == 10 and z == 20)
  186. end
  187. a[#a + 1] = "out"
  188. assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out")
  189. end
  190. do
  191. local X = false
  192. local x, closescope = func2close(function (_, msg)
  193. stack(10);
  194. assert(msg == nil)
  195. X = true
  196. end, 100)
  197. assert(x == 100); x = 101; -- 'x' is not read-only
  198. -- closing functions do not corrupt returning values
  199. local function foo (x)
  200. local _ <close> = closescope
  201. return x, X, 23
  202. end
  203. local a, b, c = foo(1.5)
  204. assert(a == 1.5 and b == false and c == 23 and X == true)
  205. X = false
  206. foo = function (x)
  207. local _<close> = func2close(function (_, msg)
  208. -- without errors, enclosing function should be still active when
  209. -- __close is called
  210. assert(debug.getinfo(2).name == "foo")
  211. assert(msg == nil)
  212. end)
  213. local _<close> = closescope
  214. local y = 15
  215. return y
  216. end
  217. assert(foo() == 15 and X == true)
  218. X = false
  219. foo = function ()
  220. local x <close> = closescope
  221. return x
  222. end
  223. assert(foo() == closescope and X == true)
  224. end
  225. -- testing to-be-closed x compile-time constants
  226. -- (there were some bugs here in Lua 5.4-rc3, due to a confusion
  227. -- between compile levels and stack levels of variables)
  228. do
  229. local flag = false
  230. local x = setmetatable({},
  231. {__close = function() assert(flag == false); flag = true end})
  232. local y <const> = nil
  233. local z <const> = nil
  234. do
  235. local a <close> = x
  236. end
  237. assert(flag) -- 'x' must be closed here
  238. end
  239. do
  240. -- similar problem, but with implicit close in for loops
  241. local flag = false
  242. local x = setmetatable({},
  243. {__close = function () assert(flag == false); flag = true end})
  244. -- return an empty iterator, nil, nil, and 'x' to be closed
  245. local function a ()
  246. return (function () return nil end), nil, nil, x
  247. end
  248. local v <const> = 1
  249. local w <const> = 1
  250. local x <const> = 1
  251. local y <const> = 1
  252. local z <const> = 1
  253. for k in a() do
  254. a = k
  255. end -- ending the loop must close 'x'
  256. assert(flag) -- 'x' must be closed here
  257. end
  258. do
  259. -- calls cannot be tail in the scope of to-be-closed variables
  260. local X, Y
  261. local function foo ()
  262. local _ <close> = func2close(function () Y = 10 end)
  263. assert(X == true and Y == nil) -- 'X' not closed yet
  264. return 1,2,3
  265. end
  266. local function bar ()
  267. local _ <close> = func2close(function () X = false end)
  268. X = true
  269. do
  270. return foo() -- not a tail call!
  271. end
  272. end
  273. local a, b, c, d = bar()
  274. assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil)
  275. end
  276. do
  277. -- bug in 5.4.3: previous condition (calls cannot be tail in the
  278. -- scope of to-be-closed variables) must be valid for tbc variables
  279. -- created by 'for' loops.
  280. local closed = false
  281. local function foo ()
  282. return function () return true end, 0, 0,
  283. func2close(function () closed = true end)
  284. end
  285. local function tail() return closed end
  286. local function foo1 ()
  287. for k in foo() do return tail() end
  288. end
  289. assert(foo1() == false)
  290. assert(closed == true)
  291. end
  292. do print("testing errors in __close")
  293. -- original error is in __close
  294. local function foo ()
  295. local x <close> =
  296. func2close(function (self, msg)
  297. assert(string.find(msg, "@y"))
  298. error("@x")
  299. end)
  300. local x1 <close> =
  301. func2close(function (self, msg)
  302. assert(string.find(msg, "@y"))
  303. end)
  304. local gc <close> = func2close(function () collectgarbage() end)
  305. local y <close> =
  306. func2close(function (self, msg)
  307. assert(string.find(msg, "@z")) -- error in 'z'
  308. error("@y")
  309. end)
  310. local z <close> =
  311. func2close(function (self, msg)
  312. assert(msg == nil)
  313. error("@z")
  314. end)
  315. return 200
  316. end
  317. local stat, msg = pcall(foo, false)
  318. assert(string.find(msg, "@x"))
  319. -- original error not in __close
  320. local function foo ()
  321. local x <close> =
  322. func2close(function (self, msg)
  323. -- after error, 'foo' was discarded, so caller now
  324. -- must be 'pcall'
  325. assert(debug.getinfo(2).name == "pcall")
  326. assert(string.find(msg, "@x1"))
  327. end)
  328. local x1 <close> =
  329. func2close(function (self, msg)
  330. assert(debug.getinfo(2).name == "pcall")
  331. assert(string.find(msg, "@y"))
  332. error("@x1")
  333. end)
  334. local gc <close> = func2close(function () collectgarbage() end)
  335. local y <close> =
  336. func2close(function (self, msg)
  337. assert(debug.getinfo(2).name == "pcall")
  338. assert(string.find(msg, "@z"))
  339. error("@y")
  340. end)
  341. local first = true
  342. local z <close> =
  343. func2close(function (self, msg)
  344. assert(debug.getinfo(2).name == "pcall")
  345. -- 'z' close is called once
  346. assert(first and msg == 4)
  347. first = false
  348. error("@z")
  349. end)
  350. error(4) -- original error
  351. end
  352. local stat, msg = pcall(foo, true)
  353. assert(string.find(msg, "@x1"))
  354. -- error leaving a block
  355. local function foo (...)
  356. do
  357. local x1 <close> =
  358. func2close(function (self, msg)
  359. assert(string.find(msg, "@X"))
  360. error("@Y")
  361. end)
  362. local x123 <close> =
  363. func2close(function (_, msg)
  364. assert(msg == nil)
  365. error("@X")
  366. end)
  367. end
  368. os.exit(false) -- should not run
  369. end
  370. local st, msg = xpcall(foo, debug.traceback)
  371. assert(string.match(msg, "^[^ ]* @Y"))
  372. -- error in toclose in vararg function
  373. local function foo (...)
  374. local x123 <close> = func2close(function () error("@x123") end)
  375. end
  376. local st, msg = xpcall(foo, debug.traceback)
  377. assert(string.match(msg, "^[^ ]* @x123"))
  378. assert(string.find(msg, "in metamethod 'close'"))
  379. end
  380. do -- errors due to non-closable values
  381. local function foo ()
  382. local x <close> = {}
  383. os.exit(false) -- should not run
  384. end
  385. local stat, msg = pcall(foo)
  386. assert(not stat and
  387. string.find(msg, "variable 'x' got a non%-closable value"))
  388. local function foo ()
  389. local xyz <close> = setmetatable({}, {__close = print})
  390. getmetatable(xyz).__close = nil -- remove metamethod
  391. end
  392. local stat, msg = pcall(foo)
  393. assert(not stat and string.find(msg, "metamethod 'close'"))
  394. local function foo ()
  395. local a1 <close> = func2close(function (_, msg)
  396. assert(string.find(msg, "number value"))
  397. error(12)
  398. end)
  399. local a2 <close> = setmetatable({}, {__close = print})
  400. local a3 <close> = func2close(function (_, msg)
  401. assert(msg == nil)
  402. error(123)
  403. end)
  404. getmetatable(a2).__close = 4 -- invalidate metamethod
  405. end
  406. local stat, msg = pcall(foo)
  407. assert(not stat and msg == 12)
  408. end
  409. do -- tbc inside close methods
  410. local track = {}
  411. local function foo ()
  412. local x <close> = func2close(function ()
  413. local xx <close> = func2close(function (_, msg)
  414. assert(msg == nil)
  415. track[#track + 1] = "xx"
  416. end)
  417. track[#track + 1] = "x"
  418. end)
  419. track[#track + 1] = "foo"
  420. return 20, 30, 40
  421. end
  422. local a, b, c, d = foo()
  423. assert(a == 20 and b == 30 and c == 40 and d == nil)
  424. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx")
  425. -- again, with errors
  426. local track = {}
  427. local function foo ()
  428. local x0 <close> = func2close(function (_, msg)
  429. assert(msg == 202)
  430. track[#track + 1] = "x0"
  431. end)
  432. local x <close> = func2close(function ()
  433. local xx <close> = func2close(function (_, msg)
  434. assert(msg == 101)
  435. track[#track + 1] = "xx"
  436. error(202)
  437. end)
  438. track[#track + 1] = "x"
  439. error(101)
  440. end)
  441. track[#track + 1] = "foo"
  442. return 20, 30, 40
  443. end
  444. local st, msg = pcall(foo)
  445. assert(not st and msg == 202)
  446. assert(track[1] == "foo" and track[2] == "x" and track[3] == "xx" and
  447. track[4] == "x0")
  448. end
  449. local function checktable (t1, t2)
  450. assert(#t1 == #t2)
  451. for i = 1, #t1 do
  452. assert(t1[i] == t2[i])
  453. end
  454. end
  455. do -- test for tbc variable high in the stack
  456. -- function to force a stack overflow
  457. local function overflow (n)
  458. overflow(n + 1)
  459. end
  460. -- error handler will create tbc variable handling a stack overflow,
  461. -- high in the stack
  462. local function errorh (m)
  463. assert(string.find(m, "stack overflow"))
  464. local x <close> = func2close(function (o) o[1] = 10 end)
  465. return x
  466. end
  467. local flag
  468. local st, obj
  469. -- run test in a coroutine so as not to swell the main stack
  470. local co = coroutine.wrap(function ()
  471. -- tbc variable down the stack
  472. local y <close> = func2close(function (obj, msg)
  473. assert(msg == nil)
  474. obj[1] = 100
  475. flag = obj
  476. end)
  477. tracegc.stop()
  478. st, obj = xpcall(overflow, errorh, 0)
  479. tracegc.start()
  480. end)
  481. co()
  482. assert(not st and obj[1] == 10 and flag[1] == 100)
  483. end
  484. if rawget(_G, "T") then
  485. do
  486. -- bug in 5.4.3
  487. -- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
  488. -- reduce stack size
  489. collectgarbage(); collectgarbage(); collectgarbage()
  490. -- force a stack reallocation
  491. local function loop (n)
  492. if n < 400 then loop(n + 1) end
  493. end
  494. -- close metamethod will reallocate the stack
  495. local o = setmetatable({}, {__close = function () loop(0) end})
  496. local script = [[toclose 2; settop 1; return 1]]
  497. assert(T.testC(script, o) == script)
  498. end
  499. -- memory error inside closing function
  500. local function foo ()
  501. local y <close> = func2close(function () T.alloccount() end)
  502. local x <close> = setmetatable({}, {__close = function ()
  503. T.alloccount(0); local x = {} -- force a memory error
  504. end})
  505. error(1000) -- common error inside the function's body
  506. end
  507. stack(5) -- ensure a minimal number of CI structures
  508. -- despite memory error, 'y' will be executed and
  509. -- memory limit will be lifted
  510. local _, msg = pcall(foo)
  511. assert(msg == "not enough memory")
  512. local closemsg
  513. local close = func2close(function (self, msg)
  514. T.alloccount()
  515. closemsg = msg
  516. end)
  517. -- set a memory limit and return a closing object to remove the limit
  518. local function enter (count)
  519. stack(10) -- reserve some stack space
  520. T.alloccount(count)
  521. closemsg = nil
  522. return close
  523. end
  524. local function test ()
  525. local x <close> = enter(0) -- set a memory limit
  526. local y = {} -- raise a memory error
  527. end
  528. local _, msg = pcall(test)
  529. assert(msg == "not enough memory" and closemsg == "not enough memory")
  530. -- repeat test with extra closing upvalues
  531. local function test ()
  532. local xxx <close> = func2close(function (self, msg)
  533. assert(msg == "not enough memory");
  534. error(1000) -- raise another error
  535. end)
  536. local xx <close> = func2close(function (self, msg)
  537. assert(msg == "not enough memory");
  538. end)
  539. local x <close> = enter(0) -- set a memory limit
  540. local y = {} -- raise a memory error
  541. end
  542. local _, msg = pcall(test)
  543. assert(msg == 1000 and closemsg == "not enough memory")
  544. do -- testing 'toclose' in C string buffer
  545. collectgarbage()
  546. local s = string.rep('a', 10000) -- large string
  547. local m = T.totalmem()
  548. collectgarbage("stop")
  549. s = string.upper(s) -- allocate buffer + new string (10K each)
  550. -- ensure buffer was deallocated
  551. assert(T.totalmem() - m <= 11000)
  552. collectgarbage("restart")
  553. end
  554. do -- now some tests for freeing buffer in case of errors
  555. local lim = 10000 -- some size larger than the static buffer
  556. local extra = 2000 -- some extra memory (for callinfo, etc.)
  557. local s = string.rep("a", lim)
  558. -- concat this table needs two buffer resizes (one for each 's')
  559. local a = {s, s}
  560. collectgarbage(); collectgarbage()
  561. m = T.totalmem()
  562. collectgarbage("stop")
  563. -- error in the first buffer allocation
  564. T. totalmem(m + extra)
  565. assert(not pcall(table.concat, a))
  566. -- first buffer was not even allocated
  567. assert(T.totalmem() - m <= extra)
  568. -- error in the second buffer allocation
  569. T. totalmem(m + lim + extra)
  570. assert(not pcall(table.concat, a))
  571. -- first buffer was released by 'toclose'
  572. assert(T.totalmem() - m <= extra)
  573. -- error in creation of final string
  574. T.totalmem(m + 2 * lim + extra)
  575. assert(not pcall(table.concat, a))
  576. -- second buffer was released by 'toclose'
  577. assert(T.totalmem() - m <= extra)
  578. -- userdata, buffer, buffer, final string
  579. T.totalmem(m + 4*lim + extra)
  580. assert(#table.concat(a) == 2*lim)
  581. T.totalmem(0) -- remove memory limit
  582. collectgarbage("restart")
  583. print'+'
  584. end
  585. do
  586. -- '__close' vs. return hooks in C functions
  587. local trace = {}
  588. local function hook (event)
  589. trace[#trace + 1] = event .. " " .. (debug.getinfo(2).name or "?")
  590. end
  591. -- create tbc variables to be used by C function
  592. local x = func2close(function (_,msg)
  593. trace[#trace + 1] = "x"
  594. end)
  595. local y = func2close(function (_,msg)
  596. trace[#trace + 1] = "y"
  597. end)
  598. debug.sethook(hook, "r")
  599. local t = {T.testC([[
  600. toclose 2 # x
  601. pushnum 10
  602. pushint 20
  603. toclose 3 # y
  604. return 2
  605. ]], x, y)}
  606. debug.sethook()
  607. -- hooks ran before return hook from 'testC'
  608. checktable(trace,
  609. {"return sethook", "y", "return ?", "x", "return ?", "return testC"})
  610. -- results are correct
  611. checktable(t, {10, 20})
  612. end
  613. end
  614. do -- '__close' vs. return hooks in Lua functions
  615. local trace = {}
  616. local function hook (event)
  617. trace[#trace + 1] = event .. " " .. debug.getinfo(2).name
  618. end
  619. local function foo (...)
  620. local x <close> = func2close(function (_,msg)
  621. trace[#trace + 1] = "x"
  622. end)
  623. local y <close> = func2close(function (_,msg)
  624. debug.sethook(hook, "r")
  625. end)
  626. return ...
  627. end
  628. local t = {foo(10,20,30)}
  629. debug.sethook()
  630. checktable(t, {10, 20, 30})
  631. checktable(trace,
  632. {"return sethook", "return close", "x", "return close", "return foo"})
  633. end
  634. print "to-be-closed variables in coroutines"
  635. do
  636. -- yielding inside closing metamethods
  637. local trace = {}
  638. local co = coroutine.wrap(function ()
  639. trace[#trace + 1] = "nowX"
  640. -- will be closed after 'y'
  641. local x <close> = func2close(function (_, msg)
  642. assert(msg == nil)
  643. trace[#trace + 1] = "x1"
  644. coroutine.yield("x")
  645. trace[#trace + 1] = "x2"
  646. end)
  647. return pcall(function ()
  648. do -- 'z' will be closed first
  649. local z <close> = func2close(function (_, msg)
  650. assert(msg == nil)
  651. trace[#trace + 1] = "z1"
  652. coroutine.yield("z")
  653. trace[#trace + 1] = "z2"
  654. end)
  655. end
  656. trace[#trace + 1] = "nowY"
  657. -- will be closed after 'z'
  658. local y <close> = func2close(function(_, msg)
  659. assert(msg == nil)
  660. trace[#trace + 1] = "y1"
  661. coroutine.yield("y")
  662. trace[#trace + 1] = "y2"
  663. end)
  664. return 10, 20, 30
  665. end)
  666. end)
  667. assert(co() == "z")
  668. assert(co() == "y")
  669. assert(co() == "x")
  670. checktable({co()}, {true, 10, 20, 30})
  671. checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"})
  672. end
  673. do
  674. -- yielding inside closing metamethods while returning
  675. -- (bug in 5.4.3)
  676. local extrares -- result from extra yield (if any)
  677. local function check (body, extra, ...)
  678. local t = table.pack(...) -- expected returns
  679. local co = coroutine.wrap(body)
  680. if extra then
  681. extrares = co() -- runs until first (extra) yield
  682. end
  683. local res = table.pack(co()) -- runs until yield inside '__close'
  684. assert(res.n == 2 and res[2] == nil)
  685. local res2 = table.pack(co()) -- runs until end of function
  686. assert(res2.n == t.n)
  687. for i = 1, #t do
  688. if t[i] == "x" then
  689. assert(res2[i] == res[1]) -- value that was closed
  690. else
  691. assert(res2[i] == t[i])
  692. end
  693. end
  694. end
  695. local function foo ()
  696. local x <close> = func2close(coroutine.yield)
  697. local extra <close> = func2close(function (self)
  698. assert(self == extrares)
  699. coroutine.yield(100)
  700. end)
  701. extrares = extra
  702. return table.unpack{10, x, 30}
  703. end
  704. check(foo, true, 10, "x", 30)
  705. assert(extrares == 100)
  706. local function foo ()
  707. local x <close> = func2close(coroutine.yield)
  708. return
  709. end
  710. check(foo, false)
  711. local function foo ()
  712. local x <close> = func2close(coroutine.yield)
  713. local y, z = 20, 30
  714. return x
  715. end
  716. check(foo, false, "x")
  717. local function foo ()
  718. local x <close> = func2close(coroutine.yield)
  719. local extra <close> = func2close(coroutine.yield)
  720. return table.unpack({}, 1, 100) -- 100 nils
  721. end
  722. check(foo, true, table.unpack({}, 1, 100))
  723. end
  724. do
  725. -- yielding inside closing metamethods after an error
  726. local co = coroutine.wrap(function ()
  727. local function foo (err)
  728. local z <close> = func2close(function(_, msg)
  729. assert(msg == nil or msg == err + 20)
  730. coroutine.yield("z")
  731. return 100, 200
  732. end)
  733. local y <close> = func2close(function(_, msg)
  734. -- still gets the original error (if any)
  735. assert(msg == err or (msg == nil and err == 1))
  736. coroutine.yield("y")
  737. if err then error(err + 20) end -- creates or changes the error
  738. end)
  739. local x <close> = func2close(function(_, msg)
  740. assert(msg == err or (msg == nil and err == 1))
  741. coroutine.yield("x")
  742. return 100, 200
  743. end)
  744. if err == 10 then error(err) else return 10, 20 end
  745. end
  746. coroutine.yield(pcall(foo, nil)) -- no error
  747. coroutine.yield(pcall(foo, 1)) -- error in __close
  748. return pcall(foo, 10) -- 'foo' will raise an error
  749. end)
  750. local a, b = co() -- first foo: no error
  751. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  752. a, b = co()
  753. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  754. a, b = co()
  755. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  756. local a, b, c = co()
  757. assert(a and b == 10 and c == 20) -- returns from 'pcall(foo, nil)'
  758. local a, b = co() -- second foo: error in __close
  759. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  760. a, b = co()
  761. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  762. a, b = co()
  763. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  764. local st, msg = co() -- reports the error in 'y'
  765. assert(not st and msg == 21)
  766. local a, b = co() -- third foo: error in function body
  767. assert(a == "x" and b == nil) -- yields inside 'x'; Ok
  768. a, b = co()
  769. assert(a == "y" and b == nil) -- yields inside 'y'; Ok
  770. a, b = co()
  771. assert(a == "z" and b == nil) -- yields inside 'z'; Ok
  772. local st, msg = co() -- gets final error
  773. assert(not st and msg == 10 + 20)
  774. end
  775. do
  776. -- an error in a wrapped coroutine closes variables
  777. local x = false
  778. local y = false
  779. local co = coroutine.wrap(function ()
  780. local xv <close> = func2close(function () x = true end)
  781. do
  782. local yv <close> = func2close(function () y = true end)
  783. coroutine.yield(100) -- yield doesn't close variable
  784. end
  785. coroutine.yield(200) -- yield doesn't close variable
  786. error(23) -- error does
  787. end)
  788. local b = co()
  789. assert(b == 100 and not x and not y)
  790. b = co()
  791. assert(b == 200 and not x and y)
  792. local a, b = pcall(co)
  793. assert(not a and b == 23 and x and y)
  794. end
  795. do
  796. -- error in a wrapped coroutine raising errors when closing a variable
  797. local x = 0
  798. local co = coroutine.wrap(function ()
  799. local xx <close> = func2close(function (_, msg)
  800. x = x + 1;
  801. assert(string.find(msg, "@XXX"))
  802. error("@YYY")
  803. end)
  804. local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
  805. coroutine.yield(100)
  806. error(200)
  807. end)
  808. assert(co() == 100); assert(x == 0)
  809. local st, msg = pcall(co); assert(x == 2)
  810. assert(not st and string.find(msg, "@YYY")) -- should get error raised
  811. local x = 0
  812. local y = 0
  813. co = coroutine.wrap(function ()
  814. local xx <close> = func2close(function (_, err)
  815. y = y + 1;
  816. assert(string.find(err, "XXX"))
  817. error("YYY")
  818. end)
  819. local xv <close> = func2close(function ()
  820. x = x + 1; error("XXX")
  821. end)
  822. coroutine.yield(100)
  823. return 200
  824. end)
  825. assert(co() == 100); assert(x == 0)
  826. local st, msg = pcall(co)
  827. assert(x == 1 and y == 1)
  828. -- should get first error raised
  829. assert(not st and string.find(msg, "%w+%.%w+:%d+: YYY"))
  830. end
  831. -- a suspended coroutine should not close its variables when collected
  832. local co
  833. co = coroutine.wrap(function()
  834. -- should not run
  835. local x <close> = func2close(function () os.exit(false) end)
  836. co = nil
  837. coroutine.yield()
  838. end)
  839. co() -- start coroutine
  840. assert(co == nil) -- eventually it will be collected
  841. collectgarbage()
  842. if rawget(_G, "T") then
  843. print("to-be-closed variables x coroutines in C")
  844. do
  845. local token = 0
  846. local count = 0
  847. local f = T.makeCfunc[[
  848. toclose 1
  849. toclose 2
  850. return .
  851. ]]
  852. local obj = func2close(function (_, msg)
  853. count = count + 1
  854. token = coroutine.yield(count, token)
  855. end)
  856. local co = coroutine.wrap(f)
  857. local ct, res = co(obj, obj, 10, 20, 30, 3) -- will return 10, 20, 30
  858. -- initial token value, after closing 2nd obj
  859. assert(ct == 1 and res == 0)
  860. -- run until yield when closing 1st obj
  861. ct, res = co(100)
  862. assert(ct == 2 and res == 100)
  863. res = {co(200)} -- run until end
  864. assert(res[1] == 10 and res[2] == 20 and res[3] == 30 and res[4] == nil)
  865. assert(token == 200)
  866. end
  867. do
  868. local f = T.makeCfunc[[
  869. toclose 1
  870. return .
  871. ]]
  872. local obj = func2close(function ()
  873. local temp
  874. local x <close> = func2close(function ()
  875. coroutine.yield(temp)
  876. return 1,2,3 -- to be ignored
  877. end)
  878. temp = coroutine.yield("closing obj")
  879. return 1,2,3 -- to be ignored
  880. end)
  881. local co = coroutine.wrap(f)
  882. local res = co(obj, 10, 30, 1) -- will return only 30
  883. assert(res == "closing obj")
  884. res = co("closing x")
  885. assert(res == "closing x")
  886. res = {co()}
  887. assert(res[1] == 30 and res[2] == nil)
  888. end
  889. do
  890. -- still cannot yield inside 'closeslot'
  891. local f = T.makeCfunc[[
  892. toclose 1
  893. closeslot 1
  894. ]]
  895. local obj = func2close(coroutine.yield)
  896. local co = coroutine.create(f)
  897. local st, msg = coroutine.resume(co, obj)
  898. assert(not st and string.find(msg, "attempt to yield across"))
  899. -- nor outside a coroutine
  900. local f = T.makeCfunc[[
  901. toclose 1
  902. ]]
  903. local st, msg = pcall(f, obj)
  904. assert(not st and string.find(msg, "attempt to yield from outside"))
  905. end
  906. end
  907. -- to-be-closed variables in generic for loops
  908. do
  909. local numopen = 0
  910. local function open (x)
  911. numopen = numopen + 1
  912. return
  913. function () -- iteraction function
  914. x = x - 1
  915. if x > 0 then return x end
  916. end,
  917. nil, -- state
  918. nil, -- control variable
  919. func2close(function () numopen = numopen - 1 end) -- closing function
  920. end
  921. local s = 0
  922. for i in open(10) do
  923. s = s + i
  924. end
  925. assert(s == 45 and numopen == 0)
  926. local s = 0
  927. for i in open(10) do
  928. if i < 5 then break end
  929. s = s + i
  930. end
  931. assert(s == 35 and numopen == 0)
  932. local s = 0
  933. for i in open(10) do
  934. for j in open(10) do
  935. if i + j < 5 then goto endloop end
  936. s = s + i
  937. end
  938. end
  939. ::endloop::
  940. assert(s == 375 and numopen == 0)
  941. end
  942. print('OK')
  943. return 5,f
  944. end -- }