re-throwing an asynchronous exception throws it synchronously
If you catch and re-throw an asynchronous exception, the second time it will be thrown synchronously. This only makes a difference when using unsafePerformIO
or unsafeInterleaveIO
, because otherwise the catch
will not be inside any thunks.
This could have the unfortunate effect of updating an unsafePerformIO
thunk with Timeout
, or KillThread
, or some other asychronous exception that should not be recorded as the value of the thunk.
We believe that exceptions thrown by an exception handler should be thrown in the same mode (synchronous or asynchronous) as the original exception. This means that we need to
-
keep track of the current exception-throwing mode
-
push a frame when in an exception handler (we already do this, because the
exception handler is implicitly wrapped in
block
) -
respect this mode when throwing exceptions.
This raises another issue: catching an exception and recovering by tail-calling out of the exception handler is not a good thing to do. Currently it has the undesirable effect that the thread remains in block
mode, and an explicit unblock
is required. With the changes above, the thread may also remain in "asynchronous exception" mode.
The right way to solve this is just "don't do that". Here's how to use the exception API:
- For cleanup, use
finally
,bracket
, andonException
. - To modify the exception, use
mapException
. - For recovery, use
try
.
Perhaps we should be deprecating catch
? Or perhaps catch
should be implemented in terms of try
, so it doesn't have the implicit block
/ re-throw async exceptions behaviour?
Trac metadata
Trac field | Value |
---|---|
Version | 6.8.3 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | Unknown |
Architecture | Unknown |