Replace calls to `ptext . sLit` with `text`
[ghc.git] / compiler / main / ErrUtils.hs
1 {-
2 (c) The AQUA Project, Glasgow University, 1994-1998
3
4 \section[ErrsUtils]{Utilities for error reporting}
5 -}
6
7 {-# LANGUAGE CPP #-}
8
9 module ErrUtils (
10 -- * Basic types
11 Validity(..), andValid, allValid, isValid, getInvalids,
12 Severity(..),
13
14 -- * Messages
15 MsgDoc, ErrMsg, ErrDoc, errDoc, WarnMsg,
16 Messages, ErrorMessages, WarningMessages,
17 unionMessages,
18 errMsgSpan, errMsgContext,
19 errorsFound, isEmptyMessages,
20
21 -- ** Formatting
22 pprMessageBag, pprErrMsgBagWithLoc,
23 pprLocErrMsg, printBagOfErrors,
24
25 -- ** Construction
26 emptyMessages, mkLocMessage, makeIntoWarning,
27 mkErrMsg, mkPlainErrMsg, mkErrDoc, mkLongErrMsg, mkWarnMsg,
28 mkPlainWarnMsg,
29 warnIsErrorMsg, mkLongWarnMsg,
30
31 -- * Utilities
32 doIfSet, doIfSet_dyn,
33
34 -- * Dump files
35 dumpIfSet, dumpIfSet_dyn, dumpIfSet_dyn_printer,
36 mkDumpDoc, dumpSDoc,
37
38 -- * Issuing messages during compilation
39 putMsg, printInfoForUser, printOutputForUser,
40 logInfo, logOutput,
41 errorMsg, warningMsg,
42 fatalErrorMsg, fatalErrorMsg', fatalErrorMsg'',
43 compilationProgressMsg,
44 showPass,
45 debugTraceMsg,
46 ghcExit,
47 prettyPrintGhcErrors,
48 ) where
49
50 #include "HsVersions.h"
51
52 import Bag
53 import Exception
54 import Outputable
55 import Panic
56 import SrcLoc
57 import DynFlags
58
59 import System.Directory
60 import System.Exit ( ExitCode(..), exitWith )
61 import System.FilePath ( takeDirectory, (</>) )
62 import Data.List
63 import qualified Data.Set as Set
64 import Data.IORef
65 import Data.Maybe ( fromMaybe )
66 import Data.Ord
67 import Data.Time
68 import Control.Monad
69 import Control.Monad.IO.Class
70 import System.IO
71
72 -------------------------
73 type MsgDoc = SDoc
74
75 -------------------------
76 data Validity
77 = IsValid -- ^ Everything is fine
78 | NotValid MsgDoc -- ^ A problem, and some indication of why
79
80 isValid :: Validity -> Bool
81 isValid IsValid = True
82 isValid (NotValid {}) = False
83
84 andValid :: Validity -> Validity -> Validity
85 andValid IsValid v = v
86 andValid v _ = v
87
88 -- | If they aren't all valid, return the first
89 allValid :: [Validity] -> Validity
90 allValid [] = IsValid
91 allValid (v : vs) = v `andValid` allValid vs
92
93 getInvalids :: [Validity] -> [MsgDoc]
94 getInvalids vs = [d | NotValid d <- vs]
95
96 -- -----------------------------------------------------------------------------
97 -- Basic error messages: just render a message with a source location.
98
99 type Messages = (WarningMessages, ErrorMessages)
100 type WarningMessages = Bag WarnMsg
101 type ErrorMessages = Bag ErrMsg
102
103 unionMessages :: Messages -> Messages -> Messages
104 unionMessages (warns1, errs1) (warns2, errs2) =
105 (warns1 `unionBags` warns2, errs1 `unionBags` errs2)
106
107 data ErrMsg = ErrMsg {
108 errMsgSpan :: SrcSpan,
109 errMsgContext :: PrintUnqualified,
110 errMsgDoc :: ErrDoc,
111 -- | This has the same text as errDocImportant . errMsgDoc.
112 errMsgShortString :: String,
113 errMsgSeverity :: Severity
114 }
115 -- The SrcSpan is used for sorting errors into line-number order
116
117 -- | Categorise error msgs by their importance. This is so each section can
118 -- be rendered visually distinct. See Note [Error report] for where these come
119 -- from.
120 data ErrDoc = ErrDoc {
121 -- | Primary error msg.
122 errDocImportant :: [MsgDoc],
123 -- | Context e.g. \"In the second argument of ...\".
124 _errDocContext :: [MsgDoc],
125 -- | Supplementary information, e.g. \"Relevant bindings include ...\".
126 _errDocSupplementary :: [MsgDoc]
127 }
128
129 errDoc :: [MsgDoc] -> [MsgDoc] -> [MsgDoc] -> ErrDoc
130 errDoc = ErrDoc
131
132 type WarnMsg = ErrMsg
133
134 data Severity
135 = SevOutput
136 | SevFatal
137 | SevInteractive
138
139 | SevDump
140 -- ^ Log messagse intended for compiler developers
141 -- No file/line/column stuff
142
143 | SevInfo
144 -- ^ Log messages intended for end users.
145 -- No file/line/column stuff.
146
147 | SevWarning
148 | SevError
149 -- ^ SevWarning and SevError are used for warnings and errors
150 -- o The message has a file/line/column heading,
151 -- plus "warning:" or "error:",
152 -- added by mkLocMessags
153 -- o Output is intended for end users
154
155
156 instance Show ErrMsg where
157 show em = errMsgShortString em
158
159 pprMessageBag :: Bag MsgDoc -> SDoc
160 pprMessageBag msgs = vcat (punctuate blankLine (bagToList msgs))
161
162 mkLocMessage :: Severity -> SrcSpan -> MsgDoc -> MsgDoc
163 -- Always print the location, even if it is unhelpful. Error messages
164 -- are supposed to be in a standard format, and one without a location
165 -- would look strange. Better to say explicitly "<no location info>".
166 mkLocMessage severity locn msg
167 = sdocWithDynFlags $ \dflags ->
168 let locn' = if gopt Opt_ErrorSpans dflags
169 then ppr locn
170 else ppr (srcSpanStart locn)
171 in hang (locn' <> colon <+> sev_info) 4 msg
172 where
173 -- Add prefixes, like Foo.hs:34: warning:
174 -- <the warning message>
175 sev_info = case severity of
176 SevWarning -> text "warning:"
177 SevError -> text "error:"
178 SevFatal -> text "fatal:"
179 _ -> empty
180
181 makeIntoWarning :: ErrMsg -> ErrMsg
182 makeIntoWarning err = err { errMsgSeverity = SevWarning }
183
184 -- -----------------------------------------------------------------------------
185 -- Collecting up messages for later ordering and printing.
186
187 mk_err_msg :: DynFlags -> Severity -> SrcSpan -> PrintUnqualified -> ErrDoc -> ErrMsg
188 mk_err_msg dflags sev locn print_unqual doc
189 = ErrMsg { errMsgSpan = locn
190 , errMsgContext = print_unqual
191 , errMsgDoc = doc
192 , errMsgShortString = showSDoc dflags (vcat (errDocImportant doc))
193 , errMsgSeverity = sev }
194
195 mkErrDoc :: DynFlags -> SrcSpan -> PrintUnqualified -> ErrDoc -> ErrMsg
196 mkErrDoc dflags = mk_err_msg dflags SevError
197
198 mkLongErrMsg, mkLongWarnMsg :: DynFlags -> SrcSpan -> PrintUnqualified -> MsgDoc -> MsgDoc -> ErrMsg
199 -- ^ A long (multi-line) error message
200 mkErrMsg, mkWarnMsg :: DynFlags -> SrcSpan -> PrintUnqualified -> MsgDoc -> ErrMsg
201 -- ^ A short (one-line) error message
202 mkPlainErrMsg, mkPlainWarnMsg :: DynFlags -> SrcSpan -> MsgDoc -> ErrMsg
203 -- ^ Variant that doesn't care about qualified/unqualified names
204
205 mkLongErrMsg dflags locn unqual msg extra = mk_err_msg dflags SevError locn unqual (ErrDoc [msg] [] [extra])
206 mkErrMsg dflags locn unqual msg = mk_err_msg dflags SevError locn unqual (ErrDoc [msg] [] [])
207 mkPlainErrMsg dflags locn msg = mk_err_msg dflags SevError locn alwaysQualify (ErrDoc [msg] [] [])
208 mkLongWarnMsg dflags locn unqual msg extra = mk_err_msg dflags SevWarning locn unqual (ErrDoc [msg] [] [extra])
209 mkWarnMsg dflags locn unqual msg = mk_err_msg dflags SevWarning locn unqual (ErrDoc [msg] [] [])
210 mkPlainWarnMsg dflags locn msg = mk_err_msg dflags SevWarning locn alwaysQualify (ErrDoc [msg] [] [])
211
212 ----------------
213 emptyMessages :: Messages
214 emptyMessages = (emptyBag, emptyBag)
215
216 isEmptyMessages :: Messages -> Bool
217 isEmptyMessages (warns, errs) = isEmptyBag warns && isEmptyBag errs
218
219 warnIsErrorMsg :: DynFlags -> ErrMsg
220 warnIsErrorMsg dflags
221 = mkPlainErrMsg dflags noSrcSpan (text "\nFailing due to -Werror.")
222
223 errorsFound :: DynFlags -> Messages -> Bool
224 errorsFound _dflags (_warns, errs) = not (isEmptyBag errs)
225
226 printBagOfErrors :: DynFlags -> Bag ErrMsg -> IO ()
227 printBagOfErrors dflags bag_of_errors
228 = sequence_ [ let style = mkErrStyle dflags unqual
229 in log_action dflags dflags sev s style (formatErrDoc dflags doc)
230 | ErrMsg { errMsgSpan = s,
231 errMsgDoc = doc,
232 errMsgSeverity = sev,
233 errMsgContext = unqual } <- sortMsgBag (Just dflags)
234 bag_of_errors ]
235
236 formatErrDoc :: DynFlags -> ErrDoc -> SDoc
237 formatErrDoc dflags (ErrDoc important context supplementary)
238 = case msgs of
239 [msg] -> vcat msg
240 _ -> vcat $ map starred msgs
241 where
242 msgs = filter (not . null) $ map (filter (not . Outputable.isEmpty dflags))
243 [important, context, supplementary]
244 starred = (bullet<+>) . vcat
245 bullet = text $ if DynFlags.useUnicode dflags then "•" else "*"
246
247 pprErrMsgBagWithLoc :: Bag ErrMsg -> [SDoc]
248 pprErrMsgBagWithLoc bag = [ pprLocErrMsg item | item <- sortMsgBag Nothing bag ]
249
250 pprLocErrMsg :: ErrMsg -> SDoc
251 pprLocErrMsg (ErrMsg { errMsgSpan = s
252 , errMsgDoc = doc
253 , errMsgSeverity = sev
254 , errMsgContext = unqual })
255 = sdocWithDynFlags $ \dflags ->
256 withPprStyle (mkErrStyle dflags unqual) $
257 mkLocMessage sev s (formatErrDoc dflags doc)
258
259 sortMsgBag :: Maybe DynFlags -> Bag ErrMsg -> [ErrMsg]
260 sortMsgBag dflags = sortBy (maybeFlip $ comparing errMsgSpan) . bagToList
261 where maybeFlip :: (a -> a -> b) -> (a -> a -> b)
262 maybeFlip
263 | fromMaybe False (fmap reverseErrors dflags) = flip
264 | otherwise = id
265
266 ghcExit :: DynFlags -> Int -> IO ()
267 ghcExit dflags val
268 | val == 0 = exitWith ExitSuccess
269 | otherwise = do errorMsg dflags (text "\nCompilation had errors\n\n")
270 exitWith (ExitFailure val)
271
272 doIfSet :: Bool -> IO () -> IO ()
273 doIfSet flag action | flag = action
274 | otherwise = return ()
275
276 doIfSet_dyn :: DynFlags -> GeneralFlag -> IO () -> IO()
277 doIfSet_dyn dflags flag action | gopt flag dflags = action
278 | otherwise = return ()
279
280 -- -----------------------------------------------------------------------------
281 -- Dumping
282
283 dumpIfSet :: DynFlags -> Bool -> String -> SDoc -> IO ()
284 dumpIfSet dflags flag hdr doc
285 | not flag = return ()
286 | otherwise = log_action dflags dflags SevDump noSrcSpan defaultDumpStyle (mkDumpDoc hdr doc)
287
288 -- | a wrapper around 'dumpSDoc'.
289 -- First check whether the dump flag is set
290 -- Do nothing if it is unset
291 dumpIfSet_dyn :: DynFlags -> DumpFlag -> String -> SDoc -> IO ()
292 dumpIfSet_dyn dflags flag hdr doc
293 = when (dopt flag dflags) $ dumpSDoc dflags alwaysQualify flag hdr doc
294
295 -- | a wrapper around 'dumpSDoc'.
296 -- First check whether the dump flag is set
297 -- Do nothing if it is unset
298 --
299 -- Unlike 'dumpIfSet_dyn',
300 -- has a printer argument but no header argument
301 dumpIfSet_dyn_printer :: PrintUnqualified
302 -> DynFlags -> DumpFlag -> SDoc -> IO ()
303 dumpIfSet_dyn_printer printer dflags flag doc
304 = when (dopt flag dflags) $ dumpSDoc dflags printer flag "" doc
305
306 mkDumpDoc :: String -> SDoc -> SDoc
307 mkDumpDoc hdr doc
308 = vcat [blankLine,
309 line <+> text hdr <+> line,
310 doc,
311 blankLine]
312 where
313 line = text (replicate 20 '=')
314
315
316 -- | Write out a dump.
317 -- If --dump-to-file is set then this goes to a file.
318 -- otherwise emit to stdout.
319 --
320 -- When @hdr@ is empty, we print in a more compact format (no separators and
321 -- blank lines)
322 --
323 -- The 'DumpFlag' is used only to choose the filename to use if @--dump-to-file@
324 -- is used; it is not used to decide whether to dump the output
325 dumpSDoc :: DynFlags -> PrintUnqualified -> DumpFlag -> String -> SDoc -> IO ()
326 dumpSDoc dflags print_unqual flag hdr doc
327 = do let mFile = chooseDumpFile dflags flag
328 dump_style = mkDumpStyle print_unqual
329 case mFile of
330 Just fileName
331 -> do
332 let gdref = generatedDumps dflags
333 gd <- readIORef gdref
334 let append = Set.member fileName gd
335 mode = if append then AppendMode else WriteMode
336 when (not append) $
337 writeIORef gdref (Set.insert fileName gd)
338 createDirectoryIfMissing True (takeDirectory fileName)
339 handle <- openFile fileName mode
340
341 -- We do not want the dump file to be affected by
342 -- environment variables, but instead to always use
343 -- UTF8. See:
344 -- https://ghc.haskell.org/trac/ghc/ticket/10762
345 hSetEncoding handle utf8
346
347 doc' <- if null hdr
348 then return doc
349 else do t <- getCurrentTime
350 let d = text (show t)
351 $$ blankLine
352 $$ doc
353 return $ mkDumpDoc hdr d
354 defaultLogActionHPrintDoc dflags handle doc' dump_style
355 hClose handle
356
357 -- write the dump to stdout
358 Nothing -> do
359 let (doc', severity)
360 | null hdr = (doc, SevOutput)
361 | otherwise = (mkDumpDoc hdr doc, SevDump)
362 log_action dflags dflags severity noSrcSpan dump_style doc'
363
364
365 -- | Choose where to put a dump file based on DynFlags
366 --
367 chooseDumpFile :: DynFlags -> DumpFlag -> Maybe FilePath
368 chooseDumpFile dflags flag
369
370 | gopt Opt_DumpToFile dflags || flag == Opt_D_th_dec_file
371 , Just prefix <- getPrefix
372 = Just $ setDir (prefix ++ (beautifyDumpName flag))
373
374 | otherwise
375 = Nothing
376
377 where getPrefix
378 -- dump file location is being forced
379 -- by the --ddump-file-prefix flag.
380 | Just prefix <- dumpPrefixForce dflags
381 = Just prefix
382 -- dump file location chosen by DriverPipeline.runPipeline
383 | Just prefix <- dumpPrefix dflags
384 = Just prefix
385 -- we haven't got a place to put a dump file.
386 | otherwise
387 = Nothing
388 setDir f = case dumpDir dflags of
389 Just d -> d </> f
390 Nothing -> f
391
392 -- | Build a nice file name from name of a 'DumpFlag' constructor
393 beautifyDumpName :: DumpFlag -> String
394 beautifyDumpName Opt_D_th_dec_file = "th.hs"
395 beautifyDumpName flag
396 = let str = show flag
397 suff = case stripPrefix "Opt_D_" str of
398 Just x -> x
399 Nothing -> panic ("Bad flag name: " ++ str)
400 dash = map (\c -> if c == '_' then '-' else c) suff
401 in dash
402
403
404 -- -----------------------------------------------------------------------------
405 -- Outputting messages from the compiler
406
407 -- We want all messages to go through one place, so that we can
408 -- redirect them if necessary. For example, when GHC is used as a
409 -- library we might want to catch all messages that GHC tries to
410 -- output and do something else with them.
411
412 ifVerbose :: DynFlags -> Int -> IO () -> IO ()
413 ifVerbose dflags val act
414 | verbosity dflags >= val = act
415 | otherwise = return ()
416
417 errorMsg :: DynFlags -> MsgDoc -> IO ()
418 errorMsg dflags msg
419 = log_action dflags dflags SevError noSrcSpan (defaultErrStyle dflags) msg
420
421 warningMsg :: DynFlags -> MsgDoc -> IO ()
422 warningMsg dflags msg
423 = log_action dflags dflags SevWarning noSrcSpan (defaultErrStyle dflags) msg
424
425 fatalErrorMsg :: DynFlags -> MsgDoc -> IO ()
426 fatalErrorMsg dflags msg = fatalErrorMsg' (log_action dflags) dflags msg
427
428 fatalErrorMsg' :: LogAction -> DynFlags -> MsgDoc -> IO ()
429 fatalErrorMsg' la dflags msg =
430 la dflags SevFatal noSrcSpan (defaultErrStyle dflags) msg
431
432 fatalErrorMsg'' :: FatalMessager -> String -> IO ()
433 fatalErrorMsg'' fm msg = fm msg
434
435 compilationProgressMsg :: DynFlags -> String -> IO ()
436 compilationProgressMsg dflags msg
437 = ifVerbose dflags 1 $
438 logOutput dflags defaultUserStyle (text msg)
439
440 showPass :: DynFlags -> String -> IO ()
441 showPass dflags what
442 = ifVerbose dflags 2 $
443 logInfo dflags defaultUserStyle (text "***" <+> text what <> colon)
444
445 debugTraceMsg :: DynFlags -> Int -> MsgDoc -> IO ()
446 debugTraceMsg dflags val msg = ifVerbose dflags val $
447 logInfo dflags defaultDumpStyle msg
448
449 putMsg :: DynFlags -> MsgDoc -> IO ()
450 putMsg dflags msg = logInfo dflags defaultUserStyle msg
451
452 printInfoForUser :: DynFlags -> PrintUnqualified -> MsgDoc -> IO ()
453 printInfoForUser dflags print_unqual msg
454 = logInfo dflags (mkUserStyle print_unqual AllTheWay) msg
455
456 printOutputForUser :: DynFlags -> PrintUnqualified -> MsgDoc -> IO ()
457 printOutputForUser dflags print_unqual msg
458 = logOutput dflags (mkUserStyle print_unqual AllTheWay) msg
459
460 logInfo :: DynFlags -> PprStyle -> MsgDoc -> IO ()
461 logInfo dflags sty msg = log_action dflags dflags SevInfo noSrcSpan sty msg
462
463 logOutput :: DynFlags -> PprStyle -> MsgDoc -> IO ()
464 -- ^ Like 'logInfo' but with 'SevOutput' rather then 'SevInfo'
465 logOutput dflags sty msg = log_action dflags dflags SevOutput noSrcSpan sty msg
466
467 prettyPrintGhcErrors :: ExceptionMonad m => DynFlags -> m a -> m a
468 prettyPrintGhcErrors dflags
469 = ghandle $ \e -> case e of
470 PprPanic str doc ->
471 pprDebugAndThen dflags panic (text str) doc
472 PprSorry str doc ->
473 pprDebugAndThen dflags sorry (text str) doc
474 PprProgramError str doc ->
475 pprDebugAndThen dflags pgmError (text str) doc
476 _ ->
477 liftIO $ throwIO e