lua-language-server
lua-language-server copied to clipboard
Operators can only be defined one way
Describe the bug Its seems like operators can only be defined one way? I want number * Vec3 to be Vec3. Am I missing something?
To Reproduce
--- @class Vec3
--- @operator mul(number): Vec3
local Vec3 = {}
local t1 = Vec3() * 2 ---Vec3
local t2 = 2 * Vec3() --Integer!
Dose not support class as the second parameter for now.
I would suggest that bi-operators accept two arguments, instead of one. One argument assumes that the first one allways will be the class itself, which is not the case A bi-operator function can only assume, that one of the arguments is of the type of the class, it is defined in. In addition to that, the implied first parameter, is inconsistent. Check out this example:
---@class namespace.ClassName
---@operator unm(): namespace.ClassName
I would assume, that since add and mul, etc. assume that the first argument is of type namespace.ClassName, the __unm operator does assume it too, but the warning is confusing. However when I use the unary minus operator, it correctly assigns the type:
---@type namespace.ClassName
local b
local a = -b -- a is of type namespace.ClassName
What I would like to see, is explicit argument descriptors, for enabling different overloads: Maybe the first parameter could be implied, if it is omitted. However one argument type allways has to be in the class it is defined in:
---@class A # operator add returns lastly added type
---@operator add(A): A
---@operator add(number): number
---@operator add(number, A): A
---@operator unm(A): A
---@operator unm(): A
Is there any reason @sumneko, why operator overloads cannot be implied from functions, defined in the class?
---@class A
local A = {}
---@generic T
---@param b T
---@return T
function A.__add(a, b)
return b
end
The current standard comes from #599 . I can supports these at the same time:
---@class A
---@operator add: A --> eqauls to `add(A, any): A`
---@operator add(): A --> eqauls to `add(A, any): A`
---@operator add(number): A --> eqauls to `add(A, number): A`
---@operator add(number, A): A --> used for `1 + A`, but it may make people interested if it can be `add(number, B): A` in `class A`
Is there any reason @sumneko, why operator overloads cannot be implied from functions, defined in the class?
Strictly speaking, if I do not analyze the setmetatable, I cannot assume that the method of __add is related to additional operations.
Yeah I think this is needed:
---@operator add(number, A): A
With something like this there can also be this case
---@class A
---@operator add(A, B): A
---@class B
---@operator add(A, B): B
local res = A + B -- A or B?
In that case res should be A because in lua metamethods the left table is checked before the right table for the presence of an arithmetic metaevent.
---@operator add(number, A): A --> used for
1 + A, but it may make people interested if it can beadd(number, B): Ain `class
Then probably a warning, that this annotation can never be used (or will be ignored), should be thrown.
Strictly speaking, if I do not analyze the
setmetatable, I cannot assume that the method of__addis related to additional operations.
Is it possible to anlayze setmetatable() without performance issues?
Is it possible to anlayze
setmetatable()without performance issues?
~Yes, just need analyze it once, then I can cache the result.~
Unless I assume that the semantics of Class:__add is to add additional operations to Class.
---@class A
local mt = {}
mt.__index = mt
mt.__add = function () end
local t = setmetatable({}, mt)
In this code, I can infer local t is class A by __index, and I can infer t has "additional operation", but I cannot infer class A has "additional operation"
The current standard comes from #599 . I can supports these at the same time:
---@class A ---@operator add: A --> eqauls to `add(A, any): A` ---@operator add(): A --> eqauls to `add(A, any): A` ---@operator add(number): A --> eqauls to `add(A, number): A` ---@operator add(number, A): A --> used for `1 + A`, but it may make people interested if it can be `add(number, B): A` in `class A`
These meanings seem quite strange to me. The most common use-case for operators, I believe, would be defining them to be symmetric. Thus, I would expect something more along the following lines:
---@class A
---@operator add:A --> add(A, A):A
---@operator add():A --> add(A, any):A and add(any, A):A
---@operator add(number):A --> add(A, number):A and add(number, A):A
Of course, there are times when it shouldn't be symmetric, so having a way to declare asymmetric operators (probably by specifying both parameters) is also important.