{-# language RankNTypes, FlexibleContexts, FlexibleInstances, ImpredicativeTypes, MultiParamTypeClasses, DataKinds, ConstraintKinds #-}

-- | This module provides utilities to ensure that you propagate
-- 'HasCallStack' constraints by introducing a class 'RequireCallStack'
-- which can only be discharged using the 'provideCallStack' function.
--
-- Let's say you have a custom prelude for your project, and you want
-- better callstack support. You replace the 'Prelude.error' with a custom
-- variant:
--
-- @
-- error :: RequireCallStack => String -> a
-- error = Prelude.error
-- @
--
-- Now, you will receive a compile-time error at every use site of 'error'
-- in your project. These errors will complain about a missing instance of
-- some weird class that gently suggests to add a 'RequireCallStack'
-- constraint, or use 'provideCallStack' to discharge it. You can add
-- 'RequireCallStack' constraints up the stack, until eventually, you have
-- complete provenance information. Or, if you want to make the work a bit
-- easier, you can use 'provideCallStack' to dismiss the constraint.
--
-- @
-- foo :: RequireCallStack => Int -> String
-- foo = error "oh no"
--
-- bar :: Int -> String
-- bar i = provideCallStack $ foo i
-- @
--
-- Couple this with @annotated-exception@ library for excellent provenance
-- information on all thrown exceptions.
module RequireCallStack
    ( RequireCallStack
    , RequireCallStackImpl
    , provideCallStack
    , errorRequireCallStack
    ) where

import GHC.Stack
import RequireCallStack.Internal

-- | This constraint is similar to 'HasCallStack' in that it's presence
-- will capture a stack frame for the call site of the function. This helps
-- to preserve callstack provenance, which
--
-- @since 0.1.0.0
type RequireCallStack = (HasCallStack, RequireCallStackImpl)

-- | Raise an 'ErrorCall' and incur a 'RequireCallStack' constraint while
-- you do so. This
--
-- @since 0.1.0.0
errorRequireCallStack :: RequireCallStack => String -> x
errorRequireCallStack :: forall x. RequireCallStack => String -> x
errorRequireCallStack = forall a. HasCallStack => String -> a
error