summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--script/core/hover/init.lua28
-rw-r--r--script/core/hover/label.lua5
-rw-r--r--script/parser/guide.lua2
-rw-r--r--script/parser/luadoc.lua3
-rw-r--r--script/vm/compiler.lua8
-rw-r--r--script/vm/global.lua24
-rw-r--r--script/vm/type.lua54
-rw-r--r--test/diagnostics/type-check.lua35
-rw-r--r--test/hover/init.lua10
-rw-r--r--test/type_inference/init.lua2
10 files changed, 149 insertions, 22 deletions
diff --git a/script/core/hover/init.lua b/script/core/hover/init.lua
index 949156aa..5a65cbce 100644
--- a/script/core/hover/init.lua
+++ b/script/core/hover/init.lua
@@ -92,19 +92,21 @@ local function getHover(source)
end
local accept = {
- ['local'] = true,
- ['setlocal'] = true,
- ['getlocal'] = true,
- ['setglobal'] = true,
- ['getglobal'] = true,
- ['field'] = true,
- ['method'] = true,
- ['string'] = true,
- ['number'] = true,
- ['integer'] = true,
- ['doc.type.name'] = true,
- ['function'] = true,
- ['doc.module'] = true,
+ ['local'] = true,
+ ['setlocal'] = true,
+ ['getlocal'] = true,
+ ['setglobal'] = true,
+ ['getglobal'] = true,
+ ['field'] = true,
+ ['method'] = true,
+ ['string'] = true,
+ ['number'] = true,
+ ['integer'] = true,
+ ['doc.type.name'] = true,
+ ['doc.class.name'] = true,
+ ['doc.enum.name'] = true,
+ ['function'] = true,
+ ['doc.module'] = true,
}
---@async
diff --git a/script/core/hover/label.lua b/script/core/hover/label.lua
index d5c0a11e..5c502ec1 100644
--- a/script/core/hover/label.lua
+++ b/script/core/hover/label.lua
@@ -36,7 +36,7 @@ local function asDocTypeName(source)
return '(alias) ' .. doc.alias[1] .. ' ' .. lang.script('HOVER_EXTENDS', vm.getInfer(doc.extends):view(guide.getUri(source)))
end
if doc.type == 'doc.enum' then
- return '(enum) ' .. doc.enum[1] .. ' ' .. lang.script('HOVER_EXTENDS', vm.getInfer(doc.extends):view(guide.getUri(source)))
+ return '(enum) ' .. doc.enum[1]
end
end
end
@@ -216,7 +216,8 @@ return function (source, oop)
elseif source.type == 'number'
or source.type == 'integer' then
return asNumber(source)
- elseif source.type == 'doc.type.name' then
+ elseif source.type == 'doc.type.name'
+ or source.type == 'doc.enum.name' then
return asDocTypeName(source)
elseif source.type == 'doc.field' then
return asDocFieldName(source)
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index 8506f7c5..e4faf47f 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -4,7 +4,7 @@ local type = type
---@class parser.object
---@field bindDocs parser.object[]
---@field bindGroup parser.object[]
----@field bindSource parser.object[]
+---@field bindSource parser.object
---@field value parser.object
---@field parent parser.object
---@field type string
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index 68286fab..6bf1a338 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -1829,7 +1829,8 @@ local function bindCommentsAndFields(binded)
end
bindCommentsToDoc(doc, comments)
comments = {}
- elseif doc.type == 'doc.alias' then
+ elseif doc.type == 'doc.alias'
+ or doc.type == 'doc.enum' then
bindCommentsToDoc(doc, comments)
comments = {}
elseif doc.type == 'doc.comment' then
diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua
index d94dd1f4..04a4f0c5 100644
--- a/script/vm/compiler.lua
+++ b/script/vm/compiler.lua
@@ -32,10 +32,6 @@ local function bindDocs(source)
vm.setNode(source, vm.compileNode(doc))
return true
end
- if doc.type == 'doc.enum' then
- vm.setNode(source, vm.compileNode(doc))
- return true
- end
if doc.type == 'doc.param' then
local node = vm.compileNode(doc)
if doc.optional then
@@ -1586,6 +1582,10 @@ local compilerSwitch = util.switch()
: call(function (source)
vm.setNode(source, vm.compileNode(source.parent))
end)
+ : case 'doc.enum.name'
+ : call(function (source)
+ vm.setNode(source, vm.compileNode(source.parent))
+ end)
: case 'doc.field'
: call(function (source)
if not source.extends then
diff --git a/script/vm/global.lua b/script/vm/global.lua
index 3fe1bee8..d9509fe7 100644
--- a/script/vm/global.lua
+++ b/script/vm/global.lua
@@ -130,6 +130,7 @@ end
---@class parser.object
---@field _globalNode vm.global|false
+---@field _enums? (string|integer)[]
---@type table<string, vm.global>
local allGlobals = {}
@@ -329,6 +330,29 @@ local compilerGlobalSwitch = util.switch()
local enum = vm.declareGlobal('type', name, uri)
enum:addSet(uri, source)
source._globalNode = enum
+
+ local tbl = source.bindSource and source.bindSource.value
+ if not tbl or tbl.type ~= 'table' then
+ return
+ end
+ source._enums = {}
+ for _, field in ipairs(tbl) do
+ if field.type == 'tablefield'
+ or field.type == 'tableindex' then
+ if not field.value then
+ goto CONTINUE
+ end
+ local key = guide.getKeyName(field)
+ if not key then
+ goto CONTINUE
+ end
+ if field.value.type == 'integer'
+ or field.value.type == 'string' then
+ source._enums[#source._enums+1] = field.value[1]
+ end
+ ::CONTINUE::
+ end
+ end
end)
: case 'doc.type.name'
: call(function (source)
diff --git a/script/vm/type.lua b/script/vm/type.lua
index 4aa1f8c8..30d509ce 100644
--- a/script/vm/type.lua
+++ b/script/vm/type.lua
@@ -2,6 +2,7 @@
local vm = require 'vm.vm'
local guide = require 'parser.guide'
local config = require 'config.config'
+local util = require 'utility'
---@param object vm.node.object
---@return string?
@@ -40,6 +41,51 @@ local function getNodeName(object)
return nil
end
+---@param parentName string
+---@param child vm.node.object
+---@param uri uri
+---@return boolean?
+local function checkEnum(parentName, child, uri)
+ local parentClass = vm.getGlobal('type', parentName)
+ if not parentClass then
+ return nil
+ end
+ for _, set in ipairs(parentClass:getSets(uri)) do
+ if set.type == 'doc.enum' then
+ if child.type ~= 'string'
+ and child.type ~= 'doc.type.string'
+ and child.type ~= 'integer'
+ and child.type ~= 'number'
+ and child.type ~= 'doc.type.integer' then
+ return false
+ end
+ return util.arrayHas(set._enums, child[1])
+ end
+ end
+
+ return nil
+end
+
+---@param parent vm.node.object
+---@param child vm.node.object
+---@return boolean
+local function checkValue(parent, child)
+ if parent.type == 'doc.type.integer' then
+ if child.type == 'integer'
+ or child.type == 'doc.type.integer'
+ or child.type == 'number' then
+ return parent[1] == child[1]
+ end
+ elseif parent.type == 'doc.type.string' then
+ if child.type == 'string'
+ or child.type == 'doc.type.string' then
+ return parent[1] == child[1]
+ end
+ end
+
+ return true
+end
+
---@param uri uri
---@param child vm.node|string|vm.node.object
---@param parent vm.node|string|vm.node.object
@@ -121,6 +167,9 @@ function vm.isSubType(uri, child, parent, mark)
end
if childName == parentName then
+ if not checkValue(parent, child) then
+ return false
+ end
return true
end
@@ -144,6 +193,11 @@ function vm.isSubType(uri, child, parent, mark)
return true
end
+ local isEnum = checkEnum(parentName, child, uri)
+ if isEnum ~= nil then
+ return isEnum
+ end
+
-- TODO: check duck
if parentName == 'table' and not guide.isBasicType(childName) then
return true
diff --git a/test/diagnostics/type-check.lua b/test/diagnostics/type-check.lua
index 46cb2471..b99e226c 100644
--- a/test/diagnostics/type-check.lua
+++ b/test/diagnostics/type-check.lua
@@ -729,5 +729,40 @@ local x = G
]]
config.set(nil, 'Lua.type.weakUnionCheck', false)
+TEST [[
+---@type 1|2
+local x
+
+x = 1
+x = 2
+<!x!> = 3
+]]
+
+TEST [[
+---@type 'x'|'y'
+local x
+
+x = 'x'
+x = 'y'
+<!x!> = 'z'
+]]
+
+TEST [[
+---@enum A
+local t = {
+ x = 1,
+ y = 2,
+}
+
+---@param x A
+local function f(x)
+end
+
+f(<!t!>)
+f(t.x)
+f(1)
+f(<!3!>)
+]]
+
config.remove(nil, 'Lua.diagnostics.disable', 'unused-local')
config.remove(nil, 'Lua.diagnostics.disable', 'undefined-global')
diff --git a/test/hover/init.lua b/test/hover/init.lua
index 0954ac80..95764923 100644
--- a/test/hover/init.lua
+++ b/test/hover/init.lua
@@ -2120,3 +2120,13 @@ local <?s?>
[[
local s: 'a'
]]
+
+TEST [[
+---@enum <?A?>
+local m = {
+ x = 1,
+}
+]]
+[[
+(enum) A
+]]
diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua
index 39d14e86..e4baf4a4 100644
--- a/test/type_inference/init.lua
+++ b/test/type_inference/init.lua
@@ -3720,7 +3720,7 @@ TEST '-2|-3|1' [[
local <?n?>
]]
-TEST 'A' [[
+TEST 'table' [[
---@enum A
local m = {}