Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Unreleased
<!-- Add all new changes here. They will be moved under a version at release -->
* `FIX` Generic class inheritance with type arguments now works correctly (e.g., `class Bar: Foo<integer>`) [#1929](https://github.com/LuaLS/lua-language-server/issues/1929)
* `FIX` Method return types on generic classes now resolve correctly (e.g., `Box<string>:getValue()` returns `string`) [#1863](https://github.com/LuaLS/lua-language-server/issues/1863)
* `FIX` Self-referential generic classes no longer cause infinite expansion in hover display [#1853](https://github.com/LuaLS/lua-language-server/issues/1853)
* `FIX` Generic type parameters now work in `@overload` annotations [#723](https://github.com/LuaLS/lua-language-server/issues/723)
* `NEW` Support `fun<T>` syntax for inline generic function types in `@field` and `@type` annotations [#1170](https://github.com/LuaLS/lua-language-server/issues/1170)
* `FIX` Methods with `@generic T` and `@param self T` now correctly resolve return type to the receiver's concrete type (e.g., `List<number>:identity()` returns `List<number>`) [#1000](https://github.com/LuaLS/lua-language-server/issues/1000)

## 3.16.4
`2025-12-25`
Expand Down
2 changes: 1 addition & 1 deletion script/parser/guide.lua
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ local childMap = {
['doc.generic.object'] = {'generic', 'extends', 'comment'},
['doc.vararg'] = {'vararg', 'comment'},
['doc.type.array'] = {'node'},
['doc.type.function'] = {'#args', '#returns', 'comment'},
['doc.type.function'] = {'#args', '#returns', '#signs', 'comment'},
['doc.type.table'] = {'#fields', 'comment'},
['doc.type.literal'] = {'node'},
['doc.type.arg'] = {'name', 'extends'},
Expand Down
57 changes: 56 additions & 1 deletion script/parser/luadoc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ local function parseTypeUnitFunction(parent)
args = {},
returns = {},
}
-- Parse optional generic params: fun<T, V>(...)
typeUnit.signs = parseSigns(typeUnit)
if not nextSymbolOrError('(') then
return nil
end
Expand Down Expand Up @@ -617,6 +619,51 @@ local function parseTypeUnitFunction(parent)
end
end
typeUnit.finish = getFinish()
-- Bind local generics from fun<T, V> to type names within this function
if typeUnit.signs then
local generics = {}
for _, sign in ipairs(typeUnit.signs) do
generics[sign[1]] = sign
end
local function bindTypeNames(obj)
if not obj then return end
if obj.type == 'doc.type.name' and generics[obj[1]] then
obj.type = 'doc.generic.name'
obj.generic = generics[obj[1]]
elseif obj.type == 'doc.type' and obj.types then
for _, t in ipairs(obj.types) do
bindTypeNames(t)
end
elseif obj.type == 'doc.type.array' then
bindTypeNames(obj.node)
elseif obj.type == 'doc.type.table' and obj.fields then
for _, field in ipairs(obj.fields) do
bindTypeNames(field.name)
bindTypeNames(field.extends)
end
elseif obj.type == 'doc.type.sign' then
bindTypeNames(obj.node)
if obj.signs then
for _, s in ipairs(obj.signs) do
bindTypeNames(s)
end
end
elseif obj.type == 'doc.type.function' then
for _, arg in ipairs(obj.args) do
bindTypeNames(arg.extends)
end
for _, ret in ipairs(obj.returns) do
bindTypeNames(ret)
end
end
end
for _, arg in ipairs(typeUnit.args) do
bindTypeNames(arg.extends)
end
for _, ret in ipairs(typeUnit.returns) do
bindTypeNames(ret)
end
end
return typeUnit
end

Expand Down Expand Up @@ -1030,6 +1077,12 @@ local docSwitch = util.switch()
}
return result
end
if extend.type == 'doc.extends.name' then
local signResult = parseTypeUnitSign(result, extend)
if signResult then
extend = signResult
end
end
result.extends[#result.extends+1] = extend
result.finish = getFinish()
if not checkToken('symbol', ',', 1) then
Expand Down Expand Up @@ -1850,7 +1903,9 @@ local function bindGeneric(binded)
or doc.type == 'doc.return'
or doc.type == 'doc.type'
or doc.type == 'doc.class'
or doc.type == 'doc.alias' then
or doc.type == 'doc.alias'
or doc.type == 'doc.field'
or doc.type == 'doc.overload' then
guide.eachSourceType(doc, 'doc.type.name', function (src)
local name = src[1]
if generics[name] then
Expand Down
Loading
Loading