summaryrefslogtreecommitdiff
path: root/compiler/GHC/Types/Demand.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Types/Demand.hs')
-rw-r--r--compiler/GHC/Types/Demand.hs61
1 files changed, 56 insertions, 5 deletions
diff --git a/compiler/GHC/Types/Demand.hs b/compiler/GHC/Types/Demand.hs
index 80c725bbfc..65f3239a9e 100644
--- a/compiler/GHC/Types/Demand.hs
+++ b/compiler/GHC/Types/Demand.hs
@@ -607,13 +607,17 @@ multCard (Card a) (Card b)
-- isn't any evaluation at all. If you don't care, simply use '(:*)'.
data Demand
= BotDmd
- -- ^ A bottoming demand, produced by a diverging function, hence there is no
+ -- ^ A bottoming demand, produced by a diverging function ('C_10'), hence there is no
-- 'SubDemand' that describes how it was evaluated.
+
| AbsDmd
-- ^ An absent demand: Evaluated exactly 0 times ('C_00'), hence there is no
-- 'SubDemand' that describes how it was evaluated.
+
| D !CardNonAbs !SubDemand
-- ^ Don't use this internal data constructor; use '(:*)' instead.
+ -- Since BotDmd deals with 'C_10' and AbsDmd deals with 'C_00', the
+ -- cardinality component is CardNonAbs
deriving Eq
-- | Only meant to be used in the pattern synonym below!
@@ -1561,10 +1565,12 @@ isTopDmdType :: DmdType -> Bool
isTopDmdType (DmdType env args div)
= div == topDiv && null args && isEmptyVarEnv env
+{- Unused
-- | The demand type of an unspecified expression that is guaranteed to
-- throw a (precise or imprecise) exception or diverge.
exnDmdType :: DmdType
exnDmdType = DmdType emptyDmdEnv [] exnDiv
+-}
dmdTypeDepth :: DmdType -> Arity
dmdTypeDepth = length . dt_args
@@ -1626,21 +1632,66 @@ findIdDemand (DmdType fv _ res) id
-- exception, we act as if there is an additional control flow path that is
-- taken if e throws a precise exception. The demand type of this control flow
-- path
--- * is lazy and absent ('topDmd') in all free variables and arguments
+-- * is lazy and absent ('topDmd') and boxed in all free variables and arguments
-- * has 'exnDiv' 'Divergence' result
+-- See Note [Precise exceptions and strictness analysis]
+--
-- So we can simply take a variant of 'nopDmdType', 'exnDmdType'.
-- Why not 'nopDmdType'? Because then the result of 'e' can never be 'exnDiv'!
-- That means failure to drop dead-ends, see #18086.
--- See Note [Precise exceptions and strictness analysis]
deferAfterPreciseException :: DmdType -> DmdType
-deferAfterPreciseException = lubDmdType exnDmdType
+-- deferAfterPreciseException = lubDmdType exnDmdType
+deferAfterPreciseException (DmdType fvs ds r)
+ = DmdType (mapVarEnv defer fvs)
+ (map defer ds)
+ (r `lubDivergence` ExnOrDiv)
+ where
+ defer :: Demand -> Demand
+ defer AbsDmd = AbsDmd
+ defer BotDmd = AbsDmd
+ defer (D n sd) = lubCard n C_00 :* lubSubDmd sd (Poly Boxed C_00)
+
+ -- Roughly: defer d = d `lubDmd` D C_00 (Poly Boxed C_00)
+ -- It is very important that we `lub` with `Boxed`; see
+ -- Note [deferAfterPreciseException]
+ -- But that formulation fails the assert in :*,
+ -- because (D C_00 (Poly Boxed C_00)) is not a legal demand
+ -- So we write defer out more explicitly here
-- | See 'keepAliveDmdEnv'.
keepAliveDmdType :: DmdType -> VarSet -> DmdType
keepAliveDmdType (DmdType fvs ds res) vars =
DmdType (fvs `keepAliveDmdEnv` vars) ds res
-{-
+{- Note [deferAfterPreciseException]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The big picture is in Note [Precise exceptions and strictness analysis]
+The idea is that we want to treat
+ case <I/O operation> of (# s', r #) -> rhs
+
+as if it was
+ case <I/O operation> of
+ Just (# s', r #) -> rhs
+ Nothing -> error
+
+That is, the I/O operation might throw an exception, so that 'rhs' never
+gets reached. For example, we don't want to be strict in the strict free
+variables of 'rhs'.
+
+So roughly speaking:
+ deferAfterPreciseException = lubDmdType (DmdType emptyDmdEnv [] exnDiv)
+
+But that doesn't work quite right for boxity becasuse
+ case <I/O operation> of
+ (# s', r) -> f x
+
+uses `x` *boxed*. If we `lub` it with `(DmdType emptyDmdEnv [] exnDiv)`
+we'll get an *unboxed* demand on `x`, which led to #20746. There is
+a fuller example in that ticket.
+
+TL;DR: deferAfterPreciseException is very careful to preserve boxity
+in its argument.
+
Note [Demand type Divergence]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In contrast to DmdSigs, DmdTypes are elicited under a specific incoming demand.