Check whether the main function is actually exported (#414)
[ghc-hetmet.git] / compiler / typecheck / TcRnMonad.lhs
index a8146ba..f4b9131 100644 (file)
@@ -114,9 +114,9 @@ initTc hsc_env hsc_src keep_rn_syntax mod do_this
                tcg_fords    = [],
                tcg_dfun_n   = dfun_n_var,
                tcg_keep     = keep_var,
-               tcg_doc      = Nothing,
-               tcg_hmi      = HaddockModInfo Nothing Nothing Nothing Nothing,
-                tcg_hpc      = False
+               tcg_doc_hdr  = Nothing,
+                tcg_hpc      = False,
+                tcg_main     = Nothing
             } ;
             lcl_env = TcLclEnv {
                tcl_errs       = errs_var,
@@ -257,29 +257,28 @@ getEpsVar = do { env <- getTopEnv; return (hsc_EPS env) }
 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) }
@@ -363,8 +362,8 @@ traceOptTcRn flag doc = ifOptM flag $ do
                        { 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 ()
@@ -456,6 +455,7 @@ wrapLocSndM fn (L loc a) =
     return (b, L loc c)
 \end{code}
 
+Reporting errors
 
 \begin{code}
 getErrsVar :: TcRn (TcRef Messages)
@@ -470,47 +470,25 @@ addErr msg = do { loc <- getSrcSpanM ; addErrAt loc msg }
 failWith :: Message -> TcRn a
 failWith msg = addErr msg >> failM
 
-addLocErr :: Located e -> (e -> Message) -> TcRn ()
-addLocErr (L loc e) fn = addErrAt loc (fn e)
-
 addErrAt :: SrcSpan -> Message -> TcRn ()
-addErrAt loc msg = addLongErrAt loc msg empty
-
-addLongErrAt :: SrcSpan -> Message -> Message -> TcRn ()
-addLongErrAt loc msg extra
-  = do { traceTc (ptext (sLit "Adding error:") <+> (mkLocMessage loc (msg $$ extra))) ;        
-        errs_var <- getErrsVar ;
-        rdr_env <- getGlobalRdrEnv ;
-         dflags <- getDOpts ;
-        let { err = mkLongErrMsg loc (mkPrintUnqualified dflags rdr_env) msg extra } ;
-        (warns, errs) <- readMutVar errs_var ;
-        writeMutVar errs_var (warns, errs `snocBag` err) }
+-- addErrAt is mainly (exclusively?) used by the renamer, where
+-- tidying is not an issue, but it's all lazy so the extra
+-- work doesn't matter
+addErrAt loc msg = do { ctxt <- getErrCtxt 
+                     ; tidy_env <- tcInitTidyEnv
+                      ; err_info <- mkErrInfo tidy_env ctxt
+                     ; addLongErrAt loc msg err_info }
 
 addErrs :: [(SrcSpan,Message)] -> TcRn ()
 addErrs msgs = mapM_ add msgs
             where
               add (loc,msg) = addErrAt loc msg
 
-addReport :: Message -> TcRn ()
-addReport msg = do loc <- getSrcSpanM; addReportAt loc msg
-
-addReportAt :: SrcSpan -> Message -> TcRn ()
-addReportAt loc msg
-  = do { errs_var <- getErrsVar ;
-        rdr_env <- getGlobalRdrEnv ;
-         dflags <- getDOpts ;
-        let { warn = mkWarnMsg loc (mkPrintUnqualified dflags rdr_env) msg } ;
-        (warns, errs) <- readMutVar errs_var ;
-        writeMutVar errs_var (warns `snocBag` warn, errs) }
-
 addWarn :: Message -> TcRn ()
-addWarn msg = addReport (ptext (sLit "Warning:") <+> msg)
+addWarn msg = addReport (ptext (sLit "Warning:") <+> msg) empty
 
 addWarnAt :: SrcSpan -> Message -> TcRn ()
-addWarnAt loc msg = addReportAt loc (ptext (sLit "Warning:") <+> msg)
-
-addLocWarn :: Located e -> (e -> Message) -> TcRn ()
-addLocWarn (L loc e) fn = addReportAt loc (fn e)
+addWarnAt loc msg = addReportAt loc (ptext (sLit "Warning:") <+> msg) empty
 
 checkErr :: Bool -> Message -> TcRn ()
 -- Add the error if the bool is False
@@ -543,6 +521,38 @@ discardWarnings thing_inside
 \end{code}
 
 
+%************************************************************************
+%*                                                                     *
+       Shared error message stuff: renamer and typechecker
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+addReport :: Message -> Message -> TcRn ()
+addReport msg extra_info = do loc <- getSrcSpanM; addReportAt loc msg extra_info
+
+addReportAt :: SrcSpan -> Message -> Message -> TcRn ()
+addReportAt loc msg extra_info
+  = do { errs_var <- getErrsVar ;
+        rdr_env <- getGlobalRdrEnv ;
+         dflags <- getDOpts ;
+        let { warn = mkLongWarnMsg loc (mkPrintUnqualified dflags rdr_env)
+                                   msg extra_info } ;
+        (warns, errs) <- readMutVar errs_var ;
+        writeMutVar errs_var (warns `snocBag` warn, errs) }
+
+addLongErrAt :: SrcSpan -> Message -> Message -> TcRn ()
+addLongErrAt loc msg extra
+  = do { traceTc (ptext (sLit "Adding error:") <+> (mkLocMessage loc (msg $$ extra))) ;        
+        errs_var <- getErrsVar ;
+        rdr_env <- getGlobalRdrEnv ;
+         dflags <- getDOpts ;
+        let { err = mkLongErrMsg loc (mkPrintUnqualified dflags rdr_env) msg extra } ;
+        (warns, errs) <- readMutVar errs_var ;
+        writeMutVar errs_var (warns, errs `snocBag` err) }
+\end{code}
+
+
 \begin{code}
 try_m :: TcRn r -> TcRn (Either IOEnvFailure r)
 -- Does try_m, with a debug-trace on failure
@@ -675,26 +685,28 @@ failIfErrsM = ifErrsM failM (return ())
 
 %************************************************************************
 %*                                                                     *
-       Context management and error message generation
-                   for the type checker
+       Context management for the type checker
 %*                                                                     *
 %************************************************************************
 
 \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 })
 
@@ -718,6 +730,12 @@ setInstCtxt (InstLoc _ src_loc ctxt) thing_inside
   = setSrcSpan src_loc (setErrCtxt ctxt thing_inside)
 \end{code}
 
+%************************************************************************
+%*                                                                     *
+            Error message generation (type checker)
+%*                                                                     *
+%************************************************************************
+
     The addErrTc functions add an error message, but do not cause failure.
     The 'M' variants pass a TidyEnv that has already been used to
     tidy up the message; we then use it to tidy the context messages
@@ -763,8 +781,8 @@ addWarnTc msg = do { env0 <- tcInitTidyEnv
 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 (ptext (sLit "Warning:") <+> msg) err_info }
 
 warnTc :: Bool -> Message -> TcM ()
 warnTc warn_if_true warn_msg
@@ -801,23 +819,30 @@ tcInitTidyEnv
 
 \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