mirror of
https://github.com/neovim/neovim.git
synced 2026-06-15 16:23:48 +00:00
fix(lua): make vim.deep_equal cycle-safe
AI-assisted: Codex
(cherry picked from commit e289f9579c)
This commit is contained in:
committed by
Justin M. Keyes
parent
243a5ac5fd
commit
0039785724
@@ -1630,6 +1630,7 @@ vim.deep_equal({a}, {b}) *vim.deep_equal()*
|
||||
|
||||
Tables are compared recursively unless they both provide the `eq`
|
||||
metamethod. All other types are compared using the equality `==` operator.
|
||||
Cyclic tables are supported.
|
||||
|
||||
Parameters: ~
|
||||
• {a} (`any`) First value
|
||||
|
||||
@@ -661,36 +661,61 @@ function vim.tbl_deep_extend(behavior, ...)
|
||||
return tbl_extend(behavior, true, ...)
|
||||
end
|
||||
|
||||
---@param left any
|
||||
---@param right any
|
||||
---@param seen? table<table, table<table, boolean>>
|
||||
---@return boolean
|
||||
local function deep_equal(left, right, seen)
|
||||
if left == right then
|
||||
return true
|
||||
end
|
||||
|
||||
if type(left) ~= type(right) then
|
||||
return false
|
||||
end
|
||||
|
||||
if type(left) ~= 'table' then
|
||||
return false
|
||||
end
|
||||
|
||||
seen = seen or {}
|
||||
local seen_left = seen[left]
|
||||
if seen_left and seen_left[right] ~= nil then
|
||||
return seen_left[right]
|
||||
end
|
||||
|
||||
seen_left = seen_left or {}
|
||||
seen[left] = seen_left
|
||||
-- Assume equality while descending so recursive structures can terminate.
|
||||
seen_left[right] = true
|
||||
|
||||
for k, v in pairs(left) do
|
||||
if not deep_equal(v, right[k], seen) then
|
||||
seen_left[right] = false
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
for k in pairs(right) do
|
||||
if left[k] == nil then
|
||||
seen_left[right] = false
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Deep compare values for equality
|
||||
---
|
||||
--- Tables are compared recursively unless they both provide the `eq` metamethod.
|
||||
--- All other types are compared using the equality `==` operator.
|
||||
--- Cyclic tables are supported.
|
||||
---@param a any First value
|
||||
---@param b any Second value
|
||||
---@return boolean `true` if values are equals, else `false`
|
||||
function vim.deep_equal(a, b)
|
||||
if a == b then
|
||||
return true
|
||||
end
|
||||
if type(a) ~= type(b) then
|
||||
return false
|
||||
end
|
||||
if type(a) == 'table' then
|
||||
--- @cast a table<any,any>
|
||||
--- @cast b table<any,any>
|
||||
for k, v in pairs(a) do
|
||||
if not vim.deep_equal(v, b[k]) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
for k in pairs(b) do
|
||||
if a[k] == nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
return deep_equal(a, b)
|
||||
end
|
||||
|
||||
--- Add the reverse lookup values to an existing table.
|
||||
|
||||
@@ -1249,10 +1249,13 @@ describe('lua stdlib', function()
|
||||
eq(true, exec_lua [[ return vim.deep_equal({a={b=1}}, {a={b=1}}) ]])
|
||||
eq(true, exec_lua [[ return vim.deep_equal({a={b={nil}}}, {a={b={}}}) ]])
|
||||
eq(true, exec_lua [[ return vim.deep_equal({a=1, [5]=5}, {nil,nil,nil,nil,5,a=1}) ]])
|
||||
eq(true, exec_lua [[ local shared = {}; return vim.deep_equal({ 1, shared, 1, shared }, { 1, {}, 1, {} }) ]])
|
||||
eq(true, exec_lua [[ local a,b={},{}; a[1]=a; b[1]=b; return vim.deep_equal(a, b) ]])
|
||||
eq(false, exec_lua [[ return vim.deep_equal(1, {nil,nil,nil,nil,5,a=1}) ]])
|
||||
eq(false, exec_lua [[ return vim.deep_equal(1, 3) ]])
|
||||
eq(false, exec_lua [[ return vim.deep_equal(nil, 3) ]])
|
||||
eq(false, exec_lua [[ return vim.deep_equal({a=1}, {a=2}) ]])
|
||||
eq(false, exec_lua [[ local a,b={},{}; a[1]=a; b[1]={}; return vim.deep_equal(a, b) ]])
|
||||
end)
|
||||
|
||||
it('vim.list_extend', function()
|
||||
|
||||
Reference in New Issue
Block a user