diff options
author | Sebastian Graf <sebastian.graf@kit.edu> | 2022-11-22 19:07:27 +0100 |
---|---|---|
committer | Sebastian Graf <sebastian.graf@kit.edu> | 2022-11-29 09:13:41 +0100 |
commit | fecf0aa1e5491ac30e491ad163bd2fc2c7510e76 (patch) | |
tree | a49800a7b1df51878dec1824043391b817cc8297 /compiler/GHC/Core/DataCon.hs | |
parent | def47dd32491311289bff26230b664c895f178cc (diff) | |
download | haskell-wip/T22475.tar.gz |
DmdAnal: Reflect the `seq` of strict fields of a DataCon worker (#22475)wip/T22475
See the updated `Note [Data-con worker strictness]`
and the new `Note [Demand transformer for data constructors]`.
Fixes #22475.
Diffstat (limited to 'compiler/GHC/Core/DataCon.hs')
-rw-r--r-- | compiler/GHC/Core/DataCon.hs | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/compiler/GHC/Core/DataCon.hs b/compiler/GHC/Core/DataCon.hs index 043cb82574..e3d6331195 100644 --- a/compiler/GHC/Core/DataCon.hs +++ b/compiler/GHC/Core/DataCon.hs @@ -901,19 +901,36 @@ instance Outputable EqSpec where ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Notice that we do *not* say the worker Id is strict even if the data constructor is declared strict - e.g. data T = MkT !(Int,Int) -Why? Because the *wrapper* $WMkT is strict (and its unfolding has case -expressions that do the evals) but the *worker* MkT itself is not. If we -pretend it is strict then when we see - case x of y -> MkT y -the simplifier thinks that y is "sure to be evaluated" (because the worker MkT -is strict) and drops the case. No, the workerId MkT is not strict. - -However, the worker does have StrictnessMarks. When the simplifier sees a -pattern - case e of MkT x -> ... -it uses the dataConRepStrictness of MkT to mark x as evaluated; but that's -fine... dataConRepStrictness comes from the data con not from the worker Id. + e.g. data T = MkT ![Int] Bool +Even though most often the evals are done by the *wrapper* $WMkT, there are +situations in which tag inference will re-insert evals around the worker. +So for all intents and purposes the *worker* MkT is strict, too! + +Unfortunately, if we exposed accurate strictness of DataCon workers, we'd +see the following transformation: + + f xs = case xs of xs' { __DEFAULT -> ... case MkT xs b of x { __DEFAULT -> [x] } } -- DmdAnal: Strict in xs + ==> { drop-seq, binder swap on xs' } + f xs = case MkT xs b of x { __DEFAULT -> [x] } -- DmdAnal: Still strict in xs + ==> { case-to-let } + f xs = let x = MkT xs' b in [x] -- DmdAnal: No longer strict in xs! + +I.e., we are ironically losing strictness in `xs` by dropping the eval on `xs` +and then doing case-to-let. The issue is that `exprIsHNF` currently says that +every DataCon worker app is a value. The implicit assumption is that surrounding +evals will have evaluated strict fields like `xs` before! But now that we had +just dropped the eval on `xs`, that assumption is no longer valid. + +Long story short: By keeping the demand signature lazy, the Simplifier will not +drop the eval on `xs` and using `exprIsHNF` to decide case-to-let and others +remains sound. + +Similarly, during demand analysis in dmdTransformDataConSig, we bump up the +field demand with `C_01`, *not* `C_11`, because the latter exposes too much +strictness that will drop the eval on `xs` above. + +This issue is discussed at length in +"Failed idea: no wrappers for strict data constructors" in #21497 and #22475. Note [Bangs on data constructor arguments] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |