diff options
-rw-r--r-- | changelog.md | 8 | ||||
-rw-r--r-- | script/core/diagnostics/assign-type-mismatch.lua | 26 | ||||
-rw-r--r-- | script/vm/node.lua | 2 | ||||
-rw-r--r-- | test/diagnostics/type-check.lua | 33 |
4 files changed, 68 insertions, 1 deletions
diff --git a/changelog.md b/changelog.md index 4e457622..4c3a4040 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,14 @@ ## 3.4.1 * `NEW` settings: * `type.weakNilCheck` +* `CHG` allow type contravariance for `setmetatable` when initializing a class + ```lua + ---@class A + local a = {} + + ---@class B: A + local b = setmetatable({}, { __index = a }) -- OK! + ``` * `FIX` [#1256](https://github.com/sumneko/lua-language-server/issues/1256) * `FIX` [#1257](https://github.com/sumneko/lua-language-server/issues/1257) * `FIX` [#1267](https://github.com/sumneko/lua-language-server/issues/1267) diff --git a/script/core/diagnostics/assign-type-mismatch.lua b/script/core/diagnostics/assign-type-mismatch.lua index a3d63ca8..d98aa021 100644 --- a/script/core/diagnostics/assign-type-mismatch.lua +++ b/script/core/diagnostics/assign-type-mismatch.lua @@ -30,6 +30,20 @@ local function hasMarkType(source) return false end +---@param source parser.object +---@return boolean +local function hasMarkClass(source) + if not source.bindDocs then + return false + end + for _, doc in ipairs(source.bindDocs) do + if doc.type == 'doc.class' then + return true + end + end + return false +end + ---@async return function (uri, callback) local state = files.getState(uri) @@ -72,6 +86,18 @@ return function (uri, callback) if vm.canCastType(uri, varNode, valueNode) then return end + + if value.type == 'select' + and value.sindex == 1 + and value.vararg + and value.vararg.type == 'call' + and value.vararg.node.special == 'setmetatable' + and hasMarkClass(source) then + if vm.canCastType(uri, valueNode:copy():remove 'table', varNode) then + return + end + end + callback { start = source.start, finish = source.finish, diff --git a/script/vm/node.lua b/script/vm/node.lua index f0d0b0ba..5d8bcd75 100644 --- a/script/vm/node.lua +++ b/script/vm/node.lua @@ -227,7 +227,7 @@ function mt:remove(name) or (c.type == 'doc.type.boolean' and name == 'false' and c[1] == false) or (c.type == 'doc.type.table' and name == 'table') or (c.type == 'doc.type.array' and name == 'table') - or (c.type == 'doc.type.sign' and name == 'table') + or (c.type == 'doc.type.sign' and name == 'table') or (c.type == 'doc.type.function' and name == 'function') then table.remove(self, index) self[c] = nil diff --git a/test/diagnostics/type-check.lua b/test/diagnostics/type-check.lua index 32f60f82..f1f14b48 100644 --- a/test/diagnostics/type-check.lua +++ b/test/diagnostics/type-check.lua @@ -631,5 +631,38 @@ n = nb ]] config.set(nil, 'Lua.type.weakNilCheck', false) +TEST [[ +---@class A +local a = {} + +---@class B: A +local <!b!> = a +]] + +TEST [[ +---@class A +local a = {} +a.__index = a + +---@class B: A +local b = setmetatable({}, a) +]] + +TEST [[ +---@class A +local a = {} + +---@class B: A +local b = setmetatable({}, {__index = a}) +]] + +TEST [[ +---@class A +local a = {} + +---@class B +local <!b!> = setmetatable({}, {__index = a}) +]] + config.remove(nil, 'Lua.diagnostics.disable', 'unused-local') config.remove(nil, 'Lua.diagnostics.disable', 'undefined-global') |