From 94048f9fb01c541215cfc9cc215af83566b63236 Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Mon, 1 Feb 2016 14:32:19 +0100 Subject: Hide the CallStack implicit parameter The implicit parameter isn't actually very relevant to the CallStack machinery, so we hide the implementation details behind a constraint alias ``` type HasCallStack = (?callStack :: CallStack) ``` This has a few benefits: 1. No need to enable `ImplicitParams` in user code. 2. No need to remember the `?callStack` naming convention. 3. Gives us the option to change the implementation details in the future with less user-land breakage. The revised `CallStack` API is exported from `GHC.Stack` and makes no mention of the implicit parameter. Test Plan: ./validate Reviewers: simonpj, austin, hvr, bgamari Reviewed By: simonpj, bgamari Subscribers: thomie Projects: #ghc Differential Revision: https://phabricator.haskell.org/D1818 --- docs/users_guide/8.0.1-notes.rst | 26 +++--- docs/users_guide/ghci.rst | 4 +- docs/users_guide/glasgow_exts.rst | 186 ++++++++++++++++++++++---------------- 3 files changed, 122 insertions(+), 94 deletions(-) (limited to 'docs/users_guide') diff --git a/docs/users_guide/8.0.1-notes.rst b/docs/users_guide/8.0.1-notes.rst index 41e6c2b579..cf4cf8dfae 100644 --- a/docs/users_guide/8.0.1-notes.rst +++ b/docs/users_guide/8.0.1-notes.rst @@ -47,8 +47,8 @@ The highlights, since the 7.10 branch, are: - :ghc-flag:`-XDuplicateRecordFields`, allowing multiple datatypes to declare the same record field names provided they are used unambiguously (see :ref:`duplicate-record-fields`) -- Support for implicit parameters providing light-weight - :ref:`callstacks and source locations ` +- Support for lightweight + :ref:`callstacks and source locations ` - User-defined error messages for type errors @@ -85,24 +85,20 @@ Language -- | Just a normal sum Sum :: Int -> Int -> Expr Int -- Implicit parameters of the new ``base`` type :base-ref:`GHC.Stack.CallStack ` - are treated specially in function calls, the solver automatically - appends the source location of the call to the ``CallStack`` in - the environment. For example :: +- The new ``base`` constraint :base-ref:`GHC.Stack.HasCallStack ` + can be used by functions to request a partial call-stack. For example :: - myerror :: (?callStack :: CallStack) => String -> a - myerror msg = error (msg ++ "\n" ++ prettyCallStack ?callStack) + errorWithCallStack :: HasCallStack => String -> a + errorWithCallStack msg = error (msg ++ "\n" ++ prettyCallStack callStack) - ghci> myerror "die" + ghci> errorWithCallStack "die" *** Exception: die - CallStack (from ImplicitParams): - myerror, called at :2:1 in interactive:Ghci1 + CallStack (from HasCallStack): + errorWithCallStack, called at :2:1 in interactive:Ghci1 - prints the call-site of ``myerror``. The name of the implicit - parameter does not matter, but within ``base`` we call it - ``?callStack``. + prints the call-site of ``errorWithCallStack``. - See :ref:`lib-base` for a description of the ``CallStack`` type. + See :ref:`hascallstack` for a description of ``HasCallStack``. - GHC now supports visible type application, allowing programmers to easily specify how type parameters should be diff --git a/docs/users_guide/ghci.rst b/docs/users_guide/ghci.rst index c1ef93508f..20afb89d0e 100644 --- a/docs/users_guide/ghci.rst +++ b/docs/users_guide/ghci.rst @@ -1136,8 +1136,8 @@ conjunction with ``-fexternal-interpreter``. There are three ways to get access to the current call stack. - ``error`` and ``undefined`` automatically attach the current stack - to the error message. This often complements the implicit stack - stack (see :ref:`implicit-callstacks`), so both call stacks are + to the error message. This often complements the ``HasCallStack`` + stack (see :ref:`hascallstack`), so both call stacks are shown. - ``Debug.Trace.traceStack`` is a version of ``Debug.Trace.trace`` diff --git a/docs/users_guide/glasgow_exts.rst b/docs/users_guide/glasgow_exts.rst index 6ea2ef65df..c09d0efe6d 100644 --- a/docs/users_guide/glasgow_exts.rst +++ b/docs/users_guide/glasgow_exts.rst @@ -8040,83 +8040,6 @@ a type signature for ``y``, then ``y`` will get type ``let`` will see the inner binding of ``?x``, so ``(f 9)`` will return ``14``. -.. _implicit-callstacks: - -Implicit CallStacks -~~~~~~~~~~~~~~~~~~~ - -Implicit parameters of the new ``base`` type ``GHC.Stack.CallStack`` are -treated specially in function calls, the solver automatically pushes -the source location of the call onto the ``CallStack`` in the -environment. For example - -:: - - myerror :: (?callStack :: CallStack) => String -> a - myerror msg = error (msg ++ "\n" ++ prettyCallStack ?callStack) - - ghci> myerror "die" - *** Exception: die - CallStack (from ImplicitParams): - myerror, called at :2:1 in interactive:Ghci1 - -prints the call-site of ``myerror``. The name of the implicit -parameter does not matter, but within ``base`` we call it -``?callStack``. - -The ``CallStack`` will only extend as far as the types allow it, for -example - -.. code-block:: none - - head :: (?callStack :: CallStack) => [a] -> a - head [] = myerror "empty" - head (x:xs) = x - - bad :: Int - bad = head [] - - ghci> bad - *** Exception: empty - CallStack (from ImplicitParams): - myerror, called at Bad.hs:8:15 in main:Bad - head, called at Bad.hs:12:7 in main:Bad - -includes the call-site of ``myerror`` in ``head``, and of ``head`` in -``bad``, but not the call-site of ``bad`` at the GHCi prompt. - -GHC will never report an unbound implicit ``CallStack``, and will -instead default such occurrences to the empty ``CallStack``. - -``CallStack`` is kept abstract, but GHC provides a function :: - - getCallStack :: CallStack -> [(String, SrcLoc)] - -to access the individual call-sites in the stack. The ``String`` is the -name of the function that was called, and the ``SrcLoc`` provides the -package, module, and file name, as well as the line and column numbers. -GHC will infer ``CallStack`` constraints using the same rules as for -ordinary implicit parameters. - -``GHC.Stack`` additionally exports a function ``freezeCallStack`` that -allows users to freeze a ``CallStack``, preventing any future push -operations from having an effect. This can be used by library authors -to prevent ``CallStack``\s from exposing unnecessary implementation -details. Consider the ``head`` example above, the ``myerror`` line in -the printed stack is not particularly enlightening, so we might choose -to suppress it by freezing the ``CallStack`` that we pass to ``myerror``. - -.. code-block:: none - - head :: (?callStack :: CallStack) => [a] -> a - head [] = let ?callStack = freezeCallStack ?callStack in myerror "empty" - head (x:xs) = x - - ghci> head []] - *** Exception: empty - CallStack (from ImplicitParams): - head, called at Bad.hs:12:7 in main:Bad - .. _kinding: @@ -12879,3 +12802,112 @@ intuitive: :: let f = /\a \(d::Eq a). fst (member, True) in body Note that the bang has no effect at all in this case + +.. _hascallstack: + +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 :: + + errorWithCallStack :: HasCallStack => String -> a + +as a variant of ``error`` that will get its call-site. We can access the +call-stack inside ``errorWithCallStack`` with ``GHC.Stack.callStack``. :: + + errorWithCallStack :: HasCallStack => String -> a + errorWithCallStack msg = error (msg ++ "\n" ++ prettyCallStack callStack) + +Thus, if we call ``errorWithCallStack`` we will get a formatted call-stack +alongside our error message. + +.. code-block:: none + + ghci> errorWithCallStack "die" + *** Exception: die + CallStack (from HasCallStack): + errorWithCallStack, called at :2:1 in interactive:Ghci1 + +The ``CallStack`` will only extend as far as the types allow it, for +example :: + + head :: HasCallStack => [a] -> a + head [] = errorWithCallStack "empty" + head (x:xs) = x + + bad :: Int + bad = head [] + +.. code-block:: none + + ghci> bad + *** Exception: empty + CallStack (from HasCallStack): + errorWithCallStack, called at Bad.hs:8:15 in main:Bad + head, called at Bad.hs:12:7 in main:Bad + +includes the call-site of ``errorWithCallStack`` in ``head``, +and of ``head`` in ``bad``, +but not the call-site of ``bad`` at the GHCi prompt. + +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 push the new call-site + onto 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`` is kept abstract, but GHC provides a function :: + + getCallStack :: CallStack -> [(String, SrcLoc)] + +to access the individual call-sites in the stack. The ``String`` is the +name of the function that was called, and the ``SrcLoc`` provides the +package, module, and file name, as well as the line and column numbers. + +``GHC.Stack`` additionally exports a function ``withFrozenCallStack`` that +allows users to freeze the current ``CallStack``, preventing any future push +operations from having an effect. This can be used by library authors +to prevent ``CallStack``\s from exposing unnecessary implementation +details. Consider the ``head`` example above, the ``errorWithCallStack`` line in +the printed stack is not particularly enlightening, so we might choose +to suppress it by freezing the ``CallStack`` that we pass to ``errorWithCallStack``. :: + + head :: HasCallStack => [a] -> a + head [] = withFrozenCallStack (errorWithCallStack "empty") + head (x:xs) = x + +.. code-block:: none + + ghci> head [] + *** Exception: empty + CallStack (from HasCallStack): + head, called at Bad.hs:12:7 in main:Bad + +**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. + +Compared with other sources of stack traces +------------------------------------------- + +``HasCallStack`` does not interact with the RTS and does not require +compilation with ``-prof``. On the other hand, as the ``CallStack`` is +built up explicitly via the ``HasCallStack`` constraints, it will +generally not contain as much information as the simulated call-stacks +maintained by the RTS. -- cgit v1.2.1