[GHC] #14911: Offer a way to augment call stacks

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature | Status: new request | Priority: normal | Milestone: 8.6.1 Component: Core | Version: 8.4.1 Libraries | Keywords: CallStacks | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- Sometimes, I may want to capture some information that can be reported when an error occurs. Suppose I have {{{#!hs f x y = g x (h y) g :: HasCallStack => ... g x y = ..... (error "whoopsy") .... }}} I may want `f` to record information about `y` that will be reported if `g` throws an exception. As far as I can tell, the only currently supported way to do this is horrible and limited: {{{#!hs f x y = unsafeDupablePerformIO $ catch (evaluate (g x (h y))) $ \e -> .... }}} I'd much rather have a function like {{{#!hs addMessage :: HasCallStack => String -> (HasCallStack => a) -> a }}} This would stick a string into the current call stack "frame" and call the argument. I imagine this can be implemented directly with the underlying implicit parameter, likely with a slight change to the `CallStack` representation. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): Here's a very rough draft. This can be written without modifying the `CallStack` type, but I imagine it would be better to modify that. {{{#!hs extraCS :: HasCallStack => String -> (HasCallStack => a) -> a extraCS s a = let cs = ?callStack in let ?callStack = case cs of EmptyCallStack -> EmptyCallStack PushCallStack x y z -> PushCallStack (x ++ " (" ++ s ++ ")") y z q@(FreezeCallStack _) -> q in a }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): I like the idea. Worth a GHC proposal? Not because it'll be controversial, but because the debate often improves the design. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): I'll be happy to write a GHC proposal if you think that's appropriate. But do we need the full weight of that process for this change, or would a discussion on the libraries list be sufficient? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): I agree that this probably falls under the bar for a full proposal, given that this is simply a combinator that is defined in terms of the existing `base` API. A libraries mailing list discussion would suffice, in my view. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nomeata): Before putting stuff in `base`, maybe start start a library `ghc-stack- utils` or something with this (and possibly other combinators)? This would allow you to experiment more freely, users can use it with old versions of GHC and we see which combinators are actually useful. We can add a reference to this library in the documentation for `HasCallStack`, so that people can find it. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): nomeata, the trouble is that I think doing this 'properly' requires modification of the `CallStack` type. We can't really do that elsewhere. I don't think the current interface has really been through the wringer either; it's brand new! Why should a minor extension have to face a high hurdle? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nomeata): What’s wrong with your implementation of `extraCS`? I don’t see it as a hurdle, and don't oppose inclusion in `base`, but rather an opportunity; separate libraries are more agile. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): My implementation of `extraCS` leads to pretty bad output, but I've finally managed to fix that. However, the only fix I managed to find involved doing some seriously shady things! Let me explain a little. If you look at `extraCS` above, you'll see a variable called `a`. That variable is very boring, and there's no point in having it show up in the stack trace. But because the passed function (bound to `a`) has a `HasCallStack` constraint, the name `a` is captured as a stack frame. Maybe there's some clever way to avoid that without shadiness, but I couldn't find one! I ended up having to do this: {{{#!hs {-# language RankNTypes #-} import GHC.Stack import GHC.Stack.Types import Unsafe.Coerce newtype Magic a = Magic (CallStack -> String -> (CallStack -> a) -> a) newtype Magic2 a = Magic2 (HasCallStack => String -> (HasCallStack => a) -> a) extraCS :: forall a. HasCallStack => String -> (HasCallStack => a) -> a extraCS = case unsafeCoerce (Magic boom) of Magic2 x -> x boom :: CallStack -> String -> (CallStack -> a) -> a boom cs s z = let cs' = case popCallStack cs of EmptyCallStack -> EmptyCallStack PushCallStack x y z -> PushCallStack (x ++ " (" ++ s ++ ")") y z r@(FreezeCallStack _) -> r in z cs' }}} What a mess! Unless someone comes up with a cleverer workaround (please do!), that leaves two options: 1. Add some sort of compiler magic to help. This would be beyond me, but potentially valuable to provide finer-grained control of call stacks in general. 2. Add logic to the call stack printer to make it skip those particular stack frames. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): nomeata, I figured I'd get the package going anyway. See [http://hackage.haskell.org/package/ghc-call-stack-extras-0.1.0.0 ghc- call-stack-extras]. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): Another problem, arguably bigger: if an exception occurs when forcing a stack message, that could be handled gracefully by `renderStack` (in `base`), but not properly elsewhere. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nomeata): Ok ok, I get buy it now that the interface provided by `base` is not good enough yet :-) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:11 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14911: Offer a way to augment call stacks -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Core Libraries | Version: 8.4.1 Resolution: | Keywords: CallStacks Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): I've opened https://github.com/ghc-proposals/ghc-proposals/pull/117 for the piece of this that I think could use compiler support. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14911#comment:12 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC