diff --git a/changelog.md b/changelog.md index c9375a4cd..6972098b7 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,7 @@ ## Unreleased +* `FIX` Infer `pcall`/`xpcall` second result from their own declaration when the called function returns nothing [#3440](https://github.com/LuaLS/lua-language-server/pull/3440) * `NEW` Support type inference for `@field` and `@type` function declarations in method overrides [#3367](https://github.com/LuaLS/lua-language-server/issues/3367) * `FIX` Deduplicate documentation bindings for parameters * `FIX` Correct `math.type` meta return annotation to use `nil` instead of the string literal `'nil'` diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index 5a673e5fa..4063d70db 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -2191,12 +2191,14 @@ local compilerSwitch = util.switch() newArgs[#newArgs+1] = args[i] end local node = getReturn(args[1], index - 1, newArgs) - if node then + if node and not node:isEmpty() then vm.setNode(source, node) + return end - return - end - if func.special == 'xpcall' and index > 1 then + -- The called function has no such return, but `pcall` still does: on failure + -- the second result is the error value. Fall through to its own declaration, + -- otherwise the result stays unknown. + elseif func.special == 'xpcall' and index > 1 then if not args then return end @@ -2205,10 +2207,12 @@ local compilerSwitch = util.switch() newArgs[#newArgs+1] = args[i] end local node = getReturn(args[1], index - 1, newArgs) - if node then + if node and not node:isEmpty() then vm.setNode(source, node) + return end - return + -- Same as `pcall`: the message handler's result comes in place of the missing + -- return, and its type is declared on `xpcall` itself. end if func.special == 'require' then if index == 2 then diff --git a/test/type_inference/common.lua b/test/type_inference/common.lua index bd2de1ea5..5db2e98f3 100644 --- a/test/type_inference/common.lua +++ b/test/type_inference/common.lua @@ -320,6 +320,20 @@ end _, = xpcall(x) ]] +-- A declared function without returns leaves nothing to take the second result from, but +-- `pcall` still has one of its own: the error value. +TEST 'any' [[ +---@type fun() +local x +_, = pcall(x) +]] + +TEST 'any' [[ +---@type fun() +local x +_, = xpcall(x, debug.traceback) +]] + TEST 'A' [[ ---@class A