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'
3
4
--- @class vm
4
- local vm = require ' vm.vm'
5
- local config = require ' config'
5
+ local vm = require ' vm.vm'
6
+ local config = require ' config'
6
7
7
8
--- @class parser.object
8
9
--- @field package _castTargetHead ? parser.object | vm.global | false
@@ -186,20 +187,53 @@ function vm.getDeprecated(value, deep)
186
187
end
187
188
188
189
--- @param value parser.object
190
+ --- @param propagate boolean
191
+ --- @param deepLevel integer ?
189
192
--- @return boolean
190
- local function isAsync (value )
193
+ local function isAsync (value , propagate , deepLevel )
191
194
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
196
196
return value ._async
197
197
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
201
234
return true
202
235
end
236
+ asyncCache [value ] = false
203
237
end
204
238
value ._async = false
205
239
return false
212
246
213
247
--- @param value parser.object
214
248
--- @param deep boolean ?
249
+ --- @param deepLevel integer ?
215
250
--- @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
218
255
return true
219
256
end
220
257
if deep then
@@ -223,7 +260,7 @@ function vm.isAsync(value, deep)
223
260
return false
224
261
end
225
262
for _ , def in ipairs (defs ) do
226
- if isAsync (def ) then
263
+ if isAsync (def , propagate , deepLevel ) then
227
264
return true
228
265
end
229
266
end
@@ -325,16 +362,17 @@ function vm.isLinkedCall(node, index)
325
362
end
326
363
327
364
--- @param call parser.object
365
+ --- @param deepLevel integer ?
328
366
--- @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
331
369
return true
332
370
end
333
371
if not call .args then
334
372
return false
335
373
end
336
374
for i , arg in ipairs (call .args ) do
337
- if vm .isAsync (arg , true )
375
+ if vm .isAsync (arg , true , deepLevel )
338
376
and isLinkedCall (call .node , i ) then
339
377
return true
340
378
end
0 commit comments