/libraries/ghc-prim/GHC/Prim/Panic.hs
https://github.com/bgamari/ghc · Haskell · 103 lines · 25 code · 10 blank · 68 comment · 2 complexity · 5aad88da44b65d8ddf5b27cd1ff45ac9 MD5 · raw file
- {-# 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)