{-# LANGUAGE GHCForeignImportPrim #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE EmptyCase #-}

-- | Primitive panics.
module GHC.Prim.Panic
   ( absentSumFieldError
   , panicError
   , absentError
   )
where

import GHC.Prim
import GHC.Magic

default () -- Double and Integer aren't available yet

{-
Note [Compiler error functions]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Most error functions (such as pattern match failure) are defined
in base:Control.Exception.Base.  But absentError# and absentSumFieldError#
are defined here in the ghc-prim package for two reasons:

* GHC itself generates calls to these functions as a result of
  strictness analysis, over which the programmer has no control. So
  it is hard to ensure that no such calls exist in the modules
  compiled "before" Control.Base.Exception.  (E.g. when compiling
  with -fdicts-strict.)

* A consequence of defining them in ghc-prim is that the libraries
  defining exceptions have not yet been built, so we can't make them
  into proper Haskell exceptions.

  However, if these functions are ever called, it's a /compiler/ error,
  not a user error, so it seems acceptable that they cannot be caught.

One might wonder why absentError doesn't just call panic#.
For absent error we want to combine two parts, one static, one call site
dependent into one error message. While for absentSumFieldError it's a
static string.

The easiest way to combine the two parts for absentError is to use a
format string with `barf` in the RTS passing the *dynamic* part of the
error as argument. There is no need to do any of this for
absentSumFieldError as it's a static string there.

The alternatives would be to:
* Drop the call site specific information from absentError.
  The call site specific information is at times very helpful for debugging
  so I don't consider this an option.
* Remove the common prefix. We would then need to include the prefix
  in the call site specific string we pass to absentError. Increasing
  code size for no good reason.

Both of which seem worse than having an stg_absentError function specific to
absentError to me.
-}

-- `stg_panic#` never returns but it can't just return `State# RealWorld` so we
-- indicate that it returns `(# #)` too to make the compiler happy.
-- See Note [Compiler error functions]
foreign import prim "stg_paniczh" panic# :: Addr# -> State# RealWorld -> (# State# RealWorld, (# #) #)

-- See Note [Compiler error functions]
foreign import prim "stg_absentErrorzh" stg_absentError# :: Addr# -> State# RealWorld -> (# State# RealWorld, (# #) #)

-- | Display the CString whose address is given as an argument and exit.
panicError :: Addr# -> a
panicError errmsg =
  runRW# (\s ->
    case panic# errmsg s of
      (# _, _ #) -> -- This bottom is unreachable but we can't
                    -- use an empty case lest the pattern match
                    -- checker squawks.
                    let x = x in x)

-- | Closure introduced by GHC.Stg.Unarise for unused unboxed sum fields.
--
-- See Note [aBSENT_SUM_FIELD_ERROR_ID] in GHC.Core.Make
absentSumFieldError :: a
absentSumFieldError = panicError "entered absent sum field!"#

-- GHC.Core.Make.aBSENT_SUM_FIELD_ERROR_ID gives absentSumFieldError a bottoming
-- demand signature. But if we ever inlined it (to a call to panicError) we'd
-- lose that information.  Should not happen because absentSumFieldError is only
-- introduced in Stg.Unarise, long after inlining has stopped, but it seems
-- more direct simply to give it a NOINLINE pragma
{-# NOINLINE absentSumFieldError #-}

-- | Displays "Oops!  Entered absent arg" ++ errormsg and exits the program.
{-# NOINLINE absentError #-}
absentError :: Addr# -> a
absentError errmsg =
  runRW# (\s ->
    case stg_absentError# errmsg s of
      (# _, _ #) -> -- This bottom is unreachable but we can't
                    -- use an empty case lest the pattern match
                    -- checker squawks.
                    let x = x in x)
