LuaLS / lua-language-server

A language server that offers Lua language support - programmed in Lua
https://luals.github.io
MIT License
3.29k stars 305 forks source link

Overload intellisense issue with type of parameters #2708

Closed Rathoz closed 3 weeks ago

Rathoz commented 3 months ago

How are you using the lua-language-server?

Visual Studio Code Extension (sumneko.lua)

Which OS are you using?

Windows

What is the issue affecting?

Type Checking

Expected Behaviour

a is string|number

Actual Behaviour

a is string

Reproduction steps

---@overload fun(a: string): string
---@overload fun(a: number): table
function Foo.Bar(a)
    -- `a` is incorrectly assumed to be a `string`
    return a:lower() -- This does not error while it should!
end

Additional Notes

No response

Log File

No response

tomlau10 commented 1 month ago

I think I've found the cause of this issue, in the compileFunctionParam() of here: https://github.com/LuaLS/lua-language-server/blob/ba8f90eb0fab18ce8aee2bdbf7007dc63050381d/script/vm/compiler.lua#L1090-L1107


I tried to remove this early break, and it can solve this issue:

local function compileFunctionParam(func, source)
    -- local call ---@type fun(f: fun(x: number));call(function (x) end) --> x -> number
    local funcNode = vm.compileNode(func)
    local found = false
    for n in funcNode:eachObject() do
        ...
        found = true -- replace the original `return true`
        ...
    end
    if found then
        return true
    end

However this fix cause a few new problems...

PS: I am working on PR #2822 to try to fix that #2509 🤔

tomlau10 commented 3 weeks ago

I just found out that even with my #2838, now although a in Foo.Bar() can be correctly inferred as string|number, a:lower() will not trigger warning 😅 . I think that's because the string.lower actually accepts number as the 1st param: https://github.com/LuaLS/lua-language-server/blob/d1320ae5e41086fd9f569c2504a88130447444b8/meta/template/string.lua#L85-L88

string.lower indeed accepts string|number as 1st param, just that it doesn't allow number:lower() call style, and it is not addressed in this issue nor in my PR #2838.

Maybe @Rathoz you have to open another issue for that 😂

Rathoz commented 3 weeks ago

Correct on string.lower() accpect string|number.

number doesn't have any metatable, unlike string. aString:lower() is just syntactic sugar for aString.lower(aString) which thanks the metatable turns into string.lower(aString). But do the same on a number aNumber:lower() is tries to call the function aNumber.lower(aNumber), which doesn't exist.

I can open a new issue on it if you like