[commit: ghc] ghc-8.4: tentative improvement to callstack docs (c105095)
git at git.haskell.org
git at git.haskell.org
Mon Jan 29 22:33:54 UTC 2018
Repository : ssh://git@git.haskell.org/ghc
On branch : ghc-8.4
Link : http://ghc.haskell.org/trac/ghc/changeset/c1050953b28b0e6ff6a749cea6935cc153b62960/ghc
>---------------------------------------------------------------
commit c1050953b28b0e6ff6a749cea6935cc153b62960
Author: Alp Mestanogullari <alp at well-typed.com>
Date: Sun Jan 21 12:07:58 2018 -0500
tentative improvement to callstack docs
This is an attempt at clarifying the docs for HasCallStack in both the
user guide and libraries/base/GHC/Stack/Types.hs. The example used right
now is built around an hypothetical 'error' function that doesn't itself
print call stacks, and the fact that this doesn't hold makes it all
confusing, see #14635.
Reviewers: hvr, bgamari
Reviewed By: bgamari
Subscribers: rwbarton, thomie, carter
GHC Trac Issues: #14635
Differential Revision: https://phabricator.haskell.org/D4317
>---------------------------------------------------------------
c1050953b28b0e6ff6a749cea6935cc153b62960
docs/users_guide/glasgow_exts.rst | 67 +++++++++++++++++++++++++++++++--------
libraries/base/GHC/Stack/Types.hs | 23 ++++++++------
2 files changed, 66 insertions(+), 24 deletions(-)
diff --git a/docs/users_guide/glasgow_exts.rst b/docs/users_guide/glasgow_exts.rst
index 3edb8d6..6bca784 100644
--- a/docs/users_guide/glasgow_exts.rst
+++ b/docs/users_guide/glasgow_exts.rst
@@ -14895,28 +14895,67 @@ HasCallStack
``GHC.Stack.HasCallStack`` is 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 ::
+A function can request its call-site with the ``HasCallStack`` constraint
+and access it as a Haskell value by using ``callStack``.
- errorWithCallStack :: HasCallStack => String -> a
+One can then use functions from ``GHC.Stack`` to inspect or pretty
+print (as is done in ``f`` below) the call stack.
-as a variant of ``error`` that will get its call-site (as of GHC 8.0,
-``error`` already gets its call-site, but let's assume for the sake of
-demonstration that it does not). We can access the call-stack inside
-``errorWithCallStack`` with ``GHC.Stack.callStack``. ::
+ f :: HasCallStack => IO ()
+ f = putStrLn (prettyCallStack callStack)
- errorWithCallStack :: HasCallStack => String -> a
- errorWithCallStack msg = error (msg ++ "\n" ++ prettyCallStack callStack)
+ g :: HasCallStack => IO ()
+ g = f
-Thus, if we call ``errorWithCallStack`` we will get a formatted call-stack
-alongside our error message.
+Evaluating ``f`` directly shows a call stack with a single entry,
+while evaluating ``g``, which also requests its call-site, shows
+two entries, one for each computation "annotated" with
+``HasCallStack``.
.. code-block:: none
- ghci> errorWithCallStack "die"
- *** Exception: die
+ ghci> f
CallStack (from HasCallStack):
- errorWithCallStack, called at <interactive>:2:1 in interactive:Ghci1
+ f, called at <interactive>:19:1 in interactive:Ghci1
+ ghci> g
+ CallStack (from HasCallStack):
+ f, called at <interactive>:17:5 in main:Main
+ g, called at <interactive>:20:1 in interactive:Ghci2
+
+The ``error`` function from the Prelude supports printing the call stack that
+led to the error in addition to the usual error message:
+
+.. code-block:: none
+
+ ghci> error "bad"
+ *** Exception: bad
+ CallStack (from HasCallStack):
+ error, called at <interactive>:25:1 in interactive:Ghci5
+
+The call stack here consists of a single entry, pinpointing the source
+of the call to ``error``. However, by annotating several computations
+with ``HasCallStack``, figuring out the exact circumstances and sequences
+of calls that lead to a call to ``error`` becomes a lot easier, as demonstrated
+with the simple example below. ::
+
+ f :: HasCallStack => IO ()
+ f = error "bad bad bad"
+
+ g :: HasCallStack => IO ()
+ g = f
+
+ h :: HasCallStack => IO ()
+ h = g
+
+.. code-block:: none
+
+ ghci> h
+ *** Exception: bad bad bad
+ CallStack (from HasCallStack):
+ error, called at call-stack.hs:4:5 in main:Main
+ f, called at call-stack.hs:7:5 in main:Main
+ g, called at call-stack.hs:10:5 in main:Main
+ h, called at <interactive>:28:1 in interactive:Ghci1
The ``CallStack`` will only extend as far as the types allow it, for
example ::
diff --git a/libraries/base/GHC/Stack/Types.hs b/libraries/base/GHC/Stack/Types.hs
index d9e7552..b5858f2 100644
--- a/libraries/base/GHC/Stack/Types.hs
+++ b/libraries/base/GHC/Stack/Types.hs
@@ -75,25 +75,28 @@ type HasCallStack = (?callStack :: CallStack)
-- For example, we can define
--
-- @
--- errorWithCallStack :: HasCallStack => String -> a
+-- putStrLnWithCallStack :: HasCallStack => String -> IO ()
-- @
--
--- as a variant of @error@ that will get its call-site. We can access the
--- call-stack inside @errorWithCallStack@ with 'GHC.Stack.callStack'.
+-- 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.Stack.callStack'.
--
-- @
--- errorWithCallStack :: HasCallStack => String -> a
--- errorWithCallStack msg = error (msg ++ "\\n" ++ prettyCallStack callStack)
+-- putStrLnWithCallStack :: HasCallStack => String -> IO ()
+-- putStrLnWithCallStack msg = do
+-- putStrLn msg
+-- putStrLn (prettyCallStack callStack)
-- @
--
--- Thus, if we call @errorWithCallStack@ we will get a formatted call-stack
--- alongside our error message.
+-- Thus, if we call @putStrLnWithCallStack@ we will get a formatted call-stack
+-- alongside our string.
--
--
--- >>> errorWithCallStack "die"
--- *** Exception: die
+-- >>> putStrLnWithCallStack "hello"
+-- hello
-- CallStack (from HasCallStack):
--- errorWithCallStack, called at <interactive>:2:1 in interactive:Ghci1
+-- putStrLnWithCallStack, called at <interactive>:2:1 in interactive:Ghci1
--
--
-- GHC solves 'HasCallStack' constraints in three steps:
More information about the ghc-commits
mailing list