Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

overloading a class stops completing fields #2945

Open
Bilal2453 opened this issue Nov 9, 2024 · 4 comments
Open

overloading a class stops completing fields #2945

Bilal2453 opened this issue Nov 9, 2024 · 4 comments

Comments

@Bilal2453
Copy link
Contributor

How are you using the lua-language-server?

Visual Studio Code Extension (sumneko.lua)

Which OS are you using?

Linux

What is the issue affecting?

Annotations, Type Checking, Completion

Expected Behaviour

---@class Cache<K, V>: {[K]: V}
---@field foo string
---@field bar fun(p1: integer)

---@type Cache<string, table>
local members = {}

print(members.<??>) ---> expected completion: `foo`, `bar`

Actual Behaviour

---@class Cache<K, V>: {[K]: V}
---@field foo string
---@field bar fun(p1: integer)

---@type Cache<string, table>
local members = {}

print(members.<??>) ---> nothing is suggested

image

Reproduction steps

  1. Copy reproduction sample
  2. Follow instructions
  3. Auto complete on members.

Additional Notes

members is typed correctly.

image

Log File

No response

@tomlau10
Copy link
Contributor

tomlau10 commented Nov 9, 2024

AFAIK, generic classes only has limited support currently as discussed here:

So this is probably a duplicate issue.


  • One non-perfect workaround / hack that I found, is to use @alias for the generic part:
---@class Cache
---@field foo string
---@field bar fun(p1: integer)

---@diagnostic disable-next-line: duplicate-doc-alias
---@alias Cache<K, V> Cache|{[K]: V}

---@type Cache<string, table>
local members = {}

members.$ --> bar|foo
  • but unfortunately this is non perfect ... because
local t = members.foo --> t: string|table

=> it will merge the generic V part into the result, since foo also matches the string type in K


More discussions here: #2632 (reply in thread)
And if you really care about generic classes, you may want to try @CppCXY 's vscode-emmylua as suggested here: #2632 (reply in thread)

@Bilal2453
Copy link
Contributor Author

Indeed seems like a duplicate, thanks for the suggested workaround!

@Bilal2453 Bilal2453 closed this as not planned Won't fix, can't repro, duplicate, stale Nov 9, 2024
@tomlau10
Copy link
Contributor

I think I have find the root cause that generic classes have no completion 🤔

  • For generic class types, they are typed as doc.type.sign in the viewpoint of LuaLS, unlike the standard global cate type.
    And currently when searching fields, it doesn't handle this special doc.type.sign. It will only do vm.getClassFields when node.type == 'global' and node.cate == 'type'
    : case 'global'
    : call(function (suri, node, key, pushResult)
    if node.cate == 'variable' then
    if key ~= vm.ANY then
    if type(key) ~= 'string' then
    return
    end
    local global = vm.getGlobal('variable', node.name, key)
    if global then
    for _, set in ipairs(global:getSets(suri)) do
    pushResult(set)
    end
    end
    else
    local globals = vm.getGlobalFields('variable', node.name)
    for _, global in ipairs(globals) do
    for _, set in ipairs(global:getSets(suri)) do
    pushResult(set)
    end
    end
    end
    end
    if node.cate == 'type' then
    vm.getClassFields(suri, node, key, pushResult)
    end
  • By looking at how the infer view BaseType<K, V> is implemented, we can retrieve the global cate type through vm.getGlobal('type', source.node[1])
    : case 'doc.type.sign'
    : call(function (source)
    local uri = guide.getUri(source)
    vm.setNode(source, source)
    if not source.node[1] then
    return
    end
    local global = vm.getGlobal('type', source.node[1])
  • Therefore we can add a switch case in the searchFieldSwitch:
    local searchFieldSwitch = util.switch()
        : case 'doc.type.sign'
        : call(function (suri, source, key, pushResult)
            if not source.node[1] then
                return
            end
            local global = vm.getGlobal('type', source.node[1])
            if not global then
                return
            end
            vm.getClassFields(suri, global, key, pushResult)
        end)

However this only solves the completion problem, not the extra type problem mentioned in my previous comment. Maybe it should be reported as another issue, since this issue only talks about completing fields.

Anyway you can try to open a PR for it after more testing 😄 @Bilal2453
To sum up, add a 'doc.type.sign' switch case in searchFieldSwitch inside script/vm/compiler.lua to search its parent class fields.

@Bilal2453
Copy link
Contributor Author

I see, yeah should be an easy case overall. I will reopen this just for the sake of linking it to a future PR.
But having done all the work for me, I feel like just PRing it myself is a bit of cheating! I will try to do it and test it more once I setup a development environment for this, thanks for the debugging.

@Bilal2453 Bilal2453 reopened this Nov 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants