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

@operator add customization for first operand? #2777

Closed SeanTheBuilder1 closed 1 month ago

SeanTheBuilder1 commented 2 months ago

How are you using the lua-language-server?

NeoVim

Which OS are you using?

Linux

What is the issue affecting?

Annotations

Expected Behaviour

I expected it would work like this

---@class Vector3
---@field x number
---@field y number
---@field z number
---@operator add(Vector, Vector3): Vector3 # Vector3 + Vector3
---@operator add(number, Vector3): Vector3 # number + Vector3
---@operator add(Vector3, number): Vector3 # Vector3 + number
Vector3 = {}

Actual Behaviour

But instead it is like this

---@class Vector3
---@field x number
---@field y number
---@field z number
---@operator add(Vector): Vector3 # Vector3 + Vector3
---@operator add(number, Vector3): Vector3 # this is impossible as far as I know
---@operator add(number): Vector3 # Vector3 + number
Vector3 = {}

Reproduction steps

copy paste 'Expected Behaviour code' displays " ')' expected "

Additional Notes

I am asking if the impossible case is actually possible and that it is only undocumented or something. I expected the binary operators to take two parameters instead of just one. Thank you.

Log File

No response

tomlau10 commented 1 month ago

From lua-users wiki, these kinds of mathematic operators will check metatables on both side (the left value first, then the right). http://lua-users.org/wiki/MetatableEvents

  • add - Addition. When writing "myTable + object" or "object + myTable", if myTable's metatable has an add key pointing to a function, that function is invoked (passing the left and right operands in order) and the return value used.
    • ''If both operands are tables, the left table is checked before the right table for the presence of an __add metaevent.

With a bit of digging in LuaLS codebase, I think this functionality can be added here: https://github.com/LuaLS/lua-language-server/blob/26a7b690c7eeb1a209b1b600886b2ac6691c5d2e/script/vm/operator.lua#L302-L306


I tested this and it works 👀

---@class Vector3
---@field x number
---@field y number
---@field z number
---@operator add(Vector3): Vector3 # Vector3 + Vector3
---@operator add(number): Vector3 # Vector3 + number | number + Vector3
Vector3 = {}

local a = 1 + Vector3
local b = 1.1 + Vector3
local c = (1*2+3) + Vector3

local x ---@type number
local d = x + Vector3

-- a, b, c, d are all inferred as `Vector3`

Note that the above demo code I only check for + operator, and from the lua user wiki, this interchangeable logic applies to: __add, __sub, __mul, __div, __mod, __pow, __concat. I suggest @SeanTheBuilder1 can try to work on this and open a PR after testing 👍

SeanTheBuilder1 commented 1 month ago

This is an interesting find and I find it a good enough workaround for now while #1371 is still being worked on for the asymmetric operations. Added that with that preliminary code snippet would make the LSP in line with the actual behavior of lua code.

SeanTheBuilder1 commented 1 month ago

whoops misclick i apologize

tomlau10 commented 1 month ago

I have never thought of an asymmetric __add ... what could be a possible use case for that 😂 ?

SeanTheBuilder1 commented 1 month ago

Good day, yeah I couldn't think of a practical one either but that might be an edge case for the future. Technically you could do that with a C binding where it returns a different type when it detects if it was the left or right operand. But that might be too weird, after all I'm just trying to have parity with a library I'm interfacing which has support for scalars on the left operand and so far I can't find a case which breaks symmetry.