Inlining forgets strictness properties with GHC 9.0.2
Summary
When updating a codebase to GHC 9.0.2, I noticed that some strictness tests were newly failing. I managed to reduce it to the following reproducer.
The Core produced by this program looks suspect. Inlining seems to lead to strictness properties being ignored, which doesn't happen with GHC 8.10.7.
Steps to reproduce
Take a look at the differences between the Core generated by GHC 8.10.7 and 9.0.2. Unfortunately this reproducer depends on mtl and unordered-containers, but my feeling is that this can be reproduced without them.
I used: mtl-2.2.2 and unordered-containers-0.2.17.0 for GHC 9.0.2
{-# LANGUAGE BangPatterns #-}
module Repro where
import Control.Monad.RWS.Strict
import qualified Data.HashMap.Strict as HM
data Box = Box !Int
addToList :: Box -> [Box] -> [Box]
addToList !b !bs = b : bs
trigger :: Int -> RWS Int () (HM.HashMap Int [Box]) ()
trigger !indx = do
v <- ask
let b = Box v
modify' $ HM.adjust (addToList b) indx
GHC-8.10.7(good)
Repro.trigger1
= \ (w_s2R5 :: Int)
(w1_s2R6 :: Int)
(w2_s2R7 :: HM.HashMap Int [Box]) ->
case w_s2R5 of { GHC.Types.I# ww1_s2Ra ->
case Repro.$w$sadjust
@ [Box]
(\ (bs_a14k :: [Box]) ->
case w1_s2R6 of { GHC.Types.I# dt1_a18g ->
case bs_a14k of bs1_X14s { __DEFAULT ->
GHC.Types.: @ Box (Repro.Box dt1_a18g) bs1_X14s
}
})
ww1_s2Ra
w2_s2R7
of vx_a2rj
{ __DEFAULT ->
(GHC.Tuple.(), vx_a2rj, GHC.Tuple.())
`cast` (Sym (Data.Functor.Identity.N:Identity[0]
<((), HM.HashMap Int [Box], ())>_R)
:: ((), HM.HashMap Int [Box], ())
~R# Identity ((), HM.HashMap Int [Box], ()))
}
}
GHC-9.0.2(bad)
trigger1
= \ w_s2P9 w1_s2Pa w2_s2Pb ->
case w_s2P9 of { I# ww1_s2Pe ->
case $w$sadjust
(let {
b_s2py = case w1_s2Pa of { I# dt1_a18B -> Box dt1_a18B } } in -- LAZY!
\ bs_a14H ->
case w1_s2Pa of { I# dt1_a18B ->
case bs_a14H of bs1_X4 { __DEFAULT -> : b_s2py bs1_X4 }
})
ww1_s2Pe
w2_s2Pb
of vx_a2pR
{ __DEFAULT ->
((), vx_a2pR, ()) `cast`
}
}
GHC-9.2.1(bad)
Repro.trigger1
= \ (w_s1Wf :: Int)
(w1_s1Wg [OS=OneShot] :: Int)
(w2_s1Wh [OS=OneShot] :: HM.HashMap Int [Box]) ->
case w_s1Wf of { GHC.Types.I# ww1_s1Wk ->
let {
b_s1Po :: Box
[LclId]
b_s1Po
= case w1_s1Wg of { GHC.Types.I# dt1_a19i ->
Repro.Box dt1_a19i
} } in -- LAZY!
case Repro.$w$s$wadjust
@[Box]
(\ (bs_a15f :: [Box]) ->
case w1_s1Wg of { GHC.Types.I# dt1_a19i ->
case bs_a15f of bs1_X4 { __DEFAULT ->
GHC.Types.: @Box b_s1Po bs1_X4
}
})
ww1_s1Wk
w2_s1Wh
of vx_a1Uc
{ __DEFAULT ->
(GHC.Tuple.(), vx_a1Uc, GHC.Tuple.())
`cast` (Sym (Data.Functor.Identity.N:Identity[0]
<((), HM.HashMap Int [Box], ())>_R)
:: ((), HM.HashMap Int [Box], ())
~R# Identity ((), HM.HashMap Int [Box], ()))
}
}
Expected behaviour
The Core generated by the trigger function should respect the strictness properties of addToList
and ensure that the list's elements are whnf and is spine-strict.
Environment
- GHC version used: 9.0.2, 9.2.1