Skip to content

Exception to I/O hack in demand analyzer too broad

The I/O hack in the demand analyzer triggers only for expressions that are not direct applications of primops (see io_hack_reqd in stranal/DmdAnal.hs). This seems rather arbitrary, and can produce surprising results. Consider

fish :: Int -> IORef Int -> IORef Int -> IO ()
fish n ref next = do
  writeIORef ref n
  writeIORef next n
  x <- getLine
  case readMaybe x of
    Just True -> fish (n + 1) ref next
    _ -> pure ()

If next is bottom, I would expect this to write n to ref and then throw an exception. But we actually get something else. First, the demand signature for fish ends up being Str=<L,U(U)><S(S),1*U(U)><S(S),1*U(U)><S,U>, which seems wrong. Then, as a result, worker/wrapper produces a wrapper that immediately unboxes both IORefs, so this is operationally wrong.

Why do I think this is wrong? The story Haskell users are told, over and over, is that evaluation is driven only by execution; that we never force anything unless we need its value to determine the next IO action. That principle is violated here.

Trac metadata
Trac field Value
Version 8.1
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information