packages feed

ghc-stack-annotations 0.1.0.0 → 0.2.0.0

raw patch · 10 files changed

+604/−218 lines, 10 filesdep +ghc-heapdep +ghc-stack-annotationsdep +tastydep ~basedep ~ghc-experimentaldep ~ghc-internalPVP ok

version bump matches the API change (PVP)

Dependencies added: ghc-heap, ghc-stack-annotations, tasty, tasty-expected-failure, tasty-hunit, unliftio-core

Dependency ranges changed: base, ghc-experimental, ghc-internal

API changes (from Hackage documentation)

- GHC.Stack.Annotation: instance GHC.Show.Show GHC.Stack.Annotation.CallStackAnnotation
- GHC.Stack.Annotation: instance GHC.Stack.Annotation.StackAnnotation GHC.Stack.Annotation.CallStackAnnotation
- GHC.Stack.Annotation: instance GHC.Stack.Annotation.StackAnnotation GHC.Stack.Annotation.ShowAnnotation
- GHC.Stack.Annotation: instance GHC.Stack.Annotation.StackAnnotation GHC.Stack.Annotation.SomeStackAnnotation
- GHC.Stack.Annotation: instance GHC.Stack.Annotation.StackAnnotation GHC.Stack.Annotation.StringAnnotation
+ GHC.Stack.Annotation: displayStackAnnotationShort :: StackAnnotation a => a -> String
+ GHC.Stack.Annotation: stackAnnotationSourceLocation :: StackAnnotation a => a -> Maybe SrcLoc
+ GHC.Stack.Annotation.UnliftIO: annotateCallStackIO :: (HasCallStack, MonadUnliftIO m) => m b -> m b
+ GHC.Stack.Annotation.UnliftIO: annotateStackIO :: (Typeable a, StackAnnotation a, MonadUnliftIO m) => a -> m b -> m b
+ GHC.Stack.Annotation.UnliftIO: annotateStackShowIO :: (Show a, MonadUnliftIO m) => a -> m b -> m b
+ GHC.Stack.Annotation.UnliftIO: annotateStackStringIO :: MonadUnliftIO m => String -> m b -> m b
- GHC.Stack.Annotation: [ShowAnnotation] :: forall a. Show a => a -> ShowAnnotation
+ GHC.Stack.Annotation: [ShowAnnotation] :: forall a. Show a => !Maybe SrcLoc -> a -> ShowAnnotation
- GHC.Stack.Annotation: [StringAnnotation] :: String -> StringAnnotation
+ GHC.Stack.Annotation: [StringAnnotation] :: !Maybe SrcLoc -> String -> StringAnnotation
- GHC.Stack.Annotation: annotateStack :: (Typeable a, StackAnnotation a) => a -> b -> b
+ GHC.Stack.Annotation: annotateStack :: (HasCallStack, Typeable a, StackAnnotation a) => a -> b -> b
- GHC.Stack.Annotation: annotateStackIO :: (Typeable a, StackAnnotation a) => a -> IO b -> IO b
+ GHC.Stack.Annotation: annotateStackIO :: (HasCallStack, Typeable a, StackAnnotation a) => a -> IO b -> IO b
- GHC.Stack.Annotation: annotateStackShow :: (Typeable a, Show a) => a -> b -> b
+ GHC.Stack.Annotation: annotateStackShow :: (HasCallStack, Typeable a, Show a) => a -> b -> b
- GHC.Stack.Annotation: annotateStackShowIO :: Show a => a -> IO b -> IO b
+ GHC.Stack.Annotation: annotateStackShowIO :: (HasCallStack, Show a) => a -> IO b -> IO b
- GHC.Stack.Annotation: annotateStackString :: String -> b -> b
+ GHC.Stack.Annotation: annotateStackString :: HasCallStack => String -> b -> b
- GHC.Stack.Annotation: annotateStackStringIO :: String -> IO b -> IO b
+ GHC.Stack.Annotation: annotateStackStringIO :: HasCallStack => String -> IO b -> IO b

Files

CHANGELOG.md view
@@ -1,6 +1,15 @@ # Revision history for ghc-stack-annotations -## 0.1.0.0 -- YYYY-mm-dd+## 0.2.0.0 -- 23-06-2026++### Breaking changes++* Support GHC 10.1 and 9.14.2 ([#5](https://github.com/well-typed/ghc-stack-annotations/pull/5)).+  * Supports `stackAnnotationSourceLocation` and `displayStackAnnotationShort` from the updated `StackAnnotation` type class.+* Add stack annotation variants in `MonadUnliftIO` ([#3](https://github.com/well-typed/ghc-stack-annotations/pull/3)).+  * Adds module `GHC.Stack.Annotation.UnliftIO`.++## 0.1.0.0 -- 09-12-2025  * Introduce `GHC.Stack.Annotation`, which is a backwards compatibility module, allowing     users to use `annotateStack*` without having to resort to `CPP` for older GHC versions.
+ cbits/macros.h view
@@ -0,0 +1,15 @@+#if !defined(MIN_VERSION_ghc_experimental)+#define MIN_VERSION_ghc_experimental(x, y, z) false+#endif++#if MIN_VERSION_ghc_experimental(9,1402,0)+#define SUPPORT_STACK_ANN_LATEST+#endif++#if MIN_VERSION_ghc_experimental(9,1402,0)+#define SUPPORT_STACK_ANN_SRCLOC+#endif++#if MIN_VERSION_ghc_experimental(9,1401,0)+#define SUPPORT_STACK_ANN+#endif
ghc-stack-annotations.cabal view
@@ -1,17 +1,23 @@ cabal-version: 3.8 name: ghc-stack-annotations-version: 0.1.0.0+version: 0.2.0.0 synopsis: RTS Callstack annotation library-description: A compatibility library for the RTS Callstack annotations introduced in GHC 9.14.-             .-             Allows you to use the stack annotations without having to worry about older GHC versions.-             As stack annotations rely on the newly introduced 'AnnFrame' stack frame type, this library-             is operationally a NO-OP for GHC versions below 9.14.-             .-             For GHC <9.14, this library exposes an API identical to 'GHC.Stack.Annotation.Experimental' including-             data types and type classes for writing 'StackAnnotation' instances, without worrying about backwards-             compatibility.-             For GHC >=9.14, this library re-exports the API of 'GHC.Stack.Annotation.Experimental'.+description:+  A compatibility library for the RTS Callstack annotations introduced in GHC 9.14.+  .+  Allows you to use the stack annotations without having to worry about older GHC versions.+  As stack annotations rely on the newly introduced 'AnnFrame' stack frame type, this library+  is operationally a NO-OP for GHC versions below 9.14.+  .+  For GHC <9.14, this library exposes an API identical to 'GHC.Stack.Annotation.Experimental' of the latest+  supported GHC version.+  For GHC >=9.14, this library exposes an API identical to 'GHC.Stack.Annotation.Experimental' of the latest+  supported GHC version.+  For the latest supported GHC version, we re-export the interface of 'GHC.Stack.Annotation.Experimental'+  .+  This API abstracts over the GHC 'StackAnnotation' type class, thus allows you to write instances for all+  supported GHC versions without any @-XCPP@.+ category: development, BSD license: BSD-3-Clause license-file: LICENSE@@ -21,8 +27,10 @@ extra-doc-files:   CHANGELOG.md   README.md+extra-source-files:+  cbits/macros.h -tested-with: GHC ==9.14 || ==9.12 || ==9.10 || ==9.8+tested-with: ghc ==10.1 || ==9.14 || ==9.12 || ==9.10 || ==9.8  common warnings   ghc-options: -Wall@@ -32,18 +40,49 @@     GADTs     ImplicitParams     RankNTypes+    TypeApplications  library   import: warnings, exts-  exposed-modules: GHC.Stack.Annotation+  exposed-modules:+    GHC.Stack.Annotation+    GHC.Stack.Annotation.UnliftIO++  other-modules:+    GHC.Stack.Annotation.Compat+    GHC.Stack.Annotation.Compat.Class+    GHC.Stack.Annotation.Types+   build-depends:     base >=4.19.1 && <5,+    unliftio-core >=0.1 && <0.3,    if impl(ghc >=9.14)     build-depends:-      ghc-internal >= 9.1400 && <10,-      ghc-experimental >= 9.1400.0 && <10,+      ghc-experimental >=9.1400.0 && <10.200   hs-source-dirs: src+  include-dirs: ./cbits+  default-language: Haskell2010++test-suite ghc-stack-annotation-tests+  import: warnings, exts+  type: exitcode-stdio-1.0+  hs-source-dirs: test+  main-is: Main.hs+  other-modules: Compat+  include-dirs: ./cbits+  build-depends:+    base,+    ghc-heap,+    ghc-stack-annotations,+    tasty >=1.5.4 && <1.6,+    tasty-expected-failure >=0.11 && <0.13,+    tasty-hunit >=0.9 && <0.13,++  if impl(ghc >=9.14)+    build-depends:+      ghc-experimental,+      ghc-internal >=9.1400.0 && <10.200,   default-language: Haskell2010  source-repository head
src/GHC/Stack/Annotation.hs view
@@ -34,205 +34,6 @@   annotateCallStack, ) where --#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 914-import GHC.Stack.Annotation.Experimental (-  SomeStackAnnotation(..),-  StackAnnotation(..),-  ShowAnnotation(..),-  StringAnnotation(..),-  CallStackAnnotation(..),-  annotateStackIO,-  annotateStackStringIO,-  annotateStackShowIO,-  annotateCallStackIO,-  annotateStack,-  annotateStackString,-  annotateStackShow,-  annotateCallStack,-  )-#else---- The following source code is a copy of ghc-experimental:---  GHC.Stack.Annotation.Experimental.hs--- The only difference is that no 'annotateStackIO' is simply the 'id' function.------ As such, we reproduce the copyright notice here.---- Copyright (c) 2023, ghc-devs@haskell.org------ All rights reserved.------ Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are met:------     * Redistributions of source code must retain the above copyright---       notice, this list of conditions and the following disclaimer.------     * Redistributions in binary form must reproduce the above---       copyright notice, this list of conditions and the following---       disclaimer in the documentation and/or other materials provided---       with the distribution.------     * Neither the name of ghc-devs@haskell.org nor the names of other---       contributors may be used to endorse or promote products derived---       from this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS--- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT--- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR--- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT--- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,--- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT--- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,--- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY--- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT--- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE--- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.--import Control.Exception-import Data.Typeable-import GHC.Exception-import GHC.Stack (withFrozenCallStack)-import GHC.Stack.Types-import System.IO.Unsafe (unsafePerformIO)---- ------------------------------------------------------------------------------- StackAnnotation--- -------------------------------------------------------------------------------- | 'StackAnnotation's are types which can be pushed onto the call stack--- as the payload of 'AnnFrame' stack frames.----class StackAnnotation a where-  displayStackAnnotation :: a -> String---- ------------------------------------------------------------------------------- Annotations--- -------------------------------------------------------------------------------- |--- The @SomeStackAnnotation@ type is the root of the stack annotation type hierarchy.--- When the call stack is annotated with a value of type @a@, behind the scenes it is--- encapsulated in a @SomeStackAnnotation@.----data SomeStackAnnotation where-  SomeStackAnnotation :: forall a. (Typeable a, StackAnnotation a) => a -> SomeStackAnnotation--instance StackAnnotation SomeStackAnnotation where-  displayStackAnnotation (SomeStackAnnotation a) = displayStackAnnotation a--data StringAnnotation where-  StringAnnotation :: String -> StringAnnotation--instance StackAnnotation StringAnnotation where-  displayStackAnnotation (StringAnnotation str) = str---- | Use the 'Show' instance of a type to display as the 'StackAnnotation'.-data ShowAnnotation where-  ShowAnnotation :: forall a . Show a => a -> ShowAnnotation--instance StackAnnotation ShowAnnotation where-  displayStackAnnotation (ShowAnnotation showAnno) = show showAnno---- | A 'CallStack' stack annotation.-newtype CallStackAnnotation = CallStackAnnotation CallStack--instance Show CallStackAnnotation where-  show (CallStackAnnotation cs) = prettyCallStack cs---- | Displays the first entry of the 'CallStack'-instance StackAnnotation CallStackAnnotation where-  displayStackAnnotation (CallStackAnnotation cs) = case getCallStack cs of-    [] -> "<unknown source location>"-    ((fnName,srcLoc):_) -> fnName ++ ", called at " ++ prettySrcLoc srcLoc---- ------------------------------------------------------------------------------- Annotate the CallStack with custom data--- -------------------------------------------------------------------------------- See Note [User-defined stack annotations for better stack traces]---- | @'annotateStack' anno b@ annotates the evaluation stack of @b@--- with the value of @anno@.------ When decoding the call stack, the annotation frames can be used to add more--- information to stack traces.------ WARNING: forces the evaluation of @b@ to WHNF.-{-# NOINLINE annotateStack #-}-annotateStack :: forall a b. (Typeable a, StackAnnotation a) => a -> b -> b-annotateStack ann b = unsafePerformIO $-  annotateStackIO ann (evaluate b)---- | @'annotateCallStack' b@ annotates the evaluation stack of @b@--- with the current 'callstack'.------ When decoding the call stack, the annotation frames can be used to add more--- information to stack traces.------ WARNING: forces the evaluation of @b@ to WHNF.-{-# NOINLINE annotateCallStack #-}-annotateCallStack :: HasCallStack => b -> b-annotateCallStack b = unsafePerformIO $ withFrozenCallStack $-  annotateCallStackIO (evaluate b)----- | @'annotateStackString' msg b@ annotates the evaluation stack of @b@--- with the value @msg@.------ When decoding the call stack, the annotation frames can be used to add more--- information to stack traces.------ WARNING: forces the evaluation of @b@ to WHNF.-annotateStackString :: forall b . String -> b -> b-annotateStackString ann =-  annotateStack (StringAnnotation ann)---- | @'annotateStackShow' showable b@ annotates the evaluation stack of @b@--- with the value @showable@.------ When decoding the call stack, the annotation frames can be used to add more--- information to stack traces.------ WARNING: forces the evaluation of @b@ to WHNF.-annotateStackShow :: forall a b . (Typeable a, Show a) => a -> b -> b-annotateStackShow ann =-  annotateStack (ShowAnnotation ann)---- | @'annotateStackIO' showable b@ annotates the evaluation stack of @b@--- with the value @showable@.------ When decoding the call stack, the annotation frames can be used to add more--- information to stack traces.-annotateStackIO :: forall a b . (Typeable a, StackAnnotation a) => a -> IO b -> IO b-annotateStackIO _ann = id---- | @'annotateStackStringIO' msg b@ annotates the evaluation stack of @b@--- with the value @msg@.------ When decoding the call stack, the annotation frames can be used to add more--- information to stack traces.-annotateStackStringIO :: forall b . String -> IO b -> IO b-annotateStackStringIO ann =-  annotateStackIO (StringAnnotation ann)---- | @'annotateStackShowIO' msg b@ annotates the evaluation stack of @b@--- with the value @msg@.------ When decoding the call stack, the annotation frames can be used to add more--- information to stack traces.-annotateStackShowIO :: forall a b . (Show a) => a -> IO b -> IO b-annotateStackShowIO ann =-  annotateStackIO (ShowAnnotation ann)---- | @'annotateCallStackIO' b@ annotates the evaluation stack of @b@ with the--- current 'callstack'.------ When decoding the call stack, the annotation frames can be used to add more--- information to stack traces.-annotateCallStackIO :: HasCallStack => IO a -> IO a-annotateCallStackIO =-  annotateStackIO (CallStackAnnotation ?callStack)--#endif+import GHC.Stack.Annotation.Compat+import GHC.Stack.Annotation.Compat.Class+import GHC.Stack.Annotation.Types
+ src/GHC/Stack/Annotation/Compat.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE CPP #-}+module GHC.Stack.Annotation.Compat where++#include "macros.h"+import Control.Exception+import Data.Typeable+import GHC.Stack (withFrozenCallStack)+import GHC.Stack.Types+import System.IO.Unsafe (unsafePerformIO)+import GHC.Stack.Annotation.Compat.Class+import GHC.Stack.Annotation.Types+#if defined(SUPPORT_STACK_ANN)+import qualified GHC.Stack.Annotation.Experimental as Annotation+#endif++-- ----------------------------------------------------------------------------+-- Annotate the CallStack with custom data+-- ----------------------------------------------------------------------------++-- See Note [User-defined stack annotations for better stack traces]++-- | @'annotateStack' anno b@ annotates the evaluation stack of @b@+-- with the value of @anno@.+--+-- When decoding the call stack, the annotation frames can be used to add more+-- information to stack traces.+--+-- WARNING: forces the evaluation of @b@ to WHNF.+{-# NOINLINE annotateStack #-}+annotateStack :: forall a b. (HasCallStack, Typeable a, StackAnnotation a) => a -> b -> b+annotateStack ann b = unsafePerformIO $+  annotateStackIO ann (evaluate b)++-- | @'annotateCallStack' b@ annotates the evaluation stack of @b@+-- with the current 'callstack'.+--+-- When decoding the call stack, the annotation frames can be used to add more+-- information to stack traces.+--+-- WARNING: forces the evaluation of @b@ to WHNF.+{-# NOINLINE annotateCallStack #-}+annotateCallStack :: HasCallStack => b -> b+annotateCallStack b = unsafePerformIO $ withFrozenCallStack $+  annotateCallStackIO (evaluate b)+++-- | @'annotateStackString' msg b@ annotates the evaluation stack of @b@+-- with the value @msg@.+--+-- When decoding the call stack, the annotation frames can be used to add more+-- information to stack traces.+--+-- WARNING: forces the evaluation of @b@ to WHNF.+annotateStackString :: forall b . HasCallStack => String -> b -> b+annotateStackString ann =+  annotateStack (StringAnnotation (callStackHeadSrcLoc ?callStack) ann)++-- | @'annotateStackShow' showable b@ annotates the evaluation stack of @b@+-- with the value @showable@.+--+-- When decoding the call stack, the annotation frames can be used to add more+-- information to stack traces.+--+-- WARNING: forces the evaluation of @b@ to WHNF.+annotateStackShow :: forall a b . (HasCallStack, Typeable a, Show a) => a -> b -> b+annotateStackShow ann =+  annotateStack (ShowAnnotation (callStackHeadSrcLoc ?callStack) ann)++-- | @'annotateStackIO' showable b@ annotates the evaluation stack of @b@+-- with the value @showable@.+--+-- When decoding the call stack, the annotation frames can be used to add more+-- information to stack traces.+annotateStackIO :: forall a b . (HasCallStack, Typeable a, StackAnnotation a) => a -> IO b -> IO b+#if defined(SUPPORT_STACK_ANN)+annotateStackIO ann act = Annotation.annotateStackIO (CompatAnnotation ann) act+#else+annotateStackIO _ann = id+#endif++-- | @'annotateStackStringIO' msg b@ annotates the evaluation stack of @b@+-- with the value @msg@.+--+-- When decoding the call stack, the annotation frames can be used to add more+-- information to stack traces.+annotateStackStringIO :: forall b . HasCallStack => String -> IO b -> IO b+annotateStackStringIO ann =+  annotateStackIO (StringAnnotation (callStackHeadSrcLoc ?callStack) ann)++-- | @'annotateStackShowIO' msg b@ annotates the evaluation stack of @b@+-- with the value @msg@.+--+-- When decoding the call stack, the annotation frames can be used to add more+-- information to stack traces.+annotateStackShowIO :: forall a b . (HasCallStack, Show a) => a -> IO b -> IO b+annotateStackShowIO ann =+  annotateStackIO (ShowAnnotation (callStackHeadSrcLoc ?callStack) ann)++-- | @'annotateCallStackIO' b@ annotates the evaluation stack of @b@ with the+-- current 'callstack'.+--+-- When decoding the call stack, the annotation frames can be used to add more+-- information to stack traces.+annotateCallStackIO :: HasCallStack => IO a -> IO a+annotateCallStackIO =+  annotateStackIO (CallStackAnnotation ?callStack)
+ src/GHC/Stack/Annotation/Compat/Class.hs view
@@ -0,0 +1,154 @@+{-# LANGUAGE CPP #-}+module GHC.Stack.Annotation.Compat.Class (+  StackAnnotation(..),+  SomeStackAnnotation(..),+  CompatAnnotation(..),+  ) where++#include "macros.h"++import Data.Typeable ( Typeable )++#if defined(SUPPORT_STACK_ANN_SRCLOC)+import GHC.Stack.Annotation.Experimental (StackAnnotation(..), SomeStackAnnotation(..))+import qualified GHC.Stack.Annotation.Experimental as Annotation+#elif defined(SUPPORT_STACK_ANN)+import GHC.Stack.Annotation.Experimental (SomeStackAnnotation(..))+import qualified GHC.Stack.Annotation.Experimental as Annotation+import GHC.Stack (SrcLoc, prettySrcLoc)+#else+import GHC.Stack (SrcLoc, prettySrcLoc)+#endif++-- The following source code is a partial copy of ghc-internal:+--  GHC.Internal.Stack.Annotation+-- It copies the `StackAnnotation` type class and its documentation.+--+-- As such, we reproduce the copyright notice here.++-- Copyright (c) 2023, ghc-devs@haskell.org+--+-- All rights reserved.+--+-- Redistribution and use in source and binary forms, with or without+-- modification, are permitted provided that the following conditions are met:+--+--     * Redistributions of source code must retain the above copyright+--       notice, this list of conditions and the following disclaimer.+--+--     * Redistributions in binary form must reproduce the above+--       copyright notice, this list of conditions and the following+--       disclaimer in the documentation and/or other materials provided+--       with the distribution.+--+--     * Neither the name of ghc-devs@haskell.org nor the names of other+--       contributors may be used to endorse or promote products derived+--       from this software without specific prior written permission.+--+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+++#if !defined(SUPPORT_STACK_ANN_LATEST)+-- | 'StackAnnotation's are types which can be pushed onto the call stack+-- as the payload of 'AnnFrame' stack frames.+--+class StackAnnotation a where+  -- | Display a human readable string for the 'StackAnnotation'.+  --+  -- This is supposed to be the long version of 'displayStackAnnotationShort'+  -- and may contain a source location.+  --+  -- If not provided, 'displayStackAnnotation' is derived from 'stackAnnotationSourceLocation'+  -- and 'displayStackAnnotationShort'.+  displayStackAnnotation :: a -> String++  -- | Get the 'SrcLoc' of the given 'StackAnnotation'.+  --+  -- This is optional, 'SrcLoc' are not strictly required for 'StackAnnotation', but+  -- it is still heavily encouraged to provide a 'SrcLoc' for better IPE backtraces.+  stackAnnotationSourceLocation :: a -> Maybe SrcLoc++  -- | The description of the StackAnnotation without any metadata such as source locations.+  --+  -- Prefer implementing 'displayStackAnnotationShort' over 'displayStackAnnotation'.+  displayStackAnnotationShort :: a -> String++  {-# MINIMAL displayStackAnnotation | displayStackAnnotationShort #-}++  displayStackAnnotation ann =+    displayStackAnnotationShort ann+      ++ case stackAnnotationSourceLocation ann of+          Nothing -> ""+          Just srcLoc -> ", called at " ++ prettySrcLoc srcLoc++  stackAnnotationSourceLocation _ann = Nothing++  displayStackAnnotationShort = displayStackAnnotation+#endif+++-- Only define this is, if `ghc-experimental` doesn't define it already. Otherwise, just re-export it.++#if !defined(SUPPORT_STACK_ANN)+-- |+-- The @SomeStackAnnotation@ type is the root of the stack annotation type hierarchy.+-- When the call stack is annotated with a value of type @a@, behind the scenes it is+-- encapsulated in a @SomeStackAnnotation@.+--+data SomeStackAnnotation where+  SomeStackAnnotation :: forall a. (Typeable a, StackAnnotation a) => a -> SomeStackAnnotation+#endif++#if defined(SUPPORT_STACK_ANN_LATEST)+{- No instance needed -}+#elif defined(SUPPORT_STACK_ANN_SRCLOC)+instance StackAnnotation SomeStackAnnotation where+  displayStackAnnotation (SomeStackAnnotation ann) =+    Annotation.displayStackAnnotation ann+  stackAnnotationSourceLocation (SomeStackAnnotation ann) =+    Annotation.stackAnnotationSourceLocation ann+  displayStackAnnotationShort (SomeStackAnnotation ann) =+    Annotation.displayStackAnnotationShort ann+#elif defined(SUPPORT_STACK_ANN)+instance StackAnnotation SomeStackAnnotation where+  displayStackAnnotation (SomeStackAnnotation ann) =+    Annotation.displayStackAnnotation ann+#else+instance StackAnnotation SomeStackAnnotation where+  displayStackAnnotation (SomeStackAnnotation ann) =+    displayStackAnnotation ann+  stackAnnotationSourceLocation (SomeStackAnnotation ann) =+    stackAnnotationSourceLocation ann+  displayStackAnnotationShort (SomeStackAnnotation ann) =+    displayStackAnnotationShort ann+#endif++-- ----------------------------------------------------------------------------+-- Backwards compatibility wrapper+-- ----------------------------------------------------------------------------++-- | A newtype that bridges the locally defined 'StackAnnotation' to GHC's 'ghc-experimental:StackAnnotation'.+--+newtype CompatAnnotation a = CompatAnnotation a++#if defined(SUPPORT_STACK_ANN)+instance (Typeable a, StackAnnotation a) => Annotation.StackAnnotation (CompatAnnotation a) where+  displayStackAnnotation (CompatAnnotation a) =+    displayStackAnnotation a+#if defined(SUPPORT_STACK_ANN_SRCLOC)+  stackAnnotationSourceLocation (CompatAnnotation a) =+    stackAnnotationSourceLocation a+  displayStackAnnotationShort (CompatAnnotation a) =+    displayStackAnnotationShort a+#endif+#endif
+ src/GHC/Stack/Annotation/Types.hs view
@@ -0,0 +1,54 @@+module GHC.Stack.Annotation.Types where++import GHC.Stack.Annotation.Compat.Class (StackAnnotation(..))+import GHC.Stack++-- | A 'String' only annotation with an optional source location.+data StringAnnotation where+  StringAnnotation :: !(Maybe SrcLoc) -> String -> StringAnnotation++instance StackAnnotation StringAnnotation where+  displayStackAnnotationShort (StringAnnotation _srcLoc str) =+    str++  stackAnnotationSourceLocation (StringAnnotation srcLoc _str) =+    srcLoc++-- | Use the 'Show' instance of a type to display as the 'StackAnnotation'.+data ShowAnnotation where+  ShowAnnotation :: forall a . Show a => !(Maybe SrcLoc) -> a -> ShowAnnotation++instance StackAnnotation ShowAnnotation where+  displayStackAnnotationShort (ShowAnnotation _srcLoc showAnno) =+    show showAnno++  stackAnnotationSourceLocation (ShowAnnotation srcLoc _showAnno) =+    srcLoc++-- | A 'CallStack' stack annotation.+--+-- Captures the whole 'CallStack'.+newtype CallStackAnnotation = CallStackAnnotation CallStack++instance Show CallStackAnnotation where+  show (CallStackAnnotation cs) = prettyCallStack cs++-- | Displays the first entry of the 'CallStack'+instance StackAnnotation CallStackAnnotation where+  stackAnnotationSourceLocation (CallStackAnnotation cs) =+    callStackHeadSrcLoc cs++  displayStackAnnotationShort (CallStackAnnotation cs) =+    callStackHeadFunctionName cs++callStackHeadSrcLoc :: CallStack -> Maybe SrcLoc+callStackHeadSrcLoc cs =+  case getCallStack cs of+    [] -> Nothing+    (_, srcLoc):_ -> Just srcLoc++callStackHeadFunctionName :: CallStack -> String+callStackHeadFunctionName cs =+  case getCallStack cs of+    [] -> "<unknown source location>"+    (fnName, _):_ -> fnName
+ src/GHC/Stack/Annotation/UnliftIO.hs view
@@ -0,0 +1,30 @@+module GHC.Stack.Annotation.UnliftIO+  (+  -- * Push stack frame annotations in 'MonadUnliftIO' code.+  --+  annotateStackIO,+  annotateStackStringIO,+  annotateStackShowIO,+  annotateCallStackIO,+  ) where++import qualified GHC.Stack.Annotation as Annotation+import Data.Typeable (Typeable)+import Control.Monad.IO.Unlift (MonadUnliftIO(..))+import GHC.Stack.Types (HasCallStack)++annotateStackIO :: (Typeable a, Annotation.StackAnnotation a, MonadUnliftIO m) => a -> m b -> m b+annotateStackIO anno action =+  withRunInIO $ \runInIO -> Annotation.annotateStackIO anno (runInIO action)++annotateStackStringIO :: MonadUnliftIO m => String -> m b -> m b+annotateStackStringIO msg action =+  withRunInIO $ \runInIO -> Annotation.annotateStackStringIO msg (runInIO action)++annotateStackShowIO :: (Show a, MonadUnliftIO m) => a -> m b -> m b+annotateStackShowIO value action =+  withRunInIO $ \runInIO -> Annotation.annotateStackShowIO value (runInIO action)++annotateCallStackIO :: (HasCallStack, MonadUnliftIO m) => m b -> m b+annotateCallStackIO action =+  withRunInIO $ \runInIO -> Annotation.annotateCallStackIO (runInIO action)
+ test/Compat.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE CPP #-}++module Compat where++#include "macros.h"++import GHC.Stack.Annotation++#if defined(SUPPORT_STACK_ANN)+import GHC.Stack.CloneStack (cloneMyStack)+import qualified Data.Maybe as Maybe+import GHC.InfoProv+import GHC.Exts.Heap.Closures+import Unsafe.Coerce++-- TODO: We should not depend on ghc-internal, expose decoding functions from ghc-experimental+import qualified GHC.Internal.Stack.Decode as Decode+#endif+++collectStackAnnotations :: IO [SomeStackAnnotation]+collectStackAnnotations = do+#if defined(SUPPORT_STACK_ANN)+  stack <- cloneMyStack+  frames <- Decode.decodeStackWithIpe stack+  pure $ Maybe.mapMaybe go frames+  where+    -- TODO: GHC should expose this decoding function+    go :: (StackFrame, Maybe InfoProv) -> Maybe SomeStackAnnotation+    go (frame, _ipeInfo) = case frame of+      AnnFrame {annotation = Box someStackAnno } ->+        case unsafeCoerce someStackAnno of+          SomeStackAnnotation ann ->+            Just $ SomeStackAnnotation ann+      _  ->+        Nothing+#else+  -- There are no stack annotations in GHC <914+  pure []+#endif
+ test/Main.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE CPP #-}++module Main where++#include "macros.h"++import Test.Tasty+import Test.Tasty.HUnit+import GHC.Stack.Annotation+import Compat+import Test.Tasty.ExpectedFailure (ignoreTestBecause)+import qualified Data.Maybe as Maybe+import GHC.Stack.Types (SrcLoc(..), getCallStack)++main :: IO ()+main = do+  defaultMain (needsStackAnnotations tests)++tests :: TestTree+tests = testGroup "tests"+  [ testGroup "simple"+    [ testCase "string" $ do+          annos <- annotateStackStringIO "Test" $ do+            collectStackAnnotations++          length annos @?= 1+    , testCase "show" $ do+        annos <- annotateStackShowIO @(Int, Int) (4, 5) $ do+          collectStackAnnotations++        length annos @?= 1+    , testCase "callstack" $ do+        annos <- annotateCallStackIO $ do+          collectStackAnnotations++        length annos @?= 1+    , testCase "custom" $ do+        annos <- annotateStackIO CustomAnnotation $ do+          collectStackAnnotations++        length annos @?= 1+    , testCase "all" $ do+        annos <-+          annotateStackIO CustomAnnotation $+            annotateCallStackIO $+              annotateStackShowIO @(Int, Int) (4, 5) $+                annotateStackStringIO "Test" $ do+                  collectStackAnnotations++        length annos @?= 4+    ]+  , needsSourceLocations $ testGroup "source locations"+    [ testCase "string" $ do+        annos <- annotateStackStringIO "Test" $ do+          collectStackAnnotations++        length annos @?= 1+        let srcLocs = Maybe.mapMaybe stackAnnotationSourceLocation annos+        length srcLocs @?= 1+        fmap srcLocModule srcLocs @?= ["Main"]+    , testCase "show" $ do+        annos <- annotateStackShowIO @(Int, Int) (4, 5) $ do+          collectStackAnnotations++        length annos @?= 1+        let srcLocs = Maybe.mapMaybe stackAnnotationSourceLocation annos+        length srcLocs @?= 1+        fmap srcLocModule srcLocs @?= ["Main"]+    , testCase "callstack" $ do+        annos <- annotateCallStackIO $ do+          collectStackAnnotations++        length annos @?= 1+        let srcLocs = Maybe.mapMaybe stackAnnotationSourceLocation annos+        length srcLocs @?= 1+        fmap srcLocModule srcLocs @?= ["Main"]+    , testCase "custom" $ do+        annos <- annotateStackIO annoWithSrcLoc $ do+          collectStackAnnotations++        length annos @?= 1+        let srcLocs = Maybe.mapMaybe stackAnnotationSourceLocation annos+        length srcLocs @?= 1+    , testCase "all" $ do+        annos <-+          annotateStackIO CustomAnnotation $+            annotateStackIO annoWithSrcLoc $+              annotateCallStackIO $+                annotateStackShowIO @(Int, Int) (4, 5) $+                  annotateStackStringIO "Test" $ do+                    collectStackAnnotations++        length annos @?= 5+        let srcLocs = Maybe.mapMaybe stackAnnotationSourceLocation annos+        length srcLocs @?= 4+        -- No source location for CustomAnnotation is missing+        fmap srcLocModule srcLocs @?= replicate 4 "Main"+    ]+  ]++data CustomAnnotation = CustomAnnotation++-- This is implicitly a test, that we can define instances compatible with the latest+-- ghc-experimental version of 'StackAnnotation'.+instance StackAnnotation CustomAnnotation where+  displayStackAnnotation CustomAnnotation = "CustomAnnotation"++annoWithSrcLoc :: HasCallStack => CustomAnnotationWithSrcLoc+annoWithSrcLoc =+  CustomAnnotationWithSrcLoc loc+  where+    loc = case getCallStack ?callStack of+      [] -> Nothing+      ((_, srcLoc):_) -> Just srcLoc++data CustomAnnotationWithSrcLoc = CustomAnnotationWithSrcLoc (Maybe SrcLoc)++-- This is implicitly a test, that we can define instances compatible with the latest+-- ghc-experimental version of 'StackAnnotation'.+instance StackAnnotation CustomAnnotationWithSrcLoc where+  displayStackAnnotationShort CustomAnnotationWithSrcLoc{} = "CustomAnnotation"+  stackAnnotationSourceLocation (CustomAnnotationWithSrcLoc loc) = loc++needsStackAnnotations :: TestTree -> TestTree+needsStackAnnotations =+#if defined(SUPPORT_STACK_ANN)+  id+#else+  ignoreTestBecause "Stack Annotations not supported on GHC <9.14"+#endif++needsSourceLocations :: TestTree -> TestTree+needsSourceLocations =+#if !defined(SUPPORT_STACK_ANN_SRCLOC)+  ignoreTestBecause "Stack Annotations not supported on GHC <9.14.2"+#else+  id+#endif