LuaLS / lua-language-server

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

[Feature Request] Automatically overload with `__call` metamethod. #2920

Open mikuhl-dev opened 1 month ago

mikuhl-dev commented 1 month ago

There is already custom behavior when __index is defined in a metatable, why not __call? You can manually define the overload, but then you have to define the signature twice.

---@overload fun(a: string, b: number): boolean
local foo = setmetatable({}, {
    ---@param a string
    ---@param b number
    ---@return boolean
    __call = function(a, b)
        return true;
    end
});
tomlau10 commented 1 month ago

This seems to be feature requested long ago: https://github.com/LuaLS/lua-language-server/issues/95

xuhuanzy commented 1 month ago

This issue seems difficult to resolve, and I think maintaining the current state is a good option. For example, simulating a 'class' often involves more complex sub-processing logic, such as dispatching to functions like 'init' or 'alloc' defined in subclasses.

tomlau10 commented 1 month ago

Also I think the code snippet is a bit incorrect 😕 the 1st param of __call will always be the table it self? i.e. foo(a, b) => __call(t=foo, a, b)

local foo = setmetatable({}, {
    ---@param a string
    ---@param b number
    ---@return boolean
    __call = function(a, b)
        print(a, b)
        return true
    end
});

print(foo)
foo(1, 2)
table: 0x7f8b47c09860
table: 0x7f8b47c09860   1

Thus the __call(t, a, b) signature is actually different from the actual call syntax foo(a, b) as seen by users This adds another difficulty as well.

ChrisKader commented 3 weeks ago

Thus the __call(t, a, b) signature is actually different from the actual call syntax foo(a, b) as seen by users This adds another difficulty as well.

The signature for __call is different than the calling syntax but its the same as the call syntax for a table when you want to pass self as the first param.

TestClass:testFunction(1, 2)

In this case, testFunction would receive 3 parameters with the first one being a reference to the instance of TestClass.

And to be honest, most of the metamethods should be able to auto-detect the types coming in, even without them specified.

tomlau10 commented 3 weeks ago

The signature for __call is different than the calling syntax but its the same as the call syntax for a table when you want to pass self as the first param.

Yes, I know this __call metamethod as well as lua's : method call syntax. But I am saying that the function signature is different between the __call and the regular function call using that table, in the viewpoint of luals. 😕


Using your example TestClass:testFunction(a, b)

So when we write a __call(t, a, b) in a metatable, certainly luals can detect the existence of such metamethod, but it cannot directly apply this function signature (fun(t, a, b)) to a t(a, b) call, since their function signatures are different. I guess this is where the difficulty lies in. 🤔 And thus requires a manual @overload fun(a, b) to table t

ChrisKader commented 1 week ago

I want to contribute and actually get this working (along with some kind of ---@environment/proper setfenv support) but I wanted to possibly do it in the 4.0 branch though I cannot get it to build on macos

tomlau10 commented 1 week ago

I wanted to possibly do it in the 4.0 branch though I cannot get it to build on macos

Thanks for your interest in contributing 😄.

AFAIK the 4.0 branch is a WIP and a total rewrite of LuaLS, but it is not ready yet. I don't think it is a good time to PR to that branch now even if it is buildable, as that may affect the design architecture that maintainer has planned.

I am sure maintainer will announce it when it is ready.