Error messages and constraints can easily be lost by accident
Today I rediscovered a nasty, subtle bug, which we have seen before: #19470 (closed)
The problem is that in the typechecker we use this idiom quite a lot
do { (gbl_env, lcl_env) <- tcRnSrcDecls ...
; setGblEnv gbl_env $ setLclEnv lcl_env $
more_stuff }
The tcRnSrcDecls
extends the environments in gbl_env
and lcl_env
which we then
want to be in scope in more stuff
.
The problem is that lcl_env :: TcLclEnv
has an IORef for error messages tcl_errs
, and another for constraints (tcl_lie
),a
and another for Linear Haskell usage information (tcl_usage
). Now suppose we change it a tiny bit
do { (gbl_env, lcl_env) <- checkNoErrs $
tcRnSrcDecls ...
; setGblEnv gbl_env $ setLclEnv lcl_env $
more_stuff }
That should be innocuous. But alas, checkNoErrs
gathers errors in a fresh IORef *which is then captured in the returned lcl_env
. When we do the setLclEnv
we'll make that captured IORef into the place where we gather error messages -- but no one is going to look at that IORef any more, so the errors are simply lost.
This was worked around in the fix to #19470 (closed), namely !5495 (closed). But it bit me in a different way today.
We should make a more general fix.