diff options
author | Tyler Miller <tmillr@proton.me> | 2024-07-03 15:36:00 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-04 06:36:00 +0800 |
commit | 7f33c1967b78ca8fda11fb0ad4c7f57d563e6ede (patch) | |
tree | 647eeb832c5fd0de361c20119e00857fdf34b3dd | |
parent | 12c9791e0fef7ee0d6cf6d3b828caa488d6347ea (diff) | |
download | rneovim-7f33c1967b78ca8fda11fb0ad4c7f57d563e6ede.tar.gz rneovim-7f33c1967b78ca8fda11fb0ad4c7f57d563e6ede.tar.bz2 rneovim-7f33c1967b78ca8fda11fb0ad4c7f57d563e6ede.zip |
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()`.
-rw-r--r-- | runtime/lua/vim/shared.lua | 2 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 54 |
2 files changed, 55 insertions, 1 deletions
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 621de2b1c2..99530bf72e 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -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"). diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 23bb9f0a2e..03c743c9ae 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -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({})')) |