diff options
m--------- | 3rd/bee.lua | 0 | ||||
m--------- | 3rd/lovr-api | 0 | ||||
m--------- | 3rd/luamake | 0 | ||||
-rw-r--r-- | changelog.md | 20 | ||||
-rw-r--r-- | meta/template/table.lua | 5 | ||||
-rw-r--r-- | script/core/formatting.lua | 2 | ||||
-rw-r--r-- | script/core/rangeformatting.lua | 2 | ||||
-rw-r--r-- | script/core/semantic-tokens.lua | 26 | ||||
-rw-r--r-- | script/language.lua | 4 | ||||
-rw-r--r-- | script/parser/luadoc.lua | 3 | ||||
-rw-r--r-- | script/provider/diagnostic.lua | 4 | ||||
-rw-r--r-- | script/vm/compiler.lua | 79 | ||||
-rw-r--r-- | script/vm/generic.lua | 2 | ||||
-rw-r--r-- | script/vm/sign.lua | 3 | ||||
-rw-r--r-- | test/type_inference/init.lua | 32 |
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' |