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