ghc-internal-9.1201.0: src/GHC/Internal/Control/Exception.hs
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NoImplicitPrelude, ExistentialQuantification #-}
-----------------------------------------------------------------------------
-- |
-- Module : GHC.Internal.Control.Exception
-- Copyright : (c) The University of Glasgow 2001
-- License : BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer : libraries@haskell.org
-- Stability : stable
-- Portability : non-portable (extended exceptions)
--
-- This module provides support for raising and catching both built-in
-- and user-defined exceptions.
--
-- In addition to exceptions thrown by 'IO' operations, exceptions may
-- be thrown by pure code (imprecise exceptions) or by external events
-- (asynchronous exceptions), but may only be caught in the 'IO' monad.
-- For more details, see:
--
-- * /A semantics for imprecise exceptions/, by Simon Peyton Jones,
-- Alastair Reid, Tony Hoare, Simon Marlow, Fergus Henderson,
-- in /PLDI'99/.
--
-- * /Asynchronous exceptions in Haskell/, by Simon Marlow, Simon Peyton
-- Jones, Andy Moran and John Reppy, in /PLDI'01/.
--
-- * /An Extensible Dynamically-Typed Hierarchy of Exceptions/,
-- by Simon Marlow, in /Haskell '06/.
--
-----------------------------------------------------------------------------
module GHC.Internal.Control.Exception (
-- * The Exception type
SomeException(..),
Exception(..), -- class
IOException, -- instance Eq, Ord, Show, Typeable, Exception
ArithException(..), -- instance Eq, Ord, Show, Typeable, Exception
ArrayException(..), -- instance Eq, Ord, Show, Typeable, Exception
AssertionFailed(..),
SomeAsyncException(..),
AsyncException(..), -- instance Eq, Ord, Show, Typeable, Exception
asyncExceptionToException, asyncExceptionFromException,
NonTermination(..),
NestedAtomically(..),
BlockedIndefinitelyOnMVar(..),
BlockedIndefinitelyOnSTM(..),
AllocationLimitExceeded(..),
CompactionFailed(..),
Deadlock(..),
NoMethodError(..),
PatternMatchFail(..),
RecConError(..),
RecSelError(..),
RecUpdError(..),
ErrorCall(..),
TypeError(..),
-- * Throwing exceptions
throw,
throwIO,
rethrowIO,
ioError,
throwTo,
-- ** The @catch@ functions
catch,
catchNoPropagate,
catches, Handler(..),
catchJust,
-- ** Exception annotation
-- ** The @handle@ functions
handle,
handleJust,
-- ** The @try@ functions
try,
tryWithContext,
tryJust,
-- ** The @evaluate@ function
evaluate,
-- ** The @mapException@ function
mapException,
-- ** Asynchronous exception control
mask,
mask_,
uninterruptibleMask,
uninterruptibleMask_,
MaskingState(..),
getMaskingState,
interruptible,
allowInterrupt,
-- * Assertions
assert,
-- * Utilities
bracket,
bracket_,
bracketOnError,
finally,
onException,
-- * Annotating exceptions
ExceptionContext(..),
annotateIO,
WhileHandling(..),
) where
import GHC.Internal.Control.Exception.Base
import GHC.Internal.Exception.Type (ExceptionWithContext(..), whileHandling)
import GHC.Internal.Base
import GHC.Internal.IO (interruptible)
-- | You need this when using 'catches'.
data Handler a = forall e . Exception e => Handler (e -> IO a)
-- | @since base-4.6.0.0
instance Functor Handler where
fmap f (Handler h) = Handler (fmap f . h)
{- |
Sometimes you want to catch two different sorts of exception. You could
do something like
> f = expr `catch` \ (ex :: ArithException) -> handleArith ex
> `catch` \ (ex :: IOException) -> handleIO ex
However, there are a couple of problems with this approach. The first is
that having two exception handlers is inefficient. However, the more
serious issue is that the second exception handler will catch exceptions
in the first, e.g. in the example above, if @handleArith@ throws an
@IOException@ then the second exception handler will catch it.
Instead, we provide a function 'catches', which would be used thus:
> f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex),
> Handler (\ (ex :: IOException) -> handleIO ex)]
-}
catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catchNoPropagate` catchesHandler handlers
catchesHandler :: [Handler a] -> ExceptionWithContext SomeException -> IO a
catchesHandler handlers ec@(ExceptionWithContext _ e) =
foldr tryHandler (rethrowIO ec) handlers
where
tryHandler (Handler handler) res =
case fromException e of
Just e' -> annotateIO (whileHandling ec) (handler e')
Nothing -> res
-- -----------------------------------------------------------------------------
-- Asynchronous exceptions
-- | When invoked inside 'mask', this function allows a masked
-- asynchronous exception to be raised, if one exists. It is
-- equivalent to performing an interruptible operation (see
-- #interruptible), but does not involve any actual blocking.
--
-- When called outside 'mask', or inside 'uninterruptibleMask', this
-- function has no effect.
--
-- @since base-4.4.0.0
allowInterrupt :: IO ()
allowInterrupt = interruptible $ return ()