
#8598: IO hack in demand analyzer gets in the way of CPR -------------------------------------+------------------------------------ Reporter: nomeata | Owner: Type: task | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Comment (by nomeata): Mail from SPJ: Well spotted. I'm on a train, hence email response. Maybe you can paste this into the ticket? There are two different issues here. '''First''', `isDoubleFinite` is declared as non-side-effecting: {{{ foreign import ccall unsafe "isDoubleFinite" isDoubleFinite :: Double -> Int }}} But (as you can see from the code you give) we currently desugar it into something that looks (to Core) as though it might have a side effect, or raise a (synchronous) exception. That is stupid. How might we fix that? I can think of two ways. * Generate a `FCallId` whose type is `Double -> Int` rather than (as now) `Double -> IO Int`. There would be a few knock-on consequences to make sure they were correctly code-generated. I like this path best, because it reflects the truth. * Currently {{{ IO a = State# RealWorld# -> (# State# RealWorld#, a #) }}} For these non-side-effecting things we could instead generate a `FCallId` with a type involving `SafeIO` instead of `IO`: {{{ SafeIO a = State# SafeWorld# -> (# State# SafeWorld#, a #) }}} The different "world token" would express the idea that the function can't throw an exception. I don't like this as much, but it might in any case be useful for things that ''do'' have side effects but ''don't'' throw exceptions. My preference is for the first. '''Second''', as you point out, consider {{{ f x = do { when (x>3) exit ; return (True, False) } }}} Function `f` might throw an exception or exit rather than returning, but ''if it does return'' it will certainly have the CPR property. So yes, CPR-ness is quite safe. It's not quite so obvious for divergence: {{{ g x = do { when (x>3) exit ; g x } h 0 y = y h x y = g x }}} Is `h` strict in `y`? You might say (reasonably) that we can ignore the possible IO exception/exit in `g` when figuring out that `g` is sure to diverge. If so, we'd say that `h` is strict in `y`. But if `(x>3)` then really `y` is not evaluated... and spotting that is exactly what the IO hack in the demand analyser is spotting. So I think it is ''not'' safe to propagate divergence information. In short, CPR info yes, guaranteed-divergence no. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8598#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler