Draft: DmdAnal: `catch#` may throw a precise exception (#20111)
... if its argument might throw one.
In #20111, we saw how catch#
hid a side-effect from DmdAnal in the action it
wraps (printing to stdout
). That happened in an infinite loop, so the whole
looping function was detected to have bottoming divergence b
instead of x
.
Because the looping function looked to DmdAnal like any other function with
divergence b
, the Simplifier was allowed to then eval the diverging field of
an argument eagerly, masking the infinite loop with the error from said field
and thus not emitting the externally visible side-effect (printing to stdout
)
anymore.
The solution is for exprMayThrowPreciseException
to recurse into the args of
catch#
. Same for other higher-order IO-like primops, like atomically#
.
We'd never say that putStrLn
may not throw a precise exception, so we fix
the particular regression in #20111.
But of course, #20111 begs the question of whether we might want to preserve other externally visible side-effects (e.g. in other threads or processes), too. The answer is yes, of course, but #17653 (closed) showed that doing so comes at the cost of regressing real-world code. We track that issue as #20121.
Regression test is T20111. Fixes #20111.