diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2022-06-28 19:09:39 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2022-06-28 19:09:39 +0800 |
commit | 7e778b31476831864dff995ae3ae4e5f223c5726 (patch) | |
tree | b570499b7b70014067d9e5cd737088df474b7c76 /script | |
parent | 09cd9882be4b66f270c74516759844683832b1d4 (diff) | |
download | lua-language-server-7e778b31476831864dff995ae3ae4e5f223c5726.zip |
new diag `return-type-mismatch`
Diffstat (limited to 'script')
-rw-r--r-- | script/core/diagnostics/return-type-mismatch.lua | 70 | ||||
-rw-r--r-- | script/parser/guide.lua | 8 | ||||
-rw-r--r-- | script/proto/diagnostic.lua | 1 | ||||
-rw-r--r-- | script/vm/compiler.lua | 35 |
4 files changed, 97 insertions, 17 deletions
diff --git a/script/core/diagnostics/return-type-mismatch.lua b/script/core/diagnostics/return-type-mismatch.lua new file mode 100644 index 00000000..ba23fa2c --- /dev/null +++ b/script/core/diagnostics/return-type-mismatch.lua @@ -0,0 +1,70 @@ +local files = require 'files' +local lang = require 'language' +local guide = require 'parser.guide' +local vm = require 'vm' +local await = require 'await' + +---@param func parser.object +---@return vm.node[]? +local function getDocReturns(func) + if not func.bindDocs then + return nil + end + local returns = {} + for _, doc in ipairs(func.bindDocs) do + if doc.type == 'doc.return' then + for _, ret in ipairs(doc.returns) do + returns[ret.returnIndex] = vm.compileNode(ret) + end + end + end + if #returns == 0 then + return nil + end + return returns +end +---@async +return function (uri, callback) + local state = files.getState(uri) + if not state then + return + end + + ---@param docReturns vm.node[] + ---@param rets parser.object + local function checkReturn(docReturns, rets) + for i, docRet in ipairs(docReturns) do + local retNode, exp = vm.selectNode(rets, i) + if not exp then + break + end + if not vm.canCastType(uri, docRet, retNode) then + callback { + start = exp.start, + finish = exp.finish, + message = lang.script('DIAG_RETURN_TYPE_MISMATCH', { + def = vm.getInfer(docRet):view(uri), + ref = vm.getInfer(retNode):view(uri), + index = i, + }), + } + end + end + end + + ---@async + guide.eachSourceType(state.ast, 'function', function (source) + if not source.returns then + return + end + local docReturns = getDocReturns(source) + if not docReturns then + return + end + await.delay() + for _, ret in ipairs(source.returns) do + checkReturn(docReturns, ret) + await.delay() + end + end) +end diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 83c84964..8de08ef9 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -1090,12 +1090,12 @@ end ---@param a table ---@param b table ---@return string|false mode ----@return table pathA? ----@return table pathB? +---@return table? pathA +---@return table? pathB function m.getPath(a, b, sameFunction) --- 首先测试双方在同一个函数内 if sameFunction and m.getParentFunction(a) ~= m.getParentFunction(b) then - return false, nil, nil + return false end local mode local objA @@ -1139,7 +1139,7 @@ function m.getPath(a, b, sameFunction) end end if not start then - return false, nil, nil + return false end -- pathA: { 1, 2, 3} -- pathB: {5, 6, 2, 3} diff --git a/script/proto/diagnostic.lua b/script/proto/diagnostic.lua index 43043b94..1065950d 100644 --- a/script/proto/diagnostic.lua +++ b/script/proto/diagnostic.lua @@ -74,6 +74,7 @@ m.register { 'assign-type-mismatch', 'param-type-mismatch', 'cast-type-mismatch', + 'return-type-mismatch', } { group = 'type-check', severity = 'Warning', diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index f42a4768..e7af1f0f 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -469,9 +469,9 @@ function vm.getReturnOfFunction(func, index) end if not func._returns[index] then func._returns[index] = { - type = 'function.return', - parent = func, - index = index, + type = 'function.return', + parent = func, + returnIndex = index, } end return func._returns[index] @@ -736,14 +736,15 @@ function vm.compileByParentNode(source, key, ref, pushResult) end end ----@return vm.node? -local function selectNode(source, list, index) - if not list then - return nil - end +---@param list parser.object[] +---@param index integer +---@return vm.node +---@return parser.object? +function vm.selectNode(list, index) local exp if list[index] then exp = list[index] + index = 1 else for i = index, 1, -1 do if list[i] then @@ -758,16 +759,14 @@ local function selectNode(source, list, index) end end if not exp then - vm.setNode(source, vm.declareGlobal('type', 'nil')) - return vm.getNode(source) + return vm.createNode(vm.declareGlobal('type', 'nil')), nil end ---@type vm.node? local result if exp.type == 'call' then result = getReturn(exp.node, index, exp.args) if not result then - vm.setNode(source, vm.declareGlobal('type', 'unknown')) - return vm.getNode(source) + return vm.createNode(vm.declareGlobal('type', 'unknown')), exp end else ---@type vm.node @@ -776,6 +775,15 @@ local function selectNode(source, list, index) result:merge(vm.declareGlobal('type', 'unknown')) end end + return result, exp +end + +---@param source parser.object +---@param list parser.object[] +---@param index integer +---@return vm.node +local function selectNode(source, list, index) + local result = vm.selectNode(list, index) if source.type == 'function.return' then -- remove any for returns local rtnNode = vm.createNode() @@ -1513,9 +1521,10 @@ local compilerSwitch = util.switch() vm.setNode(source, vm.compileNode(source.value)) end) : case 'function.return' + ---@param source parser.object : call(function (source) local func = source.parent - local index = source.index + local index = source.returnIndex local hasMarkDoc if func.bindDocs then local sign = getObjectSign(func) |