summaryrefslogtreecommitdiff
path: root/compiler/prelude/primops.txt.pp
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/prelude/primops.txt.pp')
-rw-r--r--compiler/prelude/primops.txt.pp45
1 files changed, 25 insertions, 20 deletions
diff --git a/compiler/prelude/primops.txt.pp b/compiler/prelude/primops.txt.pp
index 7361c4bea8..685a867b0d 100644
--- a/compiler/prelude/primops.txt.pp
+++ b/compiler/prelude/primops.txt.pp
@@ -2595,20 +2595,23 @@ primop RaiseOp "raise#" GenPrimOp
with
strictness = { \ _arity -> mkClosedStrictSig [topDmd] botDiv }
out_of_line = True
- has_side_effects = True
- -- raise# certainly throws a Haskell exception and hence has_side_effects
- -- It doesn't actually make much difference because the fact that it
- -- returns bottom independently ensures that we are careful not to discard
- -- it. But still, it's better to say the Right Thing.
+ can_fail = True
+ -- In contrast to 'raiseIO#', which throws a *precise* exception,
+ -- exceptions thrown by 'raise#' are considered *imprecise*.
+ -- Hence 'raise#' is marked as "can_fail" (which 'raiseIO#' is not), but
+ -- not as "has_side_effects" (which 'raiseIO#' is).
+ -- See Note [PrimOp can_fail and has_side_effects] in PrimOp.hs.
+ -- For the same reasons, it has 'botDiv', not 'exnDiv'.
-- Note [Arithmetic exception primops]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
--- The RTS provides several primops to raise specific exceptions (raiseDivZero#,
--- raiseUnderflow#, raiseOverflow#). These primops are meant to be used by the
--- package implementing arbitrary precision numbers (Natural,Integer). It can't
--- depend on `base` package to raise exceptions in a normal way because it would
--- create a package dependency circle (base <-> bignum package).
+-- The RTS provides several primops to raise specific imprecise exceptions
+-- (raiseDivZero#, raiseUnderflow#, raiseOverflow#). These primops are meant to
+-- be used by the package implementing arbitrary precision numbers
+-- (Natural,Integer). It can't depend on `base` package to raise exceptions in a
+-- normal way because it would create a package dependency circle
+-- (base <-> bignum package).
--
-- See #14664
@@ -2646,25 +2649,27 @@ primop RaiseOverflowOp "raiseOverflow#" GenPrimOp
-- raiseIO# needs to be a primop, because exceptions in the IO monad
-- must be *precise* - we don't want the strictness analyser turning
--- one kind of bottom into another, as it is allowed to do in pure code.
+-- one kind of bottom into another, as it is allowed to do with imprecise
+-- exceptions. For the same reason it doesn't return botRes, either.
+--
+-- Take the following function as an example. It should *not* be strict in @y@,
+-- because that would turn a precise into an imprecise exception for the call
+-- site @f 1 (error "boom")@ (see #13380):
--
--- But we *do* want to know that it returns bottom after
--- being applied to two arguments, so that this function is strict in y
-- f x y | x>0 = raiseIO blah
-- | y>0 = return 1
-- | otherwise = return 2
--
--- TODO Check that the above notes on @f@ are valid. The function successfully
--- produces an IO exception when compiled without optimization. If we analyze
--- it as strict in @y@, won't we change that behavior under optimization?
--- I thought the rule was that it was okay to replace one valid imprecise
--- exception with another, but not to replace a precise exception with
--- an imprecise one (dfeuer, 2017-03-05).
+-- This is scenario 2 in Note [Precise exceptions and strictness analysis] in
+-- Demand. For this reason, 'raiseIO#' should have @topDiv@, but that would
+-- entail not being able to eliminate a lot of dead code. Hence it is the only
+-- primitive to introduce @exnDiv@, which differs from @botDiv@ only in its
+-- 'defaultDmd'.
primop RaiseIOOp "raiseIO#" GenPrimOp
a -> State# RealWorld -> (# State# RealWorld, b #)
with
- strictness = { \ _arity -> mkClosedStrictSig [topDmd, topDmd] botDiv }
+ strictness = { \ _arity -> mkClosedStrictSig [topDmd, topDmd] exnDiv }
out_of_line = True
has_side_effects = True