1- local files = require ' files'
2- local guide = require ' parser.guide'
1+ local files = require ' files'
2+ local await = require ' await'
3+ local guide = require ' parser.guide'
34--- @class vm
4- local vm = require ' vm.vm'
5- local config = require ' config'
5+ local vm = require ' vm.vm'
6+ local config = require ' config'
67
78--- @class parser.object
89--- @field package _castTargetHead ? parser.object | vm.global | false
@@ -186,20 +187,53 @@ function vm.getDeprecated(value, deep)
186187end
187188
188189--- @param value parser.object
190+ --- @param propagate boolean
191+ --- @param deepLevel integer ?
189192--- @return boolean
190- local function isAsync (value )
193+ local function isAsync (value , propagate , deepLevel )
191194 if value .type == ' function' then
192- if not value .bindDocs then
193- return false
194- end
195- if value ._async ~= nil then
195+ if value ._async ~= nil then -- already calculated, directly return
196196 return value ._async
197197 end
198- for _ , doc in ipairs (value .bindDocs ) do
199- if doc .type == ' doc.async' then
200- value ._async = true
198+ local asyncCache
199+ if propagate then
200+ asyncCache = vm .getCache ' async.propagate'
201+ local result = asyncCache [value ]
202+ if result ~= nil then
203+ return result
204+ end
205+ end
206+ if value .bindDocs then -- try parse the annotation
207+ for _ , doc in ipairs (value .bindDocs ) do
208+ if doc .type == ' doc.async' then
209+ value ._async = true
210+ return true
211+ end
212+ end
213+ end
214+ if propagate then -- if enable async propagation, try check calling functions
215+ if deepLevel and deepLevel > 50 then
216+ return false
217+ end
218+ local isAsyncCall = vm .isAsyncCall
219+ local callingAsync = guide .eachSourceType (value , ' call' , function (source )
220+ local parent = guide .getParentFunction (source )
221+ if parent ~= value then
222+ return nil
223+ end
224+ local nextLevel = (deepLevel or 1 ) + 1
225+ local ok = isAsyncCall (source , nextLevel )
226+ if ok then -- if any calling function is async, directly return
227+ return ok
228+ end
229+ -- if not, try check the next calling function
230+ return nil
231+ end )
232+ if callingAsync then
233+ asyncCache [value ] = true
201234 return true
202235 end
236+ asyncCache [value ] = false
203237 end
204238 value ._async = false
205239 return false
212246
213247--- @param value parser.object
214248--- @param deep boolean ?
249+ --- @param deepLevel integer ?
215250--- @return boolean
216- function vm .isAsync (value , deep )
217- if isAsync (value ) then
251+ function vm .isAsync (value , deep , deepLevel )
252+ local uri = guide .getUri (value )
253+ local propagate = config .get (uri , ' Lua.hint.awaitPropagate' )
254+ if isAsync (value , propagate , deepLevel ) then
218255 return true
219256 end
220257 if deep then
@@ -223,7 +260,7 @@ function vm.isAsync(value, deep)
223260 return false
224261 end
225262 for _ , def in ipairs (defs ) do
226- if isAsync (def ) then
263+ if isAsync (def , propagate , deepLevel ) then
227264 return true
228265 end
229266 end
@@ -325,16 +362,17 @@ function vm.isLinkedCall(node, index)
325362end
326363
327364--- @param call parser.object
365+ --- @param deepLevel integer ?
328366--- @return boolean
329- function vm .isAsyncCall (call )
330- if vm .isAsync (call .node , true ) then
367+ function vm .isAsyncCall (call , deepLevel )
368+ if vm .isAsync (call .node , true , deepLevel ) then
331369 return true
332370 end
333371 if not call .args then
334372 return false
335373 end
336374 for i , arg in ipairs (call .args ) do
337- if vm .isAsync (arg , true )
375+ if vm .isAsync (arg , true , deepLevel )
338376 and isLinkedCall (call .node , i ) then
339377 return true
340378 end
0 commit comments