Add an option to infer CallStack implicit parameters
Adam Foltzer mentioned to me at ICFP that it would be nice if GHC had a "debug" mode that automatically inserted CallStack IPs in every function signature. Then you could easily get nice, fairly complete, call-stacks during development. Of course you could already do this with judicious use of CPP macros, but that's quite tedious (and error prone).
As an example, consider
module A where
foo xs = head xs
head :: [a] -> a
head (x:xs) = x
head _ = error "bad"
Compiling A
in this mode should result in the following signature
module A where
foo :: (?callStack :: CallStack) => [a] -> a
head :: (?callStack :: CallStack) => [a] -> a
I have a few concerns with this though:
- We're changing a type signature that the user wrote. It would be a well-defined and consistent change across the whole module, but it's still unsettling.
- How do we handle a function that already has a CallStack IP?
bar :: (?stk :: CallStack) => [a] -> a
If we're aiming for consistent insertion of CallStacks everywhere, it might make sense to remove the
?stk :: CallStack
and insert a?callStack :: CallStack
, so they'll be appended correctly. But here again we'd be changing a user-written type signature. Furthermore,bar
might call a function from a different module (or package) that hasn't been given this consistent debug treatment, and this other module might expect that the CallStack be named?stk
.
- If the CallStack is not used, e.g.
null :: (?callStack :: CallStack) => [a] -> Bool
null [] = True
null (_:_) = False
it will trigger a redundant constraint warning. I think we could address this by bubbling up CallStack constraints in much the same way that other constraints are propagated, so
module A where
foo xs = head xs
head :: [a] -> a
head (x:xs) = x
head _ = error "bad"
null [] = True
null (_:_) = False
would get the signature
module A where
foo :: (?callStack :: CallStack) => [a] -> a
head :: (?callStack :: CallStack) => [a] -> a
null :: [a] -> Bool
In other words, we would only infer a CallStack constraint for a function when the body induces a wanted CallStack constraint.
- How would this interact with cabal packages? If I accidentally install a package in debug mode, all downsteam packages will be compiled against the CallStack-laden signatures. Seems like we might need a new "debug" way..
It's pretty clear to me that a debug mode would be useful (in fact I manually added a bunch of CallStacks to my code the other day, only to remove them once I was done debugging), but the concerns (particularly 4.) are substantial. There's also the question of how all of this interacts with the ongoing DWARF work.
Trac metadata
Trac field | Value |
---|---|
Version | 7.11 |
Type | FeatureRequest |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |