Skip to content

fix(semantic): preserve vararg bindings and result types - #1294

Merged
CppCXY merged 1 commit into
EmmyLuaLs:mainfrom
lewis6991:rewrite-vararg-usage
Oct 16, 2026
Merged

CppCXY merged 1 commit into
EmmyLuaLs:mainfrom
lewis6991:rewrite-vararg-usage

Conversation

@lewis6991

Copy link
Copy Markdown
Collaborator

Vararg uses are missing from reference collection after the rewrite. This produces false unused warnings and prevents definition and reference queries from finding ...:

local function forward(...)
    print(...)
end
forward('hello')

Record each use against the nearest function's vararg declaration. A use in an inner function must not mark the outer function's varargs as used.

Type inference also confuses repeated tuple values with separate result slots. These annotations describe different arguments:

---@param ... [string, integer]
local function tuples(...)
    local packed = {...}
    return packed[2] -- [string, integer], the second tuple table
end
tuples({'a', 1}, {'b', 2})

---@param ... [string, integer]...
local function sequence(...)
    local packed = {...}
    return packed[2] -- integer, the second value
end
sequence('a', 1)

VariadicType::Base previously represented both repetition and declared tuple expansion. Add Repeat(LuaType) for repeated whole values. Keep Base for declared T... expansion, which can wait until generic types are known, and Multi for known result slots.

Carry this distinction through forwarding, table packing, generic callbacks, and select, pcall, and xpcall. Apply Lua's single-value adjustment to parentheses, operators, index keys, and non-final expressions:

---@param ... integer
local function counts(...)
    return select('#', ...),       -- unknown count
           select('#', (...)),    -- one value
           select('#', ..., 'x')  -- two values
end

Keep callback parameter compatibility separate from result value compatibility. An integer result can supply a number result, while incompatible callback parameters and redundant direct-call arguments still produce diagnostics.

Vararg uses can be missed by reference collection. Type inference also
confuses whole tuple values with separate result slots. This causes
false diagnostics, missing editor references, and incorrect types.

This use must not produce an unused warning:

    local function forward(...)
        print(...)
    end
    forward('hello')

Record each ... use against its function's declaration so reference
queries and unused checks can find it.

Tuple-valued arguments must remain whole when forwarded or packed:

    ---@PARAM ... [string, integer]
    local function pack(...)
        local packed = {...}
        return packed[2] -- [string, integer]
    end
    pack({'a', 1}, {'b', 2})

A trailing ... in the annotation instead expands the tuple fields into
separate arguments and results:

    ---@PARAM ... [string, integer]...
    local function forward(...) return ... end
    local text, count = forward('a', 1)

VariadicType::Base previously handled both repetition and tuple
expansion. Add a Repeat(LuaType) variant to VariadicType for repeated
whole values. This keeps each tuple table as one value when forwarding
or packing. Keep Base for declared T... expansion, which can wait until
generic types are known, and Multi for known result slots.
@lewis6991
lewis6991 force-pushed the rewrite-vararg-usage branch from 509927e to 0bc11af Compare October 15, 2026 08:58
@CppCXY
CppCXY merged commit ccd98f6 into EmmyLuaLs:main Oct 16, 2026
16 checks passed
@lewis6991
lewis6991 deleted the rewrite-vararg-usage branch October 16, 2026 09:14
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

Successfully merging this pull request may close these issues.

2 participants