Use IP based CallStack in error and undefined
[ghc.git] / libraries / base / GHC / IO / Exception.hs
1 {-# LANGUAGE Trustworthy #-}
2 {-# LANGUAGE DeriveGeneric, NoImplicitPrelude, MagicHash,
3 ExistentialQuantification, ImplicitParams #-}
4 {-# OPTIONS_GHC -funbox-strict-fields #-}
5 {-# OPTIONS_HADDOCK hide #-}
6
7 -----------------------------------------------------------------------------
8 -- |
9 -- Module : GHC.IO.Exception
10 -- Copyright : (c) The University of Glasgow, 2009
11 -- License : see libraries/base/LICENSE
12 --
13 -- Maintainer : libraries@haskell.org
14 -- Stability : internal
15 -- Portability : non-portable
16 --
17 -- IO-related Exception types and functions
18 --
19 -----------------------------------------------------------------------------
20
21 module GHC.IO.Exception (
22 BlockedIndefinitelyOnMVar(..), blockedIndefinitelyOnMVar,
23 BlockedIndefinitelyOnSTM(..), blockedIndefinitelyOnSTM,
24 Deadlock(..),
25 AllocationLimitExceeded(..), allocationLimitExceeded,
26 AssertionFailed(..),
27
28 SomeAsyncException(..),
29 asyncExceptionToException, asyncExceptionFromException,
30 AsyncException(..), stackOverflow, heapOverflow,
31
32 ArrayException(..),
33 ExitCode(..),
34
35 ioException,
36 ioError,
37 IOError,
38 IOException(..),
39 IOErrorType(..),
40 userError,
41 assertError,
42 unsupportedOperation,
43 untangle,
44 ) where
45
46 import GHC.Base
47 import GHC.Generics
48 import GHC.List
49 import GHC.IO
50 import GHC.Show
51 import GHC.Read
52 import GHC.Exception
53 import GHC.IO.Handle.Types
54 import Foreign.C.Types
55
56 import Data.Typeable ( cast )
57
58 -- ------------------------------------------------------------------------
59 -- Exception datatypes and operations
60
61 -- |The thread is blocked on an @MVar@, but there are no other references
62 -- to the @MVar@ so it can't ever continue.
63 data BlockedIndefinitelyOnMVar = BlockedIndefinitelyOnMVar
64
65 instance Exception BlockedIndefinitelyOnMVar
66
67 instance Show BlockedIndefinitelyOnMVar where
68 showsPrec _ BlockedIndefinitelyOnMVar = showString "thread blocked indefinitely in an MVar operation"
69
70 blockedIndefinitelyOnMVar :: SomeException -- for the RTS
71 blockedIndefinitelyOnMVar = toException BlockedIndefinitelyOnMVar
72
73 -----
74
75 -- |The thread is waiting to retry an STM transaction, but there are no
76 -- other references to any @TVar@s involved, so it can't ever continue.
77 data BlockedIndefinitelyOnSTM = BlockedIndefinitelyOnSTM
78
79 instance Exception BlockedIndefinitelyOnSTM
80
81 instance Show BlockedIndefinitelyOnSTM where
82 showsPrec _ BlockedIndefinitelyOnSTM = showString "thread blocked indefinitely in an STM transaction"
83
84 blockedIndefinitelyOnSTM :: SomeException -- for the RTS
85 blockedIndefinitelyOnSTM = toException BlockedIndefinitelyOnSTM
86
87 -----
88
89 -- |There are no runnable threads, so the program is deadlocked.
90 -- The @Deadlock@ exception is raised in the main thread only.
91 data Deadlock = Deadlock
92
93 instance Exception Deadlock
94
95 instance Show Deadlock where
96 showsPrec _ Deadlock = showString "<<deadlock>>"
97
98 -----
99
100 -- |This thread has exceeded its allocation limit. See
101 -- 'GHC.Conc.setAllocationCounter' and
102 -- 'GHC.Conc.enableAllocationLimit'.
103 --
104 -- @since 4.8.0.0
105 data AllocationLimitExceeded = AllocationLimitExceeded
106
107 instance Exception AllocationLimitExceeded where
108 toException = asyncExceptionToException
109 fromException = asyncExceptionFromException
110
111 instance Show AllocationLimitExceeded where
112 showsPrec _ AllocationLimitExceeded =
113 showString "allocation limit exceeded"
114
115 allocationLimitExceeded :: SomeException -- for the RTS
116 allocationLimitExceeded = toException AllocationLimitExceeded
117
118 -----
119
120 -- |'assert' was applied to 'False'.
121 newtype AssertionFailed = AssertionFailed String
122
123 instance Exception AssertionFailed
124
125 instance Show AssertionFailed where
126 showsPrec _ (AssertionFailed err) = showString err
127
128 -----
129
130 -- |Superclass for asynchronous exceptions.
131 --
132 -- @since 4.7.0.0
133 data SomeAsyncException = forall e . Exception e => SomeAsyncException e
134
135 instance Show SomeAsyncException where
136 show (SomeAsyncException e) = show e
137
138 instance Exception SomeAsyncException
139
140 -- |@since 4.7.0.0
141 asyncExceptionToException :: Exception e => e -> SomeException
142 asyncExceptionToException = toException . SomeAsyncException
143
144 -- |@since 4.7.0.0
145 asyncExceptionFromException :: Exception e => SomeException -> Maybe e
146 asyncExceptionFromException x = do
147 SomeAsyncException a <- fromException x
148 cast a
149
150
151 -- |Asynchronous exceptions.
152 data AsyncException
153 = StackOverflow
154 -- ^The current thread\'s stack exceeded its limit.
155 -- Since an exception has been raised, the thread\'s stack
156 -- will certainly be below its limit again, but the
157 -- programmer should take remedial action
158 -- immediately.
159 | HeapOverflow
160 -- ^The program\'s heap is reaching its limit, and
161 -- the program should take action to reduce the amount of
162 -- live data it has. Notes:
163 --
164 -- * It is undefined which thread receives this exception.
165 --
166 -- * GHC currently does not throw 'HeapOverflow' exceptions.
167 | ThreadKilled
168 -- ^This exception is raised by another thread
169 -- calling 'Control.Concurrent.killThread', or by the system
170 -- if it needs to terminate the thread for some
171 -- reason.
172 | UserInterrupt
173 -- ^This exception is raised by default in the main thread of
174 -- the program when the user requests to terminate the program
175 -- via the usual mechanism(s) (e.g. Control-C in the console).
176 deriving (Eq, Ord)
177
178 instance Exception AsyncException where
179 toException = asyncExceptionToException
180 fromException = asyncExceptionFromException
181
182 -- | Exceptions generated by array operations
183 data ArrayException
184 = IndexOutOfBounds String
185 -- ^An attempt was made to index an array outside
186 -- its declared bounds.
187 | UndefinedElement String
188 -- ^An attempt was made to evaluate an element of an
189 -- array that had not been initialized.
190 deriving (Eq, Ord)
191
192 instance Exception ArrayException
193
194 -- for the RTS
195 stackOverflow, heapOverflow :: SomeException
196 stackOverflow = toException StackOverflow
197 heapOverflow = toException HeapOverflow
198
199 instance Show AsyncException where
200 showsPrec _ StackOverflow = showString "stack overflow"
201 showsPrec _ HeapOverflow = showString "heap overflow"
202 showsPrec _ ThreadKilled = showString "thread killed"
203 showsPrec _ UserInterrupt = showString "user interrupt"
204
205 instance Show ArrayException where
206 showsPrec _ (IndexOutOfBounds s)
207 = showString "array index out of range"
208 . (if not (null s) then showString ": " . showString s
209 else id)
210 showsPrec _ (UndefinedElement s)
211 = showString "undefined array element"
212 . (if not (null s) then showString ": " . showString s
213 else id)
214
215 -- -----------------------------------------------------------------------------
216 -- The ExitCode type
217
218 -- We need it here because it is used in ExitException in the
219 -- Exception datatype (above).
220
221 -- | Defines the exit codes that a program can return.
222 data ExitCode
223 = ExitSuccess -- ^ indicates successful termination;
224 | ExitFailure Int
225 -- ^ indicates program failure with an exit code.
226 -- The exact interpretation of the code is
227 -- operating-system dependent. In particular, some values
228 -- may be prohibited (e.g. 0 on a POSIX-compliant system).
229 deriving (Eq, Ord, Read, Show, Generic)
230
231 instance Exception ExitCode
232
233 ioException :: IOException -> IO a
234 ioException err = throwIO err
235
236 -- | Raise an 'IOError' in the 'IO' monad.
237 ioError :: IOError -> IO a
238 ioError = ioException
239
240 -- ---------------------------------------------------------------------------
241 -- IOError type
242
243 -- | The Haskell 2010 type for exceptions in the 'IO' monad.
244 -- Any I\/O operation may raise an 'IOError' instead of returning a result.
245 -- For a more general type of exception, including also those that arise
246 -- in pure code, see 'Control.Exception.Exception'.
247 --
248 -- In Haskell 2010, this is an opaque type.
249 type IOError = IOException
250
251 -- |Exceptions that occur in the @IO@ monad.
252 -- An @IOException@ records a more specific error type, a descriptive
253 -- string and maybe the handle that was used when the error was
254 -- flagged.
255 data IOException
256 = IOError {
257 ioe_handle :: Maybe Handle, -- the handle used by the action flagging
258 -- the error.
259 ioe_type :: IOErrorType, -- what it was.
260 ioe_location :: String, -- location.
261 ioe_description :: String, -- error type specific information.
262 ioe_errno :: Maybe CInt, -- errno leading to this error, if any.
263 ioe_filename :: Maybe FilePath -- filename the error is related to.
264 }
265
266 instance Exception IOException
267
268 instance Eq IOException where
269 (IOError h1 e1 loc1 str1 en1 fn1) == (IOError h2 e2 loc2 str2 en2 fn2) =
270 e1==e2 && str1==str2 && h1==h2 && loc1==loc2 && en1==en2 && fn1==fn2
271
272 -- | An abstract type that contains a value for each variant of 'IOError'.
273 data IOErrorType
274 -- Haskell 2010:
275 = AlreadyExists
276 | NoSuchThing
277 | ResourceBusy
278 | ResourceExhausted
279 | EOF
280 | IllegalOperation
281 | PermissionDenied
282 | UserError
283 -- GHC only:
284 | UnsatisfiedConstraints
285 | SystemError
286 | ProtocolError
287 | OtherError
288 | InvalidArgument
289 | InappropriateType
290 | HardwareFault
291 | UnsupportedOperation
292 | TimeExpired
293 | ResourceVanished
294 | Interrupted
295
296 instance Eq IOErrorType where
297 x == y = isTrue# (getTag x ==# getTag y)
298
299 instance Show IOErrorType where
300 showsPrec _ e =
301 showString $
302 case e of
303 AlreadyExists -> "already exists"
304 NoSuchThing -> "does not exist"
305 ResourceBusy -> "resource busy"
306 ResourceExhausted -> "resource exhausted"
307 EOF -> "end of file"
308 IllegalOperation -> "illegal operation"
309 PermissionDenied -> "permission denied"
310 UserError -> "user error"
311 HardwareFault -> "hardware fault"
312 InappropriateType -> "inappropriate type"
313 Interrupted -> "interrupted"
314 InvalidArgument -> "invalid argument"
315 OtherError -> "failed"
316 ProtocolError -> "protocol error"
317 ResourceVanished -> "resource vanished"
318 SystemError -> "system error"
319 TimeExpired -> "timeout"
320 UnsatisfiedConstraints -> "unsatisfied constraints" -- ultra-precise!
321 UnsupportedOperation -> "unsupported operation"
322
323 -- | Construct an 'IOError' value with a string describing the error.
324 -- The 'fail' method of the 'IO' instance of the 'Monad' class raises a
325 -- 'userError', thus:
326 --
327 -- > instance Monad IO where
328 -- > ...
329 -- > fail s = ioError (userError s)
330 --
331 userError :: String -> IOError
332 userError str = IOError Nothing UserError "" str Nothing Nothing
333
334 -- ---------------------------------------------------------------------------
335 -- Showing IOErrors
336
337 instance Show IOException where
338 showsPrec p (IOError hdl iot loc s _ fn) =
339 (case fn of
340 Nothing -> case hdl of
341 Nothing -> id
342 Just h -> showsPrec p h . showString ": "
343 Just name -> showString name . showString ": ") .
344 (case loc of
345 "" -> id
346 _ -> showString loc . showString ": ") .
347 showsPrec p iot .
348 (case s of
349 "" -> id
350 _ -> showString " (" . showString s . showString ")")
351
352 -- Note the use of "lazy". This means that
353 -- assert False (throw e)
354 -- will throw the assertion failure rather than e. See trac #5561.
355 assertError :: (?callStack :: CallStack) => Bool -> a -> a
356 assertError predicate v
357 | predicate = lazy v
358 | otherwise = throw (AssertionFailed
359 ("Assertion failed\n"
360 ++ showCallStack (popCallStack ?callStack)))
361
362 unsupportedOperation :: IOError
363 unsupportedOperation =
364 (IOError Nothing UnsupportedOperation ""
365 "Operation is not supported" Nothing Nothing)
366
367 {-
368 (untangle coded message) expects "coded" to be of the form
369 "location|details"
370 It prints
371 location message details
372 -}
373 untangle :: Addr# -> String -> String
374 untangle coded message
375 = location
376 ++ ": "
377 ++ message
378 ++ details
379 ++ "\n"
380 where
381 coded_str = unpackCStringUtf8# coded
382
383 (location, details)
384 = case (span not_bar coded_str) of { (loc, rest) ->
385 case rest of
386 ('|':det) -> (loc, ' ' : det)
387 _ -> (loc, "")
388 }
389 not_bar c = c /= '|'
390