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

fix: improve type narrow with literal alias param during completion and signature help #2932

Merged
merged 4 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased
<!-- Add all new changes here. They will be moved under a version at release -->
* `FIX` Improve type narrow with **literal alias type** during completion and signature help
* `NEW` Setting: `Lua.type.inferTableSize`: A Small Table array can be infered

## 3.12.0
Expand Down
8 changes: 7 additions & 1 deletion script/core/signature.lua
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,13 @@ local function isEventNotMatch(call, src)
end
local eventLiteral = event.extends.types[1] and guide.getLiteral(event.extends.types[1])
if eventLiteral == nil then
return false
-- extra checking when function param is not pure literal
-- eg: it maybe an alias type with literal values
local eventMap = vm.getLiterals(event.extends.types[1])
if not eventMap then
return false
end
return not eventMap[literal]
end
return eventLiteral ~= literal
end
Expand Down
20 changes: 20 additions & 0 deletions script/vm/compiler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,26 @@ local function compileCallArgNode(arg, call, callNode, fixIndex, myIndex)
local function dealDocFunc(n)
local myEvent
if n.args[eventIndex] then
if eventMap and myIndex > eventIndex then
-- if call param has literal types, then also check if function def param has literal types
-- 1. has no literal values => not enough info, thus allowed by default
-- 2. has literal values and >= 1 matches call param's literal types => allowed
-- 3. has literal values but none matches call param's literal types => filtered
local myEventMap = vm.getLiterals(n.args[eventIndex])
if myEventMap then
local found = false
for k in pairs(eventMap) do
if myEventMap[k] then
-- there is a matching literal
found = true
break
end
end
if not found then
return
end
end
end
local argNode = vm.compileNode(n.args[eventIndex])
myEvent = argNode:get(1)
end
Expand Down
38 changes: 38 additions & 0 deletions test/completion/common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3138,6 +3138,44 @@ emit.on(emit, 'won', <??>)
}
}

TEST [[
--- @alias event.AAA "AAA"
--- @alias event.BBB "BBB"

--- @class Emit
--- @field on fun(self: Emit, eventName: string, cb: function)
--- @field on fun(self: Emit, eventName: event.AAA, cb: fun(i: integer))
--- @field on fun(self: Emit, eventName: event.BBB, cb: fun(s: string))
local emit = {}

emit:on('AAA', <??>)
]]
{
[1] = {
label = 'fun(i: integer)',
kind = define.CompletionItemKind.Function,
}
}

TEST [[
--- @alias event.AAA "AAA"
--- @alias event.BBB "BBB"

--- @class Emit
--- @field on fun(self: Emit, eventName: string, cb: function)
--- @field on fun(self: Emit, eventName: event.AAA, cb: fun(i: integer))
--- @field on fun(self: Emit, eventName: event.BBB, cb: fun(s: string))
local emit = {}

emit:on('BBB', <??>)
]]
{
[1] = {
label = 'fun(s: string)',
kind = define.CompletionItemKind.Function,
}
}

TEST [[
local function f()
local inferCache
Expand Down
34 changes: 34 additions & 0 deletions test/signature/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,40 @@ t:event("onTimer", <??>)
'(method) (ev: "onTimer", <!t: integer!>)',
}

TEST [[
---@alias event.onChat "onChat"
---@alias event.onTimer "onTimer"

---@class A
---@field event fun(self: self, ev: event.onChat, c: string)
---@field event fun(self: self, ev: event.onTimer, t: integer)

---@type A
local t

t:event("onChat", <??>)
]]
{
'(method) (ev: "onChat", <!c: string!>)',
}

TEST [[
---@alias event.onChat "onChat"
---@alias event.onTimer "onTimer"

---@class A
---@field event fun(self: self, ev: event.onChat, c: string)
---@field event fun(self: self, ev: event.onTimer, t: integer)

---@type A
local t

t:event("onTimer", <??>)
]]
{
'(method) (ev: "onTimer", <!t: integer!>)',
}

local config = require 'config'
config.set(nil, "Lua.type.inferParamType", true)

Expand Down
Loading