Ticket #1265 (closed bug: fixed)
Template Haskell fail Messages not Getting Through
|Reported by:||twhitehe@…||Owned by:||igloo|
|Type of failure:||Difficulty:||Unknown|
|Test Case:||Blocked By:|
There is (I believe) a mistake in GHC's template Haskell implementation int the way the fail member is handled. The error messages get eaten and replaced with a cryptic reference to an "IOEnv failure". For example (at the "ghci -fth" prompt):
Prelude> let doit = fail "Code not written yet" :: Language.Haskell.TH.ExpQ Loading package template-haskell ... linking ... done. Prelude> $(doit) <interactive>:1:2: Exception when trying to run compile-time code: user error (IOEnv failure) Code: doit In the expression: $[splice]doit In the definition of `it': it = $[splice]doit Prelude>
The problem seems to be that GHC runs the template code in the IOEnv monad (compiler/typecheck/TcSplite.lhs) whose fail implementation (compiler/utils/IOEnv.hs) eats its argument and instead raises "userError "IOEnv failure"".
I put a patch together for this, and will submit it soon (i.e., as soon as I finish reading the pages on how to do so). With the patch, the above examples becomes:
Prelude> let doit = fail "Code not written yet" :: Language.Haskell.TH.ExpQ Loading package template-haskell ... linking ... done. Prelude> $(doit) <interactive>:1:2: Code not written yet Prelude>
This is achieved through changing the fail implementation for the Q monad to first log the message with report before passing control through the fail member of the underlying Quasi instance (IOEnv in this case) and changing the exception handling code around the running of the template code to gracefully handle exceptions raised in such a manner (i.e., print out the logged message).
It is a bit hackish, but it was the only way I could see to do this with out changing the fail implementation for IOEnv (I assume it was written the way it is for a reason -- possibly to avoid spamming the user with messages regarding compiler problems -- although it does seems strange) or introducing an additional function into the Q monad (such as giveUp from "Notes on Template Haskell Version 2").