summaryrefslogtreecommitdiff
path: root/compiler/typecheck/TcRnMonad.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/typecheck/TcRnMonad.lhs')
-rw-r--r--compiler/typecheck/TcRnMonad.lhs1042
1 files changed, 1042 insertions, 0 deletions
diff --git a/compiler/typecheck/TcRnMonad.lhs b/compiler/typecheck/TcRnMonad.lhs
new file mode 100644
index 0000000000..ff1979bc06
--- /dev/null
+++ b/compiler/typecheck/TcRnMonad.lhs
@@ -0,0 +1,1042 @@
+\begin{code}
+module TcRnMonad(
+ module TcRnMonad,
+ module TcRnTypes,
+ module IOEnv
+ ) where
+
+#include "HsVersions.h"
+
+import TcRnTypes -- Re-export all
+import IOEnv -- Re-export all
+
+#if defined(GHCI) && defined(BREAKPOINT)
+import TypeRep ( Type(..), liftedTypeKind, TyThing(..) )
+import Var ( mkTyVar, mkGlobalId )
+import IdInfo ( GlobalIdDetails(..), vanillaIdInfo )
+import OccName ( mkOccName, tvName )
+import SrcLoc ( noSrcLoc )
+import TysWiredIn ( intTy, stringTy, mkListTy, unitTy )
+import PrelNames ( breakpointJumpName )
+import NameEnv ( mkNameEnv )
+#endif
+
+import HsSyn ( emptyLHsBinds )
+import HscTypes ( HscEnv(..), ModGuts(..), ModIface(..),
+ TyThing, TypeEnv, emptyTypeEnv, HscSource(..),
+ isHsBoot, ModSummary(..),
+ ExternalPackageState(..), HomePackageTable,
+ Deprecs(..), FixityEnv, FixItem,
+ lookupType, unQualInScope )
+import Module ( Module, unitModuleEnv )
+import RdrName ( GlobalRdrEnv, emptyGlobalRdrEnv,
+ LocalRdrEnv, emptyLocalRdrEnv )
+import Name ( Name, isInternalName, mkInternalName, tidyNameOcc, nameOccName, getSrcLoc )
+import Type ( Type )
+import TcType ( tcIsTyVarTy, tcGetTyVar )
+import NameEnv ( extendNameEnvList, nameEnvElts )
+import InstEnv ( emptyInstEnv )
+
+import Var ( setTyVarName )
+import VarSet ( emptyVarSet )
+import VarEnv ( TidyEnv, emptyTidyEnv, extendVarEnv )
+import ErrUtils ( Message, Messages, emptyMessages, errorsFound,
+ mkWarnMsg, printErrorsAndWarnings,
+ mkLocMessage, mkLongErrMsg )
+import Packages ( mkHomeModules )
+import SrcLoc ( mkGeneralSrcSpan, isGoodSrcSpan, SrcSpan, Located(..) )
+import NameEnv ( emptyNameEnv )
+import NameSet ( NameSet, emptyDUs, emptyNameSet, unionNameSets, addOneToNameSet )
+import OccName ( emptyOccEnv, tidyOccName )
+import Bag ( emptyBag )
+import Outputable
+import UniqSupply ( UniqSupply, mkSplitUniqSupply, uniqFromSupply, splitUniqSupply )
+import Unique ( Unique )
+import DynFlags ( DynFlags(..), DynFlag(..), dopt, dopt_set, GhcMode )
+import StaticFlags ( opt_PprStyle_Debug )
+import Bag ( snocBag, unionBags )
+import Panic ( showException )
+
+import IO ( stderr )
+import DATA_IOREF ( newIORef, readIORef )
+import EXCEPTION ( Exception )
+\end{code}
+
+
+
+%************************************************************************
+%* *
+ initTc
+%* *
+%************************************************************************
+
+\begin{code}
+ioToTcRn :: IO r -> TcRn r
+ioToTcRn = ioToIOEnv
+\end{code}
+
+\begin{code}
+initTc :: HscEnv
+ -> HscSource
+ -> Module
+ -> TcM r
+ -> IO (Messages, Maybe r)
+ -- Nothing => error thrown by the thing inside
+ -- (error messages should have been printed already)
+
+initTc hsc_env hsc_src mod do_this
+ = do { errs_var <- newIORef (emptyBag, emptyBag) ;
+ tvs_var <- newIORef emptyVarSet ;
+ type_env_var <- newIORef emptyNameEnv ;
+ dfuns_var <- newIORef emptyNameSet ;
+ keep_var <- newIORef emptyNameSet ;
+ th_var <- newIORef False ;
+ dfun_n_var <- newIORef 1 ;
+ let {
+ gbl_env = TcGblEnv {
+ tcg_mod = mod,
+ tcg_src = hsc_src,
+ tcg_rdr_env = emptyGlobalRdrEnv,
+ tcg_fix_env = emptyNameEnv,
+ tcg_default = Nothing,
+ tcg_type_env = emptyNameEnv,
+ tcg_type_env_var = type_env_var,
+ tcg_inst_env = emptyInstEnv,
+ tcg_inst_uses = dfuns_var,
+ tcg_th_used = th_var,
+ tcg_exports = emptyNameSet,
+ tcg_imports = init_imports,
+ tcg_home_mods = home_mods,
+ tcg_dus = emptyDUs,
+ tcg_rn_imports = Nothing,
+ tcg_rn_exports = Nothing,
+ tcg_rn_decls = Nothing,
+ tcg_binds = emptyLHsBinds,
+ tcg_deprecs = NoDeprecs,
+ tcg_insts = [],
+ tcg_rules = [],
+ tcg_fords = [],
+ tcg_dfun_n = dfun_n_var,
+ tcg_keep = keep_var
+ } ;
+ lcl_env = TcLclEnv {
+ tcl_errs = errs_var,
+ tcl_loc = mkGeneralSrcSpan FSLIT("Top level"),
+ tcl_ctxt = [],
+ tcl_rdr = emptyLocalRdrEnv,
+ tcl_th_ctxt = topStage,
+ tcl_arrow_ctxt = NoArrowCtxt,
+ tcl_env = emptyNameEnv,
+ tcl_tyvars = tvs_var,
+ tcl_lie = panic "initTc:LIE" -- LIE only valid inside a getLIE
+ } ;
+ } ;
+
+ -- OK, here's the business end!
+ maybe_res <- initTcRnIf 'a' hsc_env gbl_env lcl_env $
+ do {
+#if defined(GHCI) && defined(BREAKPOINT)
+ unique <- newUnique ;
+ let { var = mkInternalName unique (mkOccName tvName "a") noSrcLoc;
+ tyvar = mkTyVar var liftedTypeKind;
+ breakpointJumpType = mkGlobalId
+ (VanillaGlobal)
+ (breakpointJumpName)
+ (FunTy intTy
+ (FunTy (mkListTy unitTy)
+ (FunTy stringTy
+ (ForAllTy tyvar
+ (FunTy (TyVarTy tyvar)
+ (TyVarTy tyvar))))))
+ (vanillaIdInfo);
+ new_env = mkNameEnv [(breakpointJumpName,AGlobal (AnId breakpointJumpType))];
+ };
+ r <- tryM (updLclEnv (\gbl -> gbl{tcl_env=new_env}) do_this)
+#else
+ r <- tryM do_this
+#endif
+ ; case r of
+ Right res -> return (Just res)
+ Left _ -> return Nothing } ;
+
+ -- Collect any error messages
+ msgs <- readIORef errs_var ;
+
+ let { dflags = hsc_dflags hsc_env
+ ; final_res | errorsFound dflags msgs = Nothing
+ | otherwise = maybe_res } ;
+
+ return (msgs, final_res)
+ }
+ where
+ home_mods = mkHomeModules (map ms_mod (hsc_mod_graph hsc_env))
+ -- A guess at the home modules. This will be correct in
+ -- --make and GHCi modes, but in one-shot mode we need to
+ -- fix it up after we know the real dependencies of the current
+ -- module (see tcRnModule).
+ -- Setting it here is necessary for the typechecker entry points
+ -- other than tcRnModule: tcRnGetInfo, for example. These are
+ -- all called via the GHC module, so hsc_mod_graph will contain
+ -- something sensible.
+
+ init_imports = emptyImportAvails {imp_env = unitModuleEnv mod emptyNameSet}
+ -- Initialise tcg_imports with an empty set of bindings for
+ -- this module, so that if we see 'module M' in the export
+ -- list, and there are no bindings in M, we don't bleat
+ -- "unknown module M".
+
+initTcPrintErrors -- Used from the interactive loop only
+ :: HscEnv
+ -> Module
+ -> TcM r
+ -> IO (Maybe r)
+initTcPrintErrors env mod todo = do
+ (msgs, res) <- initTc env HsSrcFile mod todo
+ printErrorsAndWarnings (hsc_dflags env) msgs
+ return res
+
+-- mkImpTypeEnv makes the imported symbol table
+mkImpTypeEnv :: ExternalPackageState -> HomePackageTable
+ -> Name -> Maybe TyThing
+mkImpTypeEnv pcs hpt = lookup
+ where
+ pte = eps_PTE pcs
+ lookup name | isInternalName name = Nothing
+ | otherwise = lookupType hpt pte name
+\end{code}
+
+
+%************************************************************************
+%* *
+ Initialisation
+%* *
+%************************************************************************
+
+
+\begin{code}
+initTcRnIf :: Char -- Tag for unique supply
+ -> HscEnv
+ -> gbl -> lcl
+ -> TcRnIf gbl lcl a
+ -> IO a
+initTcRnIf uniq_tag hsc_env gbl_env lcl_env thing_inside
+ = do { us <- mkSplitUniqSupply uniq_tag ;
+ ; us_var <- newIORef us ;
+
+ ; let { env = Env { env_top = hsc_env,
+ env_us = us_var,
+ env_gbl = gbl_env,
+ env_lcl = lcl_env } }
+
+ ; runIOEnv env thing_inside
+ }
+\end{code}
+
+%************************************************************************
+%* *
+ Simple accessors
+%* *
+%************************************************************************
+
+\begin{code}
+getTopEnv :: TcRnIf gbl lcl HscEnv
+getTopEnv = do { env <- getEnv; return (env_top env) }
+
+getGblEnv :: TcRnIf gbl lcl gbl
+getGblEnv = do { env <- getEnv; return (env_gbl env) }
+
+updGblEnv :: (gbl -> gbl) -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a
+updGblEnv upd = updEnv (\ env@(Env { env_gbl = gbl }) ->
+ env { env_gbl = upd gbl })
+
+setGblEnv :: gbl -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a
+setGblEnv gbl_env = updEnv (\ env -> env { env_gbl = gbl_env })
+
+getLclEnv :: TcRnIf gbl lcl lcl
+getLclEnv = do { env <- getEnv; return (env_lcl env) }
+
+updLclEnv :: (lcl -> lcl) -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a
+updLclEnv upd = updEnv (\ env@(Env { env_lcl = lcl }) ->
+ env { env_lcl = upd lcl })
+
+setLclEnv :: lcl' -> TcRnIf gbl lcl' a -> TcRnIf gbl lcl a
+setLclEnv lcl_env = updEnv (\ env -> env { env_lcl = lcl_env })
+
+getEnvs :: TcRnIf gbl lcl (gbl, lcl)
+getEnvs = do { env <- getEnv; return (env_gbl env, env_lcl env) }
+
+setEnvs :: (gbl', lcl') -> TcRnIf gbl' lcl' a -> TcRnIf gbl lcl a
+setEnvs (gbl_env, lcl_env) = updEnv (\ env -> env { env_gbl = gbl_env, env_lcl = lcl_env })
+\end{code}
+
+
+Command-line flags
+
+\begin{code}
+getDOpts :: TcRnIf gbl lcl DynFlags
+getDOpts = do { env <- getTopEnv; return (hsc_dflags env) }
+
+doptM :: DynFlag -> TcRnIf gbl lcl Bool
+doptM flag = do { dflags <- getDOpts; return (dopt flag dflags) }
+
+setOptM :: DynFlag -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a
+setOptM flag = updEnv (\ env@(Env { env_top = top }) ->
+ env { env_top = top { hsc_dflags = dopt_set (hsc_dflags top) flag}} )
+
+ifOptM :: DynFlag -> TcRnIf gbl lcl () -> TcRnIf gbl lcl () -- Do it flag is true
+ifOptM flag thing_inside = do { b <- doptM flag;
+ if b then thing_inside else return () }
+
+getGhcMode :: TcRnIf gbl lcl GhcMode
+getGhcMode = do { env <- getTopEnv; return (ghcMode (hsc_dflags env)) }
+\end{code}
+
+\begin{code}
+getEpsVar :: TcRnIf gbl lcl (TcRef ExternalPackageState)
+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.
+
+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_ :: (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') }
+
+getHpt :: TcRnIf gbl lcl HomePackageTable
+getHpt = do { env <- getTopEnv; return (hsc_HPT env) }
+
+getEpsAndHpt :: TcRnIf gbl lcl (ExternalPackageState, HomePackageTable)
+getEpsAndHpt = do { env <- getTopEnv; eps <- readMutVar (hsc_EPS env)
+ ; return (eps, hsc_HPT env) }
+\end{code}
+
+%************************************************************************
+%* *
+ Unique supply
+%* *
+%************************************************************************
+
+\begin{code}
+newUnique :: TcRnIf gbl lcl Unique
+newUnique = do { us <- newUniqueSupply ;
+ return (uniqFromSupply us) }
+
+newUniqueSupply :: TcRnIf gbl lcl UniqSupply
+newUniqueSupply
+ = do { env <- getEnv ;
+ let { u_var = env_us env } ;
+ us <- readMutVar u_var ;
+ let { (us1, us2) = splitUniqSupply us } ;
+ writeMutVar u_var us1 ;
+ return us2 }
+
+newLocalName :: Name -> TcRnIf gbl lcl Name
+newLocalName name -- Make a clone
+ = newUnique `thenM` \ uniq ->
+ returnM (mkInternalName uniq (nameOccName name) (getSrcLoc name))
+\end{code}
+
+
+%************************************************************************
+%* *
+ Debugging
+%* *
+%************************************************************************
+
+\begin{code}
+traceTc, traceRn :: SDoc -> TcRn ()
+traceRn = traceOptTcRn Opt_D_dump_rn_trace
+traceTc = traceOptTcRn Opt_D_dump_tc_trace
+traceSplice = traceOptTcRn Opt_D_dump_splices
+
+
+traceIf :: SDoc -> TcRnIf m n ()
+traceIf = traceOptIf Opt_D_dump_if_trace
+traceHiDiffs = traceOptIf Opt_D_dump_hi_diffs
+
+
+traceOptIf :: DynFlag -> SDoc -> TcRnIf m n () -- No RdrEnv available, so qualify everything
+traceOptIf flag doc = ifOptM flag $
+ ioToIOEnv (printForUser stderr alwaysQualify doc)
+
+traceOptTcRn :: DynFlag -> SDoc -> TcRn ()
+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))
+ ; dumpTcRn real_doc }
+
+dumpTcRn :: SDoc -> TcRn ()
+dumpTcRn doc = do { rdr_env <- getGlobalRdrEnv ;
+ ioToTcRn (printForUser stderr (unQualInScope rdr_env) doc) }
+
+dumpOptTcRn :: DynFlag -> SDoc -> TcRn ()
+dumpOptTcRn flag doc = ifOptM flag (dumpTcRn doc)
+\end{code}
+
+
+%************************************************************************
+%* *
+ Typechecker global environment
+%* *
+%************************************************************************
+
+\begin{code}
+getModule :: TcRn Module
+getModule = do { env <- getGblEnv; return (tcg_mod env) }
+
+setModule :: Module -> TcRn a -> TcRn a
+setModule mod thing_inside = updGblEnv (\env -> env { tcg_mod = mod }) thing_inside
+
+tcIsHsBoot :: TcRn Bool
+tcIsHsBoot = do { env <- getGblEnv; return (isHsBoot (tcg_src env)) }
+
+getGlobalRdrEnv :: TcRn GlobalRdrEnv
+getGlobalRdrEnv = do { env <- getGblEnv; return (tcg_rdr_env env) }
+
+getImports :: TcRn ImportAvails
+getImports = do { env <- getGblEnv; return (tcg_imports env) }
+
+getFixityEnv :: TcRn FixityEnv
+getFixityEnv = do { env <- getGblEnv; return (tcg_fix_env env) }
+
+extendFixityEnv :: [(Name,FixItem)] -> RnM a -> RnM a
+extendFixityEnv new_bit
+ = updGblEnv (\env@(TcGblEnv { tcg_fix_env = old_fix_env }) ->
+ env {tcg_fix_env = extendNameEnvList old_fix_env new_bit})
+
+getDefaultTys :: TcRn (Maybe [Type])
+getDefaultTys = do { env <- getGblEnv; return (tcg_default env) }
+\end{code}
+
+%************************************************************************
+%* *
+ Error management
+%* *
+%************************************************************************
+
+\begin{code}
+getSrcSpanM :: TcRn SrcSpan
+ -- Avoid clash with Name.getSrcLoc
+getSrcSpanM = do { env <- getLclEnv; return (tcl_loc env) }
+
+setSrcSpan :: SrcSpan -> TcRn a -> TcRn a
+setSrcSpan loc thing_inside
+ | isGoodSrcSpan loc = updLclEnv (\env -> env { tcl_loc = loc }) thing_inside
+ | otherwise = thing_inside -- Don't overwrite useful info with useless
+
+addLocM :: (a -> TcM b) -> Located a -> TcM b
+addLocM fn (L loc a) = setSrcSpan loc $ fn a
+
+wrapLocM :: (a -> TcM b) -> Located a -> TcM (Located b)
+wrapLocM fn (L loc a) = setSrcSpan loc $ do b <- fn a; return (L loc b)
+
+wrapLocFstM :: (a -> TcM (b,c)) -> Located a -> TcM (Located b, c)
+wrapLocFstM fn (L loc a) =
+ setSrcSpan loc $ do
+ (b,c) <- fn a
+ return (L loc b, c)
+
+wrapLocSndM :: (a -> TcM (b,c)) -> Located a -> TcM (b, Located c)
+wrapLocSndM fn (L loc a) =
+ setSrcSpan loc $ do
+ (b,c) <- fn a
+ return (b, L loc c)
+\end{code}
+
+
+\begin{code}
+getErrsVar :: TcRn (TcRef Messages)
+getErrsVar = do { env <- getLclEnv; return (tcl_errs env) }
+
+setErrsVar :: TcRef Messages -> TcRn a -> TcRn a
+setErrsVar v = updLclEnv (\ env -> env { tcl_errs = v })
+
+addErr :: Message -> TcRn ()
+addErr msg = do { loc <- getSrcSpanM ; addErrAt loc msg }
+
+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 ;
+ let { err = mkLongErrMsg loc (unQualInScope rdr_env) msg extra } ;
+ (warns, errs) <- readMutVar errs_var ;
+ writeMutVar errs_var (warns, errs `snocBag` err) }
+
+addErrs :: [(SrcSpan,Message)] -> TcRn ()
+addErrs msgs = mappM_ 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 ;
+ let { warn = mkWarnMsg loc (unQualInScope 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)
+
+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)
+
+checkErr :: Bool -> Message -> TcRn ()
+-- Add the error if the bool is False
+checkErr ok msg = checkM ok (addErr msg)
+
+warnIf :: Bool -> Message -> TcRn ()
+warnIf True msg = addWarn msg
+warnIf False msg = return ()
+
+addMessages :: Messages -> TcRn ()
+addMessages (m_warns, m_errs)
+ = do { errs_var <- getErrsVar ;
+ (warns, errs) <- readMutVar errs_var ;
+ writeMutVar errs_var (warns `unionBags` m_warns,
+ errs `unionBags` m_errs) }
+
+discardWarnings :: TcRn a -> TcRn a
+-- Ignore warnings inside the thing inside;
+-- used to ignore-unused-variable warnings inside derived code
+-- With -dppr-debug, the effects is switched off, so you can still see
+-- what warnings derived code would give
+discardWarnings thing_inside
+ | opt_PprStyle_Debug = thing_inside
+ | otherwise
+ = do { errs_var <- newMutVar emptyMessages
+ ; result <- setErrsVar errs_var thing_inside
+ ; (_warns, errs) <- readMutVar errs_var
+ ; addMessages (emptyBag, errs)
+ ; return result }
+\end{code}
+
+
+\begin{code}
+try_m :: TcRn r -> TcRn (Either Exception r)
+-- Does try_m, with a debug-trace on failure
+try_m thing
+ = do { mb_r <- tryM thing ;
+ case mb_r of
+ Left exn -> do { traceTc (exn_msg exn); return mb_r }
+ Right r -> return mb_r }
+ where
+ exn_msg exn = text "tryTc/recoverM recovering from" <+> text (showException exn)
+
+-----------------------
+recoverM :: TcRn r -- Recovery action; do this if the main one fails
+ -> TcRn r -- Main action: do this first
+ -> TcRn r
+-- Errors in 'thing' are retained
+recoverM recover thing
+ = do { mb_res <- try_m thing ;
+ case mb_res of
+ Left exn -> recover
+ Right res -> returnM res }
+
+-----------------------
+tryTc :: TcRn a -> TcRn (Messages, Maybe a)
+-- (tryTc m) executes m, and returns
+-- Just r, if m succeeds (returning r)
+-- Nothing, if m fails
+-- It also returns all the errors and warnings accumulated by m
+-- It always succeeds (never raises an exception)
+tryTc m
+ = do { errs_var <- newMutVar emptyMessages ;
+ res <- try_m (setErrsVar errs_var m) ;
+ msgs <- readMutVar errs_var ;
+ return (msgs, case res of
+ Left exn -> Nothing
+ Right val -> Just val)
+ -- The exception is always the IOEnv built-in
+ -- in exception; see IOEnv.failM
+ }
+
+-----------------------
+tryTcErrs :: TcRn a -> TcRn (Messages, Maybe a)
+-- Run the thing, returning
+-- Just r, if m succceeds with no error messages
+-- Nothing, if m fails, or if it succeeds but has error messages
+-- Either way, the messages are returned; even in the Just case
+-- there might be warnings
+tryTcErrs thing
+ = do { (msgs, res) <- tryTc thing
+ ; dflags <- getDOpts
+ ; let errs_found = errorsFound dflags msgs
+ ; return (msgs, case res of
+ Nothing -> Nothing
+ Just val | errs_found -> Nothing
+ | otherwise -> Just val)
+ }
+
+-----------------------
+tryTcLIE :: TcM a -> TcM (Messages, Maybe a)
+-- Just like tryTcErrs, except that it ensures that the LIE
+-- for the thing is propagated only if there are no errors
+-- Hence it's restricted to the type-check monad
+tryTcLIE thing_inside
+ = do { ((msgs, mb_res), lie) <- getLIE (tryTcErrs thing_inside) ;
+ ; case mb_res of
+ Nothing -> return (msgs, Nothing)
+ Just val -> do { extendLIEs lie; return (msgs, Just val) }
+ }
+
+-----------------------
+tryTcLIE_ :: TcM r -> TcM r -> TcM r
+-- (tryTcLIE_ r m) tries m;
+-- if m succeeds with no error messages, it's the answer
+-- otherwise tryTcLIE_ drops everything from m and tries r instead.
+tryTcLIE_ recover main
+ = do { (msgs, mb_res) <- tryTcLIE main
+ ; case mb_res of
+ Just val -> do { addMessages msgs -- There might be warnings
+ ; return val }
+ Nothing -> recover -- Discard all msgs
+ }
+
+-----------------------
+checkNoErrs :: TcM r -> TcM r
+-- (checkNoErrs m) succeeds iff m succeeds and generates no errors
+-- If m fails then (checkNoErrsTc m) fails.
+-- If m succeeds, it checks whether m generated any errors messages
+-- (it might have recovered internally)
+-- If so, it fails too.
+-- Regardless, any errors generated by m are propagated to the enclosing context.
+checkNoErrs main
+ = do { (msgs, mb_res) <- tryTcLIE main
+ ; addMessages msgs
+ ; case mb_res of
+ Nothing -> failM
+ Just val -> return val
+ }
+
+ifErrsM :: TcRn r -> TcRn r -> TcRn r
+-- ifErrsM bale_out main
+-- does 'bale_out' if there are errors in errors collection
+-- otherwise does 'main'
+ifErrsM bale_out normal
+ = do { errs_var <- getErrsVar ;
+ msgs <- readMutVar errs_var ;
+ dflags <- getDOpts ;
+ if errorsFound dflags msgs then
+ bale_out
+ else
+ normal }
+
+failIfErrsM :: TcRn ()
+-- Useful to avoid error cascades
+failIfErrsM = ifErrsM failM (return ())
+\end{code}
+
+
+%************************************************************************
+%* *
+ Context management and error message generation
+ for the type checker
+%* *
+%************************************************************************
+
+\begin{code}
+getErrCtxt :: TcM ErrCtxt
+getErrCtxt = do { env <- getLclEnv; return (tcl_ctxt env) }
+
+setErrCtxt :: ErrCtxt -> TcM a -> TcM a
+setErrCtxt ctxt = updLclEnv (\ env -> env { tcl_ctxt = ctxt })
+
+addErrCtxt :: Message -> TcM a -> TcM a
+addErrCtxt msg = addErrCtxtM (\env -> returnM (env, msg))
+
+addErrCtxtM :: (TidyEnv -> TcM (TidyEnv, Message)) -> TcM a -> TcM a
+addErrCtxtM msg = updCtxt (\ msgs -> msg : msgs)
+
+-- Helper function for the above
+updCtxt :: (ErrCtxt -> ErrCtxt) -> TcM a -> TcM a
+updCtxt upd = updLclEnv (\ env@(TcLclEnv { tcl_ctxt = ctxt }) ->
+ env { tcl_ctxt = upd ctxt })
+
+-- Conditionally add an error context
+maybeAddErrCtxt :: Maybe Message -> TcM a -> TcM a
+maybeAddErrCtxt (Just msg) thing_inside = addErrCtxt msg thing_inside
+maybeAddErrCtxt Nothing thing_inside = thing_inside
+
+popErrCtxt :: TcM a -> TcM a
+popErrCtxt = updCtxt (\ msgs -> case msgs of { [] -> []; (m:ms) -> ms })
+
+getInstLoc :: InstOrigin -> TcM InstLoc
+getInstLoc origin
+ = do { loc <- getSrcSpanM ; env <- getLclEnv ;
+ return (InstLoc origin loc (tcl_ctxt env)) }
+
+addInstCtxt :: 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 (\ old_ctxt -> ctxt) thing_inside)
+\end{code}
+
+ 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
+
+\begin{code}
+addErrTc :: Message -> TcM ()
+addErrTc err_msg = do { env0 <- tcInitTidyEnv
+ ; addErrTcM (env0, err_msg) }
+
+addErrsTc :: [Message] -> TcM ()
+addErrsTc err_msgs = mappM_ addErrTc err_msgs
+
+addErrTcM :: (TidyEnv, Message) -> TcM ()
+addErrTcM (tidy_env, err_msg)
+ = do { ctxt <- getErrCtxt ;
+ loc <- getSrcSpanM ;
+ add_err_tcm tidy_env err_msg loc ctxt }
+\end{code}
+
+The failWith functions add an error message and cause failure
+
+\begin{code}
+failWithTc :: Message -> TcM a -- Add an error message and fail
+failWithTc err_msg
+ = addErrTc err_msg >> failM
+
+failWithTcM :: (TidyEnv, Message) -> TcM a -- Add an error message and fail
+failWithTcM local_and_msg
+ = addErrTcM local_and_msg >> failM
+
+checkTc :: Bool -> Message -> TcM () -- Check that the boolean is true
+checkTc True err = returnM ()
+checkTc False err = failWithTc err
+\end{code}
+
+ Warnings have no 'M' variant, nor failure
+
+\begin{code}
+addWarnTc :: Message -> TcM ()
+addWarnTc msg
+ = do { ctxt <- getErrCtxt ;
+ env0 <- tcInitTidyEnv ;
+ ctxt_msgs <- do_ctxt env0 ctxt ;
+ addWarn (vcat (msg : ctxt_to_use ctxt_msgs)) }
+
+warnTc :: Bool -> Message -> TcM ()
+warnTc warn_if_true warn_msg
+ | warn_if_true = addWarnTc warn_msg
+ | otherwise = return ()
+\end{code}
+
+-----------------------------------
+ Tidying
+
+We initialise the "tidy-env", used for tidying types before printing,
+by building a reverse map from the in-scope type variables to the
+OccName that the programmer originally used for them
+
+\begin{code}
+tcInitTidyEnv :: TcM TidyEnv
+tcInitTidyEnv
+ = do { lcl_env <- getLclEnv
+ ; let nm_tv_prs = [ (name, tcGetTyVar "tcInitTidyEnv" ty)
+ | ATyVar name ty <- nameEnvElts (tcl_env lcl_env)
+ , tcIsTyVarTy ty ]
+ ; return (foldl add emptyTidyEnv nm_tv_prs) }
+ where
+ add (env,subst) (name, tyvar)
+ = case tidyOccName env (nameOccName name) of
+ (env', occ') -> (env', extendVarEnv subst tyvar tyvar')
+ where
+ tyvar' = setTyVarName tyvar name'
+ name' = tidyNameOcc name occ'
+\end{code}
+
+-----------------------------------
+ Other helper functions
+
+\begin{code}
+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 tidy_env []
+ = 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 ctxt | opt_PprStyle_Debug = ctxt
+ | otherwise = take 3 ctxt
+\end{code}
+
+debugTc is useful for monadic debugging code
+
+\begin{code}
+debugTc :: TcM () -> TcM ()
+#ifdef DEBUG
+debugTc thing = thing
+#else
+debugTc thing = return ()
+#endif
+\end{code}
+
+ %************************************************************************
+%* *
+ Type constraints (the so-called LIE)
+%* *
+%************************************************************************
+
+\begin{code}
+nextDFunIndex :: TcM Int -- Get the next dfun index
+nextDFunIndex = do { env <- getGblEnv
+ ; let dfun_n_var = tcg_dfun_n env
+ ; n <- readMutVar dfun_n_var
+ ; writeMutVar dfun_n_var (n+1)
+ ; return n }
+
+getLIEVar :: TcM (TcRef LIE)
+getLIEVar = do { env <- getLclEnv; return (tcl_lie env) }
+
+setLIEVar :: TcRef LIE -> TcM a -> TcM a
+setLIEVar lie_var = updLclEnv (\ env -> env { tcl_lie = lie_var })
+
+getLIE :: TcM a -> TcM (a, [Inst])
+-- (getLIE m) runs m, and returns the type constraints it generates
+getLIE thing_inside
+ = do { lie_var <- newMutVar emptyLIE ;
+ res <- updLclEnv (\ env -> env { tcl_lie = lie_var })
+ thing_inside ;
+ lie <- readMutVar lie_var ;
+ return (res, lieToList lie) }
+
+extendLIE :: Inst -> TcM ()
+extendLIE inst
+ = do { lie_var <- getLIEVar ;
+ lie <- readMutVar lie_var ;
+ writeMutVar lie_var (inst `consLIE` lie) }
+
+extendLIEs :: [Inst] -> TcM ()
+extendLIEs []
+ = returnM ()
+extendLIEs insts
+ = do { lie_var <- getLIEVar ;
+ lie <- readMutVar lie_var ;
+ writeMutVar lie_var (mkLIE insts `plusLIE` lie) }
+\end{code}
+
+\begin{code}
+setLclTypeEnv :: TcLclEnv -> TcM a -> TcM a
+-- Set the local type envt, but do *not* disturb other fields,
+-- notably the lie_var
+setLclTypeEnv lcl_env thing_inside
+ = updLclEnv upd thing_inside
+ where
+ upd env = env { tcl_env = tcl_env lcl_env,
+ tcl_tyvars = tcl_tyvars lcl_env }
+\end{code}
+
+
+%************************************************************************
+%* *
+ Template Haskell context
+%* *
+%************************************************************************
+
+\begin{code}
+recordThUse :: TcM ()
+recordThUse = do { env <- getGblEnv; writeMutVar (tcg_th_used env) True }
+
+keepAliveTc :: Name -> TcM () -- Record the name in the keep-alive set
+keepAliveTc n = do { env <- getGblEnv;
+ ; updMutVar (tcg_keep env) (`addOneToNameSet` n) }
+
+keepAliveSetTc :: NameSet -> TcM () -- Record the name in the keep-alive set
+keepAliveSetTc ns = do { env <- getGblEnv;
+ ; updMutVar (tcg_keep env) (`unionNameSets` ns) }
+
+getStage :: TcM ThStage
+getStage = do { env <- getLclEnv; return (tcl_th_ctxt env) }
+
+setStage :: ThStage -> TcM a -> TcM a
+setStage s = updLclEnv (\ env -> env { tcl_th_ctxt = s })
+\end{code}
+
+
+%************************************************************************
+%* *
+ Stuff for the renamer's local env
+%* *
+%************************************************************************
+
+\begin{code}
+getLocalRdrEnv :: RnM LocalRdrEnv
+getLocalRdrEnv = do { env <- getLclEnv; return (tcl_rdr env) }
+
+setLocalRdrEnv :: LocalRdrEnv -> RnM a -> RnM a
+setLocalRdrEnv rdr_env thing_inside
+ = updLclEnv (\env -> env {tcl_rdr = rdr_env}) thing_inside
+\end{code}
+
+
+%************************************************************************
+%* *
+ Stuff for interface decls
+%* *
+%************************************************************************
+
+\begin{code}
+mkIfLclEnv :: Module -> SDoc -> IfLclEnv
+mkIfLclEnv mod loc = IfLclEnv { if_mod = mod,
+ if_loc = loc,
+ if_tv_env = emptyOccEnv,
+ if_id_env = emptyOccEnv }
+
+initIfaceTcRn :: IfG a -> TcRn a
+initIfaceTcRn thing_inside
+ = do { tcg_env <- getGblEnv
+ ; let { if_env = IfGblEnv { if_rec_types = Just (tcg_mod tcg_env, get_type_env) }
+ ; get_type_env = readMutVar (tcg_type_env_var tcg_env) }
+ ; setEnvs (if_env, ()) thing_inside }
+
+initIfaceExtCore :: IfL a -> TcRn a
+initIfaceExtCore thing_inside
+ = do { tcg_env <- getGblEnv
+ ; let { mod = tcg_mod tcg_env
+ ; doc = ptext SLIT("External Core file for") <+> quotes (ppr mod)
+ ; if_env = IfGblEnv {
+ if_rec_types = Just (mod, return (tcg_type_env tcg_env)) }
+ ; if_lenv = mkIfLclEnv mod doc
+ }
+ ; setEnvs (if_env, if_lenv) thing_inside }
+
+initIfaceCheck :: HscEnv -> IfG a -> IO a
+-- Used when checking the up-to-date-ness of the old Iface
+-- Initialise the environment with no useful info at all
+initIfaceCheck hsc_env do_this
+ = do { let gbl_env = IfGblEnv { if_rec_types = Nothing }
+ ; initTcRnIf 'i' hsc_env gbl_env () do_this
+ }
+
+initIfaceTc :: ModIface
+ -> (TcRef TypeEnv -> IfL a) -> TcRnIf gbl lcl a
+-- Used when type-checking checking an up-to-date interface file
+-- No type envt from the current module, but we do know the module dependencies
+initIfaceTc iface do_this
+ = do { tc_env_var <- newMutVar emptyTypeEnv
+ ; let { gbl_env = IfGblEnv { if_rec_types = Just (mod, readMutVar tc_env_var) } ;
+ ; if_lenv = mkIfLclEnv mod doc
+ }
+ ; setEnvs (gbl_env, if_lenv) (do_this tc_env_var)
+ }
+ where
+ mod = mi_module iface
+ doc = ptext SLIT("The interface for") <+> quotes (ppr mod)
+
+initIfaceRules :: HscEnv -> ModGuts -> IfG a -> IO a
+-- Used when sucking in new Rules in SimplCore
+-- We have available the type envt of the module being compiled, and we must use it
+initIfaceRules hsc_env guts do_this
+ = do { let {
+ type_info = (mg_module guts, return (mg_types guts))
+ ; gbl_env = IfGblEnv { if_rec_types = Just type_info } ;
+ }
+
+ -- Run the thing; any exceptions just bubble out from here
+ ; initTcRnIf 'i' hsc_env gbl_env () do_this
+ }
+
+initIfaceLcl :: Module -> SDoc -> IfL a -> IfM lcl a
+initIfaceLcl mod loc_doc thing_inside
+ = setLclEnv (mkIfLclEnv mod loc_doc) thing_inside
+
+getIfModule :: IfL Module
+getIfModule = do { env <- getLclEnv; return (if_mod env) }
+
+--------------------
+failIfM :: Message -> IfL a
+-- The Iface monad doesn't have a place to accumulate errors, so we
+-- just fall over fast if one happens; it "shouldnt happen".
+-- We use IfL here so that we can get context info out of the local env
+failIfM msg
+ = do { env <- getLclEnv
+ ; let full_msg = (if_loc env <> colon) $$ nest 2 msg
+ ; ioToIOEnv (printErrs (full_msg defaultErrStyle))
+ ; failM }
+
+--------------------
+forkM_maybe :: SDoc -> IfL a -> IfL (Maybe a)
+-- Run thing_inside in an interleaved thread.
+-- It shares everything with the parent thread, so this is DANGEROUS.
+--
+-- It returns Nothing if the computation fails
+--
+-- It's used for lazily type-checking interface
+-- signatures, which is pretty benign
+
+forkM_maybe doc thing_inside
+ = do { unsafeInterleaveM $
+ do { traceIf (text "Starting fork {" <+> doc)
+ ; mb_res <- tryM thing_inside ;
+ case mb_res of
+ Right r -> do { traceIf (text "} ending fork" <+> doc)
+ ; return (Just r) }
+ Left exn -> do {
+
+ -- Bleat about errors in the forked thread, if -ddump-if-trace is on
+ -- Otherwise we silently discard errors. Errors can legitimately
+ -- happen when compiling interface signatures (see tcInterfaceSigs)
+ ifOptM Opt_D_dump_if_trace
+ (print_errs (hang (text "forkM failed:" <+> doc)
+ 4 (text (show exn))))
+
+ ; traceIf (text "} ending fork (badly)" <+> doc)
+ ; return Nothing }
+ }}
+ where
+ print_errs sdoc = ioToIOEnv (printErrs (sdoc defaultErrStyle))
+
+forkM :: SDoc -> IfL a -> IfL a
+forkM doc thing_inside
+ = do { mb_res <- forkM_maybe doc thing_inside
+ ; return (case mb_res of
+ Nothing -> pgmError "Cannot continue after interface file error"
+ -- pprPanic "forkM" doc
+ Just r -> r) }
+\end{code}
+
+