content: {-# LANGUAGE Trustworthy #-}
  {-# LANGUAGE NoImplicitPrelude
             , ExistentialQuantification
             , MagicHash
             , DeriveDataTypeable
    #-}
  {-# OPTIONS_HADDOCK hide #-}
  
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  GHC.Exception
  -- Copyright   :  (c) The University of Glasgow, 1998-2002
  -- License     :  see libraries/base/LICENSE
  --
  -- Maintainer  :  cvs-ghc@haskell.org
  -- Stability   :  internal
  -- Portability :  non-portable (GHC extensions)
  --
  -- Exceptions and exception-handling functions.
  --
  -----------------------------------------------------------------------------
  
  module GHC.Exception
         ( Exception(..)    -- Class
         , throw
         , SomeException(..), ErrorCall(..), ArithException(..)
         , divZeroException, overflowException, ratioZeroDenomException
         , errorCallException
         ) where
  
  import Data.Maybe
  import Data.Typeable (Typeable, cast)
     -- loop: Data.Typeable -> GHC.Err -> GHC.Exception
  import GHC.Base
  import GHC.Show
  
  {- |
  The @SomeException@ type is the root of the exception type hierarchy.
  When an exception of type @e@ is thrown, behind the scenes it is
  encapsulated in a @SomeException@.
  -}
  data SomeException = forall e . Exception e => SomeException e
      deriving Typeable
  
  instance Show SomeException where
      showsPrec p (SomeException e) = showsPrec p e
  
  {- |
  Any type that you wish to throw or catch as an exception must be an
  instance of the @Exception@ class. The simplest case is a new exception
  type directly below the root:
  
  > data MyException = ThisException | ThatException
  >     deriving (Show, Typeable)
  >
  > instance Exception MyException
  
  The default method definitions in the @Exception@ class do what we need
  in this case. You can now throw and catch @ThisException@ and
  @ThatException@ as exceptions:
  
  @
  *Main> throw ThisException \`catch\` \\e -> putStrLn (\"Caught \" ++ show (e :: MyException))
  Caught ThisException
  @
  
  In more complicated examples, you may wish to define a whole hierarchy
  of exceptions:
  
  > ---------------------------------------------------------------------
  > -- Make the root exception type for all the exceptions in a compiler
  >
  > data SomeCompilerException = forall e . Exception e => SomeCompilerException e
  >     deriving Typeable
  >
  > instance Show SomeCompilerException where
  >     show (SomeCompilerException e) = show e
  >
  > instance Exception SomeCompilerException
  >
  > compilerExceptionToException :: Exception e => e -> SomeException
  > compilerExceptionToException = toException . SomeCompilerException
  >
  > compilerExceptionFromException :: Exception e => SomeException -> Maybe e
  > compilerExceptionFromException x = do
  >     SomeCompilerException a <- fromException x
  >     cast a
  >
  > ---------------------------------------------------------------------
  > -- Make a subhierarchy for exceptions in the frontend of the compiler
  >
  > data SomeFrontendException = forall e . Exception e => SomeFrontendException e
  >     deriving Typeable
  >
  > instance Show SomeFrontendException where
  >     show (SomeFrontendException e) = show e
  >
  > instance Exception SomeFrontendException where
  >     toException = compilerExceptionToException
  >     fromException = compilerExceptionFromException
  >
  > frontendExceptionToException :: Exception e => e -> SomeException
  > frontendExceptionToException = toException . SomeFrontendException
  >
  > frontendExceptionFromException :: Exception e => SomeException -> Maybe e
  > frontendExceptionFromException x = do
  >     SomeFrontendException a <- fromException x
  >     cast a
  >
  > ---------------------------------------------------------------------
  > -- Make an exception type for a particular frontend compiler exception
  >
  > data MismatchedParentheses = MismatchedParentheses
  >     deriving (Typeable, Show)
  >
  > instance Exception MismatchedParentheses where
  >     toException   = frontendExceptionToException
  >     fromException = frontendExceptionFromException
  
  We can now catch a @MismatchedParentheses@ exception as
  @MismatchedParentheses@, @SomeFrontendException@ or
  @SomeCompilerException@, but not other types, e.g. @IOException@:
  
  @
  *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: MismatchedParentheses))
  Caught MismatchedParentheses
  *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: SomeFrontendException))
  Caught MismatchedParentheses
  *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: SomeCompilerException))
  Caught MismatchedParentheses
  *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: IOException))
  *** Exception: MismatchedParentheses
  @
  
  -}
  class (Typeable e, Show e) => Exception e where
      toException   :: e -> SomeException
      fromException :: SomeException -> Maybe e
  
      toException = SomeException
      fromException (SomeException e) = cast e
  
      -- | Render this exception value in a human-friendly manner.
      --
      -- Default implementation: @'show'@.
      --
      -- @since 4.8.0.0
      displayException :: e -> String
      displayException = show
  
  instance Exception SomeException where
      toException se = se
      fromException = Just
      displayException (SomeException e) = displayException e
  
  -- | Throw an exception.  Exceptions may be thrown from purely
  -- functional code, but may only be caught within the 'IO' monad.
  throw :: Exception e => e -> a
  throw e = raise# (toException e)
  
  -- |This is thrown when the user calls 'error'. The @String@ is the
  -- argument given to 'error'.
  newtype ErrorCall = ErrorCall String
      deriving (Eq, Ord, Typeable)
  
  instance Exception ErrorCall
  
  instance Show ErrorCall where
      showsPrec _ (ErrorCall err) = showString err
  
  errorCallException :: String -> SomeException
  errorCallException s = toException (ErrorCall s)
  
  -- |Arithmetic exceptions.
  data ArithException
    = Overflow
    | Underflow
    | LossOfPrecision
    | DivideByZero
    | Denormal
    | RatioZeroDenominator -- ^ @since 4.6.0.0
    deriving (Eq, Ord, Typeable)
  
  divZeroException, overflowException, ratioZeroDenomException  :: SomeException
  divZeroException        = toException DivideByZero
  overflowException       = toException Overflow
  ratioZeroDenomException = toException RatioZeroDenominator
  
  instance Exception ArithException
  
  instance Show ArithException where
    showsPrec _ Overflow        = showString "arithmetic overflow"
    showsPrec _ Underflow       = showString "arithmetic underflow"
    showsPrec _ LossOfPrecision = showString "loss of precision"
    showsPrec _ DivideByZero    = showString "divide by zero"
    showsPrec _ Denormal        = showString "denormal"
    showsPrec _ RatioZeroDenominator = showString "Ratio has zero denominator"
  