Closed tomlau10 closed 2 months ago
Seems my latest strategy of checking param's literals map
contains arg's literal
is not working for carsakiller's example...
Because the base function signatures uses an @alias
type, and the literals map
of it will contains all enum literals value🤦♂️
So the logic will add bonus score for both the base function and the overload one => they have same bonus score => cannot do further type narrow ☹️
由於 @alias
的 literals map
實際上是包含其定義中的所有 literal
所以我最新 logic 下的 檢查 function param literals map
包含 arg's liteval 值
對 carsakiller 原有例子沒效果。。。
---@alias ccTweaked.os.event
---| "alarm"
---| "char"
---| string
---@async
---@param event? ccTweaked.os.event
---@return any ...
---@overload fun(event: "alarm"): "alarm", integer
---@overload fun(event: "char"): "char", string
function os.pullEvent(event) end
local event, alarmID = os.pullEvent("alarm")
--> any, any (expected: "alarm", integer)
local event, character = os.pullEvent("char")
--> any, any (expected: "char", string)
要再想想先。。。
想到了 🙂 計分制中不直接做 + 1
,而是 + 1/{literals map 的 entry 總數}
單個 literal
時
=> 會 + 1/1
=> + 1
+ 1/{大數}
=> 肯定少於上邊的 + 1
這樣就傾向選擇 param literal type 定義為較 narrow 的 function 了
---@alias ccTweaked.os.event
---| "alarm"
---| "char"
---| string
---@async
---@param event? ccTweaked.os.event
---@return any ...
---@overload fun(event: "alarm"): "alarm", integer
---@overload fun(event: "char"): "char", string
function os.pullEvent(event) end
local event, alarmID = os.pullEvent("alarm")
--> "alarm", integer (good)
local event, character = os.pullEvent("char")
--> "char", string (good)
先 hold 一下,我突然又有些想法估計可以 fix https://github.com/LuaLS/lua-language-server/issues/2509 🤔
@overload
定義 而沒有 @param
定義時
base function param type 會從 第1個 overload 獲取 param type@overload
而沒有 @param
=> 該 function 只會按 @overload
的方式來調用要些時間驗證一下
edit: 還是分開另外處理吧 不然出 bug 了都不知是跟哪個改動有關 😅
我没有看代码,但是看描述我觉得无论什么时候都不应该用计分。如果无法确定如何narrow,那就不做narrow。
无法确定如何narrow,那就不做narrow
我這裡的計分,最初其實是 計算 exact literal match 的 param count
(count 是數量,也就可理解成 1個 score)
並且是在 肯定的時候 才 加分,否則就當 0分
🤔
讓我具體舉一些例子
---@overload fun(a: string): string
---@overload fun(a: 'test'): integer
local function f(...) end
f()
的調用,都會找出上述2個 overload 來做判斷f('')
=> 本身做 isAllParamMatched()
只能 match 出 fun(a: string): string
f('test')
在原有 isAllParamMatched()
情況下 2個 overload 都匹配的
'test'
canCastType 成 string
,同時 'test'
也 canCastType 成 'test'
=> 原有機制無法進一步 narrow'test'
這個 literal 值跟第2個 overload 中的 a: 'test'
是 完全相同 => 是可以做 narrow1分
給他 => 最終 matchScores = [ 0, 1 ]
=> 只選 第2個
overload
=> f('test')
-> integer
而不是原有的 string|integer
---@alias ccTweaked.os.event
---| "alarm"
---| "char"
---| string
---@async
---@param event? ccTweaked.os.event
---@return any ...
---@overload fun(event: "alarm"): "alarm", integer
---@overload fun(event: "char"): "char", string
function os.pullEvent(event) end
os.pullEvent
其實有 3種
infer type
fun(event?: ccTweaked.os.event): any ...
fun(event: "alarm"): "alarm", integer
fun(event: "char"): "char", string
os.pullEvent('alarm')
時,按原機制 isAllParamMatched()
會 match 出 第1 & 第2個
'alarm'
canCastType 成 ccTweaked.os.event
,也 canCastType 成 'alarm'
第2個
infer type,因為是 exact literal matchccTweaked.os.event
這個 infer node 只是個 alias,實際上他又有幾個 literal 的解讀
+ 1 / {infer 中支持的 literal 總數}
=> + 1/2
=> 使得他的 score 肯定 低於另外出現 exact match 的 function
意義上是在符合 exact literal match (肯定的 true positive case) 大前題情況下,他的匹配率最高
os.pullEvent('alarm')
的 matchScores = [ 0.5, 1, -1 ]
=> 就能 narrow 成第2個了我大概理解你的擔心,是以為這計分制是 (胡亂) 計算什麼 similarity 之類?
但這裡不是,是在 肯定 (出現 exact literal value match) 的情況下做加分,其餘 case 都是 0 分
沒有 literal match 的情況下,不會給任何分數的 🤔
(而與期說分數,更像是 count 有多少 literal value match
)
@sumneko
明白了,这里的计分指的是narrow程度,那应该没有问题
这里的计分指的是narrow程度
確實你這個說法更準確 👍
The following related issues are not fixed by this PR, but I tested and they already work as of
v3.10.5
: ~#2509~, #1343, #1146edit: I originally thought #2509 is working, but NO. Just that the reproduction code is not complete, and I didn't reproduce it and think it is solved. I confirmed that it is still unsolved with a more complete example code.
The Problem
Originated from an example provided by @carsakiller: https://github.com/LuaLS/lua-language-server/issues/1456#issuecomment-2303627852, where the base signature contains a param type that is a superset of the other overload, type narrow feature will always includes the baseline one and cannot perform a more accurate type narrow.
A minimal example:
Proposed Solution
I introduced a match score when trying to do a further type narrow. After the 1st pass checking
isAllParamMatched
in the existing logic, I tried to check if their arguments' literal have exact match:123
,"test"
This is just an extra logic and should be no worse than current logic. Because when there are no identical view param, all functions just have the same score
0
=> all will be kept as in the existing logic.After the fix:
中文版
長話短說,我嘗試在
vm.getExactMatchedFunctions
引入1個 計分制 在滿足原有的isAllParamMatched
前題下0分
=> 全部保留我不確定有沒有更好改法 這個需要 @sumneko 來 review (希望我沒有像上次一樣,fix 了1個問題卻又引起新 bug ... 🤦♂️ )