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

Globals set with rawset are always parsed as a table #2863

Closed
LJSonik opened this issue Sep 22, 2024 · 1 comment · Fixed by #2867
Closed

Globals set with rawset are always parsed as a table #2863

LJSonik opened this issue Sep 22, 2024 · 1 comment · Fixed by #2867

Comments

@LJSonik
Copy link

LJSonik commented Sep 22, 2024

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?

Annotations, Type Checking

Expected Behaviour

I expect x to be parsed as an integer:

rawset(_G, "x", 42)
print(x) -- x should be parsed as integer here

Actual Behaviour

x is parsed as integer|table instead.

Reproduction steps

rawset(_G, "x", 42)
print(x) -- x is parsed as integer|table here

Additional Notes

No response

Log File

No response

@tomlau10
Copy link
Contributor

Root cause analysis

After some debugging, I found that the table infer type seems to be inserted by this code block 🤔:

: case 'call'
: call(function (source)
local node = getReturn(source.node, 1, source.args)
if not node then
return
end
if not node:isTyped() then
node = vm.runOperator('call', source.node) or node
end
vm.setNode(source, node)
end)

  • When compiling a rawset() call statement, this code block will be executed.
  • I believe this logic is to use the return value of the call statement to set the left hand side variable if any (?),
    and the return value of rawset() is annotated as table type by built-in meta file:
    ---@param table table
    ---@param index any
    ---@param value any
    ---@return table
    function rawset(table, index, value) end
  • so in the following code snippet
    local a = rawset() -- a: table
  • But as rawset(_G, ...) is handled specially, the created global is treated as the (assignment) value of this call (?):
    local global = vm.declareGlobal('variable', name, uri)
    if source.node.special == 'rawset' then
    global:addSet(uri, source)
    source.value = source.args[3]
  • This explains why the injected type is always table (the return type of rawset())

Proposed solution

I just tried to skip the logic if it is a rawset statement, and it worked perfectly 🎉

    : case 'call'
    : call(function (source)
        -- ignore rawset
        if source.node.special == 'rawset' then
            return
        end
  • I originally afraid that this will break the local a = rawset() case, but seems not 😄
    a can still be inferred as table
  • All existing tests passed, so no obvious side effects for this proposed change.

I believe this is the solution to this issue. I will try to open a PR for this, along with the proposed changes in #2862 (comment) to resolve these 2 issues together later 😄

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