From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp48.i.mail.ru (smtp48.i.mail.ru [94.100.177.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 16E58469719 for ; Thu, 13 Feb 2020 23:34:10 +0300 (MSK) From: olegrok@tarantool.org Date: Thu, 13 Feb 2020 23:33:52 +0300 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH 2/3] lua: table.deepcopy ignores __pairs metamethod List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@dev.tarantool.org, imun@tarantool.org, v.shpilevoy@tarantool.org Cc: Oleg Babin From: Oleg Babin After 1d85144a9b4bbbb026402848efde1ab98bf72633 table.deepcopy changed the behaviour and started iterate through tables considering __pairs metamethod. In some cases it broke backward compatibility. To avoid such problem let's ignore __pairs and iterate through tables as it was before Closes #4770 Follow-up #4560 --- Issue: https://github.com/tarantool/tarantool/issues/4770 Branch: https://github.com/tarantool/tarantool/tree/olegrok/table-fixes src/lua/table.lua | 7 ++++++- test/app-tap/table.test.lua | 26 +++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/lua/table.lua b/src/lua/table.lua index d83217dcb..4fa9c421c 100644 --- a/src/lua/table.lua +++ b/src/lua/table.lua @@ -1,3 +1,8 @@ +-- This pairs implementation doesn't trigger __pairs metamethod +local function internal_pairs(tbl) + return next, tbl, nil +end + local function table_deepcopy_internal(orig, cyclic) cyclic = cyclic or {} local copy = orig @@ -10,7 +15,7 @@ local function table_deepcopy_internal(orig, cyclic) copy = cyclic[orig] else cyclic[orig] = copy - for orig_key, orig_value in pairs(orig) do + for orig_key, orig_value in internal_pairs(orig) do local key = table_deepcopy_internal(orig_key, cyclic) copy[key] = table_deepcopy_internal(orig_value, cyclic) end diff --git a/test/app-tap/table.test.lua b/test/app-tap/table.test.lua index 07894f69e..3faf2ed23 100755 --- a/test/app-tap/table.test.lua +++ b/test/app-tap/table.test.lua @@ -8,7 +8,7 @@ yaml.cfg{ encode_invalid_as_nil = true, } local test = require('tap').test('table') -test:plan(33) +test:plan(35) do -- check basic table.copy (deepcopy) local example_table = { @@ -241,4 +241,28 @@ do -- gh-4340: deepcopy doesn't handle __metatable correctly. ) end +do -- gh-4770: deepcopy uses __pairs for iteration over table. + local original = { a = 1, b = 2 } + + local function custom_pairs(self) + local function step(tbl, k) + local k, v = next(tbl, k) + if v ~= nil then + v = v + 1 + end + return k, v + end + return step, self, nil + end + + setmetatable(original, {__pairs = custom_pairs }) + + -- Don't use is deeply as it could use pairs for check + local copy = table.deepcopy(original) + test:is(original.a, copy.a, + "checking that the first values is correctly copied") + test:is(original.b, copy.b, + "checking that the second values is correctly copied") +end + os.exit(test:check() == true and 0 or 1) -- 2.23.0