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

Field and Method of the same name not working since 3.0 #1541

Closed
johnfking opened this issue Sep 8, 2022 · 11 comments
Closed

Field and Method of the same name not working since 3.0 #1541

johnfking opened this issue Sep 8, 2022 · 11 comments
Labels
as designed Functioning as intended, will not be modified

Comments

@johnfking
Copy link

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, Completion

Expected Behaviour

I use an in-game Lua implementation where the C++ bindings (userdata) objects are returned on object fields and in-game data is returned by accessing methods on those fields. In some cases, the field name itself is also a method. So you have objects that look like this:

---@class GameData
---@field Car Car

---@class Car
---@field Tires usermeta
car = {}

---Returns the number of Tires on the Car
---@return integer number of tires
function car.Tires() end

The code completion only shows suggestions for the Field (usermeta) and not the function.

Actual Behaviour

image

Reproduction steps

  1. Cut and paste the example in a VS Code editor with the plugin loaded.
  2. Start typing car and press .

Additional Notes

No response

Log File

No response

@flrgh
Copy link
Contributor

flrgh commented Sep 8, 2022

If you omit the @field annotation and instead introduce an assignment with a type annotation, the language server will keep both as a union type (I'm honestly not sure why though).

Additionally, you can use @cast in places where you'd like to explicitly narrow the type to one or the other.

---@class Car
car = {}

--- Here is some documentation about the userdata.
---
---@type userdata
car.Tires = nil -- ignore the `nil`; it's just here to give us a valid lua expression

---Returns the number of Tires on the Car
---@return integer number of tires
function car.Tires() end

-- lua-language-server correctly infers that this is an integer
local num = car.Tires()

-- this is ambiguous, so you'll see type defs for both the userdata
-- and the function
local data = car.Tires

-- this gets you an explicit userdata def
---@cast data -function
print(data)

image

image

image

@johnfking
Copy link
Author

This is fantastic, thank you very much for the quick response. However I agree, I'm not sure why this treats this as a union in the description, as the icons and titles clearly show they are different.
image

@carsakiller
Copy link
Collaborator

It is showing as a union type because the field Tires in car is either a:

function : car.Tires() or userdata : car.Tires

The autocompletion shows how you can retrieve the field (car.Tires) and how you can call the function (car.Tires()), which means it shows the type as both possible options.


As for why setting car.Tires to nil allows you to define the field twice but using @field does not... I am not sure what the intended functionality is supposed to be. It seems the intention is to not allow multiple definitions of a field and this is a hacky way around that. If that is the case, then the issue to address is allowing multiple @field annotations to have the same name.

@johnfking
Copy link
Author

It used to work that way. I put a similar issue back in 2021. #549 But with the update to 3.0, it seems to have reverted.

In my mind, there should be some distinction between a field and a function, even if they have the same name and should not be shown together in the popup. Saying that a Field with the name "foo" that returns a string, and a function with the name "foo()" that returns an integer can return one of two values is not correct. The Field returns a string and the Function returns an integer. They are used differently and have different return values. Showing them together and saying that either can return one of two values is misleading.

@projecteon
Copy link

projecteon commented Sep 12, 2022

Have issues to get the workaround to work...

---@class Tire
---@field IsSlicks boolean

---@class Car
car = {}

--- Here is some documentation about the userdata.
---
---@type Tire
car.Tires = nil -- ignore the `nil`; it's just here to give us a valid lua expression

---Returns the number of Tires on the Car
---@return integer number of tires
function car.Tires() end

The function assignment will throw a assign-type-mismatch warning. And code hints will not show the function.

Attempts at union-ing the field makes a weird code hint.

---@class Tire
---@field IsSlicks boolean

---@class Car
---@field Tires Tire|fun():int|boolean

This results in:
Car.Tires = fun():int|boolean|Tire

Should be
Car.Tires = Tire|fun():int|boolean

@sumneko
Copy link
Collaborator

sumneko commented Sep 14, 2022

Field types have different precedences, with ---@field having the highest precedence because this is the user-explicitly defined type.
If you make car as a local variable, the behavior will be as expected. But currently car is a global variable, the behavior is not as expected, mainly because I currently have difficulty analyzing the order of global variables.

@sumneko sumneko added the bug Something isn't working label Sep 14, 2022
@projecteon
Copy link

The use of them seems fine.
It seems to be the type hint thats puts `fun? always first. So if you union type and funtioncion it looks like function also returns the type. (see car example above)

@sumneko sumneko added as designed Functioning as intended, will not be modified and removed bug Something isn't working labels Sep 15, 2022
@sumneko
Copy link
Collaborator

sumneko commented Sep 15, 2022

Judging the precedence of global variables is a bit difficult, and I decided to maintain the behavior for now.
For this issue, you must define the correct type in ---@field, as it has the highest precedence.

@projecteon
Copy link

projecteon commented Sep 20, 2022

I think you missunderstood.
Its not global variables, its the code hint in visual studio.

Using ---@field as shown above with union, the code hint seems to show the "userdata type" as part of the function return union which is not correct.

Its almost like it either prioritizes fun type first, then adds the union field or it groups all the unions together at the end. Either way it looks very wrong.

@sumneko
Copy link
Collaborator

sumneko commented Sep 20, 2022

So what you want is (fun():int|boolean)|Tire ?

@carsakiller
Copy link
Collaborator

Closing stale issue

@carsakiller carsakiller closed this as not planned Won't fix, can't repro, duplicate, stale Jan 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
as designed Functioning as intended, will not be modified
Projects
None yet
Development

No branches or pull requests

5 participants