packages feed

ghc-stack-annotations (empty) → 0.1.0.0

raw patch · 5 files changed

+351/−0 lines, 5 filesdep +basedep +ghc-experimentaldep +ghc-internal

Dependencies added: base, ghc-experimental, ghc-internal

Files

+ CHANGELOG.md view
@@ -0,0 +1,6 @@+# Revision history for ghc-stack-annotations++## 0.1.0.0 -- YYYY-mm-dd++* 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.
+ LICENSE view
@@ -0,0 +1,28 @@+BSD 3-Clause License++Copyright (c) 2025, Hannes Siebenhandl++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 the copyright holder nor the names of its+  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 HOLDER 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.
+ README.md view
@@ -0,0 +1,28 @@+# `ghc-stack-annotations`++A compatibility library for the RTS callstack annotations introduced in GHC 9.14.++```haskell+handleGetRequest :: Int -> IO Int+handleGetRequest number = annotateStackStringIO "My User Annotation" $ do+    bigOperationThatCouldFail number+```++The annotation primop called by `handleGetRequest` pushes a stack frame which contains a user-annotation.+The stack decoding logic can interpret these frames and display the user-annotated+information during exceptions and sample profiling.++* [Better Haskell stack traces via user annotations](https://www.well-typed.com/blog/2025/09/better-haskell-stack-traces/)++Since the annotation primop has only been introduced in GHC-9.14, the annotation+functions do not do anything if used on earlier GHC versions.++IPE backtraces which include annotation stack frames offers a number of advantages over the existing backtrace collection mechanisms:++* It is not necessary to modify the function API (unlike `HasCallStack`)+* A "continuous chain" of modifications is not necessary (unlike `HasCallStack`)+* The annotations work in all ways of compilation (unlike cost centre stacks)+* The backtrace is expressed in terms of predictable source locations (unlike some IPE backtraces)++Further, tools such as [`ghc-stack-profiler`](https://github.com/well-typed/ghc-stack-profiler) can also use the annotation stack frame+to provide improved profiles.
+ ghc-stack-annotations.cabal view
@@ -0,0 +1,51 @@+cabal-version: 3.8+name: ghc-stack-annotations+version: 0.1.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'.+category: development, BSD+license: BSD-3-Clause+license-file: LICENSE+author: Hannes Siebenhandl, Matthew Pickering+maintainer: hannes@well-typed.com+build-type: Simple+extra-doc-files:+  CHANGELOG.md+  README.md++tested-with: GHC ==9.14 || ==9.12 || ==9.10 || ==9.8++common warnings+  ghc-options: -Wall++common exts+  default-extensions:+    GADTs+    ImplicitParams+    RankNTypes++library+  import: warnings, exts+  exposed-modules: GHC.Stack.Annotation+  build-depends:+    base >=4.19.1 && <5,++  if impl(ghc >=9.14)+    build-depends:+      ghc-internal >= 9.1400 && <10,+      ghc-experimental >= 9.1400.0 && <10,+  hs-source-dirs: src+  default-language: Haskell2010++source-repository head+  location: https://github.com/well-typed/ghc-stack-annotations+  type: git
+ src/GHC/Stack/Annotation.hs view
@@ -0,0 +1,238 @@+{-# LANGUAGE CPP #-}++module GHC.Stack.Annotation (+  -- * The root of Stack Annotation Types+  SomeStackAnnotation(..),+  -- * Displaying Stack Annotations+  StackAnnotation(..),+  -- * Annotation helpers+  ShowAnnotation(..),+  StringAnnotation(..),+  -- * 'CallStack' annotations+  CallStackAnnotation(..),+  -- * Push stack frame annotations in 'IO' code.+  --+  --+  annotateStackIO,+  annotateStackStringIO,+  annotateStackShowIO,+  annotateCallStackIO,+  -- * Push stack frame annotations in non-'IO' code.+  --+  -- | These variants all evaluate the code to be annotated to WHNF.+  -- Otherwise, the stack annotations will not be shown in stack traces,+  -- as the computation is immediately "evaluated" to a thunk, popping the+  -- annotation frames from the stack.+  -- If the pure computation throws an exception later, the annotation frame+  -- will not be present, thus missing in the stack trace.+  --+  -- Note, you will encounter similar issues if the exception is thrown+  -- during evaluation of a nested value, for example @Just (error "Oh, no!")@.+  annotateStack,+  annotateStackString,+  annotateStackShow,+  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