summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------3rd/bee.lua0
m---------3rd/lovr-api0
m---------3rd/luamake0
-rw-r--r--changelog.md20
-rw-r--r--meta/template/table.lua5
-rw-r--r--script/core/formatting.lua2
-rw-r--r--script/core/rangeformatting.lua2
-rw-r--r--script/core/semantic-tokens.lua26
-rw-r--r--script/language.lua4
-rw-r--r--script/parser/luadoc.lua3
-rw-r--r--script/provider/diagnostic.lua4
-rw-r--r--script/vm/compiler.lua79
-rw-r--r--script/vm/generic.lua2
-rw-r--r--script/vm/sign.lua3
-rw-r--r--test/type_inference/init.lua32
15 files changed, 138 insertions, 44 deletions
diff --git a/3rd/bee.lua b/3rd/bee.lua
-Subproject 2ffa9cb493ee7e38e7ce1e49449a85cbcce247c
+Subproject c19753f0d11c4cc669ae3eb3d20beea9654adb1
diff --git a/3rd/lovr-api b/3rd/lovr-api
-Subproject d0d8e4e6e29b24edcc0ac7c3b7406225a9ec925
+Subproject e2bf41325a1fb15f90ac6ee07b61c2e927ad465
diff --git a/3rd/luamake b/3rd/luamake
-Subproject 4116cdeca3f451f3607870dc8c12781012d8036
+Subproject 842b520a2291d85562b554010cc177a6d358ff5
diff --git a/changelog.md b/changelog.md
index 983af002..0ead8edc 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,7 +1,27 @@
# changelog
## 3.1.1
+* `NEW` supports infer of callback parameter
+ ```lua
+ ---@type string[]
+ local t
+
+ table.sort(t, function (a, b)
+ -- `a` and `b` is `string` here
+ end)
+ ```
+* `NEW` using `---@overload` as class constructor
+ ```lua
+ ---@class Class
+ ---@overload fun():Class
+ local mt
+
+ local x = mt() --> x is `Class` here
+ ```
* `FIX` [#1051](https://github.com/sumneko/lua-language-server/issues/1051)
+* `FIX` [#1072](https://github.com/sumneko/lua-language-server/issues/1072)
+* `FIX` [#1077](https://github.com/sumneko/lua-language-server/issues/1077)
+* `FIX` runtime errors
## 3.1.0
`2022-4-17`
diff --git a/meta/template/table.lua b/meta/template/table.lua
index 21c8b619..02288342 100644
--- a/meta/template/table.lua
+++ b/meta/template/table.lua
@@ -50,8 +50,9 @@ function table.pack(...) end
function table.remove(list, pos) end
---#DES 'table.sort'
----@param list table
----@param comp fun(a: any, b: any):boolean
+---@generic T
+---@param list T[]
+---@param comp fun(a: T, b: T):boolean
function table.sort(list, comp) end
---@version >5.2, JIT
diff --git a/script/core/formatting.lua b/script/core/formatting.lua
index 49da6861..b52854a4 100644
--- a/script/core/formatting.lua
+++ b/script/core/formatting.lua
@@ -3,7 +3,7 @@ local files = require("files")
local log = require("log")
return function(uri, options)
- local text = files.getText(uri)
+ local text = files.getOriginText(uri)
local ast = files.getState(uri)
local status, formattedText = codeFormat.format(uri, text, options)
diff --git a/script/core/rangeformatting.lua b/script/core/rangeformatting.lua
index ccf2d21f..f64e9cda 100644
--- a/script/core/rangeformatting.lua
+++ b/script/core/rangeformatting.lua
@@ -4,7 +4,7 @@ local log = require("log")
local converter = require("proto.converter")
return function(uri, range, options)
- local text = files.getText(uri)
+ local text = files.getOriginText(uri)
local status, formattedText, startLine, endLine = codeFormat.range_format(
uri, text, range.start.line, range["end"].line, options)
diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua
index 568bb222..3b7b77ee 100644
--- a/script/core/semantic-tokens.lua
+++ b/script/core/semantic-tokens.lua
@@ -165,21 +165,17 @@ local Care = util.switch()
-- 5. Class declaration
-- only search this local
if loc.bindDocs then
- for i = #loc.bindDocs, 1, -1 do
- local doc = loc.bindDocs[i]
- if doc.type == 'doc.type' then
- break
- end
- if doc.type == "doc.class" and doc.bindSources then
- for _, src in ipairs(doc.bindSources) do
- if src == loc then
- results[#results+1] = {
- start = source.start,
- finish = source.finish,
- type = define.TokenTypes.class,
- }
- return
- end
+ local isParam = source.parent.type == 'funcargs'
+ or source.parent.type == 'in'
+ if not isParam then
+ for _, doc in ipairs(loc.bindDocs) do
+ if doc.type == 'doc.class' then
+ results[#results+1] = {
+ start = source.start,
+ finish = source.finish,
+ type = define.TokenTypes.class,
+ }
+ return
end
end
end
diff --git a/script/language.lua b/script/language.lua
index 771dc948..22546fb8 100644
--- a/script/language.lua
+++ b/script/language.lua
@@ -6,7 +6,9 @@ local function supportLanguage()
local list = {}
for path in fs.pairs(ROOT / 'locale') do
if fs.is_directory(path) then
- list[#list+1] = path:filename():string():lower()
+ local id = path:filename():string():lower()
+ list[#list+1] = id
+ list[id] = true
end
end
return list
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index b7849524..b90077d1 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -1295,7 +1295,8 @@ local function isNextLine(binded, doc)
if lastDoc.type == 'doc.class'
or lastDoc.type == 'doc.field' then
if doc.type ~= 'doc.field'
- and doc.type ~= 'doc.comment' then
+ and doc.type ~= 'doc.comment'
+ and doc.type ~= 'doc.overload' then
return false
end
end
diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua
index b359c21c..7a237700 100644
--- a/script/provider/diagnostic.lua
+++ b/script/provider/diagnostic.lua
@@ -256,13 +256,13 @@ function m.doDiagnostic(uri, isScopeDiag)
end
end
+ pushResult()
+
-- always re-sent diagnostics of current file
if not isScopeDiag then
m.cache[uri] = nil
end
- pushResult()
-
local lastPushClock = time.time()
---@async
xpcall(core, log.error, uri, isScopeDiag, function (result)
diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua
index da45b5d3..94968292 100644
--- a/script/vm/compiler.lua
+++ b/script/vm/compiler.lua
@@ -201,11 +201,13 @@ function vm.getClassFields(suri, node, key, ref, pushResult)
local hasFounded = {}
for _, field in ipairs(set.fields) do
local fieldKey = guide.getKeyName(field)
- if key == nil
- or fieldKey == key then
- if not searchedFields[fieldKey] then
- pushResult(field)
- hasFounded[fieldKey] = true
+ if fieldKey then
+ if key == nil
+ or fieldKey == key then
+ if not searchedFields[fieldKey] then
+ pushResult(field)
+ hasFounded[fieldKey] = true
+ end
end
end
end
@@ -214,19 +216,23 @@ function vm.getClassFields(suri, node, key, ref, pushResult)
for _, src in ipairs(set.bindSources) do
searchFieldSwitch(src.type, suri, src, key, ref, function (field)
local fieldKey = guide.getKeyName(field)
- if not searchedFields[fieldKey]
- and guide.isSet(field) then
- hasFounded[fieldKey] = true
- pushResult(field)
+ if fieldKey then
+ if not searchedFields[fieldKey]
+ and guide.isSet(field) then
+ hasFounded[fieldKey] = true
+ pushResult(field)
+ end
end
end)
if src.value and src.value.type == 'table' then
searchFieldSwitch('table', suri, src.value, key, ref, function (field)
local fieldKey = guide.getKeyName(field)
- if not searchedFields[fieldKey]
- and guide.isSet(field) then
- hasFounded[fieldKey] = true
- pushResult(field)
+ if fieldKey then
+ if not searchedFields[fieldKey]
+ and guide.isSet(field) then
+ hasFounded[fieldKey] = true
+ pushResult(field)
+ end
end
end)
end
@@ -283,6 +289,9 @@ local function getObjectSign(source)
end
source._sign = false
if source.type == 'function' then
+ if not source.bindDocs then
+ return false
+ end
for _, doc in ipairs(source.bindDocs) do
if doc.type == 'doc.generic' then
if not source._sign then
@@ -317,11 +326,15 @@ local function getObjectSign(source)
source._sign = signMgr()
if source.type == 'doc.type.function' then
for _, arg in ipairs(source.args) do
- local argNode = vm.compileNode(arg.extends)
- if arg.optional then
- argNode:addOptional()
+ if arg.extends then
+ local argNode = vm.compileNode(arg.extends)
+ if arg.optional then
+ argNode:addOptional()
+ end
+ source._sign:addSign(argNode)
+ else
+ source._sign:addSign(vm.createNode())
end
- source._sign:addSign(argNode)
end
end
end
@@ -667,10 +680,21 @@ local function compileCallArgNode(arg, call, callNode, fixIndex, myIndex)
for n in callNode:eachObject() do
if n.type == 'function' then
+ local sign = getObjectSign(n)
local farg = getFuncArg(n, myIndex)
if farg then
for fn in vm.compileNode(farg):eachObject() do
if isValidCallArgNode(arg, fn) then
+ if fn.type == 'doc.type.function' then
+ if sign then
+ local generic = genericMgr(fn, sign)
+ local args = {}
+ for i = fixIndex + 1, myIndex - 1 do
+ args[#args+1] = call.args[i]
+ end
+ fn = generic:resolve(guide.getUri(call), args)
+ end
+ end
vm.setNode(arg, fn)
end
end
@@ -779,7 +803,12 @@ local function compileLocal(source)
if n.type == 'doc.type.function' then
for index, arg in ipairs(n.args) do
if func.args[index] == source then
- vm.setNode(source, vm.compileNode(arg))
+ local argNode = vm.compileNode(arg)
+ for an in argNode:eachObject() do
+ if an.type ~= 'doc.generic.name' then
+ vm.setNode(source, an)
+ end
+ end
hasDocArg = true
end
end
@@ -799,6 +828,18 @@ local function compileLocal(source)
vm.setNode(source, globalMgr.getGlobal('type', 'integer'))
end
+ if source.bindDocs then
+ local isParam = source.parent.type == 'funcargs'
+ or source.parent.type == 'in'
+ for _, doc in ipairs(source.bindDocs) do
+ if doc.type == 'doc.overload' then
+ if not isParam then
+ vm.setNode(source, vm.compileNode(doc))
+ end
+ end
+ end
+ end
+
vm.getNode(source):setData('hasDefined', hasMarkDoc or hasMarkParam or hasMarkValue)
end
@@ -1504,7 +1545,7 @@ local compilerSwitch = util.switch()
if source.op.type == '%' then
local a = vm.getNumber(source[1])
local b = vm.getNumber(source[2])
- if a and b then
+ if a and b and b ~= 0 then
local result = a % b
vm.setNode(source, {
type = math.type(result) == 'integer' and 'integer' or 'number',
diff --git a/script/vm/generic.lua b/script/vm/generic.lua
index b3981ff8..b58c7bce 100644
--- a/script/vm/generic.lua
+++ b/script/vm/generic.lua
@@ -114,7 +114,7 @@ end
---@param uri uri
---@param args parser.object
----@return parser.object
+---@return vm.node
function mt:resolve(uri, args)
local resolved = self.sign:resolve(uri, args)
local protoNode = vm.compileNode(self.proto)
diff --git a/script/vm/sign.lua b/script/vm/sign.lua
index 257166ce..e997624a 100644
--- a/script/vm/sign.lua
+++ b/script/vm/sign.lua
@@ -16,8 +16,9 @@ end
---@param uri uri
---@param args parser.object
+---@param removeGeneric true?
---@return table<string, vm.node>
-function mt:resolve(uri, args)
+function mt:resolve(uri, args, removeGeneric)
if not args then
return nil
end
diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua
index cfa604e0..4ba827d3 100644
--- a/test/type_inference/init.lua
+++ b/test/type_inference/init.lua
@@ -1126,6 +1126,29 @@ local t = f('')
print(t.<?x?>)
]]
+TEST 'string' [[
+---@generic T
+---@param t T[]
+---@param callback fun(v: T)
+local function f(t, callback) end
+
+---@type string[]
+local t
+
+f(t, function (<?v?>) end)
+]]
+
+TEST 'unknown' [[
+---@generic T
+---@param t T[]
+---@param callback fun(v: T)
+local function f(t, callback) end
+
+local t = {}
+
+f(t, function (<?v?>) end)
+]]
+
TEST 'table' [[
local <?t?> = setmetatable({}, { __index = function () end })
]]
@@ -1489,6 +1512,15 @@ local function f() end
local <?x?> = f()
]]
+TEST 'AA' [[
+---@class AA
+---@overload fun():AA
+local AAA
+
+
+local <?x?> = AAA()
+]]
+
TEST 'string|integer' [[
local <?x?>
x = '1'