Skip to content

Commit

Permalink
add option Lua.hint.awaitPropagate to propagate ---@async
Browse files Browse the repository at this point in the history
This option is disabled by default.
When disabled, it has no impact on performance.
When enabled, due to its upward propagation characteristics,
     it may render some await-in-sync diagnostics ineffective,
     but not all of them.
  • Loading branch information
findstr committed Dec 10, 2024
1 parent 8d3a4c8 commit f69167e
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 17 deletions.
3 changes: 3 additions & 0 deletions locale/en-us/setting.lua
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ config.hint.arrayIndex.Disable =
'Disable hints of array index.'
config.hint.await =
'If the called function is marked `---@async`, prompt `await` at the call.'
config.hint.awaitPropagate =
'Enable the propagation of `await`. When a function calls a function marked `---@async`,\z
it will be automatically marked as `---@async`.'
config.hint.semicolon =
'If there is no semicolon at the end of the statement, display a virtual semicolon.'
config.hint.semicolon.All =
Expand Down
3 changes: 3 additions & 0 deletions locale/ja-jp/setting.lua
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ config.hint.arrayIndex.Disable = -- TODO: need translate!
'Disable hints of array index.'
config.hint.await = -- TODO: need translate!
'If the called function is marked `---@async`, prompt `await` at the call.'
config.hint.awaitPropagate = -- TODO: need translate!
'Enable the propagation of `await`. When a function calls a function marked `---@async`,\z
it will be automatically marked as `---@async`.'
config.hint.semicolon = -- TODO: need translate!
'If there is no semicolon at the end of the statement, display a virtual semicolon.'
config.hint.semicolon.All = -- TODO: need translate!
Expand Down
3 changes: 3 additions & 0 deletions locale/pt-br/setting.lua
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ config.hint.arrayIndex.Disable = -- TODO: need translate!
'Disable hints of array index.'
config.hint.await = -- TODO: need translate!
'If the called function is marked `---@async`, prompt `await` at the call.'
config.hint.awaitPropagate = -- TODO: need translate!
'Enable the propagation of `await`. When a function calls a function marked `---@async`,\z
it will be automatically marked as `---@async`.'
config.hint.semicolon = -- TODO: need translate!
'If there is no semicolon at the end of the statement, display a virtual semicolon.'
config.hint.semicolon.All = -- TODO: need translate!
Expand Down
2 changes: 2 additions & 0 deletions locale/zh-cn/setting.lua
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ config.hint.arrayIndex.Disable =
'禁用数组索引提示。'
config.hint.await =
'如果调用的函数被标记为了 `---@async` ,则在调用处提示 `await` 。'
config.hint.awaitPropagate =
'启用 `await` 的传播, 当一个函数调用了一个`---@async`标记的函数时,会自动标记为`---@async`。'
config.hint.semicolon =
'若语句尾部没有分号,则显示虚拟分号。'
config.hint.semicolon.All =
Expand Down
2 changes: 2 additions & 0 deletions locale/zh-tw/setting.lua
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ config.hint.arrayIndex.Disable =
'停用陣列索引提示。'
config.hint.await =
'如果呼叫的函數被標記為了 `---@async`,則在呼叫處提示 `await`。'
config.hint.awaitPropagate =
'啟用 `await` 的傳播,當一個函數呼叫了一個 `---@async` 標記的函數時,會自動標記為 `---@async`。'
config.hint.semicolon =
'若陳述式尾部沒有分號,則顯示虛擬分號。'
config.hint.semicolon.All =
Expand Down
1 change: 1 addition & 0 deletions script/config/template.lua
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ local template = {
'Disable',
},
['Lua.hint.await'] = Type.Boolean >> true,
['Lua.hint.awaitPropagate'] = Type.Boolean >> false,
['Lua.hint.arrayIndex'] = Type.String >> 'Auto' << {
'Enable',
'Auto',
Expand Down
100 changes: 83 additions & 17 deletions script/vm/doc.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
local files = require 'files'
local guide = require 'parser.guide'
local files = require 'files'
local await = require 'await'
local guide = require 'parser.guide'
---@class vm
local vm = require 'vm.vm'
local config = require 'config'
local vm = require 'vm.vm'
local config = require 'config'

---@class parser.object
---@field package _castTargetHead? parser.object | vm.global | false
Expand Down Expand Up @@ -186,17 +187,37 @@ function vm.getDeprecated(value, deep)
end

---@param value parser.object
---@param propagate boolean
---@param deepLevel integer?
---@return boolean
local function isAsync(value)
local function isAsync(value, propagate, deepLevel)
if value.type == 'function' then
if not value.bindDocs then
return false
end
if value._async ~= nil then
if value._async ~= nil then --already calculated, directly return
return value._async
end
for _, doc in ipairs(value.bindDocs) do
if doc.type == 'doc.async' then
if value.bindDocs then --try parse the annotation
for _, doc in ipairs(value.bindDocs) do
if doc.type == 'doc.async' then
value._async = true
return true
end
end
end
if propagate then -- if enable async propagation, try check calling functions
if deepLevel and deepLevel > 50 then
return false
end
local isAsyncCall = vm.isAsyncCall
local callingAsync = guide.eachSourceType(value, 'call', function (source)
local nextLevel = (deepLevel or 1) + 1
local ok = isAsyncCall(source, nextLevel)
if ok then --if any calling function is async, directly return
return ok
end
--if not, try check the next calling function
return nil
end)
if callingAsync then
value._async = true
return true
end
Expand All @@ -212,9 +233,12 @@ end

---@param value parser.object
---@param deep boolean?
---@param deepLevel integer?
---@return boolean
function vm.isAsync(value, deep)
if isAsync(value) then
function vm.isAsync(value, deep, deepLevel)
local uri = guide.getUri(value)
local propagate = config.get(uri, 'Lua.hint.awaitPropagate')
if isAsync(value, propagate, deepLevel) then
return true
end
if deep then
Expand All @@ -223,7 +247,7 @@ function vm.isAsync(value, deep)
return false
end
for _, def in ipairs(defs) do
if isAsync(def) then
if isAsync(def, propagate, deepLevel) then
return true
end
end
Expand Down Expand Up @@ -325,16 +349,17 @@ function vm.isLinkedCall(node, index)
end

---@param call parser.object
---@param deepLevel integer?
---@return boolean
function vm.isAsyncCall(call)
if vm.isAsync(call.node, true) then
function vm.isAsyncCall(call, deepLevel)
if vm.isAsync(call.node, true, deepLevel) then
return true
end
if not call.args then
return false
end
for i, arg in ipairs(call.args) do
if vm.isAsync(arg, true)
if vm.isAsync(arg, true, deepLevel)
and isLinkedCall(call.node, i) then
return true
end
Expand Down Expand Up @@ -485,3 +510,44 @@ function vm.docHasAttr(doc, key)
end
return false
end

---@async
local function clearAsyncPropagate(uri)
local propagate = config.get(uri, 'Lua.hint.awaitPropagate')
if not propagate then
return
end
local state = files.getState(uri)
if not state then
return
end
local marked = {}
local list = {}
guide.eachSourceType(state.ast, 'function', function (source)
marked[source] = true
list[#list+1] = source
end)
local pairs = pairs
local remove = table.remove
while #list > 0 do
local source = remove(list)
local refs = vm.getRefs(source)
for _, ref in pairs(refs) do
while ref and ref.type ~= 'function' do
ref = ref.parent
end
if ref and not marked[ref] then
ref._async = nil
marked[ref] = true
list[#list+1] = ref
end
end
await.delay()
end
end

files.watch(function (ev, uri) ---@async
if ev == 'compile' then
clearAsyncPropagate(uri)
end
end)

0 comments on commit f69167e

Please sign in to comment.