summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2021-07-05 17:12:07 +0800
committer最萌小汐 <sumneko@hotmail.com>2021-07-05 17:12:07 +0800
commitbc1baf261f3552ab5a6731389bd21824530a454b (patch)
tree38f5aaf86d09bd77a3aaacef6e376289b2cd918d
parent788709d4e2a2ae1d412a0afcfddbfbce19d04099 (diff)
downloadlua-language-server-bc1baf261f3552ab5a6731389bd21824530a454b.zip
resolve #511
-rw-r--r--changelog.md15
-rw-r--r--script/core/generic.lua45
-rw-r--r--script/core/hover/table.lua6
-rw-r--r--script/core/noder.lua227
-rw-r--r--script/parser/luadoc.lua4
-rw-r--r--test/type_inference/init.lua11
6 files changed, 182 insertions, 126 deletions
diff --git a/changelog.md b/changelog.md
index 2f4125f7..f4aa68a6 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,21 @@
# changelog
## 2.2.0
+* `NEW` `LuaDoc`: supports literal table:
+ ```lua
+ ---@generic T
+ ---@param x T
+ ---@return { x: number, y: T, z?: boolean}
+ local function f(x) end
+
+ local t = f('str')
+ -- hovering "t" shows:
+ local t: {
+ x: number,
+ y: string,
+ z?: boolean,
+ }
+ ```
* `FIX` supports for file with LF
## 2.1.0
diff --git a/script/core/generic.lua b/script/core/generic.lua
index 5f9ad5a4..47cad7df 100644
--- a/script/core/generic.lua
+++ b/script/core/generic.lua
@@ -34,9 +34,7 @@ end
---@param proto parser.guide.object
---@return generic.value
local function createValue(closure, proto, callback, road)
- if callback then
- road = road or {}
- end
+ road = road or {}
if proto.type == 'doc.type' then
local types = {}
local hasGeneric
@@ -54,6 +52,8 @@ local function createValue(closure, proto, callback, road)
end
local value = instantValue(closure, proto)
value.types = types
+ value.enums = proto.enums
+ value.resumes = proto.resumes
noder.compileNode(noder.getNoders(proto), value)
return value
end
@@ -98,18 +98,15 @@ local function createValue(closure, proto, callback, road)
return value
end
if proto.type == 'doc.type.array' then
- if road then
- road[#road+1] = noder.WEAK_ANY_FIELD
- end
+ road[#road+1] = noder.WEAK_ANY_FIELD
local node = createValue(closure, proto.node, callback, road)
- if road then
- road[#road] = nil
- end
+ road[#road] = nil
if not node then
return nil
end
local value = instantValue(closure, proto)
value.node = node
+ noder.compileNode(noder.getNoders(proto), value)
return value
end
if proto.type == 'doc.type.table' then
@@ -127,6 +124,36 @@ local function createValue(closure, proto, callback, road)
local value = instantValue(closure, proto)
value.tkey = tkey or proto.tkey
value.tvalue = tvalue or proto.tvalue
+ noder.compileNode(noder.getNoders(proto), value)
+ return value
+ end
+ if proto.type == 'doc.type.ltable' then
+ local fields = {}
+ for i, field in ipairs(proto.fields) do
+ fields[i] = createValue(closure, field, callback, road) or field
+ end
+ if #fields == 0 then
+ return nil
+ end
+ local value = instantValue(closure, proto)
+ value.fields = fields
+ noder.compileNode(noder.getNoders(proto), value)
+ return value
+ end
+ if proto.type == 'doc.type.field' then
+ road[#road+1] = ('%s%q'):format(
+ noder.SPLIT_CHAR,
+ proto.name[1]
+ )
+ local typeUnit = createValue(closure, proto.extends, callback, road)
+ road[#road] = nil
+ if not typeUnit then
+ return nil
+ end
+ local value = instantValue(closure, proto)
+ value.name = proto.name
+ value.extends = typeUnit
+ noder.compileNode(noder.getNoders(proto), value)
return value
end
end
diff --git a/script/core/hover/table.lua b/script/core/hover/table.lua
index c3a8fe95..bd0274cf 100644
--- a/script/core/hover/table.lua
+++ b/script/core/hover/table.lua
@@ -116,6 +116,12 @@ local function getOptionalMap(fields)
optionals[key] = true
end
end
+ if field.type == 'doc.type.field' then
+ if field.optional then
+ local key = vm.getKeyName(field)
+ optionals[key] = true
+ end
+ end
end
return optionals
end
diff --git a/script/core/noder.lua b/script/core/noder.lua
index eac1b9f5..2558a22e 100644
--- a/script/core/noder.lua
+++ b/script/core/noder.lua
@@ -646,6 +646,87 @@ local function compileCallReturn(noders, call, sourceID, returnIndex)
pushBackward(noders, funcXID, sourceID, 'deep')
end
+function m.compileDocValue(noders, tp, id, source)
+ if tp == 'doc.type' then
+ if source.bindSources then
+ for _, src in ipairs(source.bindSources) do
+ pushForward(noders, getID(src), id)
+ pushForward(noders, id, getID(src))
+ end
+ end
+ for _, enumUnit in ipairs(source.enums) do
+ pushForward(noders, id, getID(enumUnit))
+ end
+ for _, resumeUnit in ipairs(source.resumes) do
+ pushForward(noders, id, getID(resumeUnit))
+ end
+ for _, typeUnit in ipairs(source.types) do
+ local unitID = getID(typeUnit)
+ pushForward(noders, id, unitID)
+ if source.bindSources then
+ for _, src in ipairs(source.bindSources) do
+ pushBackward(noders, unitID, getID(src))
+ end
+ end
+ end
+ end
+ if tp == 'doc.type.table' then
+ if source.tkey then
+ local keyID = ('%s%s'):format(
+ id,
+ TABLE_KEY
+ )
+ pushForward(noders, keyID, getID(source.tkey))
+ end
+ if source.tvalue then
+ local valueID = ('%s%s'):format(
+ id,
+ ANY_FIELD
+ )
+ pushForward(noders, valueID, getID(source.tvalue))
+ end
+ end
+ if tp == 'doc.type.ltable' then
+ local firstField = source.fields[1]
+ if not firstField then
+ return
+ end
+ local keyID = ('%s%s'):format(
+ id,
+ WEAK_TABLE_KEY
+ )
+ local valueID = ('%s%s'):format(
+ id,
+ WEAK_ANY_FIELD
+ )
+ pushForward(noders, keyID, 'dn:string')
+ pushForward(noders, valueID, getID(firstField.extends))
+ for _, field in ipairs(source.fields) do
+ local extendsID = ('%s%s%q'):format(
+ id,
+ SPLIT_CHAR,
+ field.name[1]
+ )
+ pushForward(noders, extendsID, getID(field))
+ pushForward(noders, extendsID, getID(field.extends))
+ end
+ end
+ if tp == 'doc.type.array' then
+ if source.node then
+ local nodeID = ('%s%s'):format(
+ id,
+ ANY_FIELD
+ )
+ pushForward(noders, nodeID, getID(source.node))
+ end
+ local keyID = ('%s%s'):format(
+ id,
+ TABLE_KEY
+ )
+ pushForward(noders, keyID, 'dn:integer')
+ end
+end
+
---@param noders noders
---@param source parser.guide.object
---@return parser.guide.object[]
@@ -695,29 +776,29 @@ function m.compileNode(noders, source)
end
end
-- 分解 @type
- if source.type == 'doc.type' then
- if source.bindSources then
- for _, src in ipairs(source.bindSources) do
- pushForward(noders, getID(src), id)
- pushForward(noders, id, getID(src))
- end
- end
- for _, enumUnit in ipairs(source.enums) do
- pushForward(noders, id, getID(enumUnit))
- end
- for _, resumeUnit in ipairs(source.resumes) do
- pushForward(noders, id, getID(resumeUnit))
- end
- for _, typeUnit in ipairs(source.types) do
- local unitID = getID(typeUnit)
- pushForward(noders, id, unitID)
- if source.bindSources then
- for _, src in ipairs(source.bindSources) do
- pushBackward(noders, unitID, getID(src))
- end
- end
- end
- end
+ --if source.type == 'doc.type' then
+ -- if source.bindSources then
+ -- for _, src in ipairs(source.bindSources) do
+ -- pushForward(noders, getID(src), id)
+ -- pushForward(noders, id, getID(src))
+ -- end
+ -- end
+ -- for _, enumUnit in ipairs(source.enums) do
+ -- pushForward(noders, id, getID(enumUnit))
+ -- end
+ -- for _, resumeUnit in ipairs(source.resumes) do
+ -- pushForward(noders, id, getID(resumeUnit))
+ -- end
+ -- for _, typeUnit in ipairs(source.types) do
+ -- local unitID = getID(typeUnit)
+ -- pushForward(noders, id, unitID)
+ -- if source.bindSources then
+ -- for _, src in ipairs(source.bindSources) do
+ -- pushBackward(noders, unitID, getID(src))
+ -- end
+ -- end
+ -- end
+ --end
-- 分解 @alias
if source.type == 'doc.alias' then
pushForward(noders, getID(source.alias), getID(source.extends))
@@ -773,6 +854,7 @@ function m.compileNode(noders, source)
pushForward(noders, fieldID, fieldClassID)
end
end
+ m.compileDocValue(noders, source.type, id, source)
if source.type == 'call' then
if source.parent.type ~= 'select' then
compileCallReturn(noders, source, id, 1)
@@ -818,61 +900,6 @@ function m.compileNode(noders, source)
end)
end
end
- if source.type == 'doc.type.table' then
- if source.tkey then
- local keyID = ('%s%s'):format(
- id,
- TABLE_KEY
- )
- pushForward(noders, keyID, getID(source.tkey))
- end
- if source.tvalue then
- local valueID = ('%s%s'):format(
- id,
- ANY_FIELD
- )
- pushForward(noders, valueID, getID(source.tvalue))
- end
- end
- if source.type == 'doc.type.ltable' then
- local firstField = source.fields[1]
- if not firstField then
- return
- end
- local keyID = ('%s%s'):format(
- id,
- WEAK_TABLE_KEY
- )
- local valueID = ('%s%s'):format(
- id,
- WEAK_ANY_FIELD
- )
- pushForward(noders, keyID, 'dn:string')
- pushForward(noders, valueID, getID(firstField.extends))
- for _, field in ipairs(source.fields) do
- local extendsID = ('%s%s%q'):format(
- id,
- SPLIT_CHAR,
- field.name[1]
- )
- pushForward(noders, extendsID, getID(field))
- pushForward(noders, extendsID, getID(field.extends))
- end
- end
- if source.type == 'doc.type.array' then
- if source.node then
- local nodeID = ('%s%s'):format(
- id,
- ANY_FIELD
- )
- pushForward(noders, nodeID, getID(source.node))
- end
- local keyID = ('%s%s'):format(
- id,
- TABLE_KEY
- )
- pushForward(noders, keyID, 'dn:integer')
- end
if source.type == 'doc.type.name' then
local uri = guide.getUri(source)
collector.subscribe(uri, id, getNode(noders, id))
@@ -1056,43 +1083,13 @@ function m.compileNode(noders, source)
end
end
end
- if proto.type == 'doc.type' then
- for _, tp in ipairs(source.types) do
- pushForward(noders, id, getID(tp))
- pushBackward(noders, getID(tp), id)
- end
- end
- if proto.type == 'doc.type.array' then
- local nodeID = ('%s%s'):format(
- id,
- ANY_FIELD
- )
- pushForward(noders, nodeID, getID(source.node))
- local keyID = ('%s%s'):format(
- id,
- TABLE_KEY
- )
- pushForward(noders, keyID, 'dn:integer')
- end
- if proto.type == 'doc.type.table' then
- if source.tkey then
- local keyID = ('%s%s'):format(
- id,
- TABLE_KEY
- )
- pushForward(noders, keyID, getID(source.tkey))
- end
- if source.tvalue then
- local valueID = ('%s%s'):format(
- id,
- ANY_FIELD
- )
- pushForward(noders, valueID, getID(source.tvalue))
- end
- end
- if proto.type == 'doc.type.ltable' then
- -- TODO
- end
+ --if proto.type == 'doc.type' then
+ -- for _, tp in ipairs(source.types) do
+ -- pushForward(noders, id, getID(tp))
+ -- pushBackward(noders, getID(tp), id)
+ -- end
+ --end
+ m.compileDocValue(noders, proto.type, id, source)
end
end
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index 45e59fe9..f47a43c3 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -407,7 +407,7 @@ local function parseTypeUnitLiteralTable(parent)
}
do
- field.name = parseName('doc.ltfield.name', field)
+ field.name = parseName('doc.field.name', field)
if not field.name then
pushError {
type = 'LUADOC_MISS_FIELD_NAME',
@@ -438,7 +438,7 @@ local function parseTypeUnitLiteralTable(parent)
if checkToken('symbol', ',', 1) then
nextToken()
else
- nextSymbolOrError(')')
+ nextSymbolOrError('}')
break
end
end
diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua
index 3df73863..83e73487 100644
--- a/test/type_inference/init.lua
+++ b/test/type_inference/init.lua
@@ -867,3 +867,14 @@ end
xpcall(work, debug.traceback, function (<?value?>)
end)
]]
+
+TEST 'string' [[
+---@generic T
+---@param x T
+---@return { x: T }
+local function f(x) end
+
+local t = f('')
+
+print(t.<?x?>)
+]]