\begin{code}
-- | Types for the per-module compiler
module HscTypes (
- -- * 'Ghc' monad stuff
- Ghc(..), GhcT(..), liftGhcT,
- GhcMonad(..), WarnLogMonad(..),
- liftIO,
- ioMsgMaybe, ioMsg,
- logWarnings, clearWarnings, hasWarnings,
- SourceError, GhcApiError, mkSrcErr, srcErrorMessages, mkApiErr,
- throwOneError, handleSourceError,
- reflectGhc, reifyGhc,
- handleFlagWarnings,
-
- -- * Sessions and compilation state
- Session(..), withSession, modifySession, withTempSession,
+ -- * compilation state
HscEnv(..), hscEPS,
FinderCache, FindResult(..), ModLocationCache,
Target(..), TargetId(..), pprTarget, pprTargetId,
ModuleGraph, emptyMG,
- -- ** Callbacks
- GhcApiCallbacks(..), withLocalCallbacks,
-- * Information about modules
ModDetails(..), emptyModDetails,
- ModGuts(..), CoreModule(..), CgGuts(..), ForeignStubs(..),
+ ModGuts(..), CgGuts(..), ForeignStubs(..),
ImportedMods,
ModSummary(..), ms_mod_name, showModMsg, isBootSummary,
-- * Vectorisation information
VectInfo(..), IfaceVectInfo(..), noVectInfo, plusVectInfo,
- noIfaceVectInfo
+ noIfaceVectInfo,
+
+ -- * Compilation errors and warnings
+ SourceError, GhcApiError, mkSrcErr, srcErrorMessages, mkApiErr,
+ throwOneError, handleSourceError,
+ handleFlagWarnings, printOrThrowWarnings,
) where
#include "HsVersions.h"
import Rules ( RuleBase )
import CoreSyn ( CoreBind )
import VarEnv
-import VarSet
import Var
import Id
import Type
import BasicTypes ( IPName, defaultFixity, WarningTxt(..) )
import OptimizationFuel ( OptFuelState )
import IfaceSyn
-import FiniteMap ( FiniteMap )
import CoreSyn ( CoreRule )
import Maybes ( orElse, expectJust, catMaybes )
import Outputable
import Data.IORef
import Data.Array ( Array, array )
import Data.List
+import Data.Map (Map)
import Control.Monad ( mplus, guard, liftM, when )
import Exception
-\end{code}
+-- -----------------------------------------------------------------------------
+-- Source Errors
-%************************************************************************
-%* *
-\subsection{Compilation environment}
-%* *
-%************************************************************************
-
-
-\begin{code}
--- | The Session is a handle to the complete state of a compilation
--- session. A compilation session consists of a set of modules
--- constituting the current program or library, the context for
--- interactive evaluation, and various caches.
-data Session = Session !(IORef HscEnv) !(IORef WarningMessages)
+-- When the compiler (HscMain) discovers errors, it throws an
+-- exception in the IO monad.
mkSrcErr :: ErrorMessages -> SourceError
srcErrorMessages :: SourceError -> ErrorMessages
mkApiErr = GhcApiError
--- | A monad that allows logging of warnings.
-class Monad m => WarnLogMonad m where
- setWarnings :: WarningMessages -> m ()
- getWarnings :: m WarningMessages
-
-logWarnings :: WarnLogMonad m => WarningMessages -> m ()
-logWarnings warns = do
- warns0 <- getWarnings
- setWarnings (unionBags warns warns0)
-
--- | Clear the log of 'Warnings'.
-clearWarnings :: WarnLogMonad m => m ()
-clearWarnings = setWarnings emptyBag
-
--- | Returns true if there were any warnings.
-hasWarnings :: WarnLogMonad m => m Bool
-hasWarnings = getWarnings >>= return . not . isEmptyBag
-
--- | A monad that has all the features needed by GHC API calls.
---
--- In short, a GHC monad
---
--- - allows embedding of IO actions,
---
--- - can log warnings,
---
--- - allows handling of (extensible) exceptions, and
---
--- - maintains a current session.
---
--- If you do not use 'Ghc' or 'GhcT', make sure to call 'GHC.initGhcMonad'
--- before any call to the GHC API functions can occur.
---
-class (Functor m, MonadIO m, WarnLogMonad m, ExceptionMonad m)
- => GhcMonad m where
- getSession :: m HscEnv
- setSession :: HscEnv -> m ()
-
--- | Call the argument with the current session.
-withSession :: GhcMonad m => (HscEnv -> m a) -> m a
-withSession f = getSession >>= f
-
--- | Set the current session to the result of applying the current session to
--- the argument.
-modifySession :: GhcMonad m => (HscEnv -> HscEnv) -> m ()
-modifySession f = do h <- getSession
- setSession $! f h
-
-withSavedSession :: GhcMonad m => m a -> m a
-withSavedSession m = do
- saved_session <- getSession
- m `gfinally` setSession saved_session
-
--- | Call an action with a temporarily modified Session.
-withTempSession :: GhcMonad m => (HscEnv -> HscEnv) -> m a -> m a
-withTempSession f m =
- withSavedSession $ modifySession f >> m
-
--- | A minimal implementation of a 'GhcMonad'. If you need a custom monad,
--- e.g., to maintain additional state consider wrapping this monad or using
--- 'GhcT'.
-newtype Ghc a = Ghc { unGhc :: Session -> IO a }
-
-instance Functor Ghc where
- fmap f m = Ghc $ \s -> f `fmap` unGhc m s
-
-instance Monad Ghc where
- return a = Ghc $ \_ -> return a
- m >>= g = Ghc $ \s -> do a <- unGhc m s; unGhc (g a) s
-
-instance MonadIO Ghc where
- liftIO ioA = Ghc $ \_ -> ioA
-
-instance ExceptionMonad Ghc where
- gcatch act handle =
- Ghc $ \s -> unGhc act s `gcatch` \e -> unGhc (handle e) s
- gblock (Ghc m) = Ghc $ \s -> gblock (m s)
- gunblock (Ghc m) = Ghc $ \s -> gunblock (m s)
- gmask f =
- Ghc $ \s -> gmask $ \io_restore ->
- let
- g_restore (Ghc m) = Ghc $ \s -> io_restore (m s)
- in
- unGhc (f g_restore) s
-
-instance WarnLogMonad Ghc where
- setWarnings warns = Ghc $ \(Session _ wref) -> writeIORef wref warns
- -- | Return 'Warnings' accumulated so far.
- getWarnings = Ghc $ \(Session _ wref) -> readIORef wref
-
-instance GhcMonad Ghc where
- getSession = Ghc $ \(Session r _) -> readIORef r
- setSession s' = Ghc $ \(Session r _) -> writeIORef r s'
-
--- | A monad transformer to add GHC specific features to another monad.
---
--- Note that the wrapped monad must support IO and handling of exceptions.
-newtype GhcT m a = GhcT { unGhcT :: Session -> m a }
-liftGhcT :: Monad m => m a -> GhcT m a
-liftGhcT m = GhcT $ \_ -> m
-
-instance Functor m => Functor (GhcT m) where
- fmap f m = GhcT $ \s -> f `fmap` unGhcT m s
-
-instance Monad m => Monad (GhcT m) where
- return x = GhcT $ \_ -> return x
- m >>= k = GhcT $ \s -> do a <- unGhcT m s; unGhcT (k a) s
-
-instance MonadIO m => MonadIO (GhcT m) where
- liftIO ioA = GhcT $ \_ -> liftIO ioA
-
-instance ExceptionMonad m => ExceptionMonad (GhcT m) where
- gcatch act handle =
- GhcT $ \s -> unGhcT act s `gcatch` \e -> unGhcT (handle e) s
- gblock (GhcT m) = GhcT $ \s -> gblock (m s)
- gunblock (GhcT m) = GhcT $ \s -> gunblock (m s)
- gmask f =
- GhcT $ \s -> gmask $ \io_restore ->
- let
- g_restore (GhcT m) = GhcT $ \s -> io_restore (m s)
- in
- unGhcT (f g_restore) s
-
-instance MonadIO m => WarnLogMonad (GhcT m) where
- setWarnings warns = GhcT $ \(Session _ wref) -> liftIO $ writeIORef wref warns
- -- | Return 'Warnings' accumulated so far.
- getWarnings = GhcT $ \(Session _ wref) -> liftIO $ readIORef wref
-
-instance (Functor m, ExceptionMonad m, MonadIO m) => GhcMonad (GhcT m) where
- getSession = GhcT $ \(Session r _) -> liftIO $ readIORef r
- setSession s' = GhcT $ \(Session r _) -> liftIO $ writeIORef r s'
-
--- | Lift an IO action returning errors messages into a 'GhcMonad'.
---
--- In order to reduce dependencies to other parts of the compiler, functions
--- outside the "main" parts of GHC return warnings and errors as a parameter
--- and signal success via by wrapping the result in a 'Maybe' type. This
--- function logs the returned warnings and propagates errors as exceptions
--- (of type 'SourceError').
---
--- This function assumes the following invariants:
---
--- 1. If the second result indicates success (is of the form 'Just x'),
--- there must be no error messages in the first result.
---
--- 2. If there are no error messages, but the second result indicates failure
--- there should be warnings in the first result. That is, if the action
--- failed, it must have been due to the warnings (i.e., @-Werror@).
-ioMsgMaybe :: GhcMonad m =>
- IO (Messages, Maybe a) -> m a
-ioMsgMaybe ioA = do
- ((warns,errs), mb_r) <- liftIO ioA
- logWarnings warns
- case mb_r of
- Nothing -> liftIO $ throwIO (mkSrcErr errs)
- Just r -> ASSERT( isEmptyBag errs ) return r
-
--- | Lift a non-failing IO action into a 'GhcMonad'.
---
--- Like 'ioMsgMaybe', but assumes that the action will never return any error
--- messages.
-ioMsg :: GhcMonad m => IO (Messages, a) -> m a
-ioMsg ioA = do
- ((warns,errs), r) <- liftIO ioA
- logWarnings warns
- ASSERT( isEmptyBag errs ) return r
-
--- | Reflect a computation in the 'Ghc' monad into the 'IO' monad.
---
--- You can use this to call functions returning an action in the 'Ghc' monad
--- inside an 'IO' action. This is needed for some (too restrictive) callback
--- arguments of some library functions:
---
--- > libFunc :: String -> (Int -> IO a) -> IO a
--- > ghcFunc :: Int -> Ghc a
--- >
--- > ghcFuncUsingLibFunc :: String -> Ghc a -> Ghc a
--- > ghcFuncUsingLibFunc str =
--- > reifyGhc $ \s ->
--- > libFunc $ \i -> do
--- > reflectGhc (ghcFunc i) s
---
-reflectGhc :: Ghc a -> Session -> IO a
-reflectGhc m = unGhc m
-
--- > Dual to 'reflectGhc'. See its documentation.
-reifyGhc :: (Session -> IO a) -> Ghc a
-reifyGhc act = Ghc $ act
+-- | Given a bag of warnings, turn them into an exception if
+-- -Werror is enabled, or print them out otherwise.
+printOrThrowWarnings :: DynFlags -> Bag WarnMsg -> IO ()
+printOrThrowWarnings dflags warns
+ | dopt Opt_WarnIsError dflags
+ = when (not (isEmptyBag warns)) $ do
+ throwIO $ mkSrcErr $ warns `snocBag` warnIsErrorMsg
+ | otherwise
+ = printBagOfWarnings dflags warns
-handleFlagWarnings :: GhcMonad m => DynFlags -> [Located String] -> m ()
+handleFlagWarnings :: DynFlags -> [Located String] -> IO ()
handleFlagWarnings dflags warns
- = when (dopt Opt_WarnDeprecatedFlags dflags)
- (handleFlagWarnings' dflags warns)
-
-handleFlagWarnings' :: GhcMonad m => DynFlags -> [Located String] -> m ()
-handleFlagWarnings' _ [] = return ()
-handleFlagWarnings' dflags warns
- = do -- It would be nicer if warns :: [Located Message], but that has circular
- -- import problems.
- logWarnings $ listToBag (map mkFlagWarning warns)
- when (dopt Opt_WarnIsError dflags) $
- liftIO $ throwIO $ mkSrcErr emptyBag
-
-mkFlagWarning :: Located String -> WarnMsg
-mkFlagWarning (L loc warn)
- = mkPlainWarnMsg loc (text warn)
-\end{code}
-
-\begin{code}
--- | These functions are called in various places of the GHC API.
---
--- API clients can override any of these callbacks to change GHC's default
--- behaviour.
-data GhcApiCallbacks
- = GhcApiCallbacks {
-
- -- | Called by 'load' after the compilating of each module.
- --
- -- The default implementation simply prints all warnings and errors to
- -- @stderr@. Don't forget to call 'clearWarnings' when implementing your
- -- own call.
- --
- -- The first argument is the module that was compiled.
- --
- -- The second argument is @Nothing@ if no errors occured, but there may
- -- have been warnings. If it is @Just err@ at least one error has
- -- occured. If 'srcErrorMessages' is empty, compilation failed due to
- -- @-Werror@.
- reportModuleCompilationResult :: GhcMonad m =>
- ModSummary -> Maybe SourceError
- -> m ()
- }
-
--- | Temporarily modify the callbacks. After the action is executed all
--- callbacks are reset (not, however, any other modifications to the session
--- state.)
-withLocalCallbacks :: GhcMonad m =>
- (GhcApiCallbacks -> GhcApiCallbacks)
- -> m a -> m a
-withLocalCallbacks f m = do
- hsc_env <- getSession
- let cb0 = hsc_callbacks hsc_env
- let cb' = f cb0
- setSession (hsc_env { hsc_callbacks = cb' `seq` cb' })
- r <- m
- hsc_env' <- getSession
- setSession (hsc_env' { hsc_callbacks = cb0 })
- return r
+ = when (dopt Opt_WarnDeprecatedFlags dflags) $ do
+ -- It would be nicer if warns :: [Located Message], but that
+ -- has circular import problems.
+ let bag = listToBag [ mkPlainWarnMsg loc (text warn)
+ | L loc warn <- warns ]
+ printOrThrowWarnings dflags bag
\end{code}
\begin{code}
hsc_dflags :: DynFlags,
-- ^ The dynamic flag settings
- hsc_callbacks :: GhcApiCallbacks,
- -- ^ Callbacks for the GHC API.
-
hsc_targets :: [Target],
-- ^ The targets (or roots) of the current session
-- by limiting the number of transformations,
-- we can use binary search to help find compiler bugs.
- hsc_type_env_var :: Maybe (Module, IORef TypeEnv),
+ hsc_type_env_var :: Maybe (Module, IORef TypeEnv)
-- ^ Used for one-shot compilation only, to initialise
-- the 'IfGblEnv'. See 'TcRnTypes.tcg_type_env_var' for
-- 'TcRunTypes.TcGblEnv'
-
- hsc_global_rdr_env :: GlobalRdrEnv,
- -- ^ A mapping from 'RdrName's that are in global scope during
- -- the compilation of the current file to more detailed
- -- information about those names. Not necessarily just the
- -- names directly imported by the module being compiled!
-
- hsc_global_type_env :: TypeEnv
- -- ^ Typing information about all those things in global scope.
- -- Not necessarily just the things directly imported by the module
- -- being compiled!
}
hscEPS :: HscEnv -> IO ExternalPackageState
-- ^ The requested package was not found
| FoundMultiple [PackageId]
-- ^ _Error_: both in multiple packages
- | NotFound [FilePath] (Maybe PackageId) [PackageId] [PackageId]
- -- ^ The module was not found, including either
- -- * the specified places were searched
- -- * the package that this module should have been in
- -- * list of packages in which the module was hidden,
- -- * list of hidden packages containing this module
- | NotFoundInPackage PackageId
- -- ^ The module was not found in this package
+
+ | NotFound -- Not found
+ { fr_paths :: [FilePath] -- Places where I looked
+
+ , fr_pkg :: Maybe PackageId -- Just p => module is in this package's
+ -- manifest, but couldn't find
+ -- the .hi file
+
+ , fr_mods_hidden :: [PackageId] -- Module is in these packages,
+ -- but the *module* is hidden
+
+ , fr_pkgs_hidden :: [PackageId] -- Module is in these packages,
+ -- but the *package* is hidden
+
+ , fr_suggestions :: [Module] -- Possible mis-spelled modules
+ }
-- | Cache that remembers where we found a particular module. Contains both
-- home modules and package modules. On @:load@, only home modules are
-- mg_rules Orphan rules only (local ones now attached to binds)
-- mg_binds With rules attached
--- | A CoreModule consists of just the fields of a 'ModGuts' that are needed for
--- the 'GHC.compileToCoreModule' interface.
-data CoreModule
- = CoreModule {
- -- | Module name
- cm_module :: !Module,
- -- | Type environment for types declared in this module
- cm_types :: !TypeEnv,
- -- | Declarations
- cm_binds :: [CoreBind],
- -- | Imports
- cm_imports :: ![Module]
- }
-
-instance Outputable CoreModule where
- ppr (CoreModule {cm_module = mn, cm_types = te, cm_binds = cb}) =
- text "%module" <+> ppr mn <+> ppr te $$ vcat (map ppr cb)
-
-- The ModGuts takes on several slightly different forms:
--
-- After simplification, the following fields change slightly:
-- | Interactive context, recording information relevant to GHCi
data InteractiveContext
= InteractiveContext {
- ic_toplev_scope :: [Module], -- ^ The context includes the "top-level" scope of
+ ic_toplev_scope :: [Module] -- ^ The context includes the "top-level" scope of
-- these modules
- ic_exports :: [(Module, Maybe (ImportDecl RdrName))], -- ^ The context includes just the exported parts of these
+ , ic_exports :: [(Module, Maybe (ImportDecl RdrName))] -- ^ The context includes just the exported parts of these
-- modules
- ic_rn_gbl_env :: GlobalRdrEnv, -- ^ The contexts' cached 'GlobalRdrEnv', built from
+ , ic_rn_gbl_env :: GlobalRdrEnv -- ^ The contexts' cached 'GlobalRdrEnv', built from
-- 'ic_toplev_scope' and 'ic_exports'
- ic_tmp_ids :: [Id], -- ^ Names bound during interaction with the user.
- -- Later Ids shadow earlier ones with the same OccName.
-
- ic_tyvars :: TyVarSet -- ^ Skolem type variables free in
- -- 'ic_tmp_ids'. These arise at
- -- breakpoints in a polymorphic
- -- context, where we have only partial
- -- type information.
+ , ic_tmp_ids :: [Id] -- ^ Names bound during interaction with the user.
+ -- Later Ids shadow earlier ones with the same OccName
+ -- Expressions are typed with these Ids in the envt
+ -- For runtime-debugging, these Ids may have free
+ -- TcTyVars of RuntimUnkSkol flavour, but no free TyVars
+ -- (because the typechecker doesn't expect that)
#ifdef GHCI
, ic_resume :: [Resume] -- ^ The stack of breakpoint contexts
= InteractiveContext { ic_toplev_scope = [],
ic_exports = [],
ic_rn_gbl_env = emptyGlobalRdrEnv,
- ic_tmp_ids = [],
- ic_tyvars = emptyVarSet
+ ic_tmp_ids = []
#ifdef GHCI
, ic_resume = []
#endif
extendInteractiveContext
:: InteractiveContext
-> [Id]
- -> TyVarSet
-> InteractiveContext
-extendInteractiveContext ictxt ids tyvars
- = ictxt { ic_tmp_ids = snub((ic_tmp_ids ictxt \\ ids) ++ ids),
+extendInteractiveContext ictxt ids
+ = ictxt { ic_tmp_ids = snub ((ic_tmp_ids ictxt \\ ids) ++ ids)
-- NB. must be this way around, because we want
-- new ids to shadow existing bindings.
- ic_tyvars = ic_tyvars ictxt `unionVarSet` tyvars }
+ }
where snub = map head . group . sort
substInteractiveContext :: InteractiveContext -> TvSubst -> InteractiveContext
substInteractiveContext ictxt subst | isEmptyTvSubst subst = ictxt
-substInteractiveContext ictxt@InteractiveContext{ic_tmp_ids=ids} subst =
- let ids' = map (\id -> id `setIdType` substTy subst (idType id)) ids
- subst_dom= varEnvKeys$ getTvSubstEnv subst
- subst_ran= varEnvElts$ getTvSubstEnv subst
- new_tvs = [ tv | Just tv <- map getTyVar_maybe subst_ran]
- ic_tyvars'= (`delVarSetListByKey` subst_dom)
- . (`extendVarSetList` new_tvs)
- $ ic_tyvars ictxt
- in ictxt { ic_tmp_ids = ids'
- , ic_tyvars = ic_tyvars' }
-
- where delVarSetListByKey = foldl' delVarSetByKey
+substInteractiveContext ictxt@InteractiveContext{ic_tmp_ids=ids} subst
+ = ictxt { ic_tmp_ids = map subst_ty ids }
+ where
+ subst_ty id = id `setIdType` substTy subst (idType id)
\end{code}
%************************************************************************
type OrigNameCache = ModuleEnv (OccEnv Name)
-- | Module-local cache of implicit parameter 'OccName's given 'Name's
-type OrigIParamCache = FiniteMap (IPName OccName) (IPName Name)
+type OrigIParamCache = Map (IPName OccName) (IPName Name)
\end{code}
-- ^ An array giving the source span of each breakpoint.
, modBreaks_vars :: !(Array BreakIndex [OccName])
-- ^ An array giving the names of the free variables at each breakpoint.
+ , modBreaks_decls :: !(Array BreakIndex [String])
+ -- ^ An array giving the names of the declarations enclosing each breakpoint.
}
emptyModBreaks :: ModBreaks
emptyModBreaks = ModBreaks
{ modBreaks_flags = error "ModBreaks.modBreaks_array not initialised"
-- Todo: can we avoid this?
- , modBreaks_locs = array (0,-1) []
- , modBreaks_vars = array (0,-1) []
+ , modBreaks_locs = array (0,-1) []
+ , modBreaks_vars = array (0,-1) []
+ , modBreaks_decls = array (0,-1) []
}
\end{code}