DmdAnal: Improve handling of precise exceptions
This patch does two things: Fix possible unsoundness in what was called the "IO hack" and implement part 2.1 of the "fixing precise exceptions" plan in https://gitlab.haskell.org/ghc/ghc/wikis/fixing-precise-exceptions, which, in combination with !2956 (closed), supersedes !3014 (closed) and !2525 (closed).
IO hack
The "IO hack" (which is a fallback to preserve precise exceptions
semantics and thus soundness, rather than some smart thing that
increases precision) is called exprMayThrowPreciseException
now.
I came up with two testcases exemplifying possible unsoundness (if
twisted enough) in the old approach:
-
T13380d
: Demonstrating unsoundness of the "IO hack" when resorting to manual state token threading and direct use of primops. More details below. -
T13380e
: Demonstrating unsoundness of the "IO hack" when we have Nested CPR. Not currently relevant, as we don't have Nested CPR yet.
Basically, the IO hack assumed that precise exceptions can only be
thrown from a case scrutinee of type (# State# RealWorld, _ #)
. I
couldn't come up with a program using the IO
abstraction that violates
this assumption. But it's easy to do so via manual state token threading
and direct use of primops, see T13380d
. Also similar code might be
generated by Nested CPR in the (hopefully not too) distant future, see
T13380e
. Hence, we now have a more careful test in forcesRealWorld
that passes T13380{d,e}
(and will hopefully be robust to Nested CPR).
Dead code elimination and precise exceptions
In #13380 (closed) and #17676 (closed) we saw that we didn't preserve precise exception semantics in demand analysis. We fixed that with minimal changes in !2956 (closed), but that was terribly unprincipled.
That unprincipledness resulted in a loss of precision, which is tracked by these new test cases:
-
T13380b
: Regression in dead code elimination, because !2956 (closed) was too syntactic aboutraiseIO#
-
T13380c
: No need to apply the "IO hack" when the IO action may not throw a precise exception (and the existing IO hack doesn't detect that)
Fixing both issues in !3014 (closed) turned out to be too complicated and had
the potential to regress in the future. Hence we decided to only fix
T13380b
and augment the Divergence
lattice with a new middle-layer
element, ExnOrDiv
, which means either Diverges
(, throws an
imprecise exception) or throws a precise exception.
See the wiki page on Step 2.1 for more implementational details: https://gitlab.haskell.org/ghc/ghc/wikis/fixing-precise-exceptions#dead-code-elimination-for-raiseio-with-isdeadenddiv-introducing-exnordiv-step-21