Use IP based CallStack in error and undefined
[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(..), pattern ErrorCall, ArithException(..)
28 , divZeroException, overflowException, ratioZeroDenomException
29 , errorCallException, errorCallWithCallStackException
30 , showCallStack, popCallStack, showSrcLoc
31 -- re-export CallStack and SrcLoc from GHC.Types
32 , CallStack(..), SrcLoc(..)
33 ) where
34
35 import Data.Maybe
36 import Data.Typeable (Typeable, cast)
37 -- loop: Data.Typeable -> GHC.Err -> GHC.Exception
38 import GHC.Base
39 import GHC.Show
40
41 {- |
42 The @SomeException@ type is the root of the exception type hierarchy.
43 When an exception of type @e@ is thrown, behind the scenes it is
44 encapsulated in a @SomeException@.
45 -}
46 data SomeException = forall e . Exception e => SomeException e
47
48 instance Show SomeException where
49 showsPrec p (SomeException e) = showsPrec p e
50
51 {- |
52 Any type that you wish to throw or catch as an exception must be an
53 instance of the @Exception@ class. The simplest case is a new exception
54 type directly below the root:
55
56 > data MyException = ThisException | ThatException
57 > deriving (Show, Typeable)
58 >
59 > instance Exception MyException
60
61 The default method definitions in the @Exception@ class do what we need
62 in this case. You can now throw and catch @ThisException@ and
63 @ThatException@ as exceptions:
64
65 @
66 *Main> throw ThisException \`catch\` \\e -> putStrLn (\"Caught \" ++ show (e :: MyException))
67 Caught ThisException
68 @
69
70 In more complicated examples, you may wish to define a whole hierarchy
71 of exceptions:
72
73 > ---------------------------------------------------------------------
74 > -- Make the root exception type for all the exceptions in a compiler
75 >
76 > data SomeCompilerException = forall e . Exception e => SomeCompilerException e
77 > deriving Typeable
78 >
79 > instance Show SomeCompilerException where
80 > show (SomeCompilerException e) = show e
81 >
82 > instance Exception SomeCompilerException
83 >
84 > compilerExceptionToException :: Exception e => e -> SomeException
85 > compilerExceptionToException = toException . SomeCompilerException
86 >
87 > compilerExceptionFromException :: Exception e => SomeException -> Maybe e
88 > compilerExceptionFromException x = do
89 > SomeCompilerException a <- fromException x
90 > cast a
91 >
92 > ---------------------------------------------------------------------
93 > -- Make a subhierarchy for exceptions in the frontend of the compiler
94 >
95 > data SomeFrontendException = forall e . Exception e => SomeFrontendException e
96 > deriving Typeable
97 >
98 > instance Show SomeFrontendException where
99 > show (SomeFrontendException e) = show e
100 >
101 > instance Exception SomeFrontendException where
102 > toException = compilerExceptionToException
103 > fromException = compilerExceptionFromException
104 >
105 > frontendExceptionToException :: Exception e => e -> SomeException
106 > frontendExceptionToException = toException . SomeFrontendException
107 >
108 > frontendExceptionFromException :: Exception e => SomeException -> Maybe e
109 > frontendExceptionFromException x = do
110 > SomeFrontendException a <- fromException x
111 > cast a
112 >
113 > ---------------------------------------------------------------------
114 > -- Make an exception type for a particular frontend compiler exception
115 >
116 > data MismatchedParentheses = MismatchedParentheses
117 > deriving (Typeable, Show)
118 >
119 > instance Exception MismatchedParentheses where
120 > toException = frontendExceptionToException
121 > fromException = frontendExceptionFromException
122
123 We can now catch a @MismatchedParentheses@ exception as
124 @MismatchedParentheses@, @SomeFrontendException@ or
125 @SomeCompilerException@, but not other types, e.g. @IOException@:
126
127 @
128 *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: MismatchedParentheses))
129 Caught MismatchedParentheses
130 *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: SomeFrontendException))
131 Caught MismatchedParentheses
132 *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: SomeCompilerException))
133 Caught MismatchedParentheses
134 *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: IOException))
135 *** Exception: MismatchedParentheses
136 @
137
138 -}
139 class (Typeable e, Show e) => Exception e where
140 toException :: e -> SomeException
141 fromException :: SomeException -> Maybe e
142
143 toException = SomeException
144 fromException (SomeException e) = cast e
145
146 -- | Render this exception value in a human-friendly manner.
147 --
148 -- Default implementation: @'show'@.
149 --
150 -- @since 4.8.0.0
151 displayException :: e -> String
152 displayException = show
153
154 instance Exception SomeException where
155 toException se = se
156 fromException = Just
157 displayException (SomeException e) = displayException e
158
159 -- | Throw an exception. Exceptions may be thrown from purely
160 -- functional code, but may only be caught within the 'IO' monad.
161 throw :: Exception e => e -> a
162 throw e = raise# (toException e)
163
164 -- |This is thrown when the user calls 'error'. The @String@ is the
165 -- argument given to 'error'.
166 data ErrorCall = ErrorCallWithLocation String String
167 deriving (Eq, Ord)
168
169 pattern ErrorCall err <- ErrorCallWithLocation err _ where
170 ErrorCall err = ErrorCallWithLocation err ""
171
172 instance Exception ErrorCall
173
174 instance Show ErrorCall where
175 showsPrec _ (ErrorCallWithLocation err "") = showString err
176 showsPrec _ (ErrorCallWithLocation err loc) = showString (err ++ '\n' : loc)
177
178 errorCallException :: String -> SomeException
179 errorCallException s = toException (ErrorCall s)
180
181 errorCallWithCallStackException :: String -> CallStack -> SomeException
182 errorCallWithCallStackException s stk
183 = toException (ErrorCallWithLocation s (showCallStack (popCallStack stk)))
184
185
186 -- | Pretty print 'SrcLoc'
187 --
188 -- @since 4.8.2.0
189 showSrcLoc :: SrcLoc -> String
190 showSrcLoc SrcLoc {..}
191 = foldr (++) ""
192 [ srcLocFile, ":"
193 , show srcLocStartLine, ":"
194 , show srcLocStartCol, " in "
195 , srcLocPackage, ":", srcLocModule
196 ]
197
198 -- | Pretty print 'CallStack'
199 --
200 -- @since 4.8.2.0
201 showCallStack :: CallStack -> String
202 showCallStack (CallStack stk@(_:_))
203 = unlines ("CallStack:" : map (indent . showCallSite) stk)
204 where
205 -- Data.OldList isn't available yet, so we repeat the definition here
206 unlines [] = []
207 unlines [l] = l
208 unlines (l:ls) = l ++ '\n' : unlines ls
209 indent l = " " ++ l
210 showCallSite (f, loc) = f ++ ", called at " ++ showSrcLoc loc
211 showCallStack _ = error "CallStack cannot be empty!"
212
213
214 -- | Remove the most recent callsite from the 'CallStack'
215 --
216 -- @since 4.8.2.0
217 popCallStack :: CallStack -> CallStack
218 popCallStack (CallStack (_:rest)) = CallStack rest
219 popCallStack _ = error "CallStack cannot be empty!"
220
221 -- |Arithmetic exceptions.
222 data ArithException
223 = Overflow
224 | Underflow
225 | LossOfPrecision
226 | DivideByZero
227 | Denormal
228 | RatioZeroDenominator -- ^ @since 4.6.0.0
229 deriving (Eq, Ord)
230
231 divZeroException, overflowException, ratioZeroDenomException :: SomeException
232 divZeroException = toException DivideByZero
233 overflowException = toException Overflow
234 ratioZeroDenomException = toException RatioZeroDenominator
235
236 instance Exception ArithException
237
238 instance Show ArithException where
239 showsPrec _ Overflow = showString "arithmetic overflow"
240 showsPrec _ Underflow = showString "arithmetic underflow"
241 showsPrec _ LossOfPrecision = showString "loss of precision"
242 showsPrec _ DivideByZero = showString "divide by zero"
243 showsPrec _ Denormal = showString "denormal"
244 showsPrec _ RatioZeroDenominator = showString "Ratio has zero denominator"