`atomicModifyIORef'` is subtly lazier than expected
Summary
I would expect the value in an IORef to be in head-normal form after calling atomicallyModifyIORef'
. Yet, this is not always the case.
atomicModifyIORef' ref f
works by first calculating x = f old
. x
is a tuple of the new value and the returned value. It then switches out the value in ref
for the selector thunk fst x
. Finally, it forces the components of x
.
This leaves ref
holding a selection thunk, be it one that points at a head-normal form value.
My issue is that this makes finding unwanted thunks with ghc-heap
or nothunks
tricky.
It becomes unclear whether the thunk held by the IORef is a genuine one or merely one of these selection thunks pointing at something evaluated.
It would be better if atomicModifyIORef'
directly evaluated the value in the IORef, hence forcing both the selection thunk and the first component of x
. The primop and a couple of functions in GHC.IORef
would have to be modified to make this value available in the definition of atomicModifyIORef'
where it could be forced.
Steps to reproduce
See https://gitlab.haskell.org/teo/t20823-repro
Expected behavior
The program shouldn't find a thunk
Environment
- GHC version used: 8.8.4, 8.10.7, but as far as I can see, the IORef code hasn't been touched since then