locals.lua 28 KB

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