From 45d7b2c97e1e18d1b41fc7e6909da1cb34466224 Mon Sep 17 00:00:00 2001 From: romanspector Date: Fri, 31 Jul 2026 10:43:21 +0300 Subject: [PATCH 1/2] Recognize a class inheriting a generic one as a child of its parent A parent given with arguments (`---@class A : B`) is parsed into `doc.type.sign`, which keeps the name one level down. The inheritance walk only looked at plain names, so such a parent was skipped entirely: `A` was not recognized as a child of whatever `B` itself inherits, and passing it where the base type is expected reported a mismatch. The name is now taken from the sign node as well. Co-Authored-By: Claude Opus 5 --- script/vm/type.lua | 18 +++++++++++++++--- test/diagnostics/param-type-mismatch.lua | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/script/vm/type.lua b/script/vm/type.lua index 539ec204c..524eb4cc2 100644 --- a/script/vm/type.lua +++ b/script/vm/type.lua @@ -589,9 +589,21 @@ function vm.isSubType(uri, child, parent, mark, errs) for _, set in ipairs(childClass:getSets(uri)) do if set.type == 'doc.class' and set.extends then for _, ext in ipairs(set.extends) do - if ext.type == 'doc.extends.name' - and (not isBasicType or guide.isBasicType(ext[1])) - and vm.isSubType(uri, ext[1], parent, mark, errs) == true then + -- A parent given with arguments (`---@class A : B`) is + -- parsed into `doc.type.sign`, keeping the name one level down. + -- Without looking inside, such a parent is skipped entirely and + -- the class is not recognized as its child. + local extName + if ext.type == 'doc.extends.name' then + extName = ext[1] + elseif ext.type == 'doc.type.sign' + and ext.node + and ext.node.type == 'doc.extends.name' then + extName = ext.node[1] + end + if extName + and (not isBasicType or guide.isBasicType(extName)) + and vm.isSubType(uri, extName, parent, mark, errs) == true then mark[childName] = nil return true end diff --git a/test/diagnostics/param-type-mismatch.lua b/test/diagnostics/param-type-mismatch.lua index 58acba2b2..fce7dca39 100644 --- a/test/diagnostics/param-type-mismatch.lua +++ b/test/diagnostics/param-type-mismatch.lua @@ -394,4 +394,23 @@ local function f(y) end f(x) ]] +-- A class inheriting a generic one is still a child of that generic's own parent: the +-- parent given with arguments is parsed one level down and used to be skipped. +TEST [[ +---@class Base + +---@class Middle : Base +---@field Value T + +---@class Child : Middle + +---@param value Base +local function f(value) end + +---@type Child +local child + +f(child) +]] + config.set(nil, 'Lua.type.checkTableShape', false) From 8f3cc590cce8e9286b0556b3575869c2cf087981 Mon Sep 17 00:00:00 2001 From: romanspector Date: Fri, 31 Jul 2026 11:17:25 +0300 Subject: [PATCH 2/2] Add changelog entry --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index c9375a4cd..6064f100e 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,7 @@ ## Unreleased +* `FIX` Recognize a class inheriting a generic class as a child of that generic's own parent [#3441](https://github.com/LuaLS/lua-language-server/pull/3441) * `NEW` Support type inference for `@field` and `@type` function declarations in method overrides [#3367](https://github.com/LuaLS/lua-language-server/issues/3367) * `FIX` Deduplicate documentation bindings for parameters * `FIX` Correct `math.type` meta return annotation to use `nil` instead of the string literal `'nil'`