summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2022-06-22 19:00:27 +0800
committer最萌小汐 <sumneko@hotmail.com>2022-06-22 19:00:27 +0800
commit79f76ed6611701ca5994fe110eb09e9309499918 (patch)
treef470f3c16de51d92130c05e920b824e37b9993a6
parenta212b62603f6087bc5a34c4aea45f7cdb0643a8b (diff)
downloadlua-language-server-79f76ed6611701ca5994fe110eb09e9309499918.zip
update
-rw-r--r--locale/zh-cn/script.lua4
-rw-r--r--meta/template/basic.lua4
-rw-r--r--script/core/completion/completion.lua7
-rw-r--r--script/core/diagnostics/cast-type-mismatch.lua45
-rw-r--r--script/core/diagnostics/unknown-cast-variable.lua32
-rw-r--r--script/files.lua4
-rw-r--r--script/fs-utility.lua2
-rw-r--r--script/parser/guide.lua4
-rw-r--r--script/parser/luadoc.lua3
-rw-r--r--script/proto/define.lua4
-rw-r--r--script/provider/markdown.lua2
-rw-r--r--script/vm/function.lua22
-rw-r--r--script/vm/type.lua5
-rw-r--r--test/definition/luadoc.lua8
-rw-r--r--test/diagnostics/common.lua4
-rw-r--r--test/diagnostics/type-check.lua26
-rw-r--r--tools/lua51.lua2
17 files changed, 165 insertions, 13 deletions
diff --git a/locale/zh-cn/script.lua b/locale/zh-cn/script.lua
index 2738d51a..8919ff0a 100644
--- a/locale/zh-cn/script.lua
+++ b/locale/zh-cn/script.lua
@@ -124,6 +124,10 @@ DIAG_ASSIGN_TYPE_MISMATCH =
'类型不匹配,不能将 `{ref}` 赋值给 `{def}`。'
DIAG_PARAM_TYPE_MISMATCH =
'参数类型不匹配,不能将 `{ref}` 赋值给 `{def}`。'
+DIAG_UNKNOWN_CAST_VARIABLE =
+'未知的类型转换变量 `{}`。'
+DIAG_CAST_TYPE_MISMATCH =
+'类型不匹配,不能将 `{ref}` 转换为 `{def}`。'
MWS_NOT_SUPPORT =
'{} 目前还不支持多工作目录,我可能需要重启才能支持新的工作目录...'
diff --git a/meta/template/basic.lua b/meta/template/basic.lua
index 8cae0ef5..268d6539 100644
--- a/meta/template/basic.lua
+++ b/meta/template/basic.lua
@@ -215,11 +215,11 @@ function setfenv(f, table) end
function setmetatable(table, metatable) end
---#DES 'tonumber'
+---@overload fun(e: string|number, base: integer):integer?
---@param e string|number
----@param base? integer
---@return number?
---@nodiscard
-function tonumber(e, base) end
+function tonumber(e) end
---#DES 'tostring'
---@param v any
diff --git a/script/core/completion/completion.lua b/script/core/completion/completion.lua
index 165dbac5..52ec7a18 100644
--- a/script/core/completion/completion.lua
+++ b/script/core/completion/completion.lua
@@ -1103,7 +1103,7 @@ local function tryLabelInString(label, source)
if not state or not state.ast then
return label
end
- if not matchKey(source[1], state.ast[1]) then
+ if not matchKey(source[1], state.ast[1]--[[@as string]]) then
return nil
end
return util.viewString(state.ast[1], source[2])
@@ -1242,6 +1242,9 @@ local function tryIndex(state, position, results)
return
end
local word = parent.next and parent.next.index and parent.next.index[1]
+ if not word then
+ return
+ end
checkField(state, word, position, position, parent, oop, results)
end
@@ -1426,6 +1429,7 @@ local function tryCallArg(state, position, results)
if src.type == 'doc.type.string'
or src.type == 'doc.type.integer'
or src.type == 'doc.type.boolean' then
+ ---@cast src parser.object
enums[#enums+1] = {
label = vm.viewObject(src, state.uri),
description = src.comment,
@@ -1439,6 +1443,7 @@ local function tryCallArg(state, position, results)
}
end
if src.type == 'doc.type.function' then
+ ---@cast src parser.object
local insertText = buildInsertDocFunction(src)
local description
if src.comment then
diff --git a/script/core/diagnostics/cast-type-mismatch.lua b/script/core/diagnostics/cast-type-mismatch.lua
new file mode 100644
index 00000000..ecee6a84
--- /dev/null
+++ b/script/core/diagnostics/cast-type-mismatch.lua
@@ -0,0 +1,45 @@
+local files = require 'files'
+local guide = require 'parser.guide'
+local lang = require 'language'
+local vm = require 'vm'
+local await = require 'await'
+
+---@async
+return function (uri, callback)
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+
+ if not state.ast.docs then
+ return
+ end
+
+ for _, doc in ipairs(state.ast.docs) do
+ if doc.type == 'doc.cast' then
+ await.delay()
+ local defs = vm.getDefs(doc.loc)
+ local loc = defs[1]
+ if loc then
+ local defNode = vm.compileNode(loc)
+ if defNode:getData 'hasDefined' then
+ for _, cast in ipairs(doc.casts) do
+ if not cast.mode and cast.extends then
+ local refNode = vm.compileNode(cast.extends)
+ if not vm.canCastType(uri, defNode, refNode) then
+ callback {
+ start = cast.extends.start,
+ finish = cast.extends.finish,
+ message = lang.script('DIAG_UNKNOWN_CAST_VARIABLE', {
+ def = vm.getInfer(defNode):view(uri),
+ ref = vm.getInfer(refNode):view(uri),
+ })
+ }
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/script/core/diagnostics/unknown-cast-variable.lua b/script/core/diagnostics/unknown-cast-variable.lua
new file mode 100644
index 00000000..cfa25ed8
--- /dev/null
+++ b/script/core/diagnostics/unknown-cast-variable.lua
@@ -0,0 +1,32 @@
+local files = require 'files'
+local guide = require 'parser.guide'
+local lang = require 'language'
+local vm = require 'vm'
+local await = require 'await'
+
+---@async
+return function (uri, callback)
+ local state = files.getState(uri)
+ if not state then
+ return
+ end
+
+ if not state.ast.docs then
+ return
+ end
+
+ for _, doc in ipairs(state.ast.docs) do
+ if doc.type == 'doc.cast' then
+ await.delay()
+ local defs = vm.getDefs(doc.loc)
+ local loc = defs[1]
+ if not loc then
+ callback {
+ start = doc.loc.start,
+ finish = doc.loc.finish,
+ message = lang.script('DIAG_UNKNOWN_CAST_VARIABLE', doc[1])
+ }
+ end
+ end
+ end
+end
diff --git a/script/files.lua b/script/files.lua
index 252a6ee5..d0225f45 100644
--- a/script/files.lua
+++ b/script/files.lua
@@ -14,6 +14,9 @@ local progress = require "progress"
local encoder = require 'encoder'
local scope = require 'workspace.scope'
+---@class file
+---@field content string
+
---@class files
local m = {}
@@ -23,6 +26,7 @@ m.assocVersion = -1
function m.reset()
m.openMap = {}
+ ---@type table<string, file>
m.fileMap = {}
m.dllMap = {}
m.visible = {}
diff --git a/script/fs-utility.lua b/script/fs-utility.lua
index 08aae98a..cca65521 100644
--- a/script/fs-utility.lua
+++ b/script/fs-utility.lua
@@ -40,7 +40,7 @@ function m.loadFile(path, keepBom)
end
--- 写入文件
----@param path string
+---@param path any
---@param content string
function m.saveFile(path, content)
if type(path) ~= 'string' then
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index 3f68ccd2..7a9cb875 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -478,7 +478,9 @@ function m.getLocal(source, name, pos)
if not block then
return nil
end
- if block.start <= pos and block.finish >= pos then
+ if block.start <= pos
+ and block.finish >= pos
+ and blockTypes[block.type] then
break
end
block = block.parent
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index 420e78cd..c4f40ac4 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -1661,6 +1661,9 @@ return function (state)
end
end
+ ast.docs.start = ast.start
+ ast.docs.finish = ast.finish
+
if #ast.docs == 0 then
return
end
diff --git a/script/proto/define.lua b/script/proto/define.lua
index 45fbba9e..30ef621e 100644
--- a/script/proto/define.lua
+++ b/script/proto/define.lua
@@ -62,6 +62,8 @@ m.DiagnosticDefaultSeverity = {
['doc-field-no-class'] = 'Warning',
['duplicate-doc-field'] = 'Warning',
['unknown-diag-code'] = 'Warning',
+ ['unknown-cast-variable'] = 'Warning',
+ ['cast-type-mismatch'] = 'Warning',
['codestyle-check'] = 'Warning',
['spell-check'] = 'Information',
@@ -126,6 +128,8 @@ m.DiagnosticDefaultNeededFileStatus = {
['doc-field-no-class'] = 'Any',
['duplicate-doc-field'] = 'Any',
['unknown-diag-code'] = 'Any',
+ ['unknown-cast-variable'] = 'Any',
+ ['cast-type-mismatch'] = 'Any',
['codestyle-check'] = 'None',
['spell-check'] = 'None',
diff --git a/script/provider/markdown.lua b/script/provider/markdown.lua
index 6b007713..f2f7f777 100644
--- a/script/provider/markdown.lua
+++ b/script/provider/markdown.lua
@@ -10,7 +10,7 @@ function mt:__tostring()
end
---@param language string
----@param text string|markdown
+---@param text? string|markdown
function mt:add(language, text)
if not text then
return self
diff --git a/script/vm/function.lua b/script/vm/function.lua
index 2a169bd6..e8fadb38 100644
--- a/script/vm/function.lua
+++ b/script/vm/function.lua
@@ -75,14 +75,15 @@ function vm.countParamsOfNode(node)
end
---@param func parser.object
+---@param mark? table
---@return integer min
---@return integer max
-function vm.countReturnsOfFunction(func)
+function vm.countReturnsOfFunction(func, mark)
if func.type == 'function' then
local min, max
if func.returns then
for _, ret in ipairs(func.returns) do
- local rmin, rmax = vm.countList(ret)
+ local rmin, rmax = vm.countList(ret, mark)
if not min or rmin < min then
min = rmin
end
@@ -126,14 +127,15 @@ function vm.countReturnsOfFunction(func)
end
---@param func parser.object
+---@param mark? table
---@return integer min
---@return integer max
-function vm.countReturnsOfCall(func, args)
+function vm.countReturnsOfCall(func, args, mark)
local funcs = vm.getMatchedFunctions(func, args)
local min
local max
for _, f in ipairs(funcs) do
- local rmin, rmax = vm.countReturnsOfFunction(f)
+ local rmin, rmax = vm.countReturnsOfFunction(f, mark)
if not min or rmin < min then
min = rmin
end
@@ -145,9 +147,10 @@ function vm.countReturnsOfCall(func, args)
end
---@param list parser.object[]?
+---@param mark? table
---@return integer min
---@return integer max
-function vm.countList(list)
+function vm.countList(list, mark)
if not list then
return 0, 0
end
@@ -160,7 +163,14 @@ function vm.countList(list)
return #list - 1, math.huge
end
if lastArg.type == 'call' then
- local rmin, rmax = vm.countReturnsOfCall(lastArg.node, lastArg.args)
+ if not mark then
+ mark = {}
+ end
+ if mark[lastArg] then
+ return #list - 1, math.huge
+ end
+ mark[lastArg] = true
+ local rmin, rmax = vm.countReturnsOfCall(lastArg.node, lastArg.args, mark)
return #list - 1 + rmin, #list - 1 + rmax
end
return #list, #list
diff --git a/script/vm/type.lua b/script/vm/type.lua
index fa78f735..208f21ed 100644
--- a/script/vm/type.lua
+++ b/script/vm/type.lua
@@ -130,6 +130,11 @@ function vm.isSubType(uri, child, parent, mark)
end
end
end
+ if set.type == 'doc.alias' and set.extends then
+ if vm.isSubType(uri, vm.compileNode(set.extends), parent, mark) then
+ return true
+ end
+ end
end
end
end
diff --git a/test/definition/luadoc.lua b/test/definition/luadoc.lua
index 47859b15..b07396fa 100644
--- a/test/definition/luadoc.lua
+++ b/test/definition/luadoc.lua
@@ -899,3 +899,11 @@ local <!x!>
---@cast <?x?> integer
]]
+
+TEST [[
+local function f()
+ local <!x!>
+
+ ---@cast <?x?> integer
+end
+]]
diff --git a/test/diagnostics/common.lua b/test/diagnostics/common.lua
index 5de7d5db..0708f63a 100644
--- a/test/diagnostics/common.lua
+++ b/test/diagnostics/common.lua
@@ -1655,3 +1655,7 @@ end
k(f())
]]
+
+TEST [[
+---@cast <!x!> integer
+]]
diff --git a/test/diagnostics/type-check.lua b/test/diagnostics/type-check.lua
index 46997181..afd0a5b6 100644
--- a/test/diagnostics/type-check.lua
+++ b/test/diagnostics/type-check.lua
@@ -340,5 +340,31 @@ local x
x = 1 + G
]]
+TEST [[
+---@alias A integer
+
+---@type A
+local a
+
+---@type integer
+local b
+
+b = a
+]]
+
+TEST [[
+---@type string|boolean
+local t
+
+---@cast t string
+]]
+
+TEST [[
+---@type string|boolean
+local t
+
+---@cast t <!number!>
+]]
+
config.remove(nil, 'Lua.diagnostics.disable', 'unused-local')
config.remove(nil, 'Lua.diagnostics.disable', 'undefined-global')
diff --git a/tools/lua51.lua b/tools/lua51.lua
index fb13d294..20e3335d 100644
--- a/tools/lua51.lua
+++ b/tools/lua51.lua
@@ -374,7 +374,7 @@ lua51.os.difftime = os.difftime
lua51.os.execute = os.execute
function lua51.os.exit(code)
code = tonumber(code) or 0
- osExit(code)
+ osExit(code--[[@as integer]])
end
lua51.os.getenv = os.getenv
lua51.os.remove = os.remove