Skip to content

table newindex shows invalid need check for nil warning if key is false #3359

Open

Description

@sewbacca

How are you using the lua-language-server?

NeoVim

Which OS are you using?

Windows

What is the issue affecting?

Type Checking

Expected Behaviour

t[key] = {} should throw no warning if key is not nil.

Actual Behaviour

t[key] = {} throws an invalid warning if key is false but not nil.

Reproduction steps

local CACHE = {}
CACHE[false] = {} -- ok
local key = false
CACHE[key] = {} -- should be ok as well, but throws invalid warning

Additional Notes

This happened to me in a more complex method where I ensured a key is not nil, by redefining the parameter:

function apicall(input)
    local key = input or false
    -- more stuff...
    cache[key] = {}
    return cache[key]
end

I'd like to note an annoyance when it comes to casting, the following casts all throw warnings, even if explicitly casting the variable, requiring me to invent a new variable (or forcing me disable redefining local):

---@param input string?
function apicall(input)
    -- this cast does nothing and also throws no warning
    ---@cast input +false
    -- this cast warns that it can't cast string? to string|false
    ---@cast input string|false

    -- this is what I do, it just throws an info warning, which I've disabled:
    ---@type string | false
    local input = input or false
end

Log File

No response

Activity

  1. tomlau10 commented on Feb 24, 2026

    @tomlau10
    Contributor

    analysis

    The logic of need-check-nil diagnostics currently checks for node:hasFalsy(), which includes optional / nil / false and this seems to be the root problem 🤔 It should only check for optional and nil I believe?

    if node:hasFalsy() and not vm.getInfer(src):hasType(uri, 'any') then

    function mt:hasFalsy()
    if self.optional then
    return true
    end
    for _, c in ipairs(self) do
    if c.type == 'nil'
    or (c.type == 'global' and c.cate == 'type' and c.name == 'nil')
    or (c.type == 'global' and c.cate == 'type' and c.name == 'false')
    or (c.type == 'boolean' and c[1] == false)
    or (c.type == 'doc.type.boolean' and c[1] == false) then
    return true


    possible fix

    To address this issue, I tested that we can add a node:hasNil() method:

    ---@return boolean
    function mt:hasNil()
        if self.optional then
            return true
        end
        for _, c in ipairs(self) do
            if c.type == 'nil'
            or (c.type == 'global' and c.cate == 'type' and c.name == 'nil')
            then
                return true
            end
        end
        return false
    end
    • and then in diagnostics/need-check-nil.lua change that line to
    if node:hasNil() and not vm.getInfer(src):hasType(uri, 'any') then

    This can fix the case in Reproduction steps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions