fix(lua): use rawget() to get __call in vim.is_callable() (#29536)

Lua 5.1 uses a "raw get" to retrieve `__call` from a metatable to
determine if a table is callable. Mirror this behavior in
`vim.is_callable()`.
This commit is contained in:
Tyler Miller
2024-07-03 15:36:00 -07:00
committed by GitHub
parent 12c9791e0f
commit 7f33c1967b
2 changed files with 55 additions and 1 deletions

View File

@ -997,7 +997,7 @@ function vim.is_callable(f)
if m == nil then
return false
end
return type(m.__call) == 'function'
return type(rawget(m, '__call')) == 'function'
end
--- Creates a table whose missing keys are provided by {createfn} (like Python's "defaultdict").

View File

@ -1495,6 +1495,60 @@ describe('lua stdlib', function()
]])
)
eq(
{ false, false },
exec_lua([[
local meta = { __call = {} }
assert(meta.__call)
local function new()
return setmetatable({}, meta)
end
local not_callable = new()
return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
]])
)
eq(
{ false, false },
exec_lua([[
local function new()
return { __call = function()end }
end
local not_callable = new()
assert(not_callable.__call)
return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
]])
)
eq(
{ false, false },
exec_lua([[
local meta = setmetatable(
{ __index = { __call = function() end } },
{ __index = { __call = function() end } }
)
assert(meta.__call)
local not_callable = setmetatable({}, meta)
assert(not_callable.__call)
return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
]])
)
eq(
{ false, false },
exec_lua([[
local meta = setmetatable({
__index = function()
return function() end
end,
}, {
__index = function()
return function() end
end,
})
assert(meta.__call)
local not_callable = setmetatable({}, meta)
assert(not_callable.__call)
return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
]])
)
eq(false, exec_lua('return vim.is_callable(1)'))
eq(false, exec_lua("return vim.is_callable('foo')"))
eq(false, exec_lua('return vim.is_callable({})'))