Add custom exception for fixIO
authorDavid Feuer <david.feuer@gmail.com>
Thu, 2 Nov 2017 16:06:56 +0000 (12:06 -0400)
committerBen Gamari <ben@smart-cactus.org>
Thu, 2 Nov 2017 17:20:26 +0000 (13:20 -0400)
Traditionally, `fixIO f` throws `BlockedIndefinitelyOnMVar` if
`f` is strict. This is not particularly friendly, since the
`MVar` in question is just part of the way `fixIO` happens to be
implemented. Instead, throw a new `FixIOException` with a better
explanation of the problem.

Reviewers: austin, hvr, bgamari

Subscribers: rwbarton, thomie

GHC Trac Issues: #14356

Differential Revision: https://phabricator.haskell.org/D4113

libraries/base/Control/Exception/Base.hs
libraries/base/GHC/IO/Exception.hs
libraries/base/System/IO.hs
testsuite/tests/mdo/should_fail/mdofail006.stderr
testsuite/tests/typecheck/should_compile/holes2.stderr

index a15cc8e..d443159 100644 (file)
@@ -30,6 +30,7 @@ module Control.Exception.Base (
         NonTermination(..),
         NestedAtomically(..),
         BlockedIndefinitelyOnMVar(..),
+        FixIOException (..),
         BlockedIndefinitelyOnSTM(..),
         AllocationLimitExceeded(..),
         CompactionFailed(..),
index 9203f46..020bc06 100644 (file)
@@ -33,6 +33,7 @@ module GHC.IO.Exception (
 
   ArrayException(..),
   ExitCode(..),
+  FixIOException (..),
 
   ioException,
   ioError,
@@ -268,6 +269,15 @@ instance Show ArrayException where
         . (if not (null s) then showString ": " . showString s
                            else id)
 
+-- | @since TODO
+data FixIOException = FixIOException
+
+-- | @since TODO
+instance Exception FixIOException
+
+instance Show FixIOException where
+  showsPrec _ FixIOException = showString "cyclic evaluation in fixIO"
+
 -- -----------------------------------------------------------------------------
 -- The ExitCode type
 
index fde5bb6..6881724 100644 (file)
@@ -400,10 +400,15 @@ withBinaryFile name mode = bracket (openBinaryFile name mode) hClose
 -- ---------------------------------------------------------------------------
 -- fixIO
 
+-- | The implementation of 'mfix' for 'IO'. If the function passed
+-- to 'fixIO' inspects its argument, the resulting action will throw
+-- 'FixIOException'.
 fixIO :: (a -> IO a) -> IO a
 fixIO k = do
     m <- newEmptyMVar
-    ans <- unsafeDupableInterleaveIO (readMVar m)
+    ans <- unsafeDupableInterleaveIO
+             (readMVar m `catch` \BlockedIndefinitelyOnMVar ->
+                                    throwIO FixIOException)
     result <- k ans
     putMVar m result
     return result
index ea186c0..e2cf503 100644 (file)
@@ -1 +1 @@
-mdofail006: thread blocked indefinitely in an MVar operation
+mdofail006: cyclic evaluation in fixIO
index d7484fa..fd3073d 100644 (file)
@@ -9,7 +9,7 @@ holes2.hs:3:5: warning: [-Wdeferred-type-errors (in -Wdefault)]
         instance Show Ordering -- Defined in ‘GHC.Show’
         instance Show Integer -- Defined in ‘GHC.Show’
         ...plus 23 others
-        ...plus 61 instances involving out-of-scope types
+        ...plus 62 instances involving out-of-scope types
         (use -fprint-potential-instances to see them all)
     • In the expression: show _
       In an equation for ‘f’: f = show _