[project @ 2003-03-04 10:39:58 by simonmar]
[ghc-hetmet.git] / ghc / compiler / utils / Panic.lhs
1 %
2 % (c) The GRASP Project, Glasgow University, 1992-2000
3 %
4 \section{Panic error messages}
5
6 Defines basic funtions for printing error messages.
7
8 It's hard to put these functions anywhere else without causing
9 some unnecessary loops in the module dependency graph.
10
11 \begin{code}
12 module Panic  
13    ( 
14      GhcException(..), ghcError, progName, 
15      panic, panic#, assertPanic, trace,
16      showException, showGhcException, tryMost,
17      installSignalHandlers,
18
19      catchJust, tryJust, ioErrors, throwTo,
20    ) where
21
22 #include "HsVersions.h"
23 #include "config.h"
24
25 import Config
26 import FastTypes
27
28 #ifndef mingw32_HOST_OS
29 # if __GLASGOW_HASKELL__ > 504
30 import System.Posix.Signals
31 # else
32 import Posix            ( Handler(Catch), installHandler, sigINT, sigQUIT )
33 # endif /* GHC > 504 */
34
35 import CONCURRENT       ( myThreadId )
36
37 # if __GLASGOW_HASKELL__ < 500
38 import EXCEPTION        ( raiseInThread )
39 # else
40 import EXCEPTION        ( throwTo )
41 # endif /* GHC < 500 */
42 #endif /* mingw32_HOST_OS */
43
44 #if __GLASGOW_HASKELL__ > 408
45 import EXCEPTION        ( catchJust, tryJust, ioErrors )
46 #endif
47
48 import DYNAMIC
49 import qualified EXCEPTION as Exception
50 import TRACE            ( trace )
51 import UNSAFE_IO        ( unsafePerformIO )
52
53 import System
54 \end{code}
55
56 GHC's own exception type.
57
58 \begin{code}
59 ghcError :: GhcException -> a
60 ghcError e = Exception.throwDyn e
61
62 -- error messages all take the form
63 --
64 --      <location>: <error>
65 --
66 -- If the location is on the command line, or in GHC itself, then 
67 -- <location>="ghc".  All of the error types below correspond to 
68 -- a <location> of "ghc", except for ProgramError (where the string is
69 -- assumed to contain a location already, so we don't print one).
70
71 data GhcException
72   = PhaseFailed String          -- name of phase 
73                 ExitCode        -- an external phase (eg. cpp) failed
74   | Interrupted                 -- someone pressed ^C
75   | UsageError String           -- prints the short usage msg after the error
76   | CmdLineError String         -- cmdline prob, but doesn't print usage
77   | Panic String                -- the `impossible' happened
78   | InstallationError String    -- an installation problem
79   | ProgramError String         -- error in the user's code, probably
80   deriving Eq
81
82 progName = unsafePerformIO (getProgName)
83 {-# NOINLINE progName #-}
84
85 short_usage = "Usage: For basic information, try the `--help' option."
86    
87 showException :: Exception.Exception -> String
88 -- Show expected dynamic exceptions specially
89 showException (Exception.DynException d) | Just e <- fromDynamic d 
90                                          = show (e::GhcException)
91 showException other_exn                  = show other_exn
92
93 instance Show GhcException where
94   showsPrec _ e@(ProgramError _) = showGhcException e
95   showsPrec _ e = showString progName . showString ": " . showGhcException e
96
97 showGhcException (UsageError str)
98    = showString str . showChar '\n' . showString short_usage
99 showGhcException (PhaseFailed phase code)
100    = showString "phase `" . showString phase . 
101      showString "' failed (exitcode = " . shows int_code . 
102      showString ")"
103   where
104     int_code = 
105       case code of
106         ExitSuccess   -> (0::Int)
107         ExitFailure x -> x
108 showGhcException (CmdLineError str)
109    = showString str
110 showGhcException (ProgramError str)
111    = showString str
112 showGhcException (InstallationError str)
113    = showString str
114 showGhcException (Interrupted)
115    = showString "interrupted"
116 showGhcException (Panic s)
117    = showString ("panic! (the `impossible' happened, GHC version "
118                  ++ cProjectVersion ++ "):\n\t"
119                  ++ s ++ "\n\n"
120                  ++ "Please report it as a compiler bug "
121                  ++ "to glasgow-haskell-bugs@haskell.org,\n"
122                  ++ "or http://sourceforge.net/projects/ghc/.\n\n")
123
124 ghcExceptionTc = mkTyCon "GhcException"
125 {-# NOINLINE ghcExceptionTc #-}
126 instance Typeable GhcException where
127   typeOf _ = mkAppTy ghcExceptionTc []
128 \end{code}
129
130 Panics and asserts.
131
132 \begin{code}
133 panic :: String -> a
134 panic x = Exception.throwDyn (Panic x)
135
136 -- #-versions because panic can't return an unboxed int, and that's
137 -- what TAG_ is with GHC at the moment.  Ugh. (Simon)
138 -- No, man -- Too Beautiful! (Will)
139
140 panic# :: String -> FastInt
141 panic# s = case (panic s) of () -> _ILIT 0
142
143 assertPanic :: String -> Int -> a
144 assertPanic file line = 
145   Exception.throw (Exception.AssertionFailed 
146            ("ASSERT failed! file " ++ file ++ ", line " ++ show line))
147 \end{code}
148
149 \begin{code}
150 -- | tryMost is like try, but passes through Interrupted and Panic
151 -- exceptions.  Used when we want soft failures when reading interface
152 -- files, for example.
153
154 tryMost :: IO a -> IO (Either Exception.Exception a)
155 tryMost action = do r <- myTry action; filter r
156   where
157    filter (Left e@(Exception.DynException d))
158             | Just ghc_ex <- fromDynamic d
159                 = case ghc_ex of
160                     Interrupted -> Exception.throw e
161                     Panic _     -> Exception.throw e
162                     _other      -> return (Left e)
163    filter other 
164      = return other
165
166 #if __GLASGOW_HASKELL__ <= 408
167 myTry = Exception.tryAllIO
168 #else
169 myTry = Exception.try
170 #endif
171 \end{code}      
172
173 Compatibility stuff:
174
175 \begin{code}
176 #if __GLASGOW_HASKELL__ <= 408
177 catchJust = Exception.catchIO
178 tryJust   = Exception.tryIO
179 ioErrors  = Exception.justIoErrors
180 throwTo   = Exception.raiseInThread
181 #endif
182 \end{code}
183
184 Standard signal handlers for catching ^C, which just throw an
185 exception in the main thread.  NOTE: must be called from the main
186 thread.
187
188 \begin{code}
189 installSignalHandlers :: IO ()
190 installSignalHandlers = do
191 #ifndef mingw32_HOST_OS
192   main_thread <- myThreadId
193   let sig_handler = Catch (throwTo main_thread 
194                                 (Exception.DynException (toDyn Interrupted)))
195   installHandler sigQUIT sig_handler Nothing 
196   installHandler sigINT  sig_handler Nothing
197 #endif
198   return ()
199 \end{code}