Skip to content

Pattern synonyms in call stacks

Summary

When combining pattern synonyms, view patterns and GHC call stacks, the use site of the pattern synonym doesn't appear in the call stack, but any functions called through view patterns will still show up as called from within the pattern synonym. This makes it impossible to extract the source location of where the (explicitly-bidirectional) pattern synonym was used from the call stack.

The use case for having this information available would be to annotate an abstract syntax tree for an embedded language with source mapping information. We're using an explicitly bidirectional pattern synonym to construct tuples, and also to extract values from existing tuples by using view patterns to generate projection AST nodes for every element in the tuple.

Steps to reproduce

Below is a stripped down version of the pattern described above:

Main.hs
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}

module Main where

import           GHC.Stack

-- | Some useless pattern synonym that groups a value with the call stack using
-- view patterns. In the real code base where I'm using this this pattern
-- synonym generates part of an abstract syntax tree instead.
pattern Annotated :: HasCallStack => (CallStack, a) -> a
pattern Annotated x <- (addCallStack -> x)
  where
    Annotated (_, x) = x

-- | Used in 'Annotated' to pair a value with the current call stack, since
-- you cannot add the 'HasCallStack' constraint to a lambda (in the real use
-- case we would be calling a function that does something with the call stack
-- here).
addCallStack :: HasCallStack => a -> (CallStack, a)
addCallStack x = (callStack, x)

someAnnotatedValue :: (CallStack, Int)
someAnnotatedValue = let Annotated annotated = 10 in annotated

main :: IO ()
main = do
    let (stack, _) = someAnnotatedValue
    putStrLn "No lines from within 'someAnnotatedValue' (i.e. line 24) will show up here:"
    putStrLn $ prettyCallStack stack

Running this with either GHC 8.10.3 or the GHC 9.0.0.20201227 release candidate prints the following:

No lines from within 'someAnnotatedValue' (i.e. line 24) will show up here:
CallStack (from HasCallStack):
  addCallStack, called at Main.hs:12:25 in main:Main

Expected behavior

I'd expect either the use of the pattern synonym to show up in the call stack, or I'd expect the pattern synonym to be inlined and the call to addCallStack to show up as if it were originating from someAnnotatedValue (i.e. from Main.hs:24:25).

If this behaviour is intentional or an unavoidable consequence of how pattern synonyms are implemented, is there any other way to find out where Annotated was used from?

Environment

  • GHC version used: GHC 8.10.3 and 9.0.0.20201227 from ghcup

Optional:

  • Operating System: Manjaro Linux
  • System Architecture: x86_64
Edited by Robbert van der Helm
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information