X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2Ftypecheck%2FTcMonad.lhs;h=dceff864fb232890019ce1f791f05c2b3c31f034;hb=10fcd78ccde892feccda3f5eacd221c1de75feea;hp=59b9967710fed66f3730c4086deec9f8e23b08f1;hpb=6c381e873e222417d9a67aeec77b9555eca7b7a8;p=ghc-hetmet.git diff --git a/ghc/compiler/typecheck/TcMonad.lhs b/ghc/compiler/typecheck/TcMonad.lhs index 59b9967..dceff86 100644 --- a/ghc/compiler/typecheck/TcMonad.lhs +++ b/ghc/compiler/typecheck/TcMonad.lhs @@ -1,202 +1,181 @@ \begin{code} module TcMonad( - TcM(..), NF_TcM(..), TcDown, TcEnv, - SST_R, FSST_R, + TcM, NF_TcM, TcDown, TcEnv, initTc, - returnTc, thenTc, thenTc_, mapTc, listTc, + returnTc, thenTc, thenTc_, mapTc, mapTc_, listTc, foldrTc, foldlTc, mapAndUnzipTc, mapAndUnzip3Tc, - mapBagTc, fixTc, tryTc, + mapBagTc, fixTc, tryTc, tryTc_, getErrsTc, + traceTc, ioToTc, + + uniqSMToTcM, returnNF_Tc, thenNF_Tc, thenNF_Tc_, mapNF_Tc, + fixNF_Tc, forkNF_Tc, foldrNF_Tc, foldlNF_Tc, + listNF_Tc, mapAndUnzipNF_Tc, mapBagNF_Tc, checkTc, checkTcM, checkMaybeTc, checkMaybeTcM, - failTc, warnTc, recoverTc, recoverNF_Tc, + failTc, failWithTc, addErrTc, addErrsTc, warnTc, + recoverTc, checkNoErrsTc, recoverNF_Tc, discardErrsTc, + addErrTcM, addInstErrTcM, failWithTcM, tcGetEnv, tcSetEnv, tcGetDefaultTys, tcSetDefaultTys, - tcGetUnique, tcGetUniques, + tcGetUnique, tcGetUniques, + doptsTc, getDOptsTc, - tcAddSrcLoc, tcGetSrcLoc, + tcAddSrcLoc, tcGetSrcLoc, tcGetInstLoc, tcAddErrCtxtM, tcSetErrCtxtM, - tcAddErrCtxt, tcSetErrCtxt, + tcAddErrCtxt, tcSetErrCtxt, tcPopErrCtxt, - tcNewMutVar, tcReadMutVar, tcWriteMutVar, + tcNewMutVar, tcReadMutVar, tcWriteMutVar, TcRef, + tcNewMutTyVar, tcReadMutTyVar, tcWriteMutTyVar, - rn4MtoTcM, + InstOrigin(..), InstLoc, pprInstLoc, - -- For closure - MutableVar(..), _MutableArray + TcError, TcWarning, TidyEnv, emptyTidyEnv, + arityErr ) where +#include "HsVersions.h" -import TcMLoop ( TcEnv, initEnv, TcMaybe ) -- We need the type TcEnv and an initial Env +import {-# SOURCE #-} TcEnv ( TcEnv ) -import Type ( Type(..), GenType ) -import TyVar ( TyVar(..), GenTyVar ) -import Usage ( Usage(..), GenUsage ) -import ErrUtils ( Error(..), Message(..), ErrCtxt(..), - TcWarning(..), TcError(..), mkTcErr ) - -import SST -import RnMonad4 -import RnUtils ( GlobalNameMappers(..), GlobalNameMapper(..) ) +import HsLit ( HsOverLit ) +import RnHsSyn ( RenamedPat, RenamedArithSeqInfo, RenamedHsExpr ) +import TcType ( Type, Kind, TyVarDetails ) +import ErrUtils ( addShortErrLocLine, addShortWarnLocLine, ErrMsg, Message, WarnMsg ) import Bag ( Bag, emptyBag, isEmptyBag, foldBag, unitBag, unionBags, snocBag ) -import FiniteMap ( FiniteMap, emptyFM ) -import Pretty ( Pretty(..), PrettyRep ) -import PprStyle ( PprStyle ) -import Outputable ( Outputable(..), NamedThing(..), ExportFlag ) -import Maybes ( MaybeErr(..) ) +import Class ( Class ) import Name ( Name ) -import ProtoName ( ProtoName ) -import SrcLoc ( SrcLoc, mkUnknownSrcLoc ) -import UniqFM ( UniqFM, emptyUFM ) -import UniqSupply ( UniqSupply, getUnique, getUniques, splitUniqSupply ) +import Var ( Id, TyVar, newMutTyVar, readMutTyVar, writeMutTyVar ) +import VarEnv ( TidyEnv, emptyTidyEnv ) +import UniqSupply ( UniqSupply, uniqFromSupply, uniqsFromSupply, + splitUniqSupply, mkSplitUniqSupply, + UniqSM, initUs_ ) +import SrcLoc ( SrcLoc, noSrcLoc ) +import BasicTypes ( IPName ) +import UniqFM ( emptyUFM ) import Unique ( Unique ) -import Util +import CmdLineOpts +import Outputable + +import IOExts ( IORef, newIORef, readIORef, writeIORef, + unsafeInterleaveIO, fixIO + ) + infixr 9 `thenTc`, `thenTc_`, `thenNF_Tc`, `thenNF_Tc_` \end{code} -\section{TcM, NF_TcM: the type checker monads} -%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +%************************************************************************ +%* * +\subsection{The main monads: TcM, NF_TcM} +%* * +%************************************************************************ \begin{code} -type NF_TcM s r = TcDown s -> TcEnv s -> SST s r -type TcM s r = TcDown s -> TcEnv s -> FSST s r () +type NF_TcM r = TcDown -> TcEnv -> IO r -- Can't raise UserError +type TcM r = TcDown -> TcEnv -> IO r -- Can raise UserError + +type Either_TcM r = TcDown -> TcEnv -> IO r -- Either NF_TcM or TcM + -- Used only in this file for type signatures which + -- have a part that's polymorphic in whether it's NF_TcM or TcM + -- E.g. thenNF_Tc + +type TcRef a = IORef a \end{code} \begin{code} --- With a builtin polymorphic type for _runSST the type for --- initTc should use TcM s r instead of TcM _RealWorld r - -initTc :: UniqSupply - -> TcM _RealWorld r - -> MaybeErr (r, Bag TcWarning) - (Bag TcError, Bag TcWarning) - -initTc us do_this - = _runSST ( - newMutVarSST us `thenSST` \ us_var -> - newMutVarSST (emptyBag,emptyBag) `thenSST` \ errs_var -> - newMutVarSST emptyUFM `thenSST` \ tvs_var -> - let - init_down = TcDown [] us_var - mkUnknownSrcLoc - [] errs_var - init_env = initEnv tvs_var - in - recoverSST - (\_ -> returnSST Nothing) - (do_this init_down init_env `thenFSST` \ res -> - returnFSST (Just res)) - `thenSST` \ maybe_res -> - readMutVarSST errs_var `thenSST` \ (warns,errs) -> - case (maybe_res, isEmptyBag errs) of - (Just res, True) -> returnSST (Succeeded (res, warns)) - _ -> returnSST (Failed (errs, warns)) - ) - -thenNF_Tc :: NF_TcM s a - -> (a -> TcDown s -> TcEnv s -> State# s -> b) - -> TcDown s -> TcEnv s -> State# s -> b --- thenNF_Tc :: NF_TcM s a -> (a -> NF_TcM s b) -> NF_TcM s b --- thenNF_Tc :: NF_TcM s a -> (a -> TcM s b) -> TcM s b - -thenNF_Tc m k down env - = m down env `thenSST` \ r -> - k r down env - -thenNF_Tc_ :: NF_TcM s a - -> (TcDown s -> TcEnv s -> State# s -> b) - -> TcDown s -> TcEnv s -> State# s -> b --- thenNF_Tc :: NF_TcM s a -> NF_TcM s b -> NF_TcM s b --- thenNF_Tc :: NF_TcM s a -> TcM s b -> TcM s b - -thenNF_Tc_ m k down env - = m down env `thenSST_` k down env - -returnNF_Tc :: a -> NF_TcM s a -returnNF_Tc v down env = returnSST v - -mapNF_Tc :: (a -> NF_TcM s b) -> [a] -> NF_TcM s [b] -mapNF_Tc f [] = returnNF_Tc [] -mapNF_Tc f (x:xs) = f x `thenNF_Tc` \ r -> - mapNF_Tc f xs `thenNF_Tc` \ rs -> - returnNF_Tc (r:rs) - -listNF_Tc :: [NF_TcM s a] -> NF_TcM s [a] -listNF_Tc [] = returnNF_Tc [] -listNF_Tc (x:xs) = x `thenNF_Tc` \ r -> - listNF_Tc xs `thenNF_Tc` \ rs -> - returnNF_Tc (r:rs) - -mapBagNF_Tc :: (a -> NF_TcM s b) -> Bag a -> NF_TcM s (Bag b) -mapBagNF_Tc f bag - = foldBag (\ b1 b2 -> b1 `thenNF_Tc` \ r1 -> - b2 `thenNF_Tc` \ r2 -> - returnNF_Tc (unionBags r1 r2)) - (\ a -> f a `thenNF_Tc` \ r -> returnNF_Tc (unitBag r)) - (returnNF_Tc emptyBag) - bag -mapAndUnzipNF_Tc :: (a -> NF_TcM s (b,c)) -> [a] -> NF_TcM s ([b],[c]) -mapAndUnzipNF_Tc f [] = returnNF_Tc ([],[]) -mapAndUnzipNF_Tc f (x:xs) = f x `thenNF_Tc` \ (r1,r2) -> - mapAndUnzipNF_Tc f xs `thenNF_Tc` \ (rs1,rs2) -> - returnNF_Tc (r1:rs1, r2:rs2) +initTc :: DynFlags + -> TcEnv + -> TcM r + -> IO (Maybe r, (Bag WarnMsg, Bag ErrMsg)) -thenTc :: TcM s a -> (a -> TcM s b) -> TcM s b -thenTc m k down env - = m down env `thenFSST` \ r -> - k r down env +initTc dflags tc_env do_this + = do { + us <- mkSplitUniqSupply 'a' ; + us_var <- newIORef us ; + errs_var <- newIORef (emptyBag,emptyBag) ; + tvs_var <- newIORef emptyUFM ; -thenTc_ :: TcM s a -> TcM s b -> TcM s b -thenTc_ m k down env - = m down env `thenFSST_` k down env - -returnTc :: a -> TcM s a -returnTc val down env = returnFSST val + let + init_down = TcDown { tc_dflags = dflags, tc_def = [], + tc_us = us_var, tc_loc = noSrcLoc, + tc_ctxt = [], tc_errs = errs_var } + ; + + maybe_res <- catch (do { res <- do_this init_down tc_env ; + return (Just res)}) + (\_ -> return Nothing) ; + + (warns,errs) <- readIORef errs_var ; + return (maybe_res, (warns, errs)) + } + +-- Monadic operations + +returnNF_Tc :: a -> NF_TcM a +returnTc :: a -> TcM a +returnTc v down env = return v + +thenTc :: TcM a -> (a -> TcM b) -> TcM b +thenNF_Tc :: NF_TcM a -> (a -> Either_TcM b) -> Either_TcM b +thenTc m k down env = do { r <- m down env; k r down env } + +thenTc_ :: TcM a -> TcM b -> TcM b +thenNF_Tc_ :: NF_TcM a -> Either_TcM b -> Either_TcM b +thenTc_ m k down env = do { m down env; k down env } + +listTc :: [TcM a] -> TcM [a] +listNF_Tc :: [NF_TcM a] -> NF_TcM [a] +listTc [] = returnTc [] +listTc (x:xs) = x `thenTc` \ r -> + listTc xs `thenTc` \ rs -> + returnTc (r:rs) -mapTc :: (a -> TcM s b) -> [a] -> TcM s [b] +mapTc :: (a -> TcM b) -> [a] -> TcM [b] +mapTc_ :: (a -> TcM b) -> [a] -> TcM () +mapNF_Tc :: (a -> NF_TcM b) -> [a] -> NF_TcM [b] mapTc f [] = returnTc [] mapTc f (x:xs) = f x `thenTc` \ r -> mapTc f xs `thenTc` \ rs -> returnTc (r:rs) +mapTc_ f xs = mapTc f xs `thenTc_` returnTc () -listTc :: [TcM s a] -> TcM s [a] -listTc [] = returnTc [] -listTc (x:xs) = x `thenTc` \ r -> - listTc xs `thenTc` \ rs -> - returnTc (r:rs) -foldrTc :: (a -> b -> TcM s b) -> b -> [a] -> TcM s b +foldrTc :: (a -> b -> TcM b) -> b -> [a] -> TcM b +foldrNF_Tc :: (a -> b -> NF_TcM b) -> b -> [a] -> NF_TcM b foldrTc k z [] = returnTc z foldrTc k z (x:xs) = foldrTc k z xs `thenTc` \r -> k x r -foldlTc :: (a -> b -> TcM s a) -> a -> [b] -> TcM s a +foldlTc :: (a -> b -> TcM a) -> a -> [b] -> TcM a +foldlNF_Tc :: (a -> b -> NF_TcM a) -> a -> [b] -> NF_TcM a foldlTc k z [] = returnTc z foldlTc k z (x:xs) = k z x `thenTc` \r -> foldlTc k r xs -mapAndUnzipTc :: (a -> TcM s (b,c)) -> [a] -> TcM s ([b],[c]) +mapAndUnzipTc :: (a -> TcM (b,c)) -> [a] -> TcM ([b],[c]) +mapAndUnzipNF_Tc :: (a -> NF_TcM (b,c)) -> [a] -> NF_TcM ([b],[c]) mapAndUnzipTc f [] = returnTc ([],[]) mapAndUnzipTc f (x:xs) = f x `thenTc` \ (r1,r2) -> mapAndUnzipTc f xs `thenTc` \ (rs1,rs2) -> returnTc (r1:rs1, r2:rs2) -mapAndUnzip3Tc :: (a -> TcM s (b,c,d)) -> [a] -> TcM s ([b],[c],[d]) +mapAndUnzip3Tc :: (a -> TcM (b,c,d)) -> [a] -> TcM ([b],[c],[d]) mapAndUnzip3Tc f [] = returnTc ([],[],[]) mapAndUnzip3Tc f (x:xs) = f x `thenTc` \ (r1,r2,r3) -> mapAndUnzip3Tc f xs `thenTc` \ (rs1,rs2,rs3) -> returnTc (r1:rs1, r2:rs2, r3:rs3) -mapBagTc :: (a -> TcM s b) -> Bag a -> TcM s (Bag b) +mapBagTc :: (a -> TcM b) -> Bag a -> TcM (Bag b) +mapBagNF_Tc :: (a -> NF_TcM b) -> Bag a -> NF_TcM (Bag b) mapBagTc f bag = foldBag (\ b1 b2 -> b1 `thenTc` \ r1 -> b2 `thenTc` \ r2 -> @@ -205,240 +184,560 @@ mapBagTc f bag (returnTc emptyBag) bag -fixTc :: (a -> TcM s a) -> TcM s a -fixTc m env down = fixFSST (\ loop -> m loop env down) +fixTc :: (a -> TcM a) -> TcM a +fixNF_Tc :: (a -> NF_TcM a) -> NF_TcM a +fixTc m env down = fixIO (\ loop -> m loop env down) +{-# NOINLINE fixTc #-} +-- aargh! Not inlining fixTc alleviates a space leak problem. +-- Normally fixTc is used with a lazy tuple match: if the optimiser is +-- shown the definition of fixTc, it occasionally transforms the code +-- in such a way that the code generator doesn't spot the selector +-- thunks. Sigh. + +recoverTc :: TcM r -> TcM r -> TcM r +recoverNF_Tc :: NF_TcM r -> TcM r -> NF_TcM r +recoverTc recover m down env + = catch (m down env) (\ _ -> recover down env) + +returnNF_Tc = returnTc +thenNF_Tc = thenTc +thenNF_Tc_ = thenTc_ +fixNF_Tc = fixTc +recoverNF_Tc = recoverTc +mapNF_Tc = mapTc +foldrNF_Tc = foldrTc +foldlNF_Tc = foldlTc +listNF_Tc = listTc +mapAndUnzipNF_Tc = mapAndUnzipTc +mapBagNF_Tc = mapBagTc +\end{code} + +@forkNF_Tc@ runs a sub-typecheck action *lazily* in a separate state +thread. Ideally, this elegantly ensures that it can't zap any type +variables that belong to the main thread. But alas, the environment +contains TyCon and Class environments that include TcKind stuff, +which is a Royal Pain. By the time this fork stuff is used they'll +have been unified down so there won't be any kind variables, but we +can't express that in the current typechecker framework. + +So we compromise and use unsafeInterleaveIO. + +We throw away any error messages! + +\begin{code} +forkNF_Tc :: NF_TcM r -> NF_TcM r +forkNF_Tc m down@(TcDown { tc_us = u_var }) env + = do + -- Get a fresh unique supply + us <- readIORef u_var + let (us1, us2) = splitUniqSupply us + writeIORef u_var us1 + + unsafeInterleaveIO (do { + us_var' <- newIORef us2 ; + err_var' <- newIORef (emptyBag,emptyBag) ; + let { down' = down { tc_us = us_var', tc_errs = err_var' } }; + m down' env + -- ToDo: optionally dump any error messages + }) \end{code} -@forkNF_Tc@ runs a sub-typecheck action in a separate state thread. -This elegantly ensures that it can't zap any type variables that -belong to the main thread. We throw away any error messages! +\begin{code} +traceTc :: SDoc -> NF_TcM () +traceTc doc (TcDown { tc_dflags=dflags }) env + | dopt Opt_D_dump_tc_trace dflags = printDump doc + | otherwise = return () + +ioToTc :: IO a -> NF_TcM a +ioToTc io down env = io +\end{code} -\begin{pseudocode} -forkNF_Tc :: NF_TcM s r -> NF_TcM s r -forkNF_Tc m down env - = forkTcDown down `thenSST` \ down' -> - returnSST (_runSST (m down' (forkTcEnv env))) -\end{pseudocode} +%************************************************************************ +%* * +\subsection{Error handling} +%* * +%************************************************************************ -Error handling -~~~~~~~~~~~~~~ \begin{code} -failTc :: Message -> TcM s a -failTc err_msg down env - = readMutVarSST errs_var `thenSST` \ (warns,errs) -> - foldr thenNF_Tc_ (returnNF_Tc []) ctxt down env `thenSST` \ ctxt_msgs -> - let - err = mkTcErr loc ctxt_msgs err_msg - in - writeMutVarSST errs_var (warns, errs `snocBag` err) `thenSST_` - failFSST () +getErrsTc :: NF_TcM (Bag WarnMsg, Bag ErrMsg) +getErrsTc down env + = readIORef (getTcErrs down) + +failTc :: TcM a +failTc down env = give_up + +give_up :: IO a +give_up = ioError (userError "Typecheck failed") + +failWithTc :: Message -> TcM a -- Add an error message and fail +failWithTc err_msg = failWithTcM (emptyTidyEnv, err_msg) + +addErrTc :: Message -> NF_TcM () +addErrTc err_msg = addErrTcM (emptyTidyEnv, err_msg) + +addErrsTc :: [Message] -> NF_TcM () +addErrsTc [] = returnNF_Tc () +addErrsTc err_msgs = listNF_Tc (map addErrTc err_msgs) `thenNF_Tc_` returnNF_Tc () + +-- The 'M' variants do the TidyEnv bit +failWithTcM :: (TidyEnv, Message) -> TcM a -- Add an error message and fail +failWithTcM env_and_msg + = addErrTcM env_and_msg `thenNF_Tc_` + failTc + +checkTc :: Bool -> Message -> TcM () -- Check that the boolean is true +checkTc True err = returnTc () +checkTc False err = failWithTc err + +checkTcM :: Bool -> TcM () -> TcM () -- Check that the boolean is true +checkTcM True err = returnTc () +checkTcM False err = err + +checkMaybeTc :: Maybe val -> Message -> TcM val +checkMaybeTc (Just val) err = returnTc val +checkMaybeTc Nothing err = failWithTc err + +checkMaybeTcM :: Maybe val -> TcM val -> TcM val +checkMaybeTcM (Just val) err = returnTc val +checkMaybeTcM Nothing err = err + +addErrTcM :: (TidyEnv, Message) -> NF_TcM () -- Add an error message but don't fail +addErrTcM (tidy_env, err_msg) down env + = add_err_tcm tidy_env err_msg ctxt loc down env + where + ctxt = getErrCtxt down + loc = getLoc down + +addInstErrTcM :: InstLoc -> (TidyEnv, Message) -> NF_TcM () -- Add an error message but don't fail +addInstErrTcM inst_loc@(_, loc, ctxt) (tidy_env, err_msg) down env + = add_err_tcm tidy_env err_msg full_ctxt loc down env + where + full_ctxt = (\env -> returnNF_Tc (env, pprInstLoc inst_loc)) : ctxt + +add_err_tcm tidy_env err_msg ctxt loc down env + = do + (warns, errs) <- readIORef errs_var + ctxt_msgs <- do_ctxt tidy_env ctxt down env + let err = addShortErrLocLine loc $ + vcat (err_msg : ctxt_to_use ctxt_msgs) + writeIORef errs_var (warns, errs `snocBag` err) + where + errs_var = getTcErrs down + +do_ctxt tidy_env [] down env + = return [] +do_ctxt tidy_env (c:cs) down env + = do + (tidy_env', m) <- c tidy_env down env + ms <- do_ctxt tidy_env' cs down env + return (m:ms) + +-- warnings don't have an 'M' variant +warnTc :: Bool -> Message -> NF_TcM () +warnTc warn_if_true warn_msg down env + | warn_if_true + = do + (warns,errs) <- readIORef errs_var + ctxt_msgs <- do_ctxt emptyTidyEnv ctxt down env + let warn = addShortWarnLocLine loc $ + vcat (warn_msg : ctxt_to_use ctxt_msgs) + writeIORef errs_var (warns `snocBag` warn, errs) + | otherwise + = return () where errs_var = getTcErrs down ctxt = getErrCtxt down loc = getLoc down -warnTc :: Bool -> Message -> NF_TcM s () -warnTc warn_if_true warn down env - = if warn_if_true then - readMutVarSST errs_var `thenSST` \ (warns,errs) -> - writeMutVarSST errs_var (warns `snocBag` warn, errs) `thenSST_` - returnSST () - else - returnSST () +-- (tryTc r m) succeeds if m succeeds and generates no errors +-- If m fails then r is invoked, passing the warnings and errors from m +-- If m succeeds, (tryTc r m) checks whether m generated any errors messages +-- (it might have recovered internally) +-- If so, then r is invoked, passing the warnings and errors from m + +tryTc :: ((Bag WarnMsg, Bag ErrMsg) -> TcM r) -- Recovery action + -> TcM r -- Thing to try + -> TcM r +tryTc recover main down env + = do + m_errs_var <- newIORef (emptyBag,emptyBag) + catch (my_main m_errs_var) (\ _ -> my_recover m_errs_var) where errs_var = getTcErrs down -recoverTc :: TcM s r -> TcM s r -> TcM s r -recoverTc recover m down env - = recoverFSST (\ _ -> recover down env) (m down env) + my_recover m_errs_var + = do warns_and_errs <- readIORef m_errs_var + recover warns_and_errs down env + + my_main m_errs_var + = do result <- main (setTcErrs down m_errs_var) env + + -- Check that m has no errors; if it has internal recovery + -- mechanisms it might "succeed" but having found a bunch of + -- errors along the way. + (m_warns, m_errs) <- readIORef m_errs_var + if isEmptyBag m_errs then + -- No errors, so return normally, but don't lose the warnings + if isEmptyBag m_warns then + return result + else + do (warns, errs) <- readIORef errs_var + writeIORef errs_var (warns `unionBags` m_warns, errs) + return result + else + give_up -- This triggers the catch + + +-- (checkNoErrsTc 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. +checkNoErrsTc :: TcM r -> TcM r +checkNoErrsTc main + = tryTc my_recover main + where + my_recover (m_warns, m_errs) down env + = do (warns, errs) <- readIORef errs_var + writeIORef errs_var (warns `unionBags` m_warns, + errs `unionBags` m_errs) + give_up + where + errs_var = getTcErrs down -recoverNF_Tc :: NF_TcM s r -> TcM s r -> NF_TcM s r -recoverNF_Tc recover m down env - = recoverSST (\ _ -> recover down env) (m down env) --- (tryTc r m) tries m; if it succeeds it returns it, +-- (tryTc_ r m) tries m; if it succeeds it returns it, -- otherwise it returns r. Any error messages added by m are discarded, -- whether or not m succeeds. -tryTc :: TcM s r -> TcM s r -> TcM s r -tryTc recover m down env - = recoverFSST (\ _ -> recover down env) $ - newMutVarSST (emptyBag,emptyBag) `thenSST` \ new_errs_var -> - m (setTcErrs down new_errs_var) env +tryTc_ :: TcM r -> TcM r -> TcM r +tryTc_ recover main + = tryTc my_recover main + where + my_recover warns_and_errs = recover -checkTc :: Bool -> Message -> TcM s () -- Check that the boolean is true -checkTc True err = returnTc () -checkTc False err = failTc err +-- (discardErrsTc m) runs m, but throw away all its error messages. +discardErrsTc :: Either_TcM r -> Either_TcM r +discardErrsTc main down env + = do new_errs_var <- newIORef (emptyBag,emptyBag) + main (setTcErrs down new_errs_var) env +\end{code} -checkTcM :: Bool -> TcM s () -> TcM s () -- Check that the boolean is true -checkTcM True err = returnTc () -checkTcM False err = err -checkMaybeTc :: Maybe val -> Message -> TcM s val -checkMaybeTc (Just val) err = returnTc val -checkMaybeTc Nothing err = failTc err -checkMaybeTcM :: Maybe val -> TcM s val -> TcM s val -checkMaybeTcM (Just val) err = returnTc val -checkMaybeTcM Nothing err = err -\end{code} +%************************************************************************ +%* * +\subsection{Mutable variables} +%* * +%************************************************************************ -Mutable variables -~~~~~~~~~~~~~~~~~ \begin{code} -tcNewMutVar :: a -> NF_TcM s (MutableVar s a) -tcNewMutVar val down env = newMutVarSST val +tcNewMutVar :: a -> NF_TcM (TcRef a) +tcNewMutVar val down env = newIORef val + +tcWriteMutVar :: TcRef a -> a -> NF_TcM () +tcWriteMutVar var val down env = writeIORef var val + +tcReadMutVar :: TcRef a -> NF_TcM a +tcReadMutVar var down env = readIORef var -tcWriteMutVar :: MutableVar s a -> a -> NF_TcM s () -tcWriteMutVar var val down env = writeMutVarSST var val +tcNewMutTyVar :: Name -> Kind -> TyVarDetails -> NF_TcM TyVar +tcNewMutTyVar name kind details down env = newMutTyVar name kind details -tcReadMutVar :: MutableVar s a -> NF_TcM s a -tcReadMutVar var down env = readMutVarSST var +tcReadMutTyVar :: TyVar -> NF_TcM (Maybe Type) +tcReadMutTyVar tyvar down env = readMutTyVar tyvar + +tcWriteMutTyVar :: TyVar -> Maybe Type -> NF_TcM () +tcWriteMutTyVar tyvar val down env = writeMutTyVar tyvar val \end{code} -Environment -~~~~~~~~~~~ +%************************************************************************ +%* * +\subsection{The environment} +%* * +%************************************************************************ + \begin{code} -tcGetEnv :: NF_TcM s (TcEnv s) -tcGetEnv down env = returnSST env +tcGetEnv :: NF_TcM TcEnv +tcGetEnv down env = return env -tcSetEnv :: TcEnv s -> TcM s a -> TcM s a +tcSetEnv :: TcEnv -> Either_TcM a -> Either_TcM a tcSetEnv new_env m down old_env = m down new_env \end{code} -Source location -~~~~~~~~~~~~~~~ +%************************************************************************ +%* * +\subsection{Source location} +%* * +%************************************************************************ + \begin{code} -tcGetDefaultTys :: NF_TcM s [Type] -tcGetDefaultTys down env = returnSST (getDefaultTys down) +tcGetDefaultTys :: NF_TcM [Type] +tcGetDefaultTys down env = return (getDefaultTys down) -tcSetDefaultTys :: [Type] -> TcM s r -> TcM s r +tcSetDefaultTys :: [Type] -> TcM r -> TcM r tcSetDefaultTys tys m down env = m (setDefaultTys down tys) env -tcAddSrcLoc :: SrcLoc -> TcM s a -> TcM s a +tcAddSrcLoc :: SrcLoc -> Either_TcM a -> Either_TcM a tcAddSrcLoc loc m down env = m (setLoc down loc) env -tcGetSrcLoc :: NF_TcM s SrcLoc -tcGetSrcLoc down env = returnSST (getLoc down) +tcGetSrcLoc :: NF_TcM SrcLoc +tcGetSrcLoc down env = return (getLoc down) -tcSetErrCtxtM, tcAddErrCtxtM :: NF_TcM s Message -> TcM s a -> TcM s a +tcGetInstLoc :: InstOrigin -> NF_TcM InstLoc +tcGetInstLoc origin TcDown{tc_loc=loc, tc_ctxt=ctxt} env + = return (origin, loc, ctxt) + +tcSetErrCtxtM, tcAddErrCtxtM :: (TidyEnv -> NF_TcM (TidyEnv, Message)) + -> TcM a -> TcM a tcSetErrCtxtM msg m down env = m (setErrCtxt down msg) env tcAddErrCtxtM msg m down env = m (addErrCtxt down msg) env -tcSetErrCtxt, tcAddErrCtxt :: Message -> TcM s a -> TcM s a -tcSetErrCtxt msg m down env = m (setErrCtxt down (returnNF_Tc msg)) env -tcAddErrCtxt msg m down env = m (addErrCtxt down (returnNF_Tc msg)) env +tcSetErrCtxt, tcAddErrCtxt :: Message -> Either_TcM r -> Either_TcM r +-- Usual thing +tcSetErrCtxt msg m down env = m (setErrCtxt down (\env -> returnNF_Tc (env, msg))) env +tcAddErrCtxt msg m down env = m (addErrCtxt down (\env -> returnNF_Tc (env, msg))) env + +tcPopErrCtxt :: Either_TcM r -> Either_TcM r +tcPopErrCtxt m down env = m (popErrCtxt down) env \end{code} -Unique supply -~~~~~~~~~~~~~ +%************************************************************************ +%* * +\subsection{Unique supply} +%* * +%************************************************************************ + \begin{code} -tcGetUnique :: NF_TcM s Unique +tcGetUnique :: NF_TcM Unique tcGetUnique down env - = readMutVarSST u_var `thenSST` \ uniq_supply -> - let - (new_uniq_supply, uniq_s) = splitUniqSupply uniq_supply - uniq = getUnique uniq_s - in - writeMutVarSST u_var new_uniq_supply `thenSST_` - returnSST uniq + = do uniq_supply <- readIORef u_var + let (new_uniq_supply, uniq_s) = splitUniqSupply uniq_supply + uniq = uniqFromSupply uniq_s + writeIORef u_var new_uniq_supply + return uniq where u_var = getUniqSupplyVar down -tcGetUniques :: Int -> NF_TcM s [Unique] -tcGetUniques n down env - = readMutVarSST u_var `thenSST` \ uniq_supply -> - let - (new_uniq_supply, uniq_s) = splitUniqSupply uniq_supply - uniqs = getUniques n uniq_s - in - writeMutVarSST u_var new_uniq_supply `thenSST_` - returnSST uniqs +tcGetUniques :: NF_TcM [Unique] +tcGetUniques down env + = do uniq_supply <- readIORef u_var + let (new_uniq_supply, uniq_s) = splitUniqSupply uniq_supply + uniqs = uniqsFromSupply uniq_s + writeIORef u_var new_uniq_supply + return uniqs where u_var = getUniqSupplyVar down -\end{code} +uniqSMToTcM :: UniqSM a -> NF_TcM a +uniqSMToTcM m down env + = do uniq_supply <- readIORef u_var + let (new_uniq_supply, uniq_s) = splitUniqSupply uniq_supply + writeIORef u_var new_uniq_supply + return (initUs_ uniq_s m) + where + u_var = getUniqSupplyVar down +\end{code} -\section{TcDown} -%~~~~~~~~~~~~~~~ - -\begin{code} -data TcDown s - = TcDown - [Type] -- Types used for defaulting - (MutableVar s UniqSupply) -- Unique supply - SrcLoc -- Source location - (ErrCtxt s) -- Error context - (MutableVar s (Bag TcWarning, - Bag TcError)) +%************************************************************************ +%* * +\subsection{TcDown} +%* * +%************************************************************************ -type ErrCtxt s = [NF_TcM s Message] -- Innermost first. Monadic so that we have a chance - -- to deal with bound type variables just before error - -- message construction +\begin{code} +data TcDown + = TcDown { + tc_dflags :: DynFlags, + tc_def :: [Type], -- Types used for defaulting + tc_us :: (TcRef UniqSupply), -- Unique supply + tc_loc :: SrcLoc, -- Source location + tc_ctxt :: ErrCtxt, -- Error context + tc_errs :: (TcRef (Bag WarnMsg, Bag ErrMsg)) + } + +type ErrCtxt = [TidyEnv -> NF_TcM (TidyEnv, Message)] + -- Innermost first. Monadic so that we have a chance + -- to deal with bound type variables just before error + -- message construction \end{code} -- These selectors are *local* to TcMonad.lhs \begin{code} -getTcErrs (TcDown def us loc ctxt errs) = errs -setTcErrs (TcDown def us loc ctxt _ ) errs = TcDown def us loc ctxt errs +getTcErrs (TcDown{tc_errs=errs}) = errs +setTcErrs down errs = down{tc_errs=errs} + +getDefaultTys (TcDown{tc_def=def}) = def +setDefaultTys down def = down{tc_def=def} -getDefaultTys (TcDown def us loc ctxt errs) = def -setDefaultTys (TcDown _ us loc ctxt errs) def = TcDown def us loc ctxt errs +getLoc (TcDown{tc_loc=loc}) = loc +setLoc down loc = down{tc_loc=loc} -getLoc (TcDown def us loc ctxt errs) = loc -setLoc (TcDown def us _ ctxt errs) loc = TcDown def us loc ctxt errs +getUniqSupplyVar (TcDown{tc_us=us}) = us -getUniqSupplyVar (TcDown def us loc ctxt errs) = us +getErrCtxt (TcDown{tc_ctxt=ctxt}) = ctxt +setErrCtxt down msg = down{tc_ctxt=[msg]} +addErrCtxt down msg = down{tc_ctxt = msg : tc_ctxt down} -setErrCtxt (TcDown def us loc ctxt errs) msg = TcDown def us loc [msg] errs -addErrCtxt (TcDown def us loc ctxt errs) msg = TcDown def us loc (msg:ctxt) errs -getErrCtxt (TcDown def us loc ctxt errs) = ctxt +popErrCtxt down = case tc_ctxt down of + [] -> down + m : ms -> down{tc_ctxt = ms} + +doptsTc :: DynFlag -> NF_TcM Bool +doptsTc dflag (TcDown{tc_dflags=dflags}) env_down + = return (dopt dflag dflags) + +getDOptsTc :: NF_TcM DynFlags +getDOptsTc (TcDown{tc_dflags=dflags}) env_down + = return dflags \end{code} -@forkTcDown@ makes a new "down" blob for a lazily-computed fork -of the type checker. + + + +%************************************************************************ +%* * +\subsection{TypeChecking Errors} +%* * +%************************************************************************ \begin{code} -forkTcDown (TcDown deflts u_var src_loc err_cxt err_var) - = -- Get a fresh unique supply - readMutVarSST u_var `thenSST` \ us -> - let - (us1, us2) = splitUniqSupply us - in - writeMutVarSST u_var us1 `thenSST_` - - -- Make fresh MutVars for the unique supply and errors - newMutVarSST us2 `thenSST` \ u_var' -> - newMutVarSST (emptyBag, emptyBag) `thenSST` \ err_var' -> - - -- Done - returnSST (TcDown deflts u_var' src_loc err_cxt err_var') +type TcError = Message +type TcWarning = Message + +ctxt_to_use ctxt | opt_PprStyle_Debug = ctxt + | otherwise = take 3 ctxt + +arityErr kind name n m + = hsep [ text kind, quotes (ppr name), ptext SLIT("should have"), + n_arguments <> comma, text "but has been given", int m] + where + n_arguments | n == 0 = ptext SLIT("no arguments") + | n == 1 = ptext SLIT("1 argument") + | True = hsep [int n, ptext SLIT("arguments")] \end{code} -\section{rn4MtoTcM} -%~~~~~~~~~~~~~~~~~~ + +%************************************************************************ +%* * +\subsection[Inst-origin]{The @InstOrigin@ type} +%* * +%************************************************************************ + +The @InstOrigin@ type gives information about where a dictionary came from. +This is important for decent error message reporting because dictionaries +don't appear in the original source code. Doubtless this type will evolve... + +It appears in TcMonad because there are a couple of error-message-generation +functions that deal with it. \begin{code} -rn4MtoTcM :: GlobalNameMappers -> Rn4M a -> NF_TcM s (a, Bag Error) - -rn4MtoTcM name_funs rn_action down env - = readMutVarSST u_var `thenSST` \ uniq_supply -> - let - (new_uniq_supply, uniq_s) = splitUniqSupply uniq_supply - in - writeMutVarSST u_var new_uniq_supply `thenSST_` - let - (rn_result, rn_errs) - = rn_action name_funs emptyFM emptyBag uniq_s mkUnknownSrcLoc - in - returnSST (rn_result, rn_errs) +type InstLoc = (InstOrigin, SrcLoc, ErrCtxt) + +data InstOrigin + = OccurrenceOf Id -- Occurrence of an overloaded identifier + + | IPOcc (IPName Name) -- Occurrence of an implicit parameter + | IPBind (IPName Name) -- Binding site of an implicit parameter + + | RecordUpdOrigin + + | DataDeclOrigin -- Typechecking a data declaration + + | InstanceDeclOrigin -- Typechecking an instance decl + + | LiteralOrigin HsOverLit -- Occurrence of a literal + + | PatOrigin RenamedPat + + | ArithSeqOrigin RenamedArithSeqInfo -- [x..], [x..y] etc + | PArrSeqOrigin RenamedArithSeqInfo -- [:x..y:] and [:x,y..z:] + + | SignatureOrigin -- A dict created from a type signature + | Rank2Origin -- A dict created when typechecking the argument + -- of a rank-2 typed function + + | DoOrigin -- The monad for a do expression + + | ClassDeclOrigin -- Manufactured during a class decl + + | InstanceSpecOrigin Class -- in a SPECIALIZE instance pragma + Type + + -- When specialising instances the instance info attached to + -- each class is not yet ready, so we record it inside the + -- origin information. This is a bit of a hack, but it works + -- fine. (Patrick is to blame [WDP].) + + | ValSpecOrigin Name -- in a SPECIALIZE pragma for a value + + -- Argument or result of a ccall + -- Dictionaries with this origin aren't actually mentioned in the + -- translated term, and so need not be bound. Nor should they + -- be abstracted over. + + | CCallOrigin String -- CCall label + (Maybe RenamedHsExpr) -- Nothing if it's the result + -- Just arg, for an argument + + | LitLitOrigin String -- the litlit + + | UnknownOrigin -- Help! I give up... +\end{code} + +\begin{code} +pprInstLoc :: InstLoc -> SDoc +pprInstLoc (orig, locn, ctxt) + = hsep [text "arising from", pp_orig orig, text "at", ppr locn] where - u_var = getUniqSupplyVar down + pp_orig (OccurrenceOf id) + = hsep [ptext SLIT("use of"), quotes (ppr id)] + pp_orig (IPOcc name) + = hsep [ptext SLIT("use of implicit parameter"), quotes (char '?' <> ppr name)] + pp_orig (IPBind name) + = hsep [ptext SLIT("binding for implicit parameter"), quotes (char '?' <> ppr name)] + pp_orig RecordUpdOrigin + = ptext SLIT("a record update") + pp_orig DataDeclOrigin + = ptext SLIT("the data type declaration") + pp_orig InstanceDeclOrigin + = ptext SLIT("the instance declaration") + pp_orig (LiteralOrigin lit) + = hsep [ptext SLIT("the literal"), quotes (ppr lit)] + pp_orig (PatOrigin pat) + = hsep [ptext SLIT("the pattern"), quotes (ppr pat)] + pp_orig (ArithSeqOrigin seq) + = hsep [ptext SLIT("the arithmetic sequence"), quotes (ppr seq)] + pp_orig (PArrSeqOrigin seq) + = hsep [ptext SLIT("the parallel array sequence"), quotes (ppr seq)] + pp_orig (SignatureOrigin) + = ptext SLIT("a type signature") + pp_orig (Rank2Origin) + = ptext SLIT("a function with an overloaded argument type") + pp_orig (DoOrigin) + = ptext SLIT("a do statement") + pp_orig (ClassDeclOrigin) + = ptext SLIT("a class declaration") + pp_orig (InstanceSpecOrigin clas ty) + = hsep [text "a SPECIALIZE instance pragma; class", + quotes (ppr clas), text "type:", ppr ty] + pp_orig (ValSpecOrigin name) + = hsep [ptext SLIT("a SPECIALIZE user-pragma for"), quotes (ppr name)] + pp_orig (CCallOrigin clabel Nothing{-ccall result-}) + = hsep [ptext SLIT("the result of the _ccall_ to"), quotes (text clabel)] + pp_orig (CCallOrigin clabel (Just arg_expr)) + = hsep [ptext SLIT("an argument in the _ccall_ to"), quotes (text clabel) <> comma, + text "namely", quotes (ppr arg_expr)] + pp_orig (LitLitOrigin s) + = hsep [ptext SLIT("the ``literal-literal''"), quotes (text s)] + pp_orig (UnknownOrigin) + = ptext SLIT("...oops -- I don't know where the overloading came from!") \end{code}