locals.lua 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  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. -- bug in 5.1:
  6. local function f(x) x = nil; return x end
  7. assert(f(10) == nil)
  8. local function f() local x; return x end
  9. assert(f(10) == nil)
  10. local function f(x) x = nil; local y; return x, y end
  11. assert(f(10) == nil and select(2, f(20)) == nil)
  12. do
  13. local i = 10
  14. do local i = 100; assert(i==100) end
  15. do local i = 1000; assert(i==1000) end
  16. assert(i == 10)
  17. if i ~= 10 then
  18. local i = 20
  19. else
  20. local i = 30
  21. assert(i == 30)
  22. end
  23. end
  24. f = nil
  25. local f
  26. x = 1
  27. a = nil
  28. load('local a = {}')()
  29. assert(a == nil)
  30. function f (a)
  31. local _1, _2, _3, _4, _5
  32. local _6, _7, _8, _9, _10
  33. local x = 3
  34. local b = a
  35. local c,d = a,b
  36. if (d == b) then
  37. local x = 'q'
  38. x = b
  39. assert(x == 2)
  40. else
  41. assert(nil)
  42. end
  43. assert(x == 3)
  44. local f = 10
  45. end
  46. local b=10
  47. local a; repeat local b; a,b=1,2; assert(a+1==b); until a+b==3
  48. assert(x == 1)
  49. f(2)
  50. assert(type(f) == 'function')
  51. local function getenv (f)
  52. local a,b = debug.getupvalue(f, 1)
  53. assert(a == '_ENV')
  54. return b
  55. end
  56. -- test for global table of loaded chunks
  57. assert(getenv(load"a=3") == _G)
  58. local c = {}; local f = load("a = 3", nil, nil, c)
  59. assert(getenv(f) == c)
  60. assert(c.a == nil)
  61. f()
  62. assert(c.a == 3)
  63. -- old test for limits for special instructions
  64. do
  65. local i = 2
  66. local p = 4 -- p == 2^i
  67. repeat
  68. for j=-3,3 do
  69. assert(load(string.format([[local a=%s;
  70. a=a+%s;
  71. assert(a ==2^%s)]], j, p-j, i), '')) ()
  72. assert(load(string.format([[local a=%s;
  73. a=a-%s;
  74. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  75. assert(load(string.format([[local a,b=0,%s;
  76. a=b-%s;
  77. assert(a==-2^%s)]], -j, p-j, i), '')) ()
  78. end
  79. p = 2 * p; i = i + 1
  80. until p <= 0
  81. end
  82. print'+'
  83. if rawget(_G, "T") then
  84. -- testing clearing of dead elements from tables
  85. collectgarbage("stop") -- stop GC
  86. local a = {[{}] = 4, [3] = 0, alo = 1,
  87. a1234567890123456789012345678901234567890 = 10}
  88. local t = T.querytab(a)
  89. for k,_ in pairs(a) do a[k] = undef end
  90. collectgarbage() -- restore GC and collect dead fields in 'a'
  91. for i=0,t-1 do
  92. local k = querytab(a, i)
  93. assert(k == nil or type(k) == 'number' or k == 'alo')
  94. end
  95. -- testing allocation errors during table insertions
  96. local a = {}
  97. local function additems ()
  98. a.x = true; a.y = true; a.z = true
  99. a[1] = true
  100. a[2] = true
  101. end
  102. for i = 1, math.huge do
  103. T.alloccount(i)
  104. local st, msg = pcall(additems)
  105. T.alloccount()
  106. local count = 0
  107. for k, v in pairs(a) do
  108. assert(a[k] == v)
  109. count = count + 1
  110. end
  111. if st then assert(count == 5); break end
  112. end
  113. end
  114. -- testing lexical environments
  115. assert(_ENV == _G)
  116. do
  117. local dummy
  118. local _ENV = (function (...) return ... end)(_G, dummy) -- {
  119. do local _ENV = {assert=assert}; assert(true) end
  120. mt = {_G = _G}
  121. local foo,x
  122. A = false -- "declare" A
  123. do local _ENV = mt
  124. function foo (x)
  125. A = x
  126. do local _ENV = _G; A = 1000 end
  127. return function (x) return A .. x end
  128. end
  129. end
  130. assert(getenv(foo) == mt)
  131. x = foo('hi'); assert(mt.A == 'hi' and A == 1000)
  132. assert(x('*') == mt.A .. '*')
  133. do local _ENV = {assert=assert, A=10};
  134. do local _ENV = {assert=assert, A=20};
  135. assert(A==20);x=A
  136. end
  137. assert(A==10 and x==20)
  138. end
  139. assert(x==20)
  140. do -- constants
  141. local a<const>, b, c<const> = 10, 20, 30
  142. b = a + c + b -- 'b' is not constant
  143. assert(a == 10 and b == 60 and c == 30)
  144. local function checkro (name, code)
  145. local st, msg = load(code)
  146. local gab = string.format("attempt to assign to const variable '%s'", name)
  147. assert(not st and string.find(msg, gab))
  148. end
  149. checkro("y", "local x, y <const>, z = 10, 20, 30; x = 11; y = 12")
  150. checkro("x", "local x <const>, y, z <const> = 10, 20, 30; x = 11")
  151. checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
  152. checkro("z", [[
  153. local a, z <const>, b = 10;
  154. function foo() a = 20; z = 32; end
  155. ]])
  156. checkro("var1", [[
  157. local a, var1 <const> = 10;
  158. function foo() a = 20; z = function () var1 = 12; end end
  159. ]])
  160. end
  161. print"testing to-be-closed variables"
  162. local function stack(n) n = ((n == 0) or stack(n - 1)) end
  163. local function func2close (f, x, y)
  164. local obj = setmetatable({}, {__close = f})
  165. if x then
  166. return x, obj, y
  167. else
  168. return obj
  169. end
  170. end
  171. do
  172. local a = {}
  173. do
  174. local b <close> = false -- not to be closed
  175. local x <close> = setmetatable({"x"}, {__close = function (self)
  176. a[#a + 1] = self[1] end})
  177. local w, y <close>, z = func2close(function (self, err)
  178. assert(err == nil); a[#a + 1] = "y"
  179. end, 10, 20)
  180. local c <close> = nil -- not to be closed
  181. a[#a + 1] = "in"
  182. assert(w == 10 and z == 20)
  183. end
  184. a[#a + 1] = "out"
  185. assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out")
  186. end
  187. do
  188. local X = false
  189. local x, closescope = func2close(function () stack(10); X = true end, 100)
  190. assert(x == 100); x = 101; -- 'x' is not read-only
  191. -- closing functions do not corrupt returning values
  192. local function foo (x)
  193. local _ <close> = closescope
  194. return x, X, 23
  195. end
  196. local a, b, c = foo(1.5)
  197. assert(a == 1.5 and b == false and c == 23 and X == true)
  198. X = false
  199. foo = function (x)
  200. local _<close> = func2close(function ()
  201. -- without errors, enclosing function should be still active when
  202. -- __close is called
  203. assert(debug.getinfo(2).name == "foo")
  204. end)
  205. local _<close> = closescope
  206. local y = 15
  207. return y
  208. end
  209. assert(foo() == 15 and X == true)
  210. X = false
  211. foo = function ()
  212. local x <close> = closescope
  213. return x
  214. end
  215. assert(foo() == closescope and X == true)
  216. end
  217. -- testing to-be-closed x compile-time constants
  218. -- (there were some bugs here in Lua 5.4-rc3, due to a confusion
  219. -- between compile levels and stack levels of variables)
  220. do
  221. local flag = false
  222. local x = setmetatable({},
  223. {__close = function() assert(flag == false); flag = true end})
  224. local y <const> = nil
  225. local z <const> = nil
  226. do
  227. local a <close> = x
  228. end
  229. assert(flag) -- 'x' must be closed here
  230. end
  231. do
  232. -- similar problem, but with implicit close in for loops
  233. local flag = false
  234. local x = setmetatable({},
  235. {__close = function () assert(flag == false); flag = true end})
  236. -- return an empty iterator, nil, nil, and 'x' to be closed
  237. local function a ()
  238. return (function () return nil end), nil, nil, x
  239. end
  240. local v <const> = 1
  241. local w <const> = 1
  242. local x <const> = 1
  243. local y <const> = 1
  244. local z <const> = 1
  245. for k in a() do
  246. a = k
  247. end -- ending the loop must close 'x'
  248. assert(flag) -- 'x' must be closed here
  249. end
  250. do
  251. -- calls cannot be tail in the scope of to-be-closed variables
  252. local X, Y
  253. local function foo ()
  254. local _ <close> = func2close(function () Y = 10 end)
  255. assert(X == true and Y == nil) -- 'X' not closed yet
  256. return 1,2,3
  257. end
  258. local function bar ()
  259. local _ <close> = func2close(function () X = false end)
  260. X = true
  261. do
  262. return foo() -- not a tail call!
  263. end
  264. end
  265. local a, b, c, d = bar()
  266. assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil)
  267. end
  268. -- auxiliary functions for testing warnings in '__close'
  269. local function prepwarn ()
  270. if not T then -- no test library?
  271. warn("@off") -- do not show (lots of) warnings
  272. else
  273. warn("@store") -- to test the warnings
  274. end
  275. end
  276. local function endwarn ()
  277. if not T then
  278. warn("@on") -- back to normal
  279. else
  280. assert(_WARN == false)
  281. warn("@normal")
  282. end
  283. end
  284. -- errors inside __close can generate a warning instead of an
  285. -- error. This new 'assert' force them to appear.
  286. local function assert(cond, msg)
  287. if not cond then
  288. local line = debug.getinfo(2).currentline or "?"
  289. msg = string.format("assertion failed! line %d (%s)\n", line, msg or "")
  290. io.stderr:write(msg)
  291. os.exit(1)
  292. end
  293. end
  294. local function checkwarn (msg)
  295. if T then
  296. assert(string.find(_WARN, msg))
  297. _WARN = false -- reset variable to check next warning
  298. end
  299. end
  300. warn("@on")
  301. do print("testing errors in __close")
  302. prepwarn()
  303. -- original error is in __close
  304. local function foo ()
  305. local x <close> =
  306. func2close(function (self, msg)
  307. assert(string.find(msg, "@z"))
  308. error("@x")
  309. end)
  310. local x1 <close> =
  311. func2close(function (self, msg)
  312. checkwarn("@y")
  313. assert(string.find(msg, "@z"))
  314. end)
  315. local gc <close> = func2close(function () collectgarbage() end)
  316. local y <close> =
  317. func2close(function (self, msg)
  318. assert(string.find(msg, "@z")) -- first error in 'z'
  319. checkwarn("@z") -- second error in 'z' generated a warning
  320. error("@y")
  321. end)
  322. local first = true
  323. local z <close> =
  324. -- 'z' close is called twice
  325. func2close(function (self, msg)
  326. if first then
  327. assert(msg == nil)
  328. first = false
  329. else
  330. assert(string.find(msg, "@z")) -- own error
  331. end
  332. error("@z")
  333. end)
  334. return 200
  335. end
  336. local stat, msg = pcall(foo, false)
  337. assert(string.find(msg, "@z"))
  338. checkwarn("@x")
  339. -- original error not in __close
  340. local function foo ()
  341. local x <close> =
  342. func2close(function (self, msg)
  343. -- after error, 'foo' was discarded, so caller now
  344. -- must be 'pcall'
  345. assert(debug.getinfo(2).name == "pcall")
  346. assert(msg == 4)
  347. end)
  348. local x1 <close> =
  349. func2close(function (self, msg)
  350. assert(debug.getinfo(2).name == "pcall")
  351. checkwarn("@y")
  352. assert(msg == 4)
  353. error("@x1")
  354. end)
  355. local gc <close> = func2close(function () collectgarbage() end)
  356. local y <close> =
  357. func2close(function (self, msg)
  358. assert(debug.getinfo(2).name == "pcall")
  359. assert(msg == 4) -- error in body
  360. checkwarn("@z")
  361. error("@y")
  362. end)
  363. local first = true
  364. local z <close> =
  365. func2close(function (self, msg)
  366. assert(debug.getinfo(2).name == "pcall")
  367. -- 'z' close is called once
  368. assert(first and msg == 4)
  369. first = false
  370. error("@z")
  371. end)
  372. error(4) -- original error
  373. end
  374. local stat, msg = pcall(foo, true)
  375. assert(msg == 4)
  376. checkwarn("@x1") -- last error
  377. -- error leaving a block
  378. local function foo (...)
  379. do
  380. local x1 <close> =
  381. func2close(function ()
  382. checkwarn("@X")
  383. error("@Y")
  384. end)
  385. local x123 <close> =
  386. func2close(function ()
  387. error("@X")
  388. end)
  389. end
  390. os.exit(false) -- should not run
  391. end
  392. local st, msg = xpcall(foo, debug.traceback)
  393. assert(string.match(msg, "^[^ ]* @X"))
  394. assert(string.find(msg, "in metamethod 'close'"))
  395. checkwarn("@Y")
  396. -- error in toclose in vararg function
  397. local function foo (...)
  398. local x123 <close> = func2close(function () error("@x123") end)
  399. end
  400. local st, msg = xpcall(foo, debug.traceback)
  401. assert(string.match(msg, "^[^ ]* @x123"))
  402. assert(string.find(msg, "in metamethod 'close'"))
  403. checkwarn("@x123") -- from second call to close 'x123'
  404. endwarn()
  405. end
  406. do -- errors due to non-closable values
  407. local function foo ()
  408. local x <close> = {}
  409. os.exit(false) -- should not run
  410. end
  411. local stat, msg = pcall(foo)
  412. assert(not stat and
  413. string.find(msg, "variable 'x' got a non%-closable value"))
  414. local function foo ()
  415. local xyz <close> = setmetatable({}, {__close = print})
  416. getmetatable(xyz).__close = nil -- remove metamethod
  417. end
  418. local stat, msg = pcall(foo)
  419. assert(not stat and
  420. string.find(msg, "attempt to close non%-closable variable 'xyz'"))
  421. end
  422. if rawget(_G, "T") then
  423. warn("@off")
  424. -- memory error inside closing function
  425. local function foo ()
  426. local y <close> = func2close(function () T.alloccount() end)
  427. local x <close> = setmetatable({}, {__close = function ()
  428. T.alloccount(0); local x = {} -- force a memory error
  429. end})
  430. error(1000) -- common error inside the function's body
  431. end
  432. stack(5) -- ensure a minimal number of CI structures
  433. -- despite memory error, 'y' will be executed and
  434. -- memory limit will be lifted
  435. local _, msg = pcall(foo)
  436. assert(msg == 1000)
  437. local close = func2close(function (self, msg)
  438. T.alloccount()
  439. assert(msg == "not enough memory")
  440. end)
  441. -- set a memory limit and return a closing object to remove the limit
  442. local function enter (count)
  443. stack(10) -- reserve some stack space
  444. T.alloccount(count)
  445. return close
  446. end
  447. local function test ()
  448. local x <close> = enter(0) -- set a memory limit
  449. -- creation of previous upvalue will raise a memory error
  450. assert(false) -- should not run
  451. end
  452. local _, msg = pcall(test)
  453. assert(msg == "not enough memory")
  454. -- now use metamethod for closing
  455. close = setmetatable({}, {__close = function ()
  456. T.alloccount()
  457. end})
  458. -- repeat test with extra closing upvalues
  459. local function test ()
  460. local xxx <close> = func2close(function (self, msg)
  461. assert(msg == "not enough memory");
  462. error(1000) -- raise another error
  463. end)
  464. local xx <close> = func2close(function (self, msg)
  465. assert(msg == "not enough memory");
  466. end)
  467. local x <close> = enter(0) -- set a memory limit
  468. -- creation of previous upvalue will raise a memory error
  469. os.exit(false) -- should not run
  470. end
  471. local _, msg = pcall(test)
  472. assert(msg == "not enough memory") -- reported error is the first one
  473. do -- testing 'toclose' in C string buffer
  474. collectgarbage()
  475. local s = string.rep('a', 10000) -- large string
  476. local m = T.totalmem()
  477. collectgarbage("stop")
  478. s = string.upper(s) -- allocate buffer + new string (10K each)
  479. -- ensure buffer was deallocated
  480. assert(T.totalmem() - m <= 11000)
  481. collectgarbage("restart")
  482. end
  483. do -- now some tests for freeing buffer in case of errors
  484. local lim = 10000 -- some size larger than the static buffer
  485. local extra = 2000 -- some extra memory (for callinfo, etc.)
  486. local s = string.rep("a", lim)
  487. -- concat this table needs two buffer resizes (one for each 's')
  488. local a = {s, s}
  489. collectgarbage()
  490. m = T.totalmem()
  491. collectgarbage("stop")
  492. -- error in the first buffer allocation
  493. T. totalmem(m + extra)
  494. assert(not pcall(table.concat, a))
  495. -- first buffer was not even allocated
  496. assert(T.totalmem() - m <= extra)
  497. -- error in the second buffer allocation
  498. T. totalmem(m + lim + extra)
  499. assert(not pcall(table.concat, a))
  500. -- first buffer was released by 'toclose'
  501. assert(T.totalmem() - m <= extra)
  502. -- error in creation of final string
  503. T.totalmem(m + 2 * lim + extra)
  504. assert(not pcall(table.concat, a))
  505. -- second buffer was released by 'toclose'
  506. assert(T.totalmem() - m <= extra)
  507. -- userdata, upvalue, buffer, buffer, final string
  508. T.totalmem(m + 4*lim + extra)
  509. assert(#table.concat(a) == 2*lim)
  510. T.totalmem(0) -- remove memory limit
  511. collectgarbage("restart")
  512. print'+'
  513. end
  514. warn("@on")
  515. end
  516. print "to-be-closed variables in coroutines"
  517. do
  518. -- an error in a wrapped coroutine closes variables
  519. local x = false
  520. local y = false
  521. local co = coroutine.wrap(function ()
  522. local xv <close> = func2close(function () x = true end)
  523. do
  524. local yv <close> = func2close(function () y = true end)
  525. coroutine.yield(100) -- yield doesn't close variable
  526. end
  527. coroutine.yield(200) -- yield doesn't close variable
  528. error(23) -- error does
  529. end)
  530. local b = co()
  531. assert(b == 100 and not x and not y)
  532. b = co()
  533. assert(b == 200 and not x and y)
  534. local a, b = pcall(co)
  535. assert(not a and b == 23 and x and y)
  536. end
  537. do
  538. prepwarn()
  539. -- error in a wrapped coroutine raising errors when closing a variable
  540. local x = 0
  541. local co = coroutine.wrap(function ()
  542. local xx <close> = func2close(function () x = x + 1; error("@YYY") end)
  543. local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
  544. coroutine.yield(100)
  545. error(200)
  546. end)
  547. assert(co() == 100); assert(x == 0)
  548. local st, msg = pcall(co); assert(x == 2)
  549. assert(not st and msg == 200) -- should get first error raised
  550. checkwarn("@YYY")
  551. local x = 0
  552. local y = 0
  553. co = coroutine.wrap(function ()
  554. local xx <close> = func2close(function () y = y + 1; error("YYY") end)
  555. local xv <close> = func2close(function () x = x + 1; error("XXX") end)
  556. coroutine.yield(100)
  557. return 200
  558. end)
  559. assert(co() == 100); assert(x == 0)
  560. local st, msg = pcall(co)
  561. assert(x == 2 and y == 1) -- first close is called twice
  562. -- should get first error raised
  563. assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
  564. checkwarn("YYY")
  565. endwarn()
  566. end
  567. -- a suspended coroutine should not close its variables when collected
  568. local co
  569. co = coroutine.wrap(function()
  570. -- should not run
  571. local x <close> = func2close(function () os.exit(false) end)
  572. co = nil
  573. coroutine.yield()
  574. end)
  575. co() -- start coroutine
  576. assert(co == nil) -- eventually it will be collected
  577. collectgarbage()
  578. -- to-be-closed variables in generic for loops
  579. do
  580. local numopen = 0
  581. local function open (x)
  582. numopen = numopen + 1
  583. return
  584. function () -- iteraction function
  585. x = x - 1
  586. if x > 0 then return x end
  587. end,
  588. nil, -- state
  589. nil, -- control variable
  590. func2close(function () numopen = numopen - 1 end) -- closing function
  591. end
  592. local s = 0
  593. for i in open(10) do
  594. s = s + i
  595. end
  596. assert(s == 45 and numopen == 0)
  597. local s = 0
  598. for i in open(10) do
  599. if i < 5 then break end
  600. s = s + i
  601. end
  602. assert(s == 35 and numopen == 0)
  603. local s = 0
  604. for i in open(10) do
  605. for j in open(10) do
  606. if i + j < 5 then goto endloop end
  607. s = s + i
  608. end
  609. end
  610. ::endloop::
  611. assert(s == 375 and numopen == 0)
  612. end
  613. print('OK')
  614. return 5,f
  615. end -- }