From 5cb0114e6242625db56dd6440e945ed1ece10bc7 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 7 Sep 2026 15:51:08 +0100 Subject: fix(async): preserve wrapped function argument and return types Preserve wrapped parameter lists so installer options type-check. Carry return types through tasks, wait and await, and check with EmmyLua 0.25.1. Assisted-by: Codex --- Makefile | 2 +- lua/nvim-treesitter/async.lua | 42 ++++++++++++++++++++++------------------- lua/nvim-treesitter/install.lua | 6 +++--- scripts/install-parsers.lua | 1 - 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index d00b80cc0..4ed2ea978 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ NVIM_VERSION ?= nightly -EMMYLUA_VERSION ?= 0.22.0 +EMMYLUA_VERSION ?= 0.25.1 DEPDIR ?= .test-deps CURL ?= curl -sL --create-dirs diff --git a/lua/nvim-treesitter/async.lua b/lua/nvim-treesitter/async.lua index a0a59e4b1..777b48b30 100644 --- a/lua/nvim-treesitter/async.lua +++ b/lua/nvim-treesitter/async.lua @@ -40,8 +40,8 @@ end --- @alias async.CallbackFn fun(...: any): async.Handle? ---- @class async.Task : async.Handle ---- @field package _callbacks table +--- @class async.Task : async.Handle +--- @field package _callbacks table --- @field package _callback_pos integer --- @field private _thread thread --- @@ -56,13 +56,14 @@ end --- --- Result of the task. --- Must use `await` to get the result. ---- @field private _result? any[] +--- @field private _result? R[] local Task = {} Task.__index = Task --- @private ---- @param func function ---- @return async.Task +--- @generic T, R +--- @param func async fun(...: T...): R... +--- @return async.Task function Task._new(func) local thread = coroutine.create(func) @@ -78,7 +79,7 @@ function Task._new(func) return self end ---- @param callback fun(err?: any, ...: any) +--- @param callback fun(err?: any, ...: R...) function Task:await(callback) if self._closing then callback('closing') @@ -121,7 +122,7 @@ local MAX_TIMEOUT = 2 ^ 31 - 1 --- Can be called if a task is closing. --- @param timeout? integer --- @return boolean status ---- @return any ... result or error +--- @return R... result or error function Task:pwait(timeout) local done = vim.wait(timeout or MAX_TIMEOUT, function() -- Note we use self:_completed() instead of self:await() to avoid creating a @@ -148,7 +149,7 @@ end --- local result = task:wait() -- wait indefinitely --- ``` --- @param timeout? integer Timeout in milliseconds ---- @return any ... result +--- @return R result function Task:wait(timeout) local res = pack_len(self:pwait(timeout)) local stat = res[1] @@ -199,6 +200,7 @@ function Task:traceback(msg) end --- If a task completes with an error, raise the error +--- @return async.Task function Task:raise_on_error() self:await(function(err) if err then @@ -349,26 +351,26 @@ end --- @generic T, R --- @param func async fun(...: T...): R... --- @param ... T... ---- @return async.Task +--- @return async.Task function M.arun(func, ...) local task = Task._new(func) task:_resume(...) return task end ---- @alias async.TaskFun fun(...: T...): async.Task +--- @alias async.TaskFun fun(...: T...): async.Task --- @generic T, R --- @class async._TaskFun --- @field package _fun async fun(...: T...): R... ---- @operator call(...: T...): async.Task +--- @operator call(...: T...): async.Task local TaskFun = {} TaskFun.__index = TaskFun --- @generic T, R --- @param self async._TaskFun --- @param ... T... ---- @return async.Task +--- @return async.Task function TaskFun:__call(...) return M.arun(self._fun, ...) end @@ -376,7 +378,7 @@ end --- Create an async function --- @generic T, R --- @param fun async fun(...: T...): R... ---- @return async.TaskFun +--- @return fun(...: T...): async.Task function M.async(fun) return setmetatable({ _fun = fun }, TaskFun) end @@ -403,8 +405,9 @@ local function yield(fun) end --- @async ---- @param task async.Task ---- @return any ... +--- @generic R +--- @param task async.Task +--- @return R local function await_task(task) --- @param callback fun(err?: string, ...: any) --- @return function @@ -441,9 +444,9 @@ local function await_cbfun(argc, fun, ...) end --- @generic T, R ---- @param taskfun async.TaskFun +--- @param taskfun async._TaskFun --- @param ... T... ---- @return R... +--- @return R local function await_taskfun(taskfun, ...) return taskfun._fun(...) end @@ -486,9 +489,10 @@ end --- end) --- ``` --- @async +--- @generic T, R --- @overload fun(argc: integer, func: async.CallbackFn, ...:any): any ... ---- @overload fun(task: async.Task): any ... ---- @overload fun(taskfun: async.TaskFun): any ... +--- @overload fun(task: async.Task): R +--- @overload fun(taskfun: (fun(...: T...): async.Task), ...: T...): R function M.await(...) assert(running(), 'Not in async context') diff --git a/lua/nvim-treesitter/install.lua b/lua/nvim-treesitter/install.lua index 12a2e450e..0f298f848 100644 --- a/lua/nvim-treesitter/install.lua +++ b/lua/nvim-treesitter/install.lua @@ -62,7 +62,7 @@ local INSTALL_TIMEOUT = 60000 --- @async --- @param max_jobs integer ---- @param tasks async.TaskFun[] +--- @param tasks async.TaskFun<[], []>[] local function join(max_jobs, tasks) if #tasks == 0 then return @@ -514,7 +514,7 @@ local function install(languages, options) local install_dir = config.get_install_dir('parser') local installed = options.force and {} or config.get_installed() - local tasks = {} ---@type async.TaskFun[] + local tasks = {} ---@type async.TaskFun<[], []>[] local done = 0 for _, lang in ipairs(languages) do if options.force or not vim.list_contains(installed, lang) then @@ -622,7 +622,7 @@ M.uninstall = a.async(function(languages, options) local query_dir = config.get_install_dir('queries') local installed = config.get_installed() - local tasks = {} ---@type async.TaskFun[] + local tasks = {} ---@type async.TaskFun<[], []>[] local done = 0 for _, lang in ipairs(languages) do local logger = log.new('uninstall/' .. lang) diff --git a/scripts/install-parsers.lua b/scripts/install-parsers.lua index 855c73cbd..9bc46ed7b 100755 --- a/scripts/install-parsers.lua +++ b/scripts/install-parsers.lua @@ -17,7 +17,6 @@ for i = 1, #_G.arg do end end ----@type async.Task local task = update and require('nvim-treesitter').update('all', { summary = true }) or require('nvim-treesitter').install( #parsers > 0 and parsers or 'all', -- cgit v1.3.1