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

Modifying local reference of a table does not update the table in other files #3025

Closed
Poltergeist-ix opened this issue Jan 3, 2025 · 3 comments

Comments

@Poltergeist-ix
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?

Other

Expected Behaviour

See the changes to table in all files.

Actual Behaviour

The changes do not appear in other files when modifying the local reference.

Reproduction steps

File 1:

MyTable = {zx = 1}

File 2:

require "Ready"
local MyTable = MyTable
MyTable.test = {a = "abc"}

File 3:

require "Set"
local MyTable = MyTable

image

However if file 2 does not use a local reference then it works as expected.

image

Additional Notes

No response

Log File

No response

@Poltergeist-ix
Copy link
Author

Worth mentioning similar issue happens with

require("Ready").test = {a = "abc"}

@tomlau10
Copy link
Contributor

tomlau10 commented Jan 4, 2025

IIUC, luals doesn't run your actual code, it just tries its best to infer the types.
I guess for global variables, it is tracking all setglobal operation on the same name variable, to infer all its fields.

Consider the following:

  • file1
MyTable = {a = 1}
MyTable.a = nil
  • file2
MyTable = {b = 2}
MyTable.b = nil
  • file3
print(MyTable) --> what type of `MyTable` do you expect here?
-- only with field `a`?
-- only with field `b`?
-- no field at all?

no, the result is

(global) MyTable: {
    a: integer = 1,
    b: integer = 2,
}

because the server just traces all setglobal operations across all the files in your workspace.


By aliasing the global variable with a local, luals can no longer relies on the setglobal on same name variable method. Because a local variable can be with any other valid name, or even you can have that local variable points to something else and come back to points to global variable again.

Proper annotation

If you want luals to know that you are injecting fields into the same type, I think you should add proper @class annotation:

  • file1
---@class MyTable
MyTable = {zx = 1}
  • file2
require "Ready"
---@class MyTable
local MyTable = MyTable
MyTable.test = {a = "abc"}
  • file3
require "Set"
local MyTable = MyTable
-- now `MyTable` has the class type `MyTable`, has both fields `zx` and `a`

MyTable.b = 2 --> warning: Fields cannot be injected into the reference of `MyTable` for `b`. To do so, use `---@class` for `MyTable`.
-- i.e. unless you add the `---@class` like file 2, otherwise luals forbids you to inject field into an already typed variable
-- otherwise any operation you did here will not reflect to the type system

PS: I just recently learnt that this is the C# partial class concept, where you can split the definition of a class in multiple files. Our team has been widely adopting this coding pattern before I even know there is a name for this concept 😂

@Poltergeist-ix
Copy link
Author

Poltergeist-ix commented Jan 4, 2025

Thank you for reply, it's so nice to have this working now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants