Rename -XPArr to -XParallelArrays
[ghc-hetmet.git] / compiler / main / ErrUtils.lhs
1 %
2 % (c) The AQUA Project, Glasgow University, 1994-1998
3 %
4 \section[ErrsUtils]{Utilities for error reporting}
5
6 \begin{code}
7 module ErrUtils (
8         Message, mkLocMessage, printError, pprMessageBag,
9         Severity(..),
10
11         ErrMsg, WarnMsg,
12         ErrorMessages, WarningMessages,
13         errMsgSpans, errMsgContext, errMsgShortDoc, errMsgExtraInfo,
14         Messages, errorsFound, emptyMessages,
15         mkErrMsg, mkPlainErrMsg, mkLongErrMsg, mkWarnMsg, mkPlainWarnMsg,
16         printBagOfErrors, printBagOfWarnings,
17         warnIsErrorMsg, mkLongWarnMsg,
18
19         ghcExit,
20         doIfSet, doIfSet_dyn, 
21         dumpIfSet, dumpIfSet_dyn, dumpIfSet_dyn_or,
22         mkDumpDoc, dumpSDoc,
23
24         --  * Messages during compilation
25         putMsg,
26         errorMsg,
27         fatalErrorMsg,
28         compilationProgressMsg,
29         showPass,
30         debugTraceMsg,  
31     ) where
32
33 #include "HsVersions.h"
34
35 import Bag              ( Bag, bagToList, isEmptyBag, emptyBag )
36 import Util             ( sortLe )
37 import Outputable
38 import SrcLoc
39 import DynFlags         ( DynFlags(..), DynFlag(..), dopt )
40 import StaticFlags      ( opt_ErrorSpans )
41
42 import System.Exit      ( ExitCode(..), exitWith )
43 import Data.List
44 import System.IO
45
46 -- -----------------------------------------------------------------------------
47 -- Basic error messages: just render a message with a source location.
48
49 type Message = SDoc
50
51 pprMessageBag :: Bag Message -> SDoc
52 pprMessageBag msgs = vcat (punctuate blankLine (bagToList msgs))
53
54 data Severity
55   = SevOutput
56   | SevInfo
57   | SevWarning
58   | SevError
59   | SevFatal
60
61 mkLocMessage :: SrcSpan -> Message -> Message
62 mkLocMessage locn msg
63   | opt_ErrorSpans = hang (ppr locn <> colon) 4 msg
64   | otherwise      = hang (ppr (srcSpanStart locn) <> colon) 4 msg
65   -- always print the location, even if it is unhelpful.  Error messages
66   -- are supposed to be in a standard format, and one without a location
67   -- would look strange.  Better to say explicitly "<no location info>".
68
69 printError :: SrcSpan -> Message -> IO ()
70 printError span msg = printErrs (mkLocMessage span msg $ defaultErrStyle)
71
72
73 -- -----------------------------------------------------------------------------
74 -- Collecting up messages for later ordering and printing.
75
76 data ErrMsg = ErrMsg { 
77         errMsgSpans     :: [SrcSpan],
78         errMsgContext   :: PrintUnqualified,
79         errMsgShortDoc  :: Message,
80         errMsgExtraInfo :: Message
81         }
82         -- The SrcSpan is used for sorting errors into line-number order
83
84 instance Show ErrMsg where
85     show em = showSDoc (errMsgShortDoc em)
86
87 type WarnMsg = ErrMsg
88
89 -- A short (one-line) error message, with context to tell us whether
90 -- to qualify names in the message or not.
91 mkErrMsg :: SrcSpan -> PrintUnqualified -> Message -> ErrMsg
92 mkErrMsg locn print_unqual msg
93   = ErrMsg { errMsgSpans = [locn], errMsgContext = print_unqual
94            , errMsgShortDoc = msg, errMsgExtraInfo = empty }
95
96 -- Variant that doesn't care about qualified/unqualified names
97 mkPlainErrMsg :: SrcSpan -> Message -> ErrMsg
98 mkPlainErrMsg locn msg
99   = ErrMsg { errMsgSpans = [locn], errMsgContext = alwaysQualify
100            , errMsgShortDoc = msg, errMsgExtraInfo = empty }
101
102 -- A long (multi-line) error message, with context to tell us whether
103 -- to qualify names in the message or not.
104 mkLongErrMsg :: SrcSpan -> PrintUnqualified -> Message -> Message -> ErrMsg
105 mkLongErrMsg locn print_unqual msg extra 
106  = ErrMsg { errMsgSpans = [locn], errMsgContext = print_unqual
107           , errMsgShortDoc = msg, errMsgExtraInfo = extra }
108
109 mkWarnMsg :: SrcSpan -> PrintUnqualified -> Message -> WarnMsg
110 mkWarnMsg = mkErrMsg
111
112 mkLongWarnMsg :: SrcSpan -> PrintUnqualified -> Message -> Message -> ErrMsg
113 mkLongWarnMsg = mkLongErrMsg
114
115 -- Variant that doesn't care about qualified/unqualified names
116 mkPlainWarnMsg :: SrcSpan -> Message -> ErrMsg
117 mkPlainWarnMsg locn msg = mkWarnMsg locn alwaysQualify msg
118
119 type Messages = (Bag WarnMsg, Bag ErrMsg)
120
121 type WarningMessages = Bag WarnMsg
122 type ErrorMessages   = Bag ErrMsg
123
124 emptyMessages :: Messages
125 emptyMessages = (emptyBag, emptyBag)
126
127 warnIsErrorMsg :: ErrMsg
128 warnIsErrorMsg = mkPlainErrMsg noSrcSpan (text "\nFailing due to -Werror.")
129
130 errorsFound :: DynFlags -> Messages -> Bool
131 errorsFound _dflags (_warns, errs) = not (isEmptyBag errs)
132
133 printBagOfErrors :: DynFlags -> Bag ErrMsg -> IO ()
134 printBagOfErrors dflags bag_of_errors = 
135   printMsgBag dflags bag_of_errors SevError
136
137 printBagOfWarnings :: DynFlags -> Bag WarnMsg -> IO ()
138 printBagOfWarnings dflags bag_of_warns = 
139   printMsgBag dflags bag_of_warns SevWarning
140
141 printMsgBag :: DynFlags -> Bag ErrMsg -> Severity -> IO ()
142 printMsgBag dflags bag sev
143   = sequence_   [ let style = mkErrStyle unqual
144                   in log_action dflags sev s style (d $$ e)
145                 | ErrMsg { errMsgSpans = s:_,
146                            errMsgShortDoc = d,
147                            errMsgExtraInfo = e,
148                            errMsgContext = unqual } <- sorted_errs ]
149     where
150       bag_ls      = bagToList bag
151       sorted_errs = sortLe occ'ed_before bag_ls
152
153       occ'ed_before err1 err2 = 
154          case compare (head (errMsgSpans err1)) (head (errMsgSpans err2)) of
155                 LT -> True
156                 EQ -> True
157                 GT -> False
158
159 ghcExit :: DynFlags -> Int -> IO ()
160 ghcExit dflags val
161   | val == 0  = exitWith ExitSuccess
162   | otherwise = do errorMsg dflags (text "\nCompilation had errors\n\n")
163                    exitWith (ExitFailure val)
164
165 doIfSet :: Bool -> IO () -> IO ()
166 doIfSet flag action | flag      = action
167                     | otherwise = return ()
168
169 doIfSet_dyn :: DynFlags -> DynFlag -> IO () -> IO()
170 doIfSet_dyn dflags flag action | dopt flag dflags = action
171                                | otherwise        = return ()
172
173 -- -----------------------------------------------------------------------------
174 -- Dumping
175
176 dumpIfSet :: Bool -> String -> SDoc -> IO ()
177 dumpIfSet flag hdr doc
178   | not flag   = return ()
179   | otherwise  = printDump (mkDumpDoc hdr doc)
180
181 dumpIfSet_dyn :: DynFlags -> DynFlag -> String -> SDoc -> IO ()
182 dumpIfSet_dyn dflags flag hdr doc
183   | dopt flag dflags || verbosity dflags >= 4 
184   = dumpSDoc dflags flag hdr doc
185   | otherwise
186   = return ()
187
188 dumpIfSet_dyn_or :: DynFlags -> [DynFlag] -> String -> SDoc -> IO ()
189 dumpIfSet_dyn_or dflags flags hdr doc
190   | or [dopt flag dflags | flag <- flags]
191   || verbosity dflags >= 4 
192   = printDump (mkDumpDoc hdr doc)
193   | otherwise = return ()
194
195 mkDumpDoc :: String -> SDoc -> SDoc
196 mkDumpDoc hdr doc 
197    = vcat [blankLine,
198            line <+> text hdr <+> line,
199            doc,
200            blankLine]
201      where 
202         line = text (replicate 20 '=')
203
204
205 -- | Write out a dump.
206 --      If --dump-to-file is set then this goes to a file.
207 --      otherwise emit to stdout.
208 dumpSDoc :: DynFlags -> DynFlag -> String -> SDoc -> IO ()
209 dumpSDoc dflags dflag hdr doc
210  = do   let mFile       = chooseDumpFile dflags dflag
211         case mFile of
212                 -- write the dump to a file
213                 --      don't add the header in this case, we can see what kind
214                 --      of dump it is from the filename.
215                 Just fileName
216                  -> do  handle  <- openFile fileName AppendMode
217                         hPrintDump handle doc
218                         hClose handle
219
220                 -- write the dump to stdout
221                 Nothing
222                  -> do  printDump (mkDumpDoc hdr doc)
223
224
225 -- | Choose where to put a dump file based on DynFlags
226 --
227 chooseDumpFile :: DynFlags -> DynFlag -> Maybe String
228 chooseDumpFile dflags dflag
229
230         -- dump file location is being forced
231         --      by the --ddump-file-prefix flag.
232         | dumpToFile
233         , Just prefix   <- dumpPrefixForce dflags
234         = Just $ prefix ++ (beautifyDumpName dflag)
235
236         -- dump file location chosen by DriverPipeline.runPipeline
237         | dumpToFile
238         , Just prefix   <- dumpPrefix dflags
239         = Just $ prefix ++ (beautifyDumpName dflag)
240
241         -- we haven't got a place to put a dump file.
242         | otherwise
243         = Nothing
244
245         where   dumpToFile = dopt Opt_DumpToFile dflags
246
247
248 -- | Build a nice file name from name of a DynFlag constructor
249 beautifyDumpName :: DynFlag -> String
250 beautifyDumpName dflag
251  = let  str     = show dflag
252         cut     = if isPrefixOf "Opt_D_" str
253                          then drop 6 str
254                          else str
255         dash    = map   (\c -> case c of
256                                 '_'     -> '-'
257                                 _       -> c)
258                         cut
259    in   dash
260
261
262 -- -----------------------------------------------------------------------------
263 -- Outputting messages from the compiler
264
265 -- We want all messages to go through one place, so that we can
266 -- redirect them if necessary.  For example, when GHC is used as a
267 -- library we might want to catch all messages that GHC tries to
268 -- output and do something else with them.
269
270 ifVerbose :: DynFlags -> Int -> IO () -> IO ()
271 ifVerbose dflags val act
272   | verbosity dflags >= val = act
273   | otherwise               = return ()
274
275 putMsg :: DynFlags -> Message -> IO ()
276 putMsg dflags msg = log_action dflags SevInfo noSrcSpan defaultUserStyle msg
277
278 errorMsg :: DynFlags -> Message -> IO ()
279 errorMsg dflags msg = log_action dflags SevError noSrcSpan defaultErrStyle msg
280
281 fatalErrorMsg :: DynFlags -> Message -> IO ()
282 fatalErrorMsg dflags msg = log_action dflags SevFatal noSrcSpan defaultErrStyle msg
283
284 compilationProgressMsg :: DynFlags -> String -> IO ()
285 compilationProgressMsg dflags msg
286   = ifVerbose dflags 1 (log_action dflags SevOutput noSrcSpan defaultUserStyle (text msg))
287
288 showPass :: DynFlags -> String -> IO ()
289 showPass dflags what 
290   = ifVerbose dflags 2 (log_action dflags SevInfo noSrcSpan defaultUserStyle (text "***" <+> text what <> colon))
291
292 debugTraceMsg :: DynFlags -> Int -> Message -> IO ()
293 debugTraceMsg dflags val msg
294   = ifVerbose dflags val (log_action dflags SevInfo noSrcSpan defaultDumpStyle msg)
295
296 \end{code}