[GHC] #13423: Exception to I/O hack in demand analyzer too broad
#13423: Exception to I/O hack in demand analyzer too broad -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 8.1 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: Other Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- 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 {{{#!hs 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 `IORef`s, 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. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13423> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#13423: Exception to I/O hack in demand analyzer too broad -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: Other | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by rwbarton): Is this really wrong in this case though? In a single-threaded context there is no observable difference between writing an `IORef` and then diverging, and diverging immediately; and in a multi-threaded context the ordering of `writeIORef` with respect to anything else is not guaranteed. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13423#comment:1> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#13423: Exception to I/O hack in demand analyzer too broad -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: Other | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): Replying to [comment:1 rwbarton]:
Is this really wrong in this case though? In a single-threaded context there is no observable difference between writing an `IORef` and then diverging, and diverging immediately; and in a multi-threaded context the ordering of `writeIORef` with respect to anything else is not guaranteed.
That's not true. Someone could write {{{#!hs fish n ref next `catch` \(e :: E) -> readIORef ref >>= ... }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13423#comment:2> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#13423: Exception to I/O hack in demand analyzer too broad -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: Other | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): Oh, if you mean diverging in the stronger sense of falling into a hole without throwing an exception, then that's true, but it's not the situation I was talking about. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13423#comment:3> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#13423: Exception to I/O hack in demand analyzer too broad -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: Other | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): In any case, you can just swap out `writeIORef` for any other genuinely side-effecting primop and get the same sort of result, so that's not really too relevant. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13423#comment:4> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
participants (1)
-
GHC