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 |