content: {-# LANGUAGE CPP #-}
  {-# LANGUAGE QuasiQuotes #-}
  
  module Clash.GHC.Util
    ( module Clash.GHC.Util
  #if MIN_VERSION_ghc(9,2,0)
    , module X
  #endif
    )
  where
  
  #if MIN_VERSION_ghc(9,8,0)
  import GHC.Driver.Errors.Types (GhcMessage(GhcUnknownMessage))
  import GHC.Utils.Outputable as X (showPprUnsafe, showSDocUnsafe)
  import GHC.Utils.Outputable (SDoc, neverQualify)
  import GHC.Utils.Error (mkErrorMsgEnvelope, mkPlainError)
  import GHC.Plugins
    (DynFlags, SourceError, ($$), blankLine, empty, isGoodSrcSpan, liftIO,
     noSrcSpan, text, throwOneError)
  import GHC.Types.Error (mkSimpleUnknownDiagnostic)
  #elif MIN_VERSION_ghc(9,6,0)
  import GHC.Driver.Errors.Types (GhcMessage(GhcUnknownMessage))
  import GHC.Utils.Outputable as X (showPprUnsafe, showSDocUnsafe)
  import GHC.Utils.Outputable (SDoc, neverQualify)
  import GHC.Utils.Error (mkErrorMsgEnvelope, mkPlainError)
  import GHC.Plugins
    (DynFlags, SourceError, ($$), blankLine, empty, isGoodSrcSpan, liftIO,
     noSrcSpan, text, throwOneError)
  import GHC.Types.Error (UnknownDiagnostic(..))
  #elif MIN_VERSION_ghc(9,4,0)
  import GHC.Driver.Errors.Types (GhcMessage(GhcUnknownMessage))
  import GHC.Utils.Outputable as X (showPprUnsafe, showSDocUnsafe)
  import GHC.Utils.Outputable (SDoc, neverQualify)
  import GHC.Utils.Error (mkErrorMsgEnvelope, mkPlainError)
  import GHC.Plugins
    (DynFlags, SourceError, ($$), blankLine, empty, isGoodSrcSpan, liftIO,
     noSrcSpan, text, throwOneError)
  #elif MIN_VERSION_ghc(9,2,0)
  import GHC.Utils.Outputable as X (showPprUnsafe, showSDocUnsafe)
  import GHC.Utils.Outputable (SDoc, neverQualify)
  import GHC.Utils.Error (mkMsgEnvelope)
  import GHC.Plugins
    (DynFlags, SourceError, ($$), blankLine, empty, isGoodSrcSpan, liftIO,
     noSrcSpan, text, throwOneError)
  #elif MIN_VERSION_ghc(9,0,0)
  import GHC.Driver.Session (unsafeGlobalDynFlags)
  import GHC.Utils.Outputable (Outputable, SDoc, showPpr, showSDoc)
  import GHC.Utils.Error (mkPlainErrMsg)
  import GHC.Plugins
    (DynFlags, SourceError, ($$), blankLine, empty, isGoodSrcSpan, liftIO,
     noSrcSpan, text, throwOneError)
  #else
  import DynFlags           (unsafeGlobalDynFlags)
  import Outputable         (Outputable, SDoc, showPpr, showSDoc)
  import ErrUtils           (mkPlainErrMsg)
  import GhcPlugins         (DynFlags, SourceError, ($$), blankLine, empty, isGoodSrcSpan, liftIO, noSrcSpan, text, throwOneError)
  #endif
  import GHC                (GhcMonad(..), printException)
  
  import Control.Exception  (Exception(..), ErrorCall(..))
  import GHC.Exception      (SomeException)
  import System.Exit        (ExitCode(ExitFailure), exitWith)
  
  import Clash.Util         (ClashException(..))
  import Clash.Util.Interpolate (i)
  import Clash.Driver.Types (ClashOpts(..))
  
  -- | Like 'lines', but returning a horizontally spaced SDoc instead of a list:
  --
  -- >>> textLines "a\nb"
  -- a $$ b
  textLines :: String -> SDoc
  textLines s = foldl1 ($$) (map text (lines s))
  
  handleClashException
    :: GhcMonad m
    => DynFlags
    -> ClashOpts
    -> SomeException
    -> m a
  #if MIN_VERSION_ghc(9,2,0)
  handleClashException _df opts e = case fromException e of
  #else
  handleClashException df opts e = case fromException e of
  #endif
    Just (ClashException sp s eM) -> do
      let srcInfo' | isGoodSrcSpan sp = srcInfo
                   | otherwise = empty
      throwOneError
  #if MIN_VERSION_ghc(9,8,0)
        (mkErrorMsgEnvelope sp neverQualify $ GhcUnknownMessage $ mkSimpleUnknownDiagnostic $ mkPlainError []
  #elif MIN_VERSION_ghc(9,6,0)
        (mkErrorMsgEnvelope sp neverQualify $ GhcUnknownMessage $ UnknownDiagnostic $ mkPlainError []
  #elif MIN_VERSION_ghc(9,4,0)
        (mkErrorMsgEnvelope sp neverQualify $ GhcUnknownMessage $ mkPlainError []
  #elif MIN_VERSION_ghc(9,2,0)
        (mkMsgEnvelope sp neverQualify
  #else
        (mkPlainErrMsg df sp
  #endif
          (blankLine $$ textLines s $$ blankLine $$ srcInfo' $$ showExtra (opt_errorExtra opts) eM))
    _ -> case fromException e of
      Just (ErrorCallWithLocation _ _) ->
        throwOneError
  #if MIN_VERSION_ghc(9,8,0)
          (mkErrorMsgEnvelope noSrcSpan neverQualify $ GhcUnknownMessage $ mkSimpleUnknownDiagnostic $ mkPlainError []
  #elif MIN_VERSION_ghc(9,6,0)
          (mkErrorMsgEnvelope noSrcSpan neverQualify $ GhcUnknownMessage $ UnknownDiagnostic $ mkPlainError []
  #elif MIN_VERSION_ghc(9,4,0)
          (mkErrorMsgEnvelope noSrcSpan neverQualify $ GhcUnknownMessage $ mkPlainError []
  #elif MIN_VERSION_ghc(9,2,0)
          (mkMsgEnvelope noSrcSpan neverQualify
  #else
          (mkPlainErrMsg df noSrcSpan
  #endif
          (text "Clash error call:" $$ textLines (show e)))
      _ -> case fromException e of
        Just (e' :: SourceError) -> do
          GHC.printException e'
          liftIO $ exitWith (ExitFailure 1)
        _ -> throwOneError
  #if MIN_VERSION_ghc(9,8,0)
                (mkErrorMsgEnvelope noSrcSpan neverQualify $ GhcUnknownMessage $ mkSimpleUnknownDiagnostic $ mkPlainError []
  #elif MIN_VERSION_ghc(9,6,0)
                (mkErrorMsgEnvelope noSrcSpan neverQualify $ GhcUnknownMessage $ UnknownDiagnostic $ mkPlainError []
  #elif MIN_VERSION_ghc(9,4,0)
                (mkErrorMsgEnvelope noSrcSpan neverQualify $ GhcUnknownMessage  $ mkPlainError []
  #elif MIN_VERSION_ghc(9,2,0)
                (mkMsgEnvelope noSrcSpan neverQualify
  #else
                (mkPlainErrMsg df noSrcSpan
  #endif
                (text "Other error:" $$ textLines (displayException e)))
    where
      srcInfo = textLines [i|
        The source location of the error is not exact, only indicative, as it
        is acquired after optimizations. The actual location of the error can be
        in a function that is inlined. To prevent inlining of those functions,
        annotate them with a NOINLINE pragma.
      |]
  
      showExtra False (Just _)   =
        blankLine $$
        text "This error contains additional information, rerun with '-fclash-error-extra' to show this information."
      showExtra True  (Just msg) =
        blankLine $$
        text "Additional information:" $$ blankLine $$
        textLines msg
      showExtra _ _ = empty
  
  #if !MIN_VERSION_ghc(9,2,0)
  showPprUnsafe :: Outputable a => a -> String
  showPprUnsafe = showPpr unsafeGlobalDynFlags
  
  showSDocUnsafe :: SDoc -> String
  showSDocUnsafe = showSDoc unsafeGlobalDynFlags
  #endif
  