getEps :: TcRnIf gbl lcl ExternalPackageState
getEps = do { env <- getTopEnv; readMutVar (hsc_EPS env) }
--- Updating the EPS. This should be an atomic operation.
--- Note the delicate 'seq' which forces the EPS before putting it in the
--- variable. Otherwise what happens is that we get
--- write eps_var (....(unsafeRead eps_var)....)
--- and if the .... is strict, that's obviously bottom. By forcing it beforehand
--- we make the unsafeRead happen before we update the variable.
-
+-- | Update the external package state. Returns the second result of the
+-- modifier function.
+--
+-- This is an atomic operation and forces evaluation of the modified EPS in
+-- order to avoid space leaks.
updateEps :: (ExternalPackageState -> (ExternalPackageState, a))
-> TcRnIf gbl lcl a
-updateEps upd_fn = do { traceIf (text "updating EPS")
- ; eps_var <- getEpsVar
- ; eps <- readMutVar eps_var
- ; let { (eps', val) = upd_fn eps }
- ; seq eps' (writeMutVar eps_var eps')
- ; return val }
+updateEps upd_fn = do
+ traceIf (text "updating EPS")
+ eps_var <- getEpsVar
+ atomicUpdMutVar' eps_var upd_fn
+-- | Update the external package state.
+--
+-- This is an atomic operation and forces evaluation of the modified EPS in
+-- order to avoid space leaks.
updateEps_ :: (ExternalPackageState -> ExternalPackageState)
-> TcRnIf gbl lcl ()
-updateEps_ upd_fn = do { traceIf (text "updating EPS_")
- ; eps_var <- getEpsVar
- ; eps <- readMutVar eps_var
- ; let { eps' = upd_fn eps }
- ; seq eps' (writeMutVar eps_var eps') }
+updateEps_ upd_fn = do
+ traceIf (text "updating EPS_")
+ eps_var <- getEpsVar
+ atomicUpdMutVar' eps_var (\eps -> (upd_fn eps, ()))
getHpt :: TcRnIf gbl lcl HomePackageTable
getHpt = do { env <- getTopEnv; return (hsc_HPT env) }
{ ctxt <- getErrCtxt
; loc <- getSrcSpanM
; env0 <- tcInitTidyEnv
- ; ctxt_msgs <- do_ctxt env0 ctxt
- ; let real_doc = mkLocMessage loc (vcat (doc : ctxt_to_use ctxt_msgs))
+ ; err_info <- mkErrInfo env0 ctxt
+ ; let real_doc = mkLocMessage loc (doc $$ err_info)
; dumpTcRn real_doc }
dumpTcRn :: SDoc -> TcRn ()
%************************************************************************
\begin{code}
-getErrCtxt :: TcM ErrCtxt
+getErrCtxt :: TcM [ErrCtxt]
getErrCtxt = do { env <- getLclEnv; return (tcl_ctxt env) }
-setErrCtxt :: ErrCtxt -> TcM a -> TcM a
+setErrCtxt :: [ErrCtxt] -> TcM a -> TcM a
setErrCtxt ctxt = updLclEnv (\ env -> env { tcl_ctxt = ctxt })
addErrCtxt :: Message -> TcM a -> TcM a
addErrCtxt msg = addErrCtxtM (\env -> return (env, msg))
addErrCtxtM :: (TidyEnv -> TcM (TidyEnv, Message)) -> TcM a -> TcM a
-addErrCtxtM msg = updCtxt (\ msgs -> msg : msgs)
+addErrCtxtM ctxt = updCtxt (\ ctxts -> (False, ctxt) : ctxts)
+
+addLandmarkErrCtxt :: Message -> TcM a -> TcM a
+addLandmarkErrCtxt msg = updCtxt (\ctxts -> (True, \env -> return (env,msg)) : ctxts)
-- Helper function for the above
-updCtxt :: (ErrCtxt -> ErrCtxt) -> TcM a -> TcM a
+updCtxt :: ([ErrCtxt] -> [ErrCtxt]) -> TcM a -> TcM a
updCtxt upd = updLclEnv (\ env@(TcLclEnv { tcl_ctxt = ctxt }) ->
env { tcl_ctxt = upd ctxt })
= do { loc <- getSrcSpanM ; env <- getLclEnv ;
return (InstLoc origin loc (tcl_ctxt env)) }
-addInstCtxt :: InstLoc -> TcM a -> TcM a
+setInstCtxt :: InstLoc -> TcM a -> TcM a
-- Add the SrcSpan and context from the first Inst in the list
-- (they all have similar locations)
-addInstCtxt (InstLoc _ src_loc ctxt) thing_inside
- = setSrcSpan src_loc (updCtxt (\_ -> ctxt) thing_inside)
+setInstCtxt (InstLoc _ src_loc ctxt) thing_inside
+ = setSrcSpan src_loc (setErrCtxt ctxt thing_inside)
\end{code}
The addErrTc functions add an error message, but do not cause failure.
addWarnTcM :: (TidyEnv, Message) -> TcM ()
addWarnTcM (env0, msg)
= do { ctxt <- getErrCtxt ;
- ctxt_msgs <- do_ctxt env0 ctxt ;
- addReport (vcat (ptext (sLit "Warning:") <+> msg : ctxt_to_use ctxt_msgs)) }
+ err_info <- mkErrInfo env0 ctxt ;
+ addReport (vcat [ptext (sLit "Warning:") <+> msg, err_info]) }
warnTc :: Bool -> Message -> TcM ()
warnTc warn_if_true warn_msg
\begin{code}
add_err_tcm :: TidyEnv -> Message -> SrcSpan
- -> [TidyEnv -> TcM (TidyEnv, SDoc)]
+ -> [ErrCtxt]
-> TcM ()
add_err_tcm tidy_env err_msg loc ctxt
- = do { ctxt_msgs <- do_ctxt tidy_env ctxt ;
- addLongErrAt loc err_msg (vcat (ctxt_to_use ctxt_msgs)) }
-
-do_ctxt :: TidyEnv -> [TidyEnv -> TcM (TidyEnv, SDoc)] -> TcM [SDoc]
-do_ctxt _ []
- = return []
-do_ctxt tidy_env (c:cs)
- = do { (tidy_env', m) <- c tidy_env ;
- ms <- do_ctxt tidy_env' cs ;
- return (m:ms) }
-
-ctxt_to_use :: [SDoc] -> [SDoc]
-ctxt_to_use ctxt | opt_PprStyle_Debug = ctxt
- | otherwise = take 3 ctxt
+ = do { err_info <- mkErrInfo tidy_env ctxt ;
+ addLongErrAt loc err_msg err_info }
+
+mkErrInfo :: TidyEnv -> [ErrCtxt] -> TcM SDoc
+-- Tidy the error info, trimming excessive contexts
+mkErrInfo env ctxts
+ = go 0 env ctxts
+ where
+ go :: Int -> TidyEnv -> [ErrCtxt] -> TcM SDoc
+ go _ _ [] = return empty
+ go n env ((is_landmark, ctxt) : ctxts)
+ | is_landmark || opt_PprStyle_Debug || n < mAX_CONTEXTS
+ = do { (env', msg) <- ctxt env
+ ; let n' = if is_landmark then n else n+1
+ ; rest <- go n' env' ctxts
+ ; return (msg $$ rest) }
+ | otherwise
+ = go n env ctxts
+
+mAX_CONTEXTS :: Int -- No more than this number of non-landmark contexts
+mAX_CONTEXTS = 3
\end{code}
debugTc is useful for monadic debugging code