{-# LANGUAGE GADTs #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PatternSynonyms #-}

module GHC.Types.Error
   ( -- * Messages
     Messages
   , mkMessages
   , getMessages
   , emptyMessages
   , isEmptyMessages
   , singleMessage
   , addMessage
   , unionMessages
   , unionManyMessages
   , filterMessages
   , MsgEnvelope (..)

   -- * Classifying Messages

   , MessageClass (..)
   , Severity (..)
   , Diagnostic (..)
   , UnknownDiagnostic (..)
   , mkSimpleUnknownDiagnostic
   , mkUnknownDiagnostic
   , embedUnknownDiagnostic
   , DiagnosticMessage (..)
   , DiagnosticReason (WarningWithFlag, ..)
   , ResolvedDiagnosticReason(..)
   , DiagnosticHint (..)
   , mkPlainDiagnostic
   , mkPlainError
   , mkDecoratedDiagnostic
   , mkDecoratedError

   , pprDiagnostic

   , HasDefaultDiagnosticOpts(..)
   , defaultDiagnosticOpts
   , NoDiagnosticOpts(..)

   -- * Hints and refactoring actions
   , GhcHint (..)
   , AvailableBindings(..)
   , LanguageExtensionHint(..)
   , suggestExtension
   , suggestExtensionWithInfo
   , suggestExtensions
   , suggestExtensionsWithInfo
   , suggestAnyExtension
   , suggestAnyExtensionWithInfo
   , useExtensionInOrderTo
   , noHints

    -- * Rendering Messages

   , SDoc
   , DecoratedSDoc (unDecorated)
   , mkDecorated, mkSimpleDecorated
   , unionDecoratedSDoc
   , mapDecoratedSDoc

   , pprMessageBag
   , mkLocMessage
   , mkLocMessageWarningGroups
   , getCaretDiagnostic
   -- * Queries
   , isIntrinsicErrorMessage
   , isExtrinsicErrorMessage
   , isWarningMessage
   , getErrorMessages
   , getWarningMessages
   , partitionMessages
   , errorsFound
   , errorsOrFatalWarningsFound

   -- * Diagnostic codes
   , DiagnosticCode(..)
   )
where

import GHC.Prelude

import GHC.Driver.Flags

import GHC.Data.Bag
import GHC.IO (catchException)
import GHC.Utils.Outputable as Outputable
import qualified GHC.Utils.Ppr.Colour as Col
import GHC.Types.SrcLoc as SrcLoc
import GHC.Types.Hint
import GHC.Data.FastString (unpackFS)
import GHC.Data.StringBuffer (atLine, hGetStringBuffer, len, lexemeToString)
import GHC.Utils.Json
import GHC.Utils.Panic
import GHC.Unit.Module.Warnings (WarningCategory)
import Data.Bifunctor
import Data.Foldable    ( fold, toList )
import Data.List.NonEmpty ( NonEmpty (..) )
import qualified Data.List.NonEmpty as NE
import Data.List ( intercalate )
import Data.Typeable ( Typeable )
import Numeric.Natural ( Natural )
import Text.Printf ( printf )
import GHC.Version (cProjectVersion)
import GHC.Types.Hint.Ppr () -- Outputtable instance

{- Note [Messages]
~~~~~~~~~~~~~~~~~~
We represent the 'Messages' as a single bag of warnings and errors.

The reason behind that is that there is a fluid relationship between errors
and warnings and we want to be able to promote or demote errors and warnings
based on certain flags (e.g. -Werror, -fdefer-type-errors or
-XPartialTypeSignatures). More specifically, every diagnostic has a
'DiagnosticReason', but a warning 'DiagnosticReason' might be associated with
'SevError', in the case of -Werror.

We rely on the 'Severity' to distinguish between a warning and an error.

'WarningMessages' and 'ErrorMessages' are for now simple type aliases to
retain backward compatibility, but in future iterations these can be either
parameterised over an 'e' message type (to make type signatures a bit more
declarative) or removed altogether.
-}

-- | A collection of messages emitted by GHC during error reporting. A
-- diagnostic message is typically a warning or an error. See Note [Messages].
--
-- /INVARIANT/: All the messages in this collection must be relevant, i.e.
-- their 'Severity' should /not/ be 'SevIgnore'. The smart constructor
-- 'mkMessages' will filter out any message which 'Severity' is 'SevIgnore'.
newtype Messages e = Messages { forall e. Messages e -> Bag (MsgEnvelope e)
getMessages :: Bag (MsgEnvelope e) }
  deriving newtype (NonEmpty (Messages e) -> Messages e
Messages e -> Messages e -> Messages e
(Messages e -> Messages e -> Messages e)
-> (NonEmpty (Messages e) -> Messages e)
-> (forall b. Integral b => b -> Messages e -> Messages e)
-> Semigroup (Messages e)
forall b. Integral b => b -> Messages e -> Messages e
forall e. NonEmpty (Messages e) -> Messages e
forall e. Messages e -> Messages e -> Messages e
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
forall e b. Integral b => b -> Messages e -> Messages e
$c<> :: forall e. Messages e -> Messages e -> Messages e
<> :: Messages e -> Messages e -> Messages e
$csconcat :: forall e. NonEmpty (Messages e) -> Messages e
sconcat :: NonEmpty (Messages e) -> Messages e
$cstimes :: forall e b. Integral b => b -> Messages e -> Messages e
stimes :: forall b. Integral b => b -> Messages e -> Messages e
Semigroup, Semigroup (Messages e)
Messages e
Semigroup (Messages e) =>
Messages e
-> (Messages e -> Messages e -> Messages e)
-> ([Messages e] -> Messages e)
-> Monoid (Messages e)
[Messages e] -> Messages e
Messages e -> Messages e -> Messages e
forall e. Semigroup (Messages e)
forall e. Messages e
forall a.
Semigroup a =>
a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
forall e. [Messages e] -> Messages e
forall e. Messages e -> Messages e -> Messages e
$cmempty :: forall e. Messages e
mempty :: Messages e
$cmappend :: forall e. Messages e -> Messages e -> Messages e
mappend :: Messages e -> Messages e -> Messages e
$cmconcat :: forall e. [Messages e] -> Messages e
mconcat :: [Messages e] -> Messages e
Monoid)
  deriving stock ((forall a b. (a -> b) -> Messages a -> Messages b)
-> (forall a b. a -> Messages b -> Messages a) -> Functor Messages
forall a b. a -> Messages b -> Messages a
forall a b. (a -> b) -> Messages a -> Messages b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> Messages a -> Messages b
fmap :: forall a b. (a -> b) -> Messages a -> Messages b
$c<$ :: forall a b. a -> Messages b -> Messages a
<$ :: forall a b. a -> Messages b -> Messages a
Functor, (forall m. Monoid m => Messages m -> m)
-> (forall m a. Monoid m => (a -> m) -> Messages a -> m)
-> (forall m a. Monoid m => (a -> m) -> Messages a -> m)
-> (forall a b. (a -> b -> b) -> b -> Messages a -> b)
-> (forall a b. (a -> b -> b) -> b -> Messages a -> b)
-> (forall b a. (b -> a -> b) -> b -> Messages a -> b)
-> (forall b a. (b -> a -> b) -> b -> Messages a -> b)
-> (forall a. (a -> a -> a) -> Messages a -> a)
-> (forall a. (a -> a -> a) -> Messages a -> a)
-> (forall a. Messages a -> [a])
-> (forall a. Messages a -> Bool)
-> (forall a. Messages a -> Int)
-> (forall a. Eq a => a -> Messages a -> Bool)
-> (forall a. Ord a => Messages a -> a)
-> (forall a. Ord a => Messages a -> a)
-> (forall a. Num a => Messages a -> a)
-> (forall a. Num a => Messages a -> a)
-> Foldable Messages
forall a. Eq a => a -> Messages a -> Bool
forall a. Num a => Messages a -> a
forall a. Ord a => Messages a -> a
forall m. Monoid m => Messages m -> m
forall a. Messages a -> Bool
forall a. Messages a -> Int
forall a. Messages a -> [a]
forall a. (a -> a -> a) -> Messages a -> a
forall m a. Monoid m => (a -> m) -> Messages a -> m
forall b a. (b -> a -> b) -> b -> Messages a -> b
forall a b. (a -> b -> b) -> b -> Messages a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall m. Monoid m => Messages m -> m
fold :: forall m. Monoid m => Messages m -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> Messages a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> Messages a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> Messages a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> Messages a -> m
$cfoldr :: forall a b. (a -> b -> b) -> b -> Messages a -> b
foldr :: forall a b. (a -> b -> b) -> b -> Messages a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> Messages a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> Messages a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> Messages a -> b
foldl :: forall b a. (b -> a -> b) -> b -> Messages a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> Messages a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> Messages a -> b
$cfoldr1 :: forall a. (a -> a -> a) -> Messages a -> a
foldr1 :: forall a. (a -> a -> a) -> Messages a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> Messages a -> a
foldl1 :: forall a. (a -> a -> a) -> Messages a -> a
$ctoList :: forall a. Messages a -> [a]
toList :: forall a. Messages a -> [a]
$cnull :: forall a. Messages a -> Bool
null :: forall a. Messages a -> Bool
$clength :: forall a. Messages a -> Int
length :: forall a. Messages a -> Int
$celem :: forall a. Eq a => a -> Messages a -> Bool
elem :: forall a. Eq a => a -> Messages a -> Bool
$cmaximum :: forall a. Ord a => Messages a -> a
maximum :: forall a. Ord a => Messages a -> a
$cminimum :: forall a. Ord a => Messages a -> a
minimum :: forall a. Ord a => Messages a -> a
$csum :: forall a. Num a => Messages a -> a
sum :: forall a. Num a => Messages a -> a
$cproduct :: forall a. Num a => Messages a -> a
product :: forall a. Num a => Messages a -> a
Foldable, Functor Messages
Foldable Messages
(Functor Messages, Foldable Messages) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> Messages a -> f (Messages b))
-> (forall (f :: * -> *) a.
    Applicative f =>
    Messages (f a) -> f (Messages a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> Messages a -> m (Messages b))
-> (forall (m :: * -> *) a.
    Monad m =>
    Messages (m a) -> m (Messages a))
-> Traversable Messages
forall (t :: * -> *).
(Functor t, Foldable t) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> t a -> f (t b))
-> (forall (f :: * -> *) a. Applicative f => t (f a) -> f (t a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> t a -> m (t b))
-> (forall (m :: * -> *) a. Monad m => t (m a) -> m (t a))
-> Traversable t
forall (m :: * -> *) a. Monad m => Messages (m a) -> m (Messages a)
forall (f :: * -> *) a.
Applicative f =>
Messages (f a) -> f (Messages a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Messages a -> m (Messages b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Messages a -> f (Messages b)
$ctraverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Messages a -> f (Messages b)
traverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Messages a -> f (Messages b)
$csequenceA :: forall (f :: * -> *) a.
Applicative f =>
Messages (f a) -> f (Messages a)
sequenceA :: forall (f :: * -> *) a.
Applicative f =>
Messages (f a) -> f (Messages a)
$cmapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Messages a -> m (Messages b)
mapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Messages a -> m (Messages b)
$csequence :: forall (m :: * -> *) a. Monad m => Messages (m a) -> m (Messages a)
sequence :: forall (m :: * -> *) a. Monad m => Messages (m a) -> m (Messages a)
Traversable)

emptyMessages :: Messages e
emptyMessages :: forall e. Messages e
emptyMessages = Bag (MsgEnvelope e) -> Messages e
forall e. Bag (MsgEnvelope e) -> Messages e
Messages Bag (MsgEnvelope e)
forall a. Bag a
emptyBag

mkMessages :: Bag (MsgEnvelope e) -> Messages e
mkMessages :: forall e. Bag (MsgEnvelope e) -> Messages e
mkMessages = Bag (MsgEnvelope e) -> Messages e
forall e. Bag (MsgEnvelope e) -> Messages e
Messages (Bag (MsgEnvelope e) -> Messages e)
-> (Bag (MsgEnvelope e) -> Bag (MsgEnvelope e))
-> Bag (MsgEnvelope e)
-> Messages e
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MsgEnvelope e -> Bool)
-> Bag (MsgEnvelope e) -> Bag (MsgEnvelope e)
forall a. (a -> Bool) -> Bag a -> Bag a
filterBag MsgEnvelope e -> Bool
forall e. MsgEnvelope e -> Bool
interesting
  where
    interesting :: MsgEnvelope e -> Bool
    interesting :: forall e. MsgEnvelope e -> Bool
interesting = Severity -> Severity -> Bool
forall a. Eq a => a -> a -> Bool
(/=) Severity
SevIgnore (Severity -> Bool)
-> (MsgEnvelope e -> Severity) -> MsgEnvelope e -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MsgEnvelope e -> Severity
forall e. MsgEnvelope e -> Severity
errMsgSeverity

isEmptyMessages :: Messages e -> Bool
isEmptyMessages :: forall a. Messages a -> Bool
isEmptyMessages (Messages Bag (MsgEnvelope e)
msgs) = Bag (MsgEnvelope e) -> Bool
forall a. Bag a -> Bool
isEmptyBag Bag (MsgEnvelope e)
msgs

singleMessage :: MsgEnvelope e -> Messages e
singleMessage :: forall e. MsgEnvelope e -> Messages e
singleMessage MsgEnvelope e
e = MsgEnvelope e -> Messages e -> Messages e
forall e. MsgEnvelope e -> Messages e -> Messages e
addMessage MsgEnvelope e
e Messages e
forall e. Messages e
emptyMessages

instance Diagnostic e => Outputable (Messages e) where
  ppr :: Messages e -> SDoc
ppr Messages e
msgs = SDoc -> SDoc
forall doc. IsLine doc => doc -> doc
braces ([SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat ((MsgEnvelope e -> SDoc) -> [MsgEnvelope e] -> [SDoc]
forall a b. (a -> b) -> [a] -> [b]
map MsgEnvelope e -> SDoc
ppr_one (Bag (MsgEnvelope e) -> [MsgEnvelope e]
forall a. Bag a -> [a]
bagToList (Messages e -> Bag (MsgEnvelope e)
forall e. Messages e -> Bag (MsgEnvelope e)
getMessages Messages e
msgs))))
     where
       ppr_one :: MsgEnvelope e -> SDoc
       ppr_one :: MsgEnvelope e -> SDoc
ppr_one MsgEnvelope e
envelope =
        [SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat [ String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Resolved:" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> ResolvedDiagnosticReason -> SDoc
forall a. Outputable a => a -> SDoc
ppr (MsgEnvelope e -> ResolvedDiagnosticReason
forall e. MsgEnvelope e -> ResolvedDiagnosticReason
errMsgReason MsgEnvelope e
envelope),
               e -> SDoc
forall e. Diagnostic e => e -> SDoc
pprDiagnostic (MsgEnvelope e -> e
forall e. MsgEnvelope e -> e
errMsgDiagnostic MsgEnvelope e
envelope)
             ]

instance Diagnostic e => ToJson (Messages e) where
  json :: Messages e -> JsonDoc
json Messages e
msgs =  [JsonDoc] -> JsonDoc
JSArray ([JsonDoc] -> JsonDoc)
-> (Bag JsonDoc -> [JsonDoc]) -> Bag JsonDoc -> JsonDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bag JsonDoc -> [JsonDoc]
forall a. Bag a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Bag JsonDoc -> JsonDoc) -> Bag JsonDoc -> JsonDoc
forall a b. (a -> b) -> a -> b
$ MsgEnvelope e -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json (MsgEnvelope e -> JsonDoc) -> Bag (MsgEnvelope e) -> Bag JsonDoc
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Messages e -> Bag (MsgEnvelope e)
forall e. Messages e -> Bag (MsgEnvelope e)
getMessages Messages e
msgs

{- Note [Discarding Messages]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Discarding a 'SevIgnore' message from 'addMessage' and 'unionMessages' is just
an optimisation, as GHC would /also/ suppress any diagnostic which severity is
'SevIgnore' before printing the message: See for example 'putLogMsg' and
'defaultLogAction'.

-}

-- | Adds a 'Message' to the input collection of messages.
-- See Note [Discarding Messages].
addMessage :: MsgEnvelope e -> Messages e -> Messages e
addMessage :: forall e. MsgEnvelope e -> Messages e -> Messages e
addMessage MsgEnvelope e
x (Messages Bag (MsgEnvelope e)
xs)
  | Severity
SevIgnore <- MsgEnvelope e -> Severity
forall e. MsgEnvelope e -> Severity
errMsgSeverity MsgEnvelope e
x = Bag (MsgEnvelope e) -> Messages e
forall e. Bag (MsgEnvelope e) -> Messages e
Messages Bag (MsgEnvelope e)
xs
  | Bool
otherwise                     = Bag (MsgEnvelope e) -> Messages e
forall e. Bag (MsgEnvelope e) -> Messages e
Messages (MsgEnvelope e
x MsgEnvelope e -> Bag (MsgEnvelope e) -> Bag (MsgEnvelope e)
forall a. a -> Bag a -> Bag a
`consBag` Bag (MsgEnvelope e)
xs)

-- | Joins two collections of messages together.
-- See Note [Discarding Messages].
unionMessages :: Messages e -> Messages e -> Messages e
unionMessages :: forall e. Messages e -> Messages e -> Messages e
unionMessages (Messages Bag (MsgEnvelope e)
msgs1) (Messages Bag (MsgEnvelope e)
msgs2) =
  Bag (MsgEnvelope e) -> Messages e
forall e. Bag (MsgEnvelope e) -> Messages e
Messages (Bag (MsgEnvelope e)
msgs1 Bag (MsgEnvelope e) -> Bag (MsgEnvelope e) -> Bag (MsgEnvelope e)
forall a. Bag a -> Bag a -> Bag a
`unionBags` Bag (MsgEnvelope e)
msgs2)

-- | Joins many 'Messages's together
unionManyMessages :: Foldable f => f (Messages e) -> Messages e
unionManyMessages :: forall (f :: * -> *) e. Foldable f => f (Messages e) -> Messages e
unionManyMessages = f (Messages e) -> Messages e
forall m. Monoid m => f m -> m
forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold

filterMessages :: (MsgEnvelope e -> Bool) -> Messages e -> Messages e
filterMessages :: forall e. (MsgEnvelope e -> Bool) -> Messages e -> Messages e
filterMessages MsgEnvelope e -> Bool
f (Messages Bag (MsgEnvelope e)
msgs) =
  Bag (MsgEnvelope e) -> Messages e
forall e. Bag (MsgEnvelope e) -> Messages e
Messages ((MsgEnvelope e -> Bool)
-> Bag (MsgEnvelope e) -> Bag (MsgEnvelope e)
forall a. (a -> Bool) -> Bag a -> Bag a
filterBag MsgEnvelope e -> Bool
f Bag (MsgEnvelope e)
msgs)

-- | A 'DecoratedSDoc' is isomorphic to a '[SDoc]' but it carries the
-- invariant that the input '[SDoc]' needs to be rendered /decorated/ into its
-- final form, where the typical case would be adding bullets between each
-- elements of the list. The type of decoration depends on the formatting
-- function used, but in practice GHC uses the 'formatBulleted'.
newtype DecoratedSDoc = Decorated { DecoratedSDoc -> [SDoc]
unDecorated :: [SDoc] }

-- | Creates a new 'DecoratedSDoc' out of a list of 'SDoc'.
mkDecorated :: [SDoc] -> DecoratedSDoc
mkDecorated :: [SDoc] -> DecoratedSDoc
mkDecorated = [SDoc] -> DecoratedSDoc
Decorated

-- | Creates a new 'DecoratedSDoc' out of a single 'SDoc'
mkSimpleDecorated :: SDoc -> DecoratedSDoc
mkSimpleDecorated :: SDoc -> DecoratedSDoc
mkSimpleDecorated SDoc
doc = [SDoc] -> DecoratedSDoc
Decorated [SDoc
doc]

-- | Joins two 'DecoratedSDoc' together. The resulting 'DecoratedSDoc'
-- will have a number of entries which is the sum of the lengths of
-- the input.
unionDecoratedSDoc :: DecoratedSDoc -> DecoratedSDoc -> DecoratedSDoc
unionDecoratedSDoc :: DecoratedSDoc -> DecoratedSDoc -> DecoratedSDoc
unionDecoratedSDoc (Decorated [SDoc]
s1) (Decorated [SDoc]
s2) =
  [SDoc] -> DecoratedSDoc
Decorated ([SDoc]
s1 [SDoc] -> [SDoc] -> [SDoc]
forall a. Monoid a => a -> a -> a
`mappend` [SDoc]
s2)

-- | Apply a transformation function to all elements of a 'DecoratedSDoc'.
mapDecoratedSDoc :: (SDoc -> SDoc) -> DecoratedSDoc -> DecoratedSDoc
mapDecoratedSDoc :: (SDoc -> SDoc) -> DecoratedSDoc -> DecoratedSDoc
mapDecoratedSDoc SDoc -> SDoc
f (Decorated [SDoc]
s1) =
  [SDoc] -> DecoratedSDoc
Decorated ((SDoc -> SDoc) -> [SDoc] -> [SDoc]
forall a b. (a -> b) -> [a] -> [b]
map SDoc -> SDoc
f [SDoc]
s1)

class HasDefaultDiagnosticOpts opts where
  defaultOpts :: opts


defaultDiagnosticOpts :: forall opts . HasDefaultDiagnosticOpts (DiagnosticOpts opts) => DiagnosticOpts opts
defaultDiagnosticOpts :: forall opts.
HasDefaultDiagnosticOpts (DiagnosticOpts opts) =>
DiagnosticOpts opts
defaultDiagnosticOpts = forall opts. HasDefaultDiagnosticOpts opts => opts
defaultOpts @(DiagnosticOpts opts)




-- | A class identifying a diagnostic.
-- Dictionary.com defines a diagnostic as:
--
-- \"a message output by a computer diagnosing an error in a computer program,
-- computer system, or component device\".
--
-- A 'Diagnostic' carries the /actual/ description of the message (which, in
-- GHC's case, it can be an error or a warning) and the /reason/ why such
-- message was generated in the first place.
class (HasDefaultDiagnosticOpts (DiagnosticOpts a)) => Diagnostic a where

  -- | Type of configuration options for the diagnostic.
  type DiagnosticOpts a

  -- | Extract the error message text from a 'Diagnostic'.
  diagnosticMessage :: DiagnosticOpts a -> a -> DecoratedSDoc

  -- | Extract the reason for this diagnostic. For warnings,
  -- a 'DiagnosticReason' includes the warning flag.
  diagnosticReason  :: a -> DiagnosticReason

  -- | Extract any hints a user might use to repair their
  -- code to avoid this diagnostic.
  diagnosticHints   :: a -> [GhcHint]

  -- | Get the 'DiagnosticCode' associated with this 'Diagnostic'.
  -- This can return 'Nothing' for at least two reasons:
  --
  -- 1. The message might be from a plugin that does not supply codes.
  -- 2. The message might not yet have been assigned a code. See the
  --    'Diagnostic' instance for 'DiagnosticMessage'.
  --
  -- Ideally, case (2) would not happen, but because
  -- some errors in GHC still use the old system of just writing the
  -- error message in-place (instead of using a dedicated error type
  -- and constructor), we do not have error codes for all errors.
  -- #18516 tracks our progress toward this goal.
  diagnosticCode    :: a -> Maybe DiagnosticCode

-- | An existential wrapper around an unknown diagnostic.
data UnknownDiagnostic opts where
  UnknownDiagnostic :: (Diagnostic a, Typeable a)
                    => (opts -> DiagnosticOpts a) -- Inject the options of the outer context
                                                  -- into the options for the wrapped diagnostic.
                    -> a
                    -> UnknownDiagnostic opts

instance HasDefaultDiagnosticOpts opts => Diagnostic (UnknownDiagnostic opts) where
  type DiagnosticOpts (UnknownDiagnostic opts) = opts
  diagnosticMessage :: DiagnosticOpts (UnknownDiagnostic opts)
-> UnknownDiagnostic opts -> DecoratedSDoc
diagnosticMessage DiagnosticOpts (UnknownDiagnostic opts)
opts (UnknownDiagnostic opts -> DiagnosticOpts a
f a
diag) = DiagnosticOpts a -> a -> DecoratedSDoc
forall a. Diagnostic a => DiagnosticOpts a -> a -> DecoratedSDoc
diagnosticMessage (opts -> DiagnosticOpts a
f opts
DiagnosticOpts (UnknownDiagnostic opts)
opts) a
diag
  diagnosticReason :: UnknownDiagnostic opts -> DiagnosticReason
diagnosticReason    (UnknownDiagnostic opts -> DiagnosticOpts a
_ a
diag) = a -> DiagnosticReason
forall a. Diagnostic a => a -> DiagnosticReason
diagnosticReason  a
diag
  diagnosticHints :: UnknownDiagnostic opts -> [GhcHint]
diagnosticHints     (UnknownDiagnostic opts -> DiagnosticOpts a
_ a
diag) = a -> [GhcHint]
forall a. Diagnostic a => a -> [GhcHint]
diagnosticHints   a
diag
  diagnosticCode :: UnknownDiagnostic opts -> Maybe DiagnosticCode
diagnosticCode      (UnknownDiagnostic opts -> DiagnosticOpts a
_ a
diag) = a -> Maybe DiagnosticCode
forall a. Diagnostic a => a -> Maybe DiagnosticCode
diagnosticCode    a
diag

-- A fallback 'DiagnosticOpts' which can be used when there are no options
-- for a particular diagnostic.
data NoDiagnosticOpts = NoDiagnosticOpts
instance HasDefaultDiagnosticOpts NoDiagnosticOpts where
  defaultOpts :: NoDiagnosticOpts
defaultOpts = NoDiagnosticOpts
NoDiagnosticOpts

-- | Make a "simple" unknown diagnostic which doesn't have any configuration options.
mkSimpleUnknownDiagnostic :: (Diagnostic a, Typeable a, DiagnosticOpts a ~ NoDiagnosticOpts) => a -> UnknownDiagnostic b
mkSimpleUnknownDiagnostic :: forall a b.
(Diagnostic a, Typeable a, DiagnosticOpts a ~ NoDiagnosticOpts) =>
a -> UnknownDiagnostic b
mkSimpleUnknownDiagnostic = (b -> DiagnosticOpts a) -> a -> UnknownDiagnostic b
forall a opts.
(Diagnostic a, Typeable a) =>
(opts -> DiagnosticOpts a) -> a -> UnknownDiagnostic opts
UnknownDiagnostic (NoDiagnosticOpts -> b -> NoDiagnosticOpts
forall a b. a -> b -> a
const NoDiagnosticOpts
NoDiagnosticOpts)

-- | Make an unknown diagnostic which uses the same options as the context it will be embedded into.
mkUnknownDiagnostic :: (Typeable a, Diagnostic a) => a -> UnknownDiagnostic (DiagnosticOpts a)
mkUnknownDiagnostic :: forall a.
(Typeable a, Diagnostic a) =>
a -> UnknownDiagnostic (DiagnosticOpts a)
mkUnknownDiagnostic = (DiagnosticOpts a -> DiagnosticOpts a)
-> a -> UnknownDiagnostic (DiagnosticOpts a)
forall a opts.
(Diagnostic a, Typeable a) =>
(opts -> DiagnosticOpts a) -> a -> UnknownDiagnostic opts
UnknownDiagnostic DiagnosticOpts a -> DiagnosticOpts a
forall a. a -> a
id

-- | Embed a more complicated diagnostic which requires a potentially different options type.
embedUnknownDiagnostic :: (Diagnostic a, Typeable a) => (opts -> DiagnosticOpts a) -> a -> UnknownDiagnostic opts
embedUnknownDiagnostic :: forall a opts.
(Diagnostic a, Typeable a) =>
(opts -> DiagnosticOpts a) -> a -> UnknownDiagnostic opts
embedUnknownDiagnostic = (opts -> DiagnosticOpts a) -> a -> UnknownDiagnostic opts
forall a opts.
(Diagnostic a, Typeable a) =>
(opts -> DiagnosticOpts a) -> a -> UnknownDiagnostic opts
UnknownDiagnostic

--------------------------------------------------------------------------------

pprDiagnostic :: forall e . Diagnostic e => e -> SDoc
pprDiagnostic :: forall e. Diagnostic e => e -> SDoc
pprDiagnostic e
e = [SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat [ DiagnosticReason -> SDoc
forall a. Outputable a => a -> SDoc
ppr (e -> DiagnosticReason
forall a. Diagnostic a => a -> DiagnosticReason
diagnosticReason e
e)
                       , Int -> SDoc -> SDoc
nest Int
2 ([SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat (DecoratedSDoc -> [SDoc]
unDecorated (DiagnosticOpts e -> e -> DecoratedSDoc
forall a. Diagnostic a => DiagnosticOpts a -> a -> DecoratedSDoc
diagnosticMessage DiagnosticOpts e
opts e
e))) ]
  where opts :: DiagnosticOpts e
opts = forall opts.
HasDefaultDiagnosticOpts (DiagnosticOpts opts) =>
DiagnosticOpts opts
defaultDiagnosticOpts @e

-- | A generic 'Hint' message, to be used with 'DiagnosticMessage'.
data DiagnosticHint = DiagnosticHint !SDoc

instance Outputable DiagnosticHint where
  ppr :: DiagnosticHint -> SDoc
ppr (DiagnosticHint SDoc
msg) = SDoc
msg

-- | A generic 'Diagnostic' message, without any further classification or
-- provenance: By looking at a 'DiagnosticMessage' we don't know neither
-- /where/ it was generated nor how to interpret its payload (as it's just a
-- structured document). All we can do is to print it out and look at its
-- 'DiagnosticReason'.
data DiagnosticMessage = DiagnosticMessage
  { DiagnosticMessage -> DecoratedSDoc
diagMessage :: !DecoratedSDoc
  , DiagnosticMessage -> DiagnosticReason
diagReason  :: !DiagnosticReason
  , DiagnosticMessage -> [GhcHint]
diagHints   :: [GhcHint]
  }

instance Diagnostic DiagnosticMessage where
  type DiagnosticOpts DiagnosticMessage = NoDiagnosticOpts
  diagnosticMessage :: DiagnosticOpts DiagnosticMessage
-> DiagnosticMessage -> DecoratedSDoc
diagnosticMessage DiagnosticOpts DiagnosticMessage
_ = DiagnosticMessage -> DecoratedSDoc
diagMessage
  diagnosticReason :: DiagnosticMessage -> DiagnosticReason
diagnosticReason  = DiagnosticMessage -> DiagnosticReason
diagReason
  diagnosticHints :: DiagnosticMessage -> [GhcHint]
diagnosticHints   = DiagnosticMessage -> [GhcHint]
diagHints
  diagnosticCode :: DiagnosticMessage -> Maybe DiagnosticCode
diagnosticCode DiagnosticMessage
_  = Maybe DiagnosticCode
forall a. Maybe a
Nothing

-- | Helper function to use when no hints can be provided. Currently this function
-- can be used to construct plain 'DiagnosticMessage' and add hints to them, but
-- once #18516 will be fully executed, the main usage of this function would be in
-- the implementation of the 'diagnosticHints' typeclass method, to report the fact
-- that a particular 'Diagnostic' has no hints.
noHints :: [GhcHint]
noHints :: [GhcHint]
noHints = [GhcHint]
forall a. Monoid a => a
mempty

mkPlainDiagnostic :: DiagnosticReason -> [GhcHint] -> SDoc -> DiagnosticMessage
mkPlainDiagnostic :: DiagnosticReason -> [GhcHint] -> SDoc -> DiagnosticMessage
mkPlainDiagnostic DiagnosticReason
rea [GhcHint]
hints SDoc
doc = DecoratedSDoc -> DiagnosticReason -> [GhcHint] -> DiagnosticMessage
DiagnosticMessage (SDoc -> DecoratedSDoc
mkSimpleDecorated SDoc
doc) DiagnosticReason
rea [GhcHint]
hints

-- | Create an error 'DiagnosticMessage' holding just a single 'SDoc'
mkPlainError :: [GhcHint] -> SDoc -> DiagnosticMessage
mkPlainError :: [GhcHint] -> SDoc -> DiagnosticMessage
mkPlainError [GhcHint]
hints SDoc
doc = DecoratedSDoc -> DiagnosticReason -> [GhcHint] -> DiagnosticMessage
DiagnosticMessage (SDoc -> DecoratedSDoc
mkSimpleDecorated SDoc
doc) DiagnosticReason
ErrorWithoutFlag [GhcHint]
hints

-- | Create a 'DiagnosticMessage' from a list of bulleted SDocs and a 'DiagnosticReason'
mkDecoratedDiagnostic :: DiagnosticReason -> [GhcHint] -> [SDoc] -> DiagnosticMessage
mkDecoratedDiagnostic :: DiagnosticReason -> [GhcHint] -> [SDoc] -> DiagnosticMessage
mkDecoratedDiagnostic DiagnosticReason
rea [GhcHint]
hints [SDoc]
docs = DecoratedSDoc -> DiagnosticReason -> [GhcHint] -> DiagnosticMessage
DiagnosticMessage ([SDoc] -> DecoratedSDoc
mkDecorated [SDoc]
docs) DiagnosticReason
rea [GhcHint]
hints

-- | Create an error 'DiagnosticMessage' from a list of bulleted SDocs
mkDecoratedError :: [GhcHint] -> [SDoc] -> DiagnosticMessage
mkDecoratedError :: [GhcHint] -> [SDoc] -> DiagnosticMessage
mkDecoratedError [GhcHint]
hints [SDoc]
docs = DecoratedSDoc -> DiagnosticReason -> [GhcHint] -> DiagnosticMessage
DiagnosticMessage ([SDoc] -> DecoratedSDoc
mkDecorated [SDoc]
docs) DiagnosticReason
ErrorWithoutFlag [GhcHint]
hints

-- | The reason /why/ a 'Diagnostic' was emitted in the first place.
-- Diagnostic messages are born within GHC with a very precise reason, which
-- can be completely statically-computed (i.e. this is an error or a warning
-- no matter what), or influenced by the specific state of the 'DynFlags' at
-- the moment of the creation of a new 'Diagnostic'. For example, a parsing
-- error is /always/ going to be an error, whereas a 'WarningWithoutFlag
-- Opt_WarnUnusedImports' might turn into an error due to '-Werror' or
-- '-Werror=warn-unused-imports'. Interpreting a 'DiagnosticReason' together
-- with its associated 'Severity' gives us the full picture.
data DiagnosticReason
  = WarningWithoutFlag
  -- ^ Born as a warning.
  | WarningWithFlags !(NE.NonEmpty WarningFlag)
  -- ^ Warning was enabled with the flag.
  | WarningWithCategory !WarningCategory
  -- ^ Warning was enabled with a custom category.
  | ErrorWithoutFlag
  -- ^ Born as an error.
  deriving (DiagnosticReason -> DiagnosticReason -> Bool
(DiagnosticReason -> DiagnosticReason -> Bool)
-> (DiagnosticReason -> DiagnosticReason -> Bool)
-> Eq DiagnosticReason
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DiagnosticReason -> DiagnosticReason -> Bool
== :: DiagnosticReason -> DiagnosticReason -> Bool
$c/= :: DiagnosticReason -> DiagnosticReason -> Bool
/= :: DiagnosticReason -> DiagnosticReason -> Bool
Eq, Int -> DiagnosticReason -> ShowS
[DiagnosticReason] -> ShowS
DiagnosticReason -> String
(Int -> DiagnosticReason -> ShowS)
-> (DiagnosticReason -> String)
-> ([DiagnosticReason] -> ShowS)
-> Show DiagnosticReason
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DiagnosticReason -> ShowS
showsPrec :: Int -> DiagnosticReason -> ShowS
$cshow :: DiagnosticReason -> String
show :: DiagnosticReason -> String
$cshowList :: [DiagnosticReason] -> ShowS
showList :: [DiagnosticReason] -> ShowS
Show)

-- | Like a 'DiagnosticReason', but resolved against a specific set of `DynFlags` to
-- work out which warning flag actually enabled this warning.
newtype ResolvedDiagnosticReason
          = ResolvedDiagnosticReason { ResolvedDiagnosticReason -> DiagnosticReason
resolvedDiagnosticReason :: DiagnosticReason }

-- | The single warning case 'DiagnosticReason' is very common.
pattern WarningWithFlag :: WarningFlag -> DiagnosticReason
pattern $mWarningWithFlag :: forall {r}.
DiagnosticReason -> (WarningFlag -> r) -> ((# #) -> r) -> r
$bWarningWithFlag :: WarningFlag -> DiagnosticReason
WarningWithFlag w = WarningWithFlags (w :| [])

{-
Note [Warnings controlled by multiple flags]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Diagnostics that started life as flag-controlled warnings have a
'diagnosticReason' of 'WarningWithFlags', giving the flags that control the
warning. Usually there is only one flag, but in a few cases multiple flags
apply. Where there are more than one, they are listed highest-priority first.

For example, the same exported binding may give rise to a warning if either
`-Wmissing-signatures` or `-Wmissing-exported-signatures` is enabled. Here
`-Wmissing-signatures` has higher priority, because we want to mention it if
before are enabled.  See `missingSignatureWarningFlags` for the specific logic
in this case.

When reporting such a warning to the user, it is important to mention the
correct flag (e.g. `-Wmissing-signatures` if it is enabled, or
`-Wmissing-exported-signatures` if only the latter is enabled).  Thus
`diag_reason_severity` filters the `DiagnosticReason` based on the currently
active `DiagOpts`. For a `WarningWithFlags` it returns only the flags that are
enabled; it leaves other `DiagnosticReason`s unchanged. This is then wrapped
in a `ResolvedDiagnosticReason` newtype which records that this filtering has
taken place.

If we have `-Wmissing-signatures -Werror=missing-exported-signatures` we want
the error to mention `-Werror=missing-exported-signatures` (even though
`-Wmissing-signatures` would normally take precedence). Thus if there are any
fatal warnings, `diag_reason_severity` returns those alone.

The `MsgEnvelope` stores the filtered `ResolvedDiagnosticReason` listing only the
relevant flags for subsequent display.


Side note: we do not treat `-Wmissing-signatures` as a warning group that
includes `-Wmissing-exported-signatures`, because

  (a) this would require us to provide a flag for the complement, and

  (b) currently, in `-Wmissing-exported-signatures -Wno-missing-signatures`, the
      latter option does not switch off the former.
-}

instance Outputable DiagnosticReason where
  ppr :: DiagnosticReason -> SDoc
ppr = \case
    DiagnosticReason
WarningWithoutFlag  -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"WarningWithoutFlag"
    WarningWithFlags NonEmpty WarningFlag
wf -> String -> SDoc
forall doc. IsLine doc => String -> doc
text (String
"WarningWithFlags " String -> ShowS
forall a. [a] -> [a] -> [a]
++ NonEmpty WarningFlag -> String
forall a. Show a => a -> String
show NonEmpty WarningFlag
wf)
    WarningWithCategory WarningCategory
cat -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"WarningWithCategory" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> WarningCategory -> SDoc
forall a. Outputable a => a -> SDoc
ppr WarningCategory
cat
    DiagnosticReason
ErrorWithoutFlag    -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"ErrorWithoutFlag"

instance Outputable ResolvedDiagnosticReason where
  ppr :: ResolvedDiagnosticReason -> SDoc
ppr = DiagnosticReason -> SDoc
forall a. Outputable a => a -> SDoc
ppr (DiagnosticReason -> SDoc)
-> (ResolvedDiagnosticReason -> DiagnosticReason)
-> ResolvedDiagnosticReason
-> SDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ResolvedDiagnosticReason -> DiagnosticReason
resolvedDiagnosticReason

-- | An envelope for GHC's facts about a running program, parameterised over the
-- /domain-specific/ (i.e. parsing, typecheck-renaming, etc) diagnostics.
--
-- To say things differently, GHC emits /diagnostics/ about the running
-- program, each of which is wrapped into a 'MsgEnvelope' that carries
-- specific information like where the error happened, etc. Finally, multiple
-- 'MsgEnvelope's are aggregated into 'Messages' that are returned to the
-- user.
data MsgEnvelope e = MsgEnvelope
   { forall e. MsgEnvelope e -> SrcSpan
errMsgSpan        :: SrcSpan
      -- ^ The SrcSpan is used for sorting errors into line-number order
   , forall e. MsgEnvelope e -> NamePprCtx
errMsgContext     :: NamePprCtx
   , forall e. MsgEnvelope e -> e
errMsgDiagnostic  :: e
   , forall e. MsgEnvelope e -> Severity
errMsgSeverity    :: Severity
   , forall e. MsgEnvelope e -> ResolvedDiagnosticReason
errMsgReason      :: ResolvedDiagnosticReason
      -- ^ The actual reason caused this message
      --
      -- See Note [Warnings controlled by multiple flags]
   } deriving ((forall a b. (a -> b) -> MsgEnvelope a -> MsgEnvelope b)
-> (forall a b. a -> MsgEnvelope b -> MsgEnvelope a)
-> Functor MsgEnvelope
forall a b. a -> MsgEnvelope b -> MsgEnvelope a
forall a b. (a -> b) -> MsgEnvelope a -> MsgEnvelope b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> MsgEnvelope a -> MsgEnvelope b
fmap :: forall a b. (a -> b) -> MsgEnvelope a -> MsgEnvelope b
$c<$ :: forall a b. a -> MsgEnvelope b -> MsgEnvelope a
<$ :: forall a b. a -> MsgEnvelope b -> MsgEnvelope a
Functor, (forall m. Monoid m => MsgEnvelope m -> m)
-> (forall m a. Monoid m => (a -> m) -> MsgEnvelope a -> m)
-> (forall m a. Monoid m => (a -> m) -> MsgEnvelope a -> m)
-> (forall a b. (a -> b -> b) -> b -> MsgEnvelope a -> b)
-> (forall a b. (a -> b -> b) -> b -> MsgEnvelope a -> b)
-> (forall b a. (b -> a -> b) -> b -> MsgEnvelope a -> b)
-> (forall b a. (b -> a -> b) -> b -> MsgEnvelope a -> b)
-> (forall a. (a -> a -> a) -> MsgEnvelope a -> a)
-> (forall a. (a -> a -> a) -> MsgEnvelope a -> a)
-> (forall a. MsgEnvelope a -> [a])
-> (forall e. MsgEnvelope e -> Bool)
-> (forall a. MsgEnvelope a -> Int)
-> (forall a. Eq a => a -> MsgEnvelope a -> Bool)
-> (forall a. Ord a => MsgEnvelope a -> a)
-> (forall a. Ord a => MsgEnvelope a -> a)
-> (forall a. Num a => MsgEnvelope a -> a)
-> (forall a. Num a => MsgEnvelope a -> a)
-> Foldable MsgEnvelope
forall a. Eq a => a -> MsgEnvelope a -> Bool
forall a. Num a => MsgEnvelope a -> a
forall a. Ord a => MsgEnvelope a -> a
forall m. Monoid m => MsgEnvelope m -> m
forall e. MsgEnvelope e -> Bool
forall a. MsgEnvelope a -> Int
forall a. MsgEnvelope a -> [a]
forall a. (a -> a -> a) -> MsgEnvelope a -> a
forall m a. Monoid m => (a -> m) -> MsgEnvelope a -> m
forall b a. (b -> a -> b) -> b -> MsgEnvelope a -> b
forall a b. (a -> b -> b) -> b -> MsgEnvelope a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall m. Monoid m => MsgEnvelope m -> m
fold :: forall m. Monoid m => MsgEnvelope m -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> MsgEnvelope a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> MsgEnvelope a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> MsgEnvelope a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> MsgEnvelope a -> m
$cfoldr :: forall a b. (a -> b -> b) -> b -> MsgEnvelope a -> b
foldr :: forall a b. (a -> b -> b) -> b -> MsgEnvelope a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> MsgEnvelope a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> MsgEnvelope a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> MsgEnvelope a -> b
foldl :: forall b a. (b -> a -> b) -> b -> MsgEnvelope a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> MsgEnvelope a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> MsgEnvelope a -> b
$cfoldr1 :: forall a. (a -> a -> a) -> MsgEnvelope a -> a
foldr1 :: forall a. (a -> a -> a) -> MsgEnvelope a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> MsgEnvelope a -> a
foldl1 :: forall a. (a -> a -> a) -> MsgEnvelope a -> a
$ctoList :: forall a. MsgEnvelope a -> [a]
toList :: forall a. MsgEnvelope a -> [a]
$cnull :: forall e. MsgEnvelope e -> Bool
null :: forall e. MsgEnvelope e -> Bool
$clength :: forall a. MsgEnvelope a -> Int
length :: forall a. MsgEnvelope a -> Int
$celem :: forall a. Eq a => a -> MsgEnvelope a -> Bool
elem :: forall a. Eq a => a -> MsgEnvelope a -> Bool
$cmaximum :: forall a. Ord a => MsgEnvelope a -> a
maximum :: forall a. Ord a => MsgEnvelope a -> a
$cminimum :: forall a. Ord a => MsgEnvelope a -> a
minimum :: forall a. Ord a => MsgEnvelope a -> a
$csum :: forall a. Num a => MsgEnvelope a -> a
sum :: forall a. Num a => MsgEnvelope a -> a
$cproduct :: forall a. Num a => MsgEnvelope a -> a
product :: forall a. Num a => MsgEnvelope a -> a
Foldable, Functor MsgEnvelope
Foldable MsgEnvelope
(Functor MsgEnvelope, Foldable MsgEnvelope) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> MsgEnvelope a -> f (MsgEnvelope b))
-> (forall (f :: * -> *) a.
    Applicative f =>
    MsgEnvelope (f a) -> f (MsgEnvelope a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> MsgEnvelope a -> m (MsgEnvelope b))
-> (forall (m :: * -> *) a.
    Monad m =>
    MsgEnvelope (m a) -> m (MsgEnvelope a))
-> Traversable MsgEnvelope
forall (t :: * -> *).
(Functor t, Foldable t) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> t a -> f (t b))
-> (forall (f :: * -> *) a. Applicative f => t (f a) -> f (t a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> t a -> m (t b))
-> (forall (m :: * -> *) a. Monad m => t (m a) -> m (t a))
-> Traversable t
forall (m :: * -> *) a.
Monad m =>
MsgEnvelope (m a) -> m (MsgEnvelope a)
forall (f :: * -> *) a.
Applicative f =>
MsgEnvelope (f a) -> f (MsgEnvelope a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> MsgEnvelope a -> m (MsgEnvelope b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> MsgEnvelope a -> f (MsgEnvelope b)
$ctraverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> MsgEnvelope a -> f (MsgEnvelope b)
traverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> MsgEnvelope a -> f (MsgEnvelope b)
$csequenceA :: forall (f :: * -> *) a.
Applicative f =>
MsgEnvelope (f a) -> f (MsgEnvelope a)
sequenceA :: forall (f :: * -> *) a.
Applicative f =>
MsgEnvelope (f a) -> f (MsgEnvelope a)
$cmapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> MsgEnvelope a -> m (MsgEnvelope b)
mapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> MsgEnvelope a -> m (MsgEnvelope b)
$csequence :: forall (m :: * -> *) a.
Monad m =>
MsgEnvelope (m a) -> m (MsgEnvelope a)
sequence :: forall (m :: * -> *) a.
Monad m =>
MsgEnvelope (m a) -> m (MsgEnvelope a)
Traversable)

-- | The class for a diagnostic message. The main purpose is to classify a
-- message within GHC, to distinguish it from a debug/dump message vs a proper
-- diagnostic, for which we include a 'DiagnosticReason'.
data MessageClass
  = MCOutput
  | MCFatal
  | MCInteractive

  | MCDump
    -- ^ Log message intended for compiler developers
    -- No file\/line\/column stuff

  | MCInfo
    -- ^ Log messages intended for end users.
    -- No file\/line\/column stuff.

  | MCDiagnostic Severity ResolvedDiagnosticReason (Maybe DiagnosticCode)
    -- ^ Diagnostics from the compiler. This constructor is very powerful as
    -- it allows the construction of a 'MessageClass' with a completely
    -- arbitrary permutation of 'Severity' and 'DiagnosticReason'. As such,
    -- users are encouraged to use the 'mkMCDiagnostic' smart constructor
    -- instead. Use this constructor directly only if you need to construct
    -- and manipulate diagnostic messages directly, for example inside
    -- 'GHC.Utils.Error'. In all the other circumstances, /especially/ when
    -- emitting compiler diagnostics, use the smart constructor.
    --
    -- The @Maybe 'DiagnosticCode'@ field carries a code (if available) for
    -- this diagnostic. If you are creating a message not tied to any
    -- error-message type, then use Nothing. In the long run, this really
    -- should always have a 'DiagnosticCode'. See Note [Diagnostic codes].

{-
Note [Suppressing Messages]
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'SevIgnore' constructor is used to generate messages for diagnostics which
are meant to be suppressed and not reported to the user: the classic example
are warnings for which the user didn't enable the corresponding 'WarningFlag',
so GHC shouldn't print them.

A different approach would be to extend the zoo of 'mkMsgEnvelope' functions
to return a 'Maybe (MsgEnvelope e)', so that we won't need to even create the
message to begin with. Both approaches have been evaluated, but we settled on
the "SevIgnore one" for a number of reasons:

* It's less invasive to deal with;
* It plays slightly better with deferred diagnostics (see 'GHC.Tc.Errors') as
  for those we need to be able to /always/ produce a message (so that is
  reported at runtime);
* It gives us more freedom: we can still decide to drop a 'SevIgnore' message
  at leisure, or we can decide to keep it around until the last moment. Maybe
  in the future we would need to turn a 'SevIgnore' into something else, for
  example to "unsuppress" diagnostics if a flag is set: with this approach, we
  have more leeway to accommodate new features.

-}


-- | Used to describe warnings and errors
--   o The message has a file\/line\/column heading,
--     plus "warning:" or "error:",
--     added by mkLocMessage
--   o With 'SevIgnore' the message is suppressed
--   o Output is intended for end users
data Severity
  = SevIgnore
  -- ^ Ignore this message, for example in
  -- case of suppression of warnings users
  -- don't want to see. See Note [Suppressing Messages]
  | SevWarning
  | SevError
  deriving (Severity -> Severity -> Bool
(Severity -> Severity -> Bool)
-> (Severity -> Severity -> Bool) -> Eq Severity
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Severity -> Severity -> Bool
== :: Severity -> Severity -> Bool
$c/= :: Severity -> Severity -> Bool
/= :: Severity -> Severity -> Bool
Eq, Eq Severity
Eq Severity =>
(Severity -> Severity -> Ordering)
-> (Severity -> Severity -> Bool)
-> (Severity -> Severity -> Bool)
-> (Severity -> Severity -> Bool)
-> (Severity -> Severity -> Bool)
-> (Severity -> Severity -> Severity)
-> (Severity -> Severity -> Severity)
-> Ord Severity
Severity -> Severity -> Bool
Severity -> Severity -> Ordering
Severity -> Severity -> Severity
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Severity -> Severity -> Ordering
compare :: Severity -> Severity -> Ordering
$c< :: Severity -> Severity -> Bool
< :: Severity -> Severity -> Bool
$c<= :: Severity -> Severity -> Bool
<= :: Severity -> Severity -> Bool
$c> :: Severity -> Severity -> Bool
> :: Severity -> Severity -> Bool
$c>= :: Severity -> Severity -> Bool
>= :: Severity -> Severity -> Bool
$cmax :: Severity -> Severity -> Severity
max :: Severity -> Severity -> Severity
$cmin :: Severity -> Severity -> Severity
min :: Severity -> Severity -> Severity
Ord, Int -> Severity -> ShowS
[Severity] -> ShowS
Severity -> String
(Int -> Severity -> ShowS)
-> (Severity -> String) -> ([Severity] -> ShowS) -> Show Severity
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Severity -> ShowS
showsPrec :: Int -> Severity -> ShowS
$cshow :: Severity -> String
show :: Severity -> String
$cshowList :: [Severity] -> ShowS
showList :: [Severity] -> ShowS
Show)

instance Outputable Severity where
  ppr :: Severity -> SDoc
ppr = \case
    Severity
SevIgnore  -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"SevIgnore"
    Severity
SevWarning -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"SevWarning"
    Severity
SevError   -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"SevError"

instance ToJson Severity where
  json :: Severity -> JsonDoc
json Severity
SevIgnore = String -> JsonDoc
JSString String
"Ignore"
  json Severity
SevWarning = String -> JsonDoc
JSString String
"Warning"
  json Severity
SevError = String -> JsonDoc
JSString String
"Error"

instance ToJson MessageClass where
  json :: MessageClass -> JsonDoc
json MessageClass
MCOutput = String -> JsonDoc
JSString String
"MCOutput"
  json MessageClass
MCFatal  = String -> JsonDoc
JSString String
"MCFatal"
  json MessageClass
MCInteractive = String -> JsonDoc
JSString String
"MCInteractive"
  json MessageClass
MCDump = String -> JsonDoc
JSString String
"MCDump"
  json MessageClass
MCInfo = String -> JsonDoc
JSString String
"MCInfo"
  json (MCDiagnostic Severity
sev ResolvedDiagnosticReason
reason Maybe DiagnosticCode
code) =
    String -> JsonDoc
JSString (String -> JsonDoc) -> String -> JsonDoc
forall a b. (a -> b) -> a -> b
$ SDocContext -> SDoc -> String
renderWithContext SDocContext
defaultSDocContext (SDoc -> SDoc
forall a. Outputable a => a -> SDoc
ppr (SDoc -> SDoc) -> SDoc -> SDoc
forall a b. (a -> b) -> a -> b
$ String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"MCDiagnostic" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> Severity -> SDoc
forall a. Outputable a => a -> SDoc
ppr Severity
sev SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> ResolvedDiagnosticReason -> SDoc
forall a. Outputable a => a -> SDoc
ppr ResolvedDiagnosticReason
reason SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> Maybe DiagnosticCode -> SDoc
forall a. Outputable a => a -> SDoc
ppr Maybe DiagnosticCode
code)

instance ToJson DiagnosticCode where
  json :: DiagnosticCode -> JsonDoc
json DiagnosticCode
c = Int -> JsonDoc
JSInt (Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (DiagnosticCode -> Natural
diagnosticCodeNumber DiagnosticCode
c))

{- Note [Diagnostic Message JSON Schema]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The below instance of ToJson must conform to the JSON schema
specified in docs/users_guide/diagnostics-as-json-schema-1_0.json.
When the schema is altered, please bump the version.
If the content is altered in a backwards compatible way,
update the minor version (e.g. 1.3 ~> 1.4).
If the content is breaking, update the major version (e.g. 1.3 ~> 2.3).
When updating the schema, replace the above file and name it appropriately with
the version appended, and change the documentation of the -fdiagnostics-as-json
flag to reflect the new schema.
To learn more about JSON schemas, check out the below link:
https://json-schema.org
-}

schemaVersion :: String
schemaVersion :: String
schemaVersion = String
"1.0"
-- See Note [Diagnostic Message JSON Schema] before editing!
instance Diagnostic e => ToJson (MsgEnvelope e) where
  json :: MsgEnvelope e -> JsonDoc
json MsgEnvelope e
m = [(String, JsonDoc)] -> JsonDoc
JSObject [
    (String
"version", String -> JsonDoc
JSString String
schemaVersion),
    (String
"ghcVersion", String -> JsonDoc
JSString (String -> JsonDoc) -> String -> JsonDoc
forall a b. (a -> b) -> a -> b
$ String
"ghc-" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
cProjectVersion),
    (String
"span", SrcSpan -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json (SrcSpan -> JsonDoc) -> SrcSpan -> JsonDoc
forall a b. (a -> b) -> a -> b
$ MsgEnvelope e -> SrcSpan
forall e. MsgEnvelope e -> SrcSpan
errMsgSpan MsgEnvelope e
m),
    (String
"severity", Severity -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json (Severity -> JsonDoc) -> Severity -> JsonDoc
forall a b. (a -> b) -> a -> b
$ MsgEnvelope e -> Severity
forall e. MsgEnvelope e -> Severity
errMsgSeverity MsgEnvelope e
m),
    (String
"code", JsonDoc
-> (DiagnosticCode -> JsonDoc) -> Maybe DiagnosticCode -> JsonDoc
forall b a. b -> (a -> b) -> Maybe a -> b
maybe JsonDoc
JSNull DiagnosticCode -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json (e -> Maybe DiagnosticCode
forall a. Diagnostic a => a -> Maybe DiagnosticCode
diagnosticCode e
diag)),
    (String
"message", [JsonDoc] -> JsonDoc
JSArray ([JsonDoc] -> JsonDoc) -> [JsonDoc] -> JsonDoc
forall a b. (a -> b) -> a -> b
$ (SDoc -> JsonDoc) -> [SDoc] -> [JsonDoc]
forall a b. (a -> b) -> [a] -> [b]
map SDoc -> JsonDoc
renderToJSString [SDoc]
diagMsg),
    (String
"hints", [JsonDoc] -> JsonDoc
JSArray ([JsonDoc] -> JsonDoc) -> [JsonDoc] -> JsonDoc
forall a b. (a -> b) -> a -> b
$ (GhcHint -> JsonDoc) -> [GhcHint] -> [JsonDoc]
forall a b. (a -> b) -> [a] -> [b]
map (SDoc -> JsonDoc
renderToJSString (SDoc -> JsonDoc) -> (GhcHint -> SDoc) -> GhcHint -> JsonDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GhcHint -> SDoc
forall a. Outputable a => a -> SDoc
ppr) (e -> [GhcHint]
forall a. Diagnostic a => a -> [GhcHint]
diagnosticHints e
diag) )
    ]
    where diag :: e
diag = MsgEnvelope e -> e
forall e. MsgEnvelope e -> e
errMsgDiagnostic MsgEnvelope e
m
          opts :: DiagnosticOpts e
opts = forall opts.
HasDefaultDiagnosticOpts (DiagnosticOpts opts) =>
DiagnosticOpts opts
defaultDiagnosticOpts @e
          style :: PprStyle
style = NamePprCtx -> PprStyle
mkErrStyle (MsgEnvelope e -> NamePprCtx
forall e. MsgEnvelope e -> NamePprCtx
errMsgContext MsgEnvelope e
m)
          ctx :: SDocContext
ctx = SDocContext
defaultSDocContext {sdocStyle = style }
          diagMsg :: [SDoc]
diagMsg = (SDoc -> Bool) -> [SDoc] -> [SDoc]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (SDoc -> Bool) -> SDoc -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SDocContext -> SDoc -> Bool
isEmpty SDocContext
ctx) (DecoratedSDoc -> [SDoc]
unDecorated (DiagnosticOpts e -> e -> DecoratedSDoc
forall a. Diagnostic a => DiagnosticOpts a -> a -> DecoratedSDoc
diagnosticMessage (DiagnosticOpts e
opts) e
diag))
          renderToJSString :: SDoc -> JsonDoc
          renderToJSString :: SDoc -> JsonDoc
renderToJSString = String -> JsonDoc
JSString (String -> JsonDoc) -> (SDoc -> String) -> SDoc -> JsonDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SDocContext -> SDoc -> String
renderWithContext SDocContext
ctx)

instance Show (MsgEnvelope DiagnosticMessage) where
    show :: MsgEnvelope DiagnosticMessage -> String
show = MsgEnvelope DiagnosticMessage -> String
forall a. Diagnostic a => MsgEnvelope a -> String
showMsgEnvelope

-- | Shows an 'MsgEnvelope'. Only use this for debugging.
showMsgEnvelope :: forall a . Diagnostic a => MsgEnvelope a -> String
showMsgEnvelope :: forall a. Diagnostic a => MsgEnvelope a -> String
showMsgEnvelope MsgEnvelope a
err =
  SDocContext -> SDoc -> String
renderWithContext SDocContext
defaultSDocContext ([SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat (DecoratedSDoc -> [SDoc]
unDecorated (DecoratedSDoc -> [SDoc]) -> (a -> DecoratedSDoc) -> a -> [SDoc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (DiagnosticOpts a -> a -> DecoratedSDoc
forall a. Diagnostic a => DiagnosticOpts a -> a -> DecoratedSDoc
diagnosticMessage (forall opts.
HasDefaultDiagnosticOpts (DiagnosticOpts opts) =>
DiagnosticOpts opts
defaultDiagnosticOpts @a)) (a -> [SDoc]) -> a -> [SDoc]
forall a b. (a -> b) -> a -> b
$ MsgEnvelope a -> a
forall e. MsgEnvelope e -> e
errMsgDiagnostic MsgEnvelope a
err))

pprMessageBag :: Bag SDoc -> SDoc
pprMessageBag :: Bag SDoc -> SDoc
pprMessageBag Bag SDoc
msgs = [SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat (SDoc -> [SDoc] -> [SDoc]
forall doc. IsLine doc => doc -> [doc] -> [doc]
punctuate SDoc
blankLine (Bag SDoc -> [SDoc]
forall a. Bag a -> [a]
bagToList Bag SDoc
msgs))

mkLocMessage
  :: MessageClass                       -- ^ What kind of message?
  -> SrcSpan                            -- ^ location
  -> SDoc                               -- ^ message
  -> SDoc
mkLocMessage :: MessageClass -> SrcSpan -> SDoc -> SDoc
mkLocMessage = Bool -> MessageClass -> SrcSpan -> SDoc -> SDoc
mkLocMessageWarningGroups Bool
True

-- | Make an error message with location info, specifying whether to show
-- warning groups (if applicable).
mkLocMessageWarningGroups
  :: Bool                               -- ^ Print warning groups (if applicable)?
  -> MessageClass                       -- ^ What kind of message?
  -> SrcSpan                            -- ^ location
  -> SDoc                               -- ^ message
  -> SDoc
  -- Always print the location, even if it is unhelpful.  Error messages
  -- are supposed to be in a standard format, and one without a location
  -- would look strange.  Better to say explicitly "<no location info>".
mkLocMessageWarningGroups :: Bool -> MessageClass -> SrcSpan -> SDoc -> SDoc
mkLocMessageWarningGroups Bool
show_warn_groups MessageClass
msg_class SrcSpan
locn SDoc
msg
    = (SDocContext -> Scheme) -> (Scheme -> SDoc) -> SDoc
forall a. (SDocContext -> a) -> (a -> SDoc) -> SDoc
sdocOption SDocContext -> Scheme
sdocColScheme ((Scheme -> SDoc) -> SDoc) -> (Scheme -> SDoc) -> SDoc
forall a b. (a -> b) -> a -> b
$ \Scheme
col_scheme ->
      let locn' :: SDoc
locn' = (SDocContext -> Bool) -> (Bool -> SDoc) -> SDoc
forall a. (SDocContext -> a) -> (a -> SDoc) -> SDoc
sdocOption SDocContext -> Bool
sdocErrorSpans ((Bool -> SDoc) -> SDoc) -> (Bool -> SDoc) -> SDoc
forall a b. (a -> b) -> a -> b
$ \case
                     Bool
True  -> SrcSpan -> SDoc
forall a. Outputable a => a -> SDoc
ppr SrcSpan
locn
                     Bool
False -> SrcLoc -> SDoc
forall a. Outputable a => a -> SDoc
ppr (SrcSpan -> SrcLoc
srcSpanStart SrcSpan
locn)

          msg_colour :: PprColour
msg_colour = MessageClass -> Scheme -> PprColour
getMessageClassColour MessageClass
msg_class Scheme
col_scheme
          col :: String -> SDoc
col = PprColour -> SDoc -> SDoc
coloured PprColour
msg_colour (SDoc -> SDoc) -> (String -> SDoc) -> String -> SDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> SDoc
forall doc. IsLine doc => String -> doc
text

          msg_title :: SDoc
msg_title = PprColour -> SDoc -> SDoc
coloured PprColour
msg_colour (SDoc -> SDoc) -> SDoc -> SDoc
forall a b. (a -> b) -> a -> b
$
            case MessageClass
msg_class of
              MCDiagnostic Severity
SevError   ResolvedDiagnosticReason
_ Maybe DiagnosticCode
_ -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"error"
              MCDiagnostic Severity
SevWarning ResolvedDiagnosticReason
_ Maybe DiagnosticCode
_ -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"warning"
              MessageClass
MCFatal                     -> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"fatal"
              MessageClass
_                           -> SDoc
forall doc. IsOutput doc => doc
empty

          warning_flag_doc :: SDoc
warning_flag_doc =
            case MessageClass
msg_class of
              MCDiagnostic Severity
sev ResolvedDiagnosticReason
reason Maybe DiagnosticCode
_code
                | Just SDoc
msg <- Severity -> DiagnosticReason -> Maybe SDoc
flag_msg Severity
sev (ResolvedDiagnosticReason -> DiagnosticReason
resolvedDiagnosticReason ResolvedDiagnosticReason
reason)
                  -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc
brackets SDoc
msg
              MessageClass
_   -> SDoc
forall doc. IsOutput doc => doc
empty

          ppr_with_hyperlink :: DiagnosticCode -> SDoc
ppr_with_hyperlink DiagnosticCode
code =
            -- this is a bit hacky, but we assume that if the terminal supports colors
            -- then it should also support links
            (SDocContext -> Bool) -> (Bool -> SDoc) -> SDoc
forall a. (SDocContext -> a) -> (a -> SDoc) -> SDoc
sdocOption (\ SDocContext
ctx -> SDocContext -> Bool
sdocPrintErrIndexLinks SDocContext
ctx) ((Bool -> SDoc) -> SDoc) -> (Bool -> SDoc) -> SDoc
forall a b. (a -> b) -> a -> b
$
              \ Bool
use_hyperlinks ->
                 if Bool
use_hyperlinks
                 then LinkedDiagCode -> SDoc
forall a. Outputable a => a -> SDoc
ppr (LinkedDiagCode -> SDoc) -> LinkedDiagCode -> SDoc
forall a b. (a -> b) -> a -> b
$ DiagnosticCode -> LinkedDiagCode
LinkedDiagCode DiagnosticCode
code
                 else DiagnosticCode -> SDoc
forall a. Outputable a => a -> SDoc
ppr DiagnosticCode
code

          code_doc :: SDoc
code_doc =
            case MessageClass
msg_class of
              MCDiagnostic Severity
_ ResolvedDiagnosticReason
_ (Just DiagnosticCode
code) -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc
brackets (DiagnosticCode -> SDoc
ppr_with_hyperlink DiagnosticCode
code)
              MessageClass
_                            -> SDoc
forall doc. IsOutput doc => doc
empty

          flag_msg :: Severity -> DiagnosticReason -> Maybe SDoc
          flag_msg :: Severity -> DiagnosticReason -> Maybe SDoc
flag_msg Severity
SevIgnore DiagnosticReason
_                 = Maybe SDoc
forall a. Maybe a
Nothing
            -- The above can happen when displaying an error message
            -- in a log file, e.g. with -ddump-tc-trace. It should not
            -- happen otherwise, though.
          flag_msg Severity
SevError DiagnosticReason
WarningWithoutFlag = SDoc -> Maybe SDoc
forall a. a -> Maybe a
Just (String -> SDoc
col String
"-Werror")
          flag_msg Severity
SevError (WarningWithFlags (WarningFlag
wflag :| [WarningFlag]
_)) =
            let name :: String
name = NonEmpty String -> String
forall a. NonEmpty a -> a
NE.head (WarningFlag -> NonEmpty String
warnFlagNames WarningFlag
wflag) in
            SDoc -> Maybe SDoc
forall a. a -> Maybe a
Just (SDoc -> Maybe SDoc) -> SDoc -> Maybe SDoc
forall a b. (a -> b) -> a -> b
$ String -> SDoc
col (String
"-W" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name) SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> [WarningGroup] -> SDoc
warn_flag_grp (WarningFlag -> [WarningGroup]
smallestWarningGroups WarningFlag
wflag)
                                      SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
comma
                                      SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> String -> SDoc
col (String
"Werror=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name)
          flag_msg Severity
SevError   (WarningWithCategory WarningCategory
cat) =
            SDoc -> Maybe SDoc
forall a. a -> Maybe a
Just (SDoc -> Maybe SDoc) -> SDoc -> Maybe SDoc
forall a b. (a -> b) -> a -> b
$ PprColour -> SDoc -> SDoc
coloured PprColour
msg_colour (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"-W" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> WarningCategory -> SDoc
forall a. Outputable a => a -> SDoc
ppr WarningCategory
cat)
                       SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> [WarningGroup] -> SDoc
warn_flag_grp [WarningGroup]
smallestWarningGroupsForCategory
                       SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
comma
                       SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> PprColour -> SDoc -> SDoc
coloured PprColour
msg_colour (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"-Werror=" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> WarningCategory -> SDoc
forall a. Outputable a => a -> SDoc
ppr WarningCategory
cat)
          flag_msg Severity
SevError   DiagnosticReason
ErrorWithoutFlag   = Maybe SDoc
forall a. Maybe a
Nothing
          flag_msg Severity
SevWarning DiagnosticReason
WarningWithoutFlag = Maybe SDoc
forall a. Maybe a
Nothing
          flag_msg Severity
SevWarning (WarningWithFlags (WarningFlag
wflag :| [WarningFlag]
_)) =
            let name :: String
name = NonEmpty String -> String
forall a. NonEmpty a -> a
NE.head (WarningFlag -> NonEmpty String
warnFlagNames WarningFlag
wflag) in
            SDoc -> Maybe SDoc
forall a. a -> Maybe a
Just (String -> SDoc
col (String
"-W" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name) SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> [WarningGroup] -> SDoc
warn_flag_grp (WarningFlag -> [WarningGroup]
smallestWarningGroups WarningFlag
wflag))
          flag_msg Severity
SevWarning (WarningWithCategory WarningCategory
cat) =
            SDoc -> Maybe SDoc
forall a. a -> Maybe a
Just (PprColour -> SDoc -> SDoc
coloured PprColour
msg_colour (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"-W" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> WarningCategory -> SDoc
forall a. Outputable a => a -> SDoc
ppr WarningCategory
cat)
                      SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> [WarningGroup] -> SDoc
warn_flag_grp [WarningGroup]
smallestWarningGroupsForCategory)
          flag_msg Severity
SevWarning DiagnosticReason
ErrorWithoutFlag =
            String -> SDoc -> Maybe SDoc
forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"SevWarning with ErrorWithoutFlag" (SDoc -> Maybe SDoc) -> SDoc -> Maybe SDoc
forall a b. (a -> b) -> a -> b
$
              [SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat [ String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"locn:" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> SrcSpan -> SDoc
forall a. Outputable a => a -> SDoc
ppr SrcSpan
locn
                   , String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"msg:" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> SDoc -> SDoc
forall a. Outputable a => a -> SDoc
ppr SDoc
msg ]

          warn_flag_grp :: [WarningGroup] -> SDoc
warn_flag_grp [WarningGroup]
groups
              | Bool
show_warn_groups, Bool -> Bool
not ([WarningGroup] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [WarningGroup]
groups)
                          = String -> SDoc
forall doc. IsLine doc => String -> doc
text (String -> SDoc) -> String -> SDoc
forall a b. (a -> b) -> a -> b
$ String
"(in " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " ((WarningGroup -> String) -> [WarningGroup] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ((String
"-W"String -> ShowS
forall a. [a] -> [a] -> [a]
++) ShowS -> (WarningGroup -> String) -> WarningGroup -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WarningGroup -> String
warningGroupName) [WarningGroup]
groups) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"
              | Bool
otherwise = SDoc
forall doc. IsOutput doc => doc
empty

          -- Add prefixes, like    Foo.hs:34: warning:
          --                           <the warning message>
          header :: SDoc
header = SDoc
locn' SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
colon SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+>
                   SDoc
msg_title SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> SDoc
forall doc. IsLine doc => doc
colon SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+>
                   SDoc
code_doc SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> SDoc
warning_flag_doc

      in PprColour -> SDoc -> SDoc
coloured (Scheme -> PprColour
Col.sMessage Scheme
col_scheme)
                  (SDoc -> Int -> SDoc -> SDoc
hang (PprColour -> SDoc -> SDoc
coloured (Scheme -> PprColour
Col.sHeader Scheme
col_scheme) SDoc
header) Int
4
                        SDoc
msg)

getMessageClassColour :: MessageClass -> Col.Scheme -> Col.PprColour
getMessageClassColour :: MessageClass -> Scheme -> PprColour
getMessageClassColour (MCDiagnostic Severity
SevError ResolvedDiagnosticReason
_reason Maybe DiagnosticCode
_code)   = Scheme -> PprColour
Col.sError
getMessageClassColour (MCDiagnostic Severity
SevWarning ResolvedDiagnosticReason
_reason Maybe DiagnosticCode
_code) = Scheme -> PprColour
Col.sWarning
getMessageClassColour MessageClass
MCFatal                                 = Scheme -> PprColour
Col.sFatal
getMessageClassColour MessageClass
_                                       = PprColour -> Scheme -> PprColour
forall a b. a -> b -> a
const PprColour
forall a. Monoid a => a
mempty

getCaretDiagnostic :: MessageClass -> SrcSpan -> IO SDoc
getCaretDiagnostic :: MessageClass -> SrcSpan -> IO SDoc
getCaretDiagnostic MessageClass
_ (UnhelpfulSpan UnhelpfulSpanReason
_) = SDoc -> IO SDoc
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure SDoc
forall doc. IsOutput doc => doc
empty
getCaretDiagnostic MessageClass
msg_class (RealSrcSpan RealSrcSpan
span Maybe BufSpan
_) =
  Maybe String -> SDoc
caretDiagnostic (Maybe String -> SDoc) -> IO (Maybe String) -> IO SDoc
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FastString -> Int -> IO (Maybe String)
getSrcLine (RealSrcSpan -> FastString
srcSpanFile RealSrcSpan
span) Int
row
  where
    getSrcLine :: FastString -> Int -> IO (Maybe String)
getSrcLine FastString
fn Int
i =
      Int -> String -> IO (Maybe String)
getLine Int
i (FastString -> String
unpackFS FastString
fn)
        IO (Maybe String)
-> (IOError -> IO (Maybe String)) -> IO (Maybe String)
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catchException` \(IOError
_ :: IOError) ->
          Maybe String -> IO (Maybe String)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe String
forall a. Maybe a
Nothing

    getLine :: Int -> String -> IO (Maybe String)
getLine Int
i String
fn = do
      -- StringBuffer has advantages over readFile:
      -- (a) no lazy IO, otherwise IO exceptions may occur in pure code
      -- (b) always UTF-8, rather than some system-dependent encoding
      --     (Haskell source code must be UTF-8 anyway)
      content <- String -> IO StringBuffer
hGetStringBuffer String
fn
      case atLine i content of
        Just StringBuffer
at_line -> Maybe String -> IO (Maybe String)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe String -> IO (Maybe String))
-> Maybe String -> IO (Maybe String)
forall a b. (a -> b) -> a -> b
$
          case String -> [String]
lines (Char -> Char
fix (Char -> Char) -> ShowS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StringBuffer -> Int -> String
lexemeToString StringBuffer
at_line (StringBuffer -> Int
len StringBuffer
at_line)) of
            String
srcLine : [String]
_ -> String -> Maybe String
forall a. a -> Maybe a
Just String
srcLine
            [String]
_           -> Maybe String
forall a. Maybe a
Nothing
        Maybe StringBuffer
_ -> Maybe String -> IO (Maybe String)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe String
forall a. Maybe a
Nothing

    -- allow user to visibly see that their code is incorrectly encoded
    -- (StringBuffer.nextChar uses \0 to represent undecodable characters)
    fix :: Char -> Char
fix Char
'\0' = Char
'\xfffd'
    fix Char
c    = Char
c

    row :: Int
row = RealSrcSpan -> Int
srcSpanStartLine RealSrcSpan
span
    rowStr :: String
rowStr = Int -> String
forall a. Show a => a -> String
show Int
row
    multiline :: Bool
multiline = Int
row Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= RealSrcSpan -> Int
srcSpanEndLine RealSrcSpan
span

    caretDiagnostic :: Maybe String -> SDoc
caretDiagnostic Maybe String
Nothing = SDoc
forall doc. IsOutput doc => doc
empty
    caretDiagnostic (Just String
srcLineWithNewline) =
      (SDocContext -> Scheme) -> (Scheme -> SDoc) -> SDoc
forall a. (SDocContext -> a) -> (a -> SDoc) -> SDoc
sdocOption SDocContext -> Scheme
sdocColScheme((Scheme -> SDoc) -> SDoc) -> (Scheme -> SDoc) -> SDoc
forall a b. (a -> b) -> a -> b
$ \Scheme
col_scheme ->
      let sevColour :: PprColour
sevColour = MessageClass -> Scheme -> PprColour
getMessageClassColour MessageClass
msg_class Scheme
col_scheme
          marginColour :: PprColour
marginColour = Scheme -> PprColour
Col.sMargin Scheme
col_scheme
      in
      PprColour -> SDoc -> SDoc
coloured PprColour
marginColour (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
marginSpace) SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<>
      String -> SDoc
forall doc. IsLine doc => String -> doc
text (String
"\n") SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<>
      PprColour -> SDoc -> SDoc
coloured PprColour
marginColour (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
marginRow) SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<>
      String -> SDoc
forall doc. IsLine doc => String -> doc
text (String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
srcLinePre) SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<>
      PprColour -> SDoc -> SDoc
coloured PprColour
sevColour (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
srcLineSpan) SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<>
      String -> SDoc
forall doc. IsLine doc => String -> doc
text (String
srcLinePost String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"\n") SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<>
      PprColour -> SDoc -> SDoc
coloured PprColour
marginColour (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
marginSpace) SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<>
      PprColour -> SDoc -> SDoc
coloured PprColour
sevColour (String -> SDoc
forall doc. IsLine doc => String -> doc
text (String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
caretLine))

      where

        -- expand tabs in a device-independent manner #13664
        expandTabs :: Int -> Int -> ShowS
expandTabs Int
tabWidth Int
i String
s =
          case String
s of
            String
""        -> String
""
            Char
'\t' : String
cs -> Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
effectiveWidth Char
' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++
                         Int -> Int -> ShowS
expandTabs Int
tabWidth (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
effectiveWidth) String
cs
            Char
c    : String
cs -> Char
c Char -> ShowS
forall a. a -> [a] -> [a]
: Int -> Int -> ShowS
expandTabs Int
tabWidth (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) String
cs
          where effectiveWidth :: Int
effectiveWidth = Int
tabWidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
tabWidth

        srcLine :: String
srcLine = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\n') (Int -> Int -> ShowS
expandTabs Int
8 Int
0 String
srcLineWithNewline)

        start :: Int
start = RealSrcSpan -> Int
srcSpanStartCol RealSrcSpan
span Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
        end :: Int
end | Bool
multiline = String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
srcLine
            | Bool
otherwise = RealSrcSpan -> Int
srcSpanEndCol RealSrcSpan
span Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
        width :: Int
width = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Int
end Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
start)

        marginWidth :: Int
marginWidth = String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
rowStr
        marginSpace :: String
marginSpace = Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
marginWidth Char
' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" |"
        marginRow :: String
marginRow   = String
rowStr String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" |"

        (String
srcLinePre,  String
srcLineRest) = Int -> String -> (String, String)
forall a. Int -> [a] -> ([a], [a])
splitAt Int
start String
srcLine
        (String
srcLineSpan, String
srcLinePost) = Int -> String -> (String, String)
forall a. Int -> [a] -> ([a], [a])
splitAt Int
width String
srcLineRest

        caretEllipsis :: String
caretEllipsis | Bool
multiline = String
"..."
                      | Bool
otherwise = String
""
        caretLine :: String
caretLine = Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
start Char
' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
width Char
'^' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
caretEllipsis

--
-- Queries
--

{- Note [Intrinsic And Extrinsic Failures]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We distinguish between /intrinsic/ and /extrinsic/ failures. We classify in
the former category those diagnostics which are /essentially/ failures, and
their nature can't be changed. This is the case for 'ErrorWithoutFlag'. We
classify as /extrinsic/ all those diagnostics (like fatal warnings) which are
born as warnings but which are still failures under particular 'DynFlags'
settings. It's important to be aware of such logic distinction, because when
we are inside the typechecker or the desugarer, we are interested about
intrinsic errors, and to bail out as soon as we find one of them. Conversely,
if we find an /extrinsic/ one, for example because a particular 'WarningFlag'
makes a warning into an error, we /don't/ want to bail out, that's still not the
right time to do so: Rather, we want to first collect all the diagnostics, and
later classify and report them appropriately (in the driver).
-}

-- | Returns 'True' if this is, intrinsically, a failure. See
-- Note [Intrinsic And Extrinsic Failures].
isIntrinsicErrorMessage :: Diagnostic e => MsgEnvelope e -> Bool
isIntrinsicErrorMessage :: forall e. Diagnostic e => MsgEnvelope e -> Bool
isIntrinsicErrorMessage = DiagnosticReason -> DiagnosticReason -> Bool
forall a. Eq a => a -> a -> Bool
(==) DiagnosticReason
ErrorWithoutFlag (DiagnosticReason -> Bool)
-> (MsgEnvelope e -> DiagnosticReason) -> MsgEnvelope e -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ResolvedDiagnosticReason -> DiagnosticReason
resolvedDiagnosticReason (ResolvedDiagnosticReason -> DiagnosticReason)
-> (MsgEnvelope e -> ResolvedDiagnosticReason)
-> MsgEnvelope e
-> DiagnosticReason
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MsgEnvelope e -> ResolvedDiagnosticReason
forall e. MsgEnvelope e -> ResolvedDiagnosticReason
errMsgReason

isWarningMessage :: Diagnostic e => MsgEnvelope e -> Bool
isWarningMessage :: forall e. Diagnostic e => MsgEnvelope e -> Bool
isWarningMessage = Bool -> Bool
not (Bool -> Bool) -> (MsgEnvelope e -> Bool) -> MsgEnvelope e -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MsgEnvelope e -> Bool
forall e. Diagnostic e => MsgEnvelope e -> Bool
isIntrinsicErrorMessage

-- | Are there any hard errors here? -Werror warnings are /not/ detected. If
-- you want to check for -Werror warnings, use 'errorsOrFatalWarningsFound'.
errorsFound :: Diagnostic e => Messages e -> Bool
errorsFound :: forall e. Diagnostic e => Messages e -> Bool
errorsFound (Messages Bag (MsgEnvelope e)
msgs) = (MsgEnvelope e -> Bool) -> Bag (MsgEnvelope e) -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any MsgEnvelope e -> Bool
forall e. Diagnostic e => MsgEnvelope e -> Bool
isIntrinsicErrorMessage Bag (MsgEnvelope e)
msgs

-- | Returns 'True' if the envelope contains a message that will stop
-- compilation: either an intrinsic error or a fatal (-Werror) warning
isExtrinsicErrorMessage :: MsgEnvelope e -> Bool
isExtrinsicErrorMessage :: forall e. MsgEnvelope e -> Bool
isExtrinsicErrorMessage = Severity -> Severity -> Bool
forall a. Eq a => a -> a -> Bool
(==) Severity
SevError (Severity -> Bool)
-> (MsgEnvelope e -> Severity) -> MsgEnvelope e -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MsgEnvelope e -> Severity
forall e. MsgEnvelope e -> Severity
errMsgSeverity

-- | Are there any errors or -Werror warnings here?
errorsOrFatalWarningsFound :: Messages e -> Bool
errorsOrFatalWarningsFound :: forall a. Messages a -> Bool
errorsOrFatalWarningsFound (Messages Bag (MsgEnvelope e)
msgs) = (MsgEnvelope e -> Bool) -> Bag (MsgEnvelope e) -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any MsgEnvelope e -> Bool
forall e. MsgEnvelope e -> Bool
isExtrinsicErrorMessage Bag (MsgEnvelope e)
msgs

getWarningMessages :: Diagnostic e => Messages e -> Bag (MsgEnvelope e)
getWarningMessages :: forall e. Diagnostic e => Messages e -> Bag (MsgEnvelope e)
getWarningMessages (Messages Bag (MsgEnvelope e)
xs) = (Bag (MsgEnvelope e), Bag (MsgEnvelope e)) -> Bag (MsgEnvelope e)
forall a b. (a, b) -> a
fst ((Bag (MsgEnvelope e), Bag (MsgEnvelope e)) -> Bag (MsgEnvelope e))
-> (Bag (MsgEnvelope e), Bag (MsgEnvelope e))
-> Bag (MsgEnvelope e)
forall a b. (a -> b) -> a -> b
$ (MsgEnvelope e -> Bool)
-> Bag (MsgEnvelope e)
-> (Bag (MsgEnvelope e), Bag (MsgEnvelope e))
forall a. (a -> Bool) -> Bag a -> (Bag a, Bag a)
partitionBag MsgEnvelope e -> Bool
forall e. Diagnostic e => MsgEnvelope e -> Bool
isWarningMessage Bag (MsgEnvelope e)
xs

getErrorMessages :: Diagnostic e => Messages e -> Bag (MsgEnvelope e)
getErrorMessages :: forall e. Diagnostic e => Messages e -> Bag (MsgEnvelope e)
getErrorMessages (Messages Bag (MsgEnvelope e)
xs) = (Bag (MsgEnvelope e), Bag (MsgEnvelope e)) -> Bag (MsgEnvelope e)
forall a b. (a, b) -> a
fst ((Bag (MsgEnvelope e), Bag (MsgEnvelope e)) -> Bag (MsgEnvelope e))
-> (Bag (MsgEnvelope e), Bag (MsgEnvelope e))
-> Bag (MsgEnvelope e)
forall a b. (a -> b) -> a -> b
$ (MsgEnvelope e -> Bool)
-> Bag (MsgEnvelope e)
-> (Bag (MsgEnvelope e), Bag (MsgEnvelope e))
forall a. (a -> Bool) -> Bag a -> (Bag a, Bag a)
partitionBag MsgEnvelope e -> Bool
forall e. Diagnostic e => MsgEnvelope e -> Bool
isIntrinsicErrorMessage Bag (MsgEnvelope e)
xs

-- | Partitions the 'Messages' and returns a tuple which first element are the
-- warnings, and the second the errors.
partitionMessages :: Diagnostic e => Messages e -> (Messages e, Messages e)
partitionMessages :: forall e. Diagnostic e => Messages e -> (Messages e, Messages e)
partitionMessages (Messages Bag (MsgEnvelope e)
xs) = (Bag (MsgEnvelope e) -> Messages e)
-> (Bag (MsgEnvelope e) -> Messages e)
-> (Bag (MsgEnvelope e), Bag (MsgEnvelope e))
-> (Messages e, Messages e)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap Bag (MsgEnvelope e) -> Messages e
forall e. Bag (MsgEnvelope e) -> Messages e
Messages Bag (MsgEnvelope e) -> Messages e
forall e. Bag (MsgEnvelope e) -> Messages e
Messages ((MsgEnvelope e -> Bool)
-> Bag (MsgEnvelope e)
-> (Bag (MsgEnvelope e), Bag (MsgEnvelope e))
forall a. (a -> Bool) -> Bag a -> (Bag a, Bag a)
partitionBag MsgEnvelope e -> Bool
forall e. Diagnostic e => MsgEnvelope e -> Bool
isWarningMessage Bag (MsgEnvelope e)
xs)

----------------------------------------------------------------
--                                                            --
-- Definition of diagnostic codes                             --
--                                                            --
----------------------------------------------------------------

-- | A diagnostic code is a namespaced numeric identifier
-- unique to the given diagnostic (error or warning).
--
-- All diagnostic codes defined within GHC are given the
-- GHC namespace.
--
-- See Note [Diagnostic codes] in GHC.Types.Error.Codes.
data DiagnosticCode =
  DiagnosticCode
    { DiagnosticCode -> String
diagnosticCodeNameSpace :: String
        -- ^ diagnostic code prefix (e.g. "GHC")
    , DiagnosticCode -> Natural
diagnosticCodeNumber    :: Natural
        -- ^ the actual diagnostic code
    }
  deriving ( DiagnosticCode -> DiagnosticCode -> Bool
(DiagnosticCode -> DiagnosticCode -> Bool)
-> (DiagnosticCode -> DiagnosticCode -> Bool) -> Eq DiagnosticCode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DiagnosticCode -> DiagnosticCode -> Bool
== :: DiagnosticCode -> DiagnosticCode -> Bool
$c/= :: DiagnosticCode -> DiagnosticCode -> Bool
/= :: DiagnosticCode -> DiagnosticCode -> Bool
Eq, Eq DiagnosticCode
Eq DiagnosticCode =>
(DiagnosticCode -> DiagnosticCode -> Ordering)
-> (DiagnosticCode -> DiagnosticCode -> Bool)
-> (DiagnosticCode -> DiagnosticCode -> Bool)
-> (DiagnosticCode -> DiagnosticCode -> Bool)
-> (DiagnosticCode -> DiagnosticCode -> Bool)
-> (DiagnosticCode -> DiagnosticCode -> DiagnosticCode)
-> (DiagnosticCode -> DiagnosticCode -> DiagnosticCode)
-> Ord DiagnosticCode
DiagnosticCode -> DiagnosticCode -> Bool
DiagnosticCode -> DiagnosticCode -> Ordering
DiagnosticCode -> DiagnosticCode -> DiagnosticCode
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: DiagnosticCode -> DiagnosticCode -> Ordering
compare :: DiagnosticCode -> DiagnosticCode -> Ordering
$c< :: DiagnosticCode -> DiagnosticCode -> Bool
< :: DiagnosticCode -> DiagnosticCode -> Bool
$c<= :: DiagnosticCode -> DiagnosticCode -> Bool
<= :: DiagnosticCode -> DiagnosticCode -> Bool
$c> :: DiagnosticCode -> DiagnosticCode -> Bool
> :: DiagnosticCode -> DiagnosticCode -> Bool
$c>= :: DiagnosticCode -> DiagnosticCode -> Bool
>= :: DiagnosticCode -> DiagnosticCode -> Bool
$cmax :: DiagnosticCode -> DiagnosticCode -> DiagnosticCode
max :: DiagnosticCode -> DiagnosticCode -> DiagnosticCode
$cmin :: DiagnosticCode -> DiagnosticCode -> DiagnosticCode
min :: DiagnosticCode -> DiagnosticCode -> DiagnosticCode
Ord )

instance Show DiagnosticCode where
  show :: DiagnosticCode -> String
show (DiagnosticCode String
prefix Natural
c) =
    String
prefix String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"-" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> Natural -> String
forall r. PrintfType r => String -> r
printf String
"%05d" Natural
c
      -- pad the numeric code to have at least 5 digits

instance Outputable DiagnosticCode where
  ppr :: DiagnosticCode -> SDoc
ppr DiagnosticCode
code = String -> SDoc
forall doc. IsLine doc => String -> doc
text (DiagnosticCode -> String
forall a. Show a => a -> String
show DiagnosticCode
code)

-- | A newtype that is a witness to the `-fprint-error-index-links` flag. It
-- alters the @Outputable@ instance to emit @DiagnosticCode@ as ANSI hyperlinks
-- to the HF error index
newtype LinkedDiagCode = LinkedDiagCode DiagnosticCode

instance Outputable LinkedDiagCode where
  ppr :: LinkedDiagCode -> SDoc
ppr (LinkedDiagCode d :: DiagnosticCode
d@DiagnosticCode{}) = DiagnosticCode -> SDoc
linkEscapeCode DiagnosticCode
d

-- | Wrap the link in terminal escape codes specified by OSC 8.
linkEscapeCode :: DiagnosticCode -> SDoc
linkEscapeCode :: DiagnosticCode -> SDoc
linkEscapeCode DiagnosticCode
d = String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"\ESC]8;;" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> DiagnosticCode -> SDoc
hfErrorLink DiagnosticCode
d -- make the actual link
                   SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"\ESC\\" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> DiagnosticCode -> SDoc
forall a. Outputable a => a -> SDoc
ppr DiagnosticCode
d SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"\ESC]8;;\ESC\\" -- the rest is the visible text

-- | create a link to the HF error index given an error code.
hfErrorLink :: DiagnosticCode -> SDoc
hfErrorLink :: DiagnosticCode -> SDoc
hfErrorLink DiagnosticCode
errorCode = String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"https://errors.haskell.org/messages/" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<> DiagnosticCode -> SDoc
forall a. Outputable a => a -> SDoc
ppr DiagnosticCode
errorCode