@@ -353,6 +353,35 @@ local function isAllParamMatched(uri, args, params)
353353 return true
354354end
355355
356+ --- @param uri uri
357+ --- @param args parser.object[]
358+ --- @param func parser.object
359+ --- @return number
360+ local function calcFunctionMatchScore (uri , args , func )
361+ if vm .isVarargFunctionWithOverloads (func )
362+ or not isAllParamMatched (uri , args , func .args )
363+ then
364+ return - 1
365+ end
366+ local matchScore = 0
367+ for i = 1 , math.min (# args , # func .args ) do
368+ local arg , param = args [i ], func .args [i ]
369+ local defLiterals , literalsCount = vm .getLiterals (param )
370+ if defLiterals then
371+ for n in vm .compileNode (arg ):eachObject () do
372+ -- if param's literals map contains arg's literal, this is narrower than a subtype match
373+ if defLiterals [guide .getLiteral (n )] then
374+ -- the more the literals defined in the param, the less bonus score will be added
375+ -- this favors matching overload param with exact literal value, over alias/enum that has many literal values
376+ matchScore = matchScore + 1 / literalsCount
377+ break
378+ end
379+ end
380+ end
381+ end
382+ return matchScore
383+ end
384+
356385--- @param func parser.object
357386--- @param args ? parser.object[]
358387--- @return parser.object[] ?
@@ -365,21 +394,29 @@ function vm.getExactMatchedFunctions(func, args)
365394 return funcs
366395 end
367396 local uri = guide .getUri (func )
368- local needRemove
397+ local matchScores = {}
369398 for i , n in ipairs (funcs ) do
370- if vm . isVarargFunctionWithOverloads ( n )
371- or not isAllParamMatched ( uri , args , n . args ) then
372- if not needRemove then
373- needRemove = {}
374- end
375- needRemove [ # needRemove + 1 ] = i
376- end
399+ matchScores [ i ] = calcFunctionMatchScore ( uri , args , n )
400+ end
401+
402+ local maxMatchScore = math.max ( table.unpack ( matchScores ))
403+ if maxMatchScore == - 1 then
404+ -- all should be removed
405+ return nil
377406 end
378- if not needRemove then
407+
408+ local minMatchScore = math.min (table.unpack (matchScores ))
409+ if minMatchScore == maxMatchScore then
410+ -- all should be kept
379411 return funcs
380412 end
381- if # needRemove == # funcs then
382- return nil
413+
414+ -- remove functions that have matchScore < maxMatchScore
415+ local needRemove = {}
416+ for i , matchScore in ipairs (matchScores ) do
417+ if matchScore < maxMatchScore then
418+ needRemove [# needRemove + 1 ] = i
419+ end
383420 end
384421 util .tableMultiRemove (funcs , needRemove )
385422 return funcs
0 commit comments