be2ee3f4c945583f6cd529bf67cf3572934fa69a
[ghc.git] / libraries / base / GHC / Exception.hs
1 {-# LANGUAGE Trustworthy #-}
2 {-# LANGUAGE NoImplicitPrelude
3 , ExistentialQuantification
4 , MagicHash
5 , RecordWildCards
6 , PatternSynonyms
7 #-}
8 {-# OPTIONS_HADDOCK hide #-}
9
10 -----------------------------------------------------------------------------
11 -- |
12 -- Module : GHC.Exception
13 -- Copyright : (c) The University of Glasgow, 1998-2002
14 -- License : see libraries/base/LICENSE
15 --
16 -- Maintainer : cvs-ghc@haskell.org
17 -- Stability : internal
18 -- Portability : non-portable (GHC extensions)
19 --
20 -- Exceptions and exception-handling functions.
21 --
22 -----------------------------------------------------------------------------
23
24 module GHC.Exception
25 ( Exception(..) -- Class
26 , throw
27 , SomeException(..), ErrorCall(..,ErrorCall), ArithException(..)
28 , divZeroException, overflowException, ratioZeroDenomException
29 , underflowException
30 , errorCallException, errorCallWithCallStackException
31 -- re-export CallStack and SrcLoc from GHC.Types
32 , CallStack, fromCallSiteList, getCallStack, prettyCallStack
33 , prettyCallStackLines, showCCSStack
34 , SrcLoc(..), prettySrcLoc
35 ) where
36
37 import Data.Maybe
38 import Data.Typeable (Typeable, cast)
39 -- loop: Data.Typeable -> GHC.Err -> GHC.Exception
40 import GHC.Base
41 import GHC.Show
42 import GHC.Stack.Types
43 import GHC.OldList
44 import GHC.IO.Unsafe
45 import {-# SOURCE #-} GHC.Stack.CCS
46
47 {- |
48 The @SomeException@ type is the root of the exception type hierarchy.
49 When an exception of type @e@ is thrown, behind the scenes it is
50 encapsulated in a @SomeException@.
51 -}
52 data SomeException = forall e . Exception e => SomeException e
53
54 -- | @since 3.0
55 instance Show SomeException where
56 showsPrec p (SomeException e) = showsPrec p e
57
58 {- |
59 Any type that you wish to throw or catch as an exception must be an
60 instance of the @Exception@ class. The simplest case is a new exception
61 type directly below the root:
62
63 > data MyException = ThisException | ThatException
64 > deriving Show
65 >
66 > instance Exception MyException
67
68 The default method definitions in the @Exception@ class do what we need
69 in this case. You can now throw and catch @ThisException@ and
70 @ThatException@ as exceptions:
71
72 @
73 *Main> throw ThisException \`catch\` \\e -> putStrLn (\"Caught \" ++ show (e :: MyException))
74 Caught ThisException
75 @
76
77 In more complicated examples, you may wish to define a whole hierarchy
78 of exceptions:
79
80 > ---------------------------------------------------------------------
81 > -- Make the root exception type for all the exceptions in a compiler
82 >
83 > data SomeCompilerException = forall e . Exception e => SomeCompilerException e
84 >
85 > instance Show SomeCompilerException where
86 > show (SomeCompilerException e) = show e
87 >
88 > instance Exception SomeCompilerException
89 >
90 > compilerExceptionToException :: Exception e => e -> SomeException
91 > compilerExceptionToException = toException . SomeCompilerException
92 >
93 > compilerExceptionFromException :: Exception e => SomeException -> Maybe e
94 > compilerExceptionFromException x = do
95 > SomeCompilerException a <- fromException x
96 > cast a
97 >
98 > ---------------------------------------------------------------------
99 > -- Make a subhierarchy for exceptions in the frontend of the compiler
100 >
101 > data SomeFrontendException = forall e . Exception e => SomeFrontendException e
102 >
103 > instance Show SomeFrontendException where
104 > show (SomeFrontendException e) = show e
105 >
106 > instance Exception SomeFrontendException where
107 > toException = compilerExceptionToException
108 > fromException = compilerExceptionFromException
109 >
110 > frontendExceptionToException :: Exception e => e -> SomeException
111 > frontendExceptionToException = toException . SomeFrontendException
112 >
113 > frontendExceptionFromException :: Exception e => SomeException -> Maybe e
114 > frontendExceptionFromException x = do
115 > SomeFrontendException a <- fromException x
116 > cast a
117 >
118 > ---------------------------------------------------------------------
119 > -- Make an exception type for a particular frontend compiler exception
120 >
121 > data MismatchedParentheses = MismatchedParentheses
122 > deriving Show
123 >
124 > instance Exception MismatchedParentheses where
125 > toException = frontendExceptionToException
126 > fromException = frontendExceptionFromException
127
128 We can now catch a @MismatchedParentheses@ exception as
129 @MismatchedParentheses@, @SomeFrontendException@ or
130 @SomeCompilerException@, but not other types, e.g. @IOException@:
131
132 @
133 *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: MismatchedParentheses))
134 Caught MismatchedParentheses
135 *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: SomeFrontendException))
136 Caught MismatchedParentheses
137 *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: SomeCompilerException))
138 Caught MismatchedParentheses
139 *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: IOException))
140 *** Exception: MismatchedParentheses
141 @
142
143 -}
144 class (Typeable e, Show e) => Exception e where
145 toException :: e -> SomeException
146 fromException :: SomeException -> Maybe e
147
148 toException = SomeException
149 fromException (SomeException e) = cast e
150
151 -- | Render this exception value in a human-friendly manner.
152 --
153 -- Default implementation: @'show'@.
154 --
155 -- @since 4.8.0.0
156 displayException :: e -> String
157 displayException = show
158
159 -- | @since 3.0
160 instance Exception SomeException where
161 toException se = se
162 fromException = Just
163 displayException (SomeException e) = displayException e
164
165 -- | Throw an exception. Exceptions may be thrown from purely
166 -- functional code, but may only be caught within the 'IO' monad.
167 throw :: Exception e => e -> a
168 throw e = raise# (toException e)
169
170 -- |This is thrown when the user calls 'error'. The @String@ is the
171 -- argument given to 'error'.
172 data ErrorCall = ErrorCallWithLocation String String
173 deriving (Eq, Ord)
174
175 pattern ErrorCall :: String -> ErrorCall
176 pattern ErrorCall err <- ErrorCallWithLocation err _ where
177 ErrorCall err = ErrorCallWithLocation err ""
178
179 -- | @since 4.0.0.0
180 instance Exception ErrorCall
181
182 -- | @since 4.0.0.0
183 instance Show ErrorCall where
184 showsPrec _ (ErrorCallWithLocation err "") = showString err
185 showsPrec _ (ErrorCallWithLocation err loc) = showString (err ++ '\n' : loc)
186
187 errorCallException :: String -> SomeException
188 errorCallException s = toException (ErrorCall s)
189
190 errorCallWithCallStackException :: String -> CallStack -> SomeException
191 errorCallWithCallStackException s stk = unsafeDupablePerformIO $ do
192 ccsStack <- currentCallStack
193 let
194 implicitParamCallStack = prettyCallStackLines stk
195 ccsCallStack = showCCSStack ccsStack
196 stack = intercalate "\n" $ implicitParamCallStack ++ ccsCallStack
197 return $ toException (ErrorCallWithLocation s stack)
198
199 showCCSStack :: [String] -> [String]
200 showCCSStack [] = []
201 showCCSStack stk = "CallStack (from -prof):" : map (" " ++) (reverse stk)
202
203 -- prettySrcLoc and prettyCallStack are defined here to avoid hs-boot
204 -- files. See Note [Definition of CallStack]
205
206 -- | Pretty print a 'SrcLoc'.
207 --
208 -- @since 4.9.0.0
209 prettySrcLoc :: SrcLoc -> String
210 prettySrcLoc SrcLoc {..}
211 = foldr (++) ""
212 [ srcLocFile, ":"
213 , show srcLocStartLine, ":"
214 , show srcLocStartCol, " in "
215 , srcLocPackage, ":", srcLocModule
216 ]
217
218 -- | Pretty print a 'CallStack'.
219 --
220 -- @since 4.9.0.0
221 prettyCallStack :: CallStack -> String
222 prettyCallStack = intercalate "\n" . prettyCallStackLines
223
224 prettyCallStackLines :: CallStack -> [String]
225 prettyCallStackLines cs = case getCallStack cs of
226 [] -> []
227 stk -> "CallStack (from HasCallStack):"
228 : map ((" " ++) . prettyCallSite) stk
229 where
230 prettyCallSite (f, loc) = f ++ ", called at " ++ prettySrcLoc loc
231
232 -- |Arithmetic exceptions.
233 data ArithException
234 = Overflow
235 | Underflow
236 | LossOfPrecision
237 | DivideByZero
238 | Denormal
239 | RatioZeroDenominator -- ^ @since 4.6.0.0
240 deriving (Eq, Ord)
241
242 divZeroException, overflowException, ratioZeroDenomException, underflowException :: SomeException
243 divZeroException = toException DivideByZero
244 overflowException = toException Overflow
245 ratioZeroDenomException = toException RatioZeroDenominator
246 underflowException = toException Underflow
247
248 -- | @since 4.0.0.0
249 instance Exception ArithException
250
251 -- | @since 4.0.0.0
252 instance Show ArithException where
253 showsPrec _ Overflow = showString "arithmetic overflow"
254 showsPrec _ Underflow = showString "arithmetic underflow"
255 showsPrec _ LossOfPrecision = showString "loss of precision"
256 showsPrec _ DivideByZero = showString "divide by zero"
257 showsPrec _ Denormal = showString "denormal"
258 showsPrec _ RatioZeroDenominator = showString "Ratio has zero denominator"