diff options
author | Eric Seidel <gridaphobe@gmail.com> | 2016-02-01 14:32:19 +0100 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2016-02-01 14:32:25 +0100 |
commit | 94048f9fb01c541215cfc9cc215af83566b63236 (patch) | |
tree | e2407615eaf3b9d2298ebf0c688d04bbb5f40bd2 | |
parent | 0d601657ca6ec1812492bb16a7d0e181b370e2d8 (diff) | |
download | haskell-94048f9fb01c541215cfc9cc215af83566b63236.tar.gz |
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
-rw-r--r-- | compiler/typecheck/TcEvidence.hs | 25 | ||||
-rw-r--r-- | docs/users_guide/8.0.1-notes.rst | 26 | ||||
-rw-r--r-- | docs/users_guide/ghci.rst | 4 | ||||
-rw-r--r-- | docs/users_guide/glasgow_exts.rst | 186 | ||||
-rw-r--r-- | libraries/base/GHC/Err.hs | 21 | ||||
-rw-r--r-- | libraries/base/GHC/Exception.hs | 6 | ||||
-rw-r--r-- | libraries/base/GHC/Stack.hs | 31 | ||||
-rw-r--r-- | libraries/base/GHC/Stack/Types.hs | 93 | ||||
-rw-r--r-- | testsuite/driver/testlib.py | 6 |
9 files changed, 245 insertions, 153 deletions
diff --git a/compiler/typecheck/TcEvidence.hs b/compiler/typecheck/TcEvidence.hs index 5dfc7ac4e1..f58b73cf7f 100644 --- a/compiler/typecheck/TcEvidence.hs +++ b/compiler/typecheck/TcEvidence.hs @@ -527,16 +527,18 @@ Note [Overview of implicit CallStacks] The goal of CallStack evidence terms is to reify locations in the program source as runtime values, without any support from the RTS. We accomplish this by assigning a special meaning -to implicit parameters of type GHC.Stack.CallStack. +to constraints of type GHC.Stack.Types.HasCallStack, an alias -Implicit CallStacks are regular implicit parameters, augmented with two -extra rules in the constraint solver: + type HasCallStack = (?callStack :: CallStack) + +Implicit parameters of type GHC.Stack.Types.CallStack (the name is not +important) are solved in three steps: 1. Occurrences of CallStack IPs are solved directly from the given IP, just like a regular IP. For example, the occurrence of `?stk` in error :: (?stk :: CallStack) => String -> a - error s = raise (ErrorCall (s ++ show ?stk)) + error s = raise (ErrorCall (s ++ prettyCallStack ?stk)) will be solved for the `?stk` in `error`s context as before. @@ -604,14 +606,15 @@ in `g`, because `head` did not explicitly request a CallStack. Important Details: - GHC should NEVER report an insoluble CallStack constraint. -- A CallStack (defined in GHC.Stack) is a [(String, SrcLoc)], where the String - is the name of the binder that is used at the SrcLoc. SrcLoc is defined in - GHC.SrcLoc and contains the package/module/file name, as well as the full - source-span. Both CallStack and SrcLoc are kept abstract so only GHC can - construct new values. +- A CallStack (defined in GHC.Stack.Types) is a [(String, SrcLoc)], + where the String is the name of the binder that is used at the + SrcLoc. SrcLoc is also defined in GHC.Stack.Types and contains the + package/module/file name, as well as the full source-span. Both + CallStack and SrcLoc are kept abstract so only GHC can construct new + values. -- We will automatically solve any wanted CallStack regardless of the name of the - IP, i.e. +- We will automatically solve any wanted CallStack regardless of the + name of the IP, i.e. f = show (?stk :: CallStack) g = show (?loc :: CallStack) 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 <implicit-callstacks>` +- Support for lightweight + :ref:`callstacks and source locations <hascallstack>` - 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 <GHC-Stack.html>` - 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 <GHC-Stack.html>` + 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 <interactive>:2:1 in interactive:Ghci1 + CallStack (from HasCallStack): + errorWithCallStack, called at <interactive>: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 <interactive>: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 <interactive>: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. diff --git a/libraries/base/GHC/Err.hs b/libraries/base/GHC/Err.hs index f786359ba2..88b9c39898 100644 --- a/libraries/base/GHC/Err.hs +++ b/libraries/base/GHC/Err.hs @@ -34,25 +34,30 @@ import {-# SOURCE #-} GHC.Exception( errorCallWithCallStackException ) -- | 'error' stops execution and displays an error message. error :: forall (v :: Levity). forall (a :: TYPE v). - (?callStack :: CallStack) => [Char] -> a + HasCallStack => [Char] -> a error s = raise# (errorCallWithCallStackException s ?callStack) + -- Bleh, we should be using 'GHC.Stack.callStack' instead of + -- '?callStack' here, but 'GHC.Stack.callStack' depends on + -- 'GHC.Stack.popCallStack', which is partial and depends on + -- 'error'.. Do as I say, not as I do. -- | A variant of 'error' that does not produce a stack trace. -- -- @since 4.9.0.0 errorWithoutStackTrace :: forall (v :: Levity). forall (a :: TYPE v). [Char] -> a -errorWithoutStackTrace s - = let ?callStack = freezeCallStack ?callStack - in error s -{-# NOINLINE errorWithoutStackTrace #-} +errorWithoutStackTrace s = + -- we don't have withFrozenCallStack yet, so we just inline the definition + let ?callStack = freezeCallStack emptyCallStack + in error s + -- Note [Errors in base] -- ~~~~~~~~~~~~~~~~~~~~~ -- As of base-4.9.0.0, `error` produces a stack trace alongside the --- error message using the Implicit CallStack machinery. This provides +-- error message using the HasCallStack machinery. This provides -- a partial stack trace, containing the call-site of each function --- with a (?callStack :: CallStack) implicit parameter constraint. +-- with a HasCallStack constraint. -- -- In base, however, the only functions that have such constraints are -- error and undefined, so the stack traces from partial functions in @@ -70,7 +75,7 @@ errorWithoutStackTrace s -- messages which are more appropriate to the context in which 'undefined' -- appears. undefined :: forall (v :: Levity). forall (a :: TYPE v). - (?callStack :: CallStack) => a + HasCallStack => a undefined = error "Prelude.undefined" -- | Used for compiler-generated error message; diff --git a/libraries/base/GHC/Exception.hs b/libraries/base/GHC/Exception.hs index 6c579f0372..187ff88e33 100644 --- a/libraries/base/GHC/Exception.hs +++ b/libraries/base/GHC/Exception.hs @@ -200,7 +200,7 @@ showCCSStack stk = "CallStack (from -prof):" : map (" " ++) (reverse stk) -- prettySrcLoc and prettyCallStack are defined here to avoid hs-boot -- files. See Note [Definition of CallStack] --- | Pretty print 'SrcLoc' +-- | Pretty print a 'SrcLoc'. -- -- @since 4.8.1.0 prettySrcLoc :: SrcLoc -> String @@ -212,7 +212,7 @@ prettySrcLoc SrcLoc {..} , srcLocPackage, ":", srcLocModule ] --- | Pretty print 'CallStack' +-- | Pretty print a 'CallStack'. -- -- @since 4.8.1.0 prettyCallStack :: CallStack -> String @@ -221,7 +221,7 @@ prettyCallStack = intercalate "\n" . prettyCallStackLines prettyCallStackLines :: CallStack -> [String] prettyCallStackLines cs = case getCallStack cs of [] -> [] - stk -> "CallStack (from ImplicitParams):" + stk -> "CallStack (from HasCallStack):" : map ((" " ++) . prettyCallSite) stk where prettyCallSite (f, loc) = f ++ ", called at " ++ prettySrcLoc loc diff --git a/libraries/base/GHC/Stack.hs b/libraries/base/GHC/Stack.hs index 727910a659..477dcdc505 100644 --- a/libraries/base/GHC/Stack.hs +++ b/libraries/base/GHC/Stack.hs @@ -17,14 +17,16 @@ {-# LANGUAGE MagicHash, NoImplicitPrelude, ImplicitParams, RankNTypes #-} module GHC.Stack ( - -- * Call stacks + errorWithStackTrace, + + -- * Profiling call stacks currentCallStack, whoCreated, - errorWithStackTrace, - -- * Implicit parameter call stacks - CallStack, emptyCallStack, freezeCallStack, getCallStack, popCallStack, - prettyCallStack, pushCallStack, withFrozenCallStack, + -- * HasCallStack call stacks + CallStack, HasCallStack, callStack, emptyCallStack, freezeCallStack, + getCallStack, popCallStack, prettyCallStack, pushCallStack, + withFrozenCallStack, -- * Source locations SrcLoc(..), prettySrcLoc, @@ -75,16 +77,25 @@ popCallStack stk = case stk of EmptyCallStack -> errorWithoutStackTrace "popCallStack: empty stack" PushCallStack _ stk' -> stk' FreezeCallStack _ -> stk +{-# INLINE popCallStack #-} +-- | Return the current 'CallStack'. +-- +-- Does *not* include the call-site of 'callStack'. +-- +-- @since 4.9.0.0 +callStack :: HasCallStack => CallStack +callStack = popCallStack ?callStack +{-# INLINE callStack #-} -- | Perform some computation without adding new entries to the 'CallStack'. -- -- @since 4.9.0.0 -withFrozenCallStack :: (?callStack :: CallStack) - => ( (?callStack :: CallStack) => a ) +withFrozenCallStack :: HasCallStack + => ( HasCallStack => a ) -> a withFrozenCallStack do_this = - -- we pop the stack before freezing it to remove - -- withFrozenCallStack's call-site - let ?callStack = freezeCallStack (popCallStack ?callStack) + -- we pop the stack before freezing it to remove + -- withFrozenCallStack's call-site + let ?callStack = freezeCallStack (popCallStack callStack) in do_this diff --git a/libraries/base/GHC/Stack/Types.hs b/libraries/base/GHC/Stack/Types.hs index a971f7c86a..fb92522ab5 100644 --- a/libraries/base/GHC/Stack/Types.hs +++ b/libraries/base/GHC/Stack/Types.hs @@ -1,4 +1,10 @@ {-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE ImplicitParams #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE RankNTypes #-} + {-# OPTIONS_HADDOCK hide #-} -- we hide this module from haddock to enforce GHC.Stack as the main -- access point. @@ -13,15 +19,17 @@ -- Stability : internal -- Portability : non-portable (GHC Extensions) -- --- type definitions for call-stacks via implicit parameters. +-- type definitions for implicit call-stacks. -- Use "GHC.Stack" from the base package instead of importing this -- module directly. -- ----------------------------------------------------------------------------- module GHC.Stack.Types ( - -- * Implicit parameter call stacks - CallStack(..), emptyCallStack, freezeCallStack, getCallStack, pushCallStack, + -- * Implicit call stacks + CallStack(..), HasCallStack, + emptyCallStack, freezeCallStack, getCallStack, pushCallStack, + -- * Source locations SrcLoc(..) ) where @@ -49,43 +57,75 @@ import GHC.Integer () -- Explicit call-stacks built via ImplicitParams ---------------------------------------------------------------------- --- | Implicit @CallStack@s are an alternate method of obtaining the call stack --- at a given point in the program. +-- | Request a CallStack. -- --- GHC has two built-in rules for solving implicit-parameters of type --- @CallStack@. +-- NOTE: The implicit parameter @?callStack :: CallStack@ is an +-- implementation detail and __should not__ be considered part of the +-- 'CallStack' API, we may decide to change the implementation in the +-- future. -- --- 1. If the @CallStack@ occurs in a function call, it appends the --- source location of the call to the @CallStack@ in the environment. --- 2. @CallStack@s that cannot be solved normally (i.e. unbound --- occurrences) are defaulted to the empty @CallStack@. +-- @since 4.9.0.0 +type HasCallStack = (?callStack :: CallStack) + +-- | 'CallStack's are a lightweight method of obtaining a +-- partial call-stack at any point in the program. -- --- Otherwise implicit @CallStack@s behave just like ordinary implicit --- parameters. For example: +-- A function can request its call-site with the 'HasCallStack' constraint. +-- For example, we can define -- -- @ --- myerror :: (?callStack :: CallStack) => String -> a --- myerror msg = error (msg ++ "\n" ++ prettyCallStack ?callStack) +-- errorWithCallStack :: HasCallStack => String -> a -- @ -- --- Will produce the following when evaluated, +-- as a variant of @error@ that will get its call-site. We can access the +-- call-stack inside @errorWithCallStack@ with 'GHC.Stack.callStack'. -- -- @ --- ghci> myerror "die" --- *** Exception: die --- CallStack (from ImplicitParams): --- myerror, called at <interactive>:2:1 in interactive:Ghci1 +-- errorWithCallStack :: HasCallStack => String -> a +-- errorWithCallStack msg = error (msg ++ "\n" ++ prettyCallStack callStack) -- @ -- --- @CallStack@s do not interact with the RTS and do not require compilation with --- @-prof@. On the other hand, as they are built up explicitly using --- implicit-parameters, they will generally not contain as much information as --- the simulated call-stacks maintained by the RTS. +-- Thus, if we call @errorWithCallStack@ we will get a formatted call-stack +-- alongside our error message. +-- +-- +-- >>> errorWithCallStack "die" +-- *** Exception: die +-- CallStack (from HasCallStack): +-- errorWithCallStack, called at <interactive>:2:1 in interactive:Ghci1 +-- +-- +-- 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 append the new +-- call-site to 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). -- --- A @CallStack@ is a @[(String, SrcLoc)]@. The @String@ is the name of +-- 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's do not interact with the RTS and do not require compilation +-- with @-prof@. On the other hand, as they are built up explicitly via the +-- 'HasCallStack' constraints, they will generally not contain as much +-- information as the simulated call-stacks maintained by the RTS. +-- +-- A 'CallStack' is a @[(String, SrcLoc)]@. The @String@ is the name of -- function that was called, the 'SrcLoc' is the call-site. The list is -- ordered with the most recently called function at the head. -- +-- 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. +-- -- @since 4.8.1.0 data CallStack = EmptyCallStack @@ -110,7 +150,7 @@ getCallStack stk = case stk of -- Note [Definition of CallStack] -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- Implicit CallStacks are defined very early in base because they are +-- CallStack is defined very early in base because it is -- used by error and undefined. At this point in the dependency graph, -- we do not have enough functionality to (conveniently) write a nice -- pretty-printer for CallStack. The sensible place to define the @@ -143,6 +183,7 @@ emptyCallStack :: CallStack emptyCallStack = EmptyCallStack {-# INLINE emptyCallStack #-} + -- | Freeze a call-stack, preventing any further call-sites from being appended. -- -- prop> pushCallStack callSite (freezeCallStack callStack) = freezeCallStack callStack diff --git a/testsuite/driver/testlib.py b/testsuite/driver/testlib.py index 97a5a0d4be..0251884dc4 100644 --- a/testsuite/driver/testlib.py +++ b/testsuite/driver/testlib.py @@ -1689,13 +1689,17 @@ def normalise_whitespace( str ): # Merge contiguous whitespace characters into a single space. return ' '.join(w for w in str.split()) +callSite_re = re.compile(r', called at (.+):[\d]+:[\d]+ in [\w\-\.]+:') + def normalise_callstacks(str): def repl(matches): location = matches.group(1) location = normalise_slashes_(location) return ', called at {0}:<line>:<column> in <package-id>:'.format(location) # Ignore line number differences in call stacks (#10834). - return re.sub(', called at (.+):[\\d]+:[\\d]+ in [\\w\-\.]+:', repl, str) + str1 = re.sub(callSite_re, repl, str) + # Ignore the change in how we identify implicit call-stacks + return str1.replace('from ImplicitParams', 'from HasCallStack') tyCon_re = re.compile(r'TyCon\s*\d+L?\#\#\s*\d+L?\#\#\s*', flags=re.MULTILINE) |