diff options
author | Shadman <13149513+shadmansaleh@users.noreply.github.com> | 2021-11-26 16:06:43 +0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-26 11:06:43 +0100 |
commit | eb876a0a6f5efb4706625723a8dd45b0c6c133a4 (patch) | |
tree | 97d966ef8e3666593bf496ea9414c5981ba8868f | |
parent | 3451121a4e517b42f1df73caed35c3663f57e5eb (diff) | |
download | rneovim-eb876a0a6f5efb4706625723a8dd45b0c6c133a4.tar.gz rneovim-eb876a0a6f5efb4706625723a8dd45b0c6c133a4.tar.bz2 rneovim-eb876a0a6f5efb4706625723a8dd45b0c6c133a4.zip |
fix(lua): fix vim.deepcopy for metatables & cycled tables (#16435)
vim.deepcopy previously didn't retain metatables in copies
and caused stackoverflow on recursive tables/cycled tables this
fixes these issues
-rw-r--r-- | runtime/lua/vim/shared.lua | 19 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 14 |
2 files changed, 23 insertions, 10 deletions
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 6e40b6ca52..bf77f0c776 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -12,7 +12,7 @@ local vim = vim or {} --- same functions as those in the input table. Userdata and threads are not --- copied and will throw an error. --- ----@param orig Table to copy +---@param orig table Table to copy ---@returns New table of copied keys and (nested) values. function vim.deepcopy(orig) end -- luacheck: no unused vim.deepcopy = (function() @@ -21,17 +21,16 @@ vim.deepcopy = (function() end local deepcopy_funcs = { - table = function(orig) + table = function(orig, cache) + if cache[orig] then return cache[orig] end local copy = {} - if vim._empty_dict_mt ~= nil and getmetatable(orig) == vim._empty_dict_mt then - copy = vim.empty_dict() - end - + cache[orig] = copy + local mt = getmetatable(orig) for k, v in pairs(orig) do - copy[vim.deepcopy(k)] = vim.deepcopy(v) + copy[vim.deepcopy(k, cache)] = vim.deepcopy(v, cache) end - return copy + return setmetatable(copy, mt) end, number = _id, string = _id, @@ -40,10 +39,10 @@ vim.deepcopy = (function() ['function'] = _id, } - return function(orig) + return function(orig, cache) local f = deepcopy_funcs[type(orig)] if f then - return f(orig) + return f(orig, cache or {}) else error("Cannot deepcopy object of type "..type(orig)) end diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 3832d27a22..28471bdd46 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -396,6 +396,20 @@ describe('lua stdlib', function() return t1.f() ~= t2.f() ]])) + ok(exec_lua([[ + local t1 = {a = 5} + t1.self = t1 + local t2 = vim.deepcopy(t1) + return t2.self == t2 and t2.self ~= t1 + ]])) + + ok(exec_lua([[ + local mt = {mt=true} + local t1 = setmetatable({a = 5}, mt) + local t2 = vim.deepcopy(t1) + return getmetatable(t2) == mt + ]])) + eq('Error executing lua: vim/shared.lua:0: Cannot deepcopy object of type thread', pcall_err(exec_lua, [[ local thread = coroutine.create(function () return 0 end) |