Skip to content

Commit 274edb0

Browse files
authored
Merge pull request #6 from wookayin/error-handling
fix: do not lose stacktrace on errors when rejecting a promise
2 parents 81a9878 + 61f5736 commit 274edb0

File tree

3 files changed

+29
-19
lines changed

3 files changed

+29
-19
lines changed

lua/async.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ function Async.sync(executor)
4747
local function afterResume(status, ...)
4848
if not status then
4949
local reason = select(1, ...)
50-
reject(reason)
50+
reject(debug.traceback(co, reason))
5151
return
5252
elseif coroutine.status(co) == 'dead' then
5353
local value

lua/promise-async/error.lua

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,24 @@ end
4141
---@param thread? thread
4242
---@param level number
4343
---@param skipShortSrc? string
44-
---@return boolean, string|nil
44+
---@return string?
4545
function Error.format(thread, level, skipShortSrc)
46-
local ok = false
4746
local res
4847
local dInfo = thread and debug.getinfo(thread, level, 'nSl') or debug.getinfo(level, 'nSl')
4948
if dInfo then
5049
local name, shortSrc, currentline = dInfo.name, dInfo.short_src, dInfo.currentline
5150
if skipShortSrc == shortSrc then
52-
return true, nil
51+
return
5352
end
5453
local detail
5554
if not name or name == '' then
5655
detail = ('in function <Anonymous:%d>'):format(dInfo.linedefined)
5756
else
5857
detail = ([[in function '%s']]):format(name)
5958
end
60-
ok = true
6159
res = (' %s:%d: %s'):format(shortSrc, currentline, detail)
6260
end
63-
return ok, res
61+
return res
6462
end
6563

6664
---@param err any

lua/promise.lua

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,24 @@ end
9191
---@return PromiseAsyncError
9292
local function buildError(err)
9393
local o = errFactory.new(err)
94-
local level = 3
95-
local ok, value
94+
local level = 4
95+
local value
96+
local thread = coroutine.running()
9697
repeat
97-
ok, value = errFactory.format(coroutine.running(), level, shortSrc)
98+
value = errFactory.format(thread, level, shortSrc)
9899
level = level + 1
99100
o:push(value)
100-
until not ok
101+
until not value
102+
table.remove(o.queue)
101103
return o
102104
end
103105

106+
---@param errmsg any
107+
---@return PromiseAsyncError | any
108+
local function xpcallMessageWrapper(errmsg)
109+
return type(errmsg) == 'string' and buildError(errmsg) or errmsg
110+
end
111+
104112
local resolvePromise, rejectPromise
105113

106114
---@param promise Promise
@@ -133,11 +141,13 @@ local function handleQueue(promise)
133141
end
134142
end
135143
if func then
136-
local ok, res = pcall(func, result)
144+
local ok, res = xpcall(function()
145+
return func(result)
146+
end, xpcallMessageWrapper)
137147
if ok then
138148
resolvePromise(newPromise, res)
139149
else
140-
newPromise.err = buildError(res)
150+
newPromise.err = res
141151
rejectPromise(newPromise, res)
142152
end
143153
end
@@ -177,14 +187,16 @@ local function wrapExecutor(promise, executor, self)
177187
called = true
178188
end
179189

180-
local ok, res
181-
if self then
182-
ok, res = pcall(executor, self, resolve, reject)
183-
else
184-
ok, res = pcall(executor, resolve, reject)
185-
end
190+
local ok, res = xpcall(function()
191+
if self then
192+
---@diagnostic disable-next-line: redundant-parameter, param-type-mismatch
193+
return executor(self, resolve, reject)
194+
else
195+
return executor(resolve, reject)
196+
end
197+
end, xpcallMessageWrapper)
186198
if not ok and not called then
187-
promise.err = buildError(res)
199+
promise.err = res
188200
reject(res)
189201
end
190202
end

0 commit comments

Comments
 (0)