{-# LANGUAGE ConstraintKinds   #-}
{-# LANGUAGE ImplicitParams    #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE PolyKinds         #-}
{-# LANGUAGE RankNTypes        #-}
{-# LANGUAGE Trustworthy       #-}

{-# OPTIONS_HADDOCK not-home #-}
-- we hide this module from haddock to enforce GHC.Internal.Stack as the main
-- access point.

-----------------------------------------------------------------------------
-- |
-- Module      :  GHC.Internal.Stack.Types
-- Copyright   :  (c) The University of Glasgow 2015
-- License     :  see libraries/ghc-prim/LICENSE
--
-- Maintainer  :  ghc-devs@haskell.org
-- Stability   :  internal
-- Portability :  non-portable (GHC Extensions)
--
-- Type definitions for implicit call-stacks.
-- Use "GHC.Stack" from the base package instead of importing this
-- module directly.
--
-- /The API of this module is unstable and not meant to be consumed by the general public./
-- If you absolutely must depend on it, make sure to use a tight upper
-- bound, e.g., @base < 4.X@ rather than @base < 5@, because the interface can
-- change rapidly without much warning.
--
-----------------------------------------------------------------------------

module GHC.Internal.Stack.Types (
    -- * Implicit call stacks
    CallStack(..), HasCallStack,
    emptyCallStack, freezeCallStack, fromCallSiteList,
    getCallStack, pushCallStack,

    -- * Source locations
    SrcLoc(..)
  ) where

{-
Ideally these would live in GHC.Internal.Stack but sadly they can't due to this
import cycle,

    Module imports form a cycle:
           module ‘GHC.Base’ (libraries/base/GHC/Base.hs)
          imports ‘GHC.Err’ (libraries/base/GHC/Err.hs)
    which imports ‘GHC.Stack’ (libraries/base/dist-install/build/GHC/Stack.hs)
    which imports ‘GHC.Base‘ (libraries/base/GHC/Base.hs)
-}

import GHC.Classes (Eq)
import GHC.Types (Char, Int)

default ()

-- $setup
-- >>> import Prelude
-- >>> import GHC.Internal.Stack (prettyCallStack, callStack)

----------------------------------------------------------------------
-- Explicit call-stacks built via ImplicitParams
----------------------------------------------------------------------

-- | Request a CallStack.
--
-- NOTE: The implicit parameter @?callStack :: CallStack@ is an
-- implementation detail and __should not__ be considered part of the
-- 'CallStack' API, we may decide to change the implementation in the
-- future.
--
-- @since base-4.9.0.0
type HasCallStack = (?callStack :: CallStack)

-- | 'CallStack's are a lightweight method of obtaining a
-- partial call-stack at any point in the program.
--
-- A function can request its call-site with the 'HasCallStack' constraint.
-- For example, we can define
--
-- @
-- putStrLnWithCallStack :: HasCallStack => String -> IO ()
-- @
--
-- as a variant of @putStrLn@ that will get its call-site and print it,
-- along with the string given as argument. We can access the
-- call-stack inside @putStrLnWithCallStack@ with 'GHC.Internal.Stack.callStack'.
--
-- >>> :{
-- putStrLnWithCallStack :: HasCallStack => String -> IO ()
-- putStrLnWithCallStack msg = do
--   putStrLn msg
--   putStrLn (prettyCallStack callStack)
-- :}
--
-- Thus, if we call @putStrLnWithCallStack@ we will get a formatted call-stack
-- alongside our string.
--
--
-- >>> putStrLnWithCallStack "hello"
-- hello
-- CallStack (from HasCallStack):
--   putStrLnWithCallStack, called at <interactive>:... in interactive:Ghci...
--
--
-- GHC solves 'HasCallStack' constraints in three steps:
--
-- 1. If there is a 'CallStack' in scope -- i.e. the enclosing function
--    has a 'HasCallStack' constraint -- GHC will append the new
--    call-site to the existing 'CallStack'.
--
-- 2. If there is no 'CallStack' in scope -- e.g. in the GHCi session
--    above -- and the enclosing definition does not have an explicit
--    type signature, GHC will infer a 'HasCallStack' constraint for the
--    enclosing definition (subject to the monomorphism restriction).
--
-- 3. If there is no 'CallStack' in scope and the enclosing definition
--    has an explicit type signature, GHC will solve the 'HasCallStack'
--    constraint for the singleton 'CallStack' containing just the
--    current call-site.
--
-- 'CallStack's do not interact with the RTS and do not require compilation
-- with @-prof@. On the other hand, as they are built up explicitly via the
-- 'HasCallStack' constraints, they will generally not contain as much
-- information as the simulated call-stacks maintained by the RTS.
--
-- A 'CallStack' is a @[(String, SrcLoc)]@. The @String@ is the name of
-- function that was called, the 'SrcLoc' is the call-site. The list is
-- ordered with the most recently called function at the head.
--
-- NOTE: The intrepid user may notice that 'HasCallStack' is just an
-- alias for an implicit parameter @?callStack :: CallStack@. This is an
-- implementation detail and __should not__ be considered part of the
-- 'CallStack' API, we may decide to change the implementation in the
-- future.
--
-- @since base-4.8.1.0
data CallStack
  = EmptyCallStack
  | PushCallStack [Char] SrcLoc CallStack
  | FreezeCallStack CallStack
    -- ^ Freeze the stack at the given @CallStack@, preventing any further
    -- call-sites from being pushed onto it.

  -- See Note [Overview of implicit CallStacks]

-- | Extract a list of call-sites from the 'CallStack'.
--
-- The list is ordered by most recent call.
--
-- @since base-4.8.1.0
getCallStack :: CallStack -> [([Char], SrcLoc)]
getCallStack :: CallStack -> [([Char], SrcLoc)]
getCallStack CallStack
stk = case CallStack
stk of
  CallStack
EmptyCallStack            -> []
  PushCallStack [Char]
fn SrcLoc
loc CallStack
stk' -> ([Char]
fn,SrcLoc
loc) ([Char], SrcLoc) -> [([Char], SrcLoc)] -> [([Char], SrcLoc)]
forall a. a -> [a] -> [a]
: CallStack -> [([Char], SrcLoc)]
getCallStack CallStack
stk'
  FreezeCallStack CallStack
stk'      -> CallStack -> [([Char], SrcLoc)]
getCallStack CallStack
stk'

-- | Convert a list of call-sites to a 'CallStack'.
--
-- @since base-4.9.0.0
fromCallSiteList :: [([Char], SrcLoc)] -> CallStack
fromCallSiteList :: [([Char], SrcLoc)] -> CallStack
fromCallSiteList (([Char]
fn,SrcLoc
loc):[([Char], SrcLoc)]
cs) = [Char] -> SrcLoc -> CallStack -> CallStack
PushCallStack [Char]
fn SrcLoc
loc ([([Char], SrcLoc)] -> CallStack
fromCallSiteList [([Char], SrcLoc)]
cs)
fromCallSiteList []            = CallStack
EmptyCallStack

-- Note [Definition of CallStack]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- CallStack is defined very early in base because it is
-- used by error and undefined. At this point in the dependency graph,
-- we do not have enough functionality to (conveniently) write a nice
-- pretty-printer for CallStack. The sensible place to define the
-- pretty-printer would be GHC.Stack, which is the main access point,
-- but unfortunately GHC.Internal.Stack imports GHC.Exception, which *needs*
-- the pretty-printer. So the CallStack type and functions are split
-- between three modules:
--
-- 1. GHC.Internal.Stack.Types: defines the type and *simple* functions
-- 2. GHC.Internal.Exception: defines the pretty-printer
-- 3. GHC.Internal.Stack: exports everything and acts as the main access point


-- | Push a call-site onto the stack.
--
-- This function has no effect on a frozen 'CallStack'.
--
-- @since base-4.9.0.0
pushCallStack :: ([Char], SrcLoc) -> CallStack -> CallStack
pushCallStack :: ([Char], SrcLoc) -> CallStack -> CallStack
pushCallStack ([Char]
fn, SrcLoc
loc) CallStack
stk = case CallStack
stk of
  FreezeCallStack CallStack
_ -> CallStack
stk
  CallStack
_                 -> [Char] -> SrcLoc -> CallStack -> CallStack
PushCallStack [Char]
fn SrcLoc
loc CallStack
stk
{-# INLINE pushCallStack #-}


-- | The empty 'CallStack'.
--
-- @since base-4.9.0.0
emptyCallStack :: CallStack
emptyCallStack :: CallStack
emptyCallStack = CallStack
EmptyCallStack
{-# INLINE emptyCallStack #-}


-- | Freeze a call-stack, preventing any further call-sites from being appended.
--
-- prop> pushCallStack callSite (freezeCallStack callStack) = freezeCallStack callStack
--
-- @since base-4.9.0.0
freezeCallStack :: CallStack -> CallStack
freezeCallStack :: CallStack -> CallStack
freezeCallStack CallStack
stk = CallStack -> CallStack
FreezeCallStack CallStack
stk
{-# INLINE freezeCallStack #-}


-- | A single location in the source code.
--
-- @since base-4.8.1.0
data SrcLoc = SrcLoc
  { SrcLoc -> [Char]
srcLocPackage   :: [Char]
  , SrcLoc -> [Char]
srcLocModule    :: [Char]
  , SrcLoc -> [Char]
srcLocFile      :: [Char]
  , SrcLoc -> Int
srcLocStartLine :: !Int
  , SrcLoc -> Int
srcLocStartCol  :: !Int
  , SrcLoc -> Int
srcLocEndLine   :: !Int
  , SrcLoc -> Int
srcLocEndCol    :: !Int
  } deriving SrcLoc -> SrcLoc -> Bool
(SrcLoc -> SrcLoc -> Bool)
-> (SrcLoc -> SrcLoc -> Bool) -> Eq SrcLoc
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SrcLoc -> SrcLoc -> Bool
== :: SrcLoc -> SrcLoc -> Bool
$c/= :: SrcLoc -> SrcLoc -> Bool
/= :: SrcLoc -> SrcLoc -> Bool
Eq -- ^ @since base-4.9.0.0