diff options
author | Sylvain Henry <sylvain@haskus.fr> | 2020-02-18 11:08:48 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-02-21 20:46:40 -0500 |
commit | 240f5bf6f53515535be5bf3ef7632aa69ae21e3e (patch) | |
tree | dc7be78ca126c66af0aeb9f7944ebfc0ac5a211c /compiler/main/HscMain.hs | |
parent | be7068a6130f394dcefbcb5d09c2944deca2270d (diff) | |
download | haskell-240f5bf6f53515535be5bf3ef7632aa69ae21e3e.tar.gz |
Modules: Driver (#13009)
submodule updates: nofib, haddock
Diffstat (limited to 'compiler/main/HscMain.hs')
-rw-r--r-- | compiler/main/HscMain.hs | 1952 |
1 files changed, 0 insertions, 1952 deletions
diff --git a/compiler/main/HscMain.hs b/compiler/main/HscMain.hs deleted file mode 100644 index 879d8a05ec..0000000000 --- a/compiler/main/HscMain.hs +++ /dev/null @@ -1,1952 +0,0 @@ -{-# LANGUAGE BangPatterns, CPP, MagicHash, NondecreasingIndentation #-} -{-# OPTIONS_GHC -fprof-auto-top #-} - -------------------------------------------------------------------------------- --- --- | Main API for compiling plain Haskell source code. --- --- This module implements compilation of a Haskell source. It is --- /not/ concerned with preprocessing of source files; this is handled --- in "DriverPipeline". --- --- There are various entry points depending on what mode we're in: --- "batch" mode (@--make@), "one-shot" mode (@-c@, @-S@ etc.), and --- "interactive" mode (GHCi). There are also entry points for --- individual passes: parsing, typechecking/renaming, desugaring, and --- simplification. --- --- All the functions here take an 'HscEnv' as a parameter, but none of --- them return a new one: 'HscEnv' is treated as an immutable value --- from here on in (although it has mutable components, for the --- caches). --- --- We use the Hsc monad to deal with warning messages consistently: --- specifically, while executing within an Hsc monad, warnings are --- collected. When a Hsc monad returns to an IO monad, the --- warnings are printed, or compilation aborts if the @-Werror@ --- flag is enabled. --- --- (c) The GRASP/AQUA Project, Glasgow University, 1993-2000 --- -------------------------------------------------------------------------------- - -module HscMain - ( - -- * Making an HscEnv - newHscEnv - - -- * Compiling complete source files - , Messager, batchMsg - , HscStatus (..) - , hscIncrementalCompile - , hscMaybeWriteIface - , hscCompileCmmFile - - , hscGenHardCode - , hscInteractive - - -- * Running passes separately - , hscParse - , hscTypecheckRename - , hscDesugar - , makeSimpleDetails - , hscSimplify -- ToDo, shouldn't really export this - - -- * Safe Haskell - , hscCheckSafe - , hscGetSafe - - -- * Support for interactive evaluation - , hscParseIdentifier - , hscTcRcLookupName - , hscTcRnGetInfo - , hscIsGHCiMonad - , hscGetModuleInterface - , hscRnImportDecls - , hscTcRnLookupRdrName - , hscStmt, hscParseStmtWithLocation, hscStmtWithLocation, hscParsedStmt - , hscDecls, hscParseDeclsWithLocation, hscDeclsWithLocation, hscParsedDecls - , hscTcExpr, TcRnExprMode(..), hscImport, hscKcType - , hscParseExpr - , hscParseType - , hscCompileCoreExpr - -- * Low-level exports for hooks - , hscCompileCoreExpr' - -- We want to make sure that we export enough to be able to redefine - -- hsc_typecheck in client code - , hscParse', hscSimplify', hscDesugar', tcRnModule', doCodeGen - , getHscEnv - , hscSimpleIface' - , oneShotMsg - , dumpIfaceStats - , ioMsgMaybe - , showModuleIndex - , hscAddSptEntries - ) where - -import GhcPrelude - -import Data.Data hiding (Fixity, TyCon) -import Data.Maybe ( fromJust ) -import Id -import GHC.Runtime.Interpreter ( addSptEntry ) -import GHCi.RemoteTypes ( ForeignHValue ) -import GHC.CoreToByteCode ( byteCodeGen, coreExprToBCOs ) -import GHC.Runtime.Linker -import CoreTidy ( tidyExpr ) -import Type ( Type ) -import {- Kind parts of -} Type ( Kind ) -import CoreLint ( lintInteractiveExpr ) -import VarEnv ( emptyTidyEnv ) -import Panic -import ConLike -import Control.Concurrent - -import ApiAnnotation -import Module -import Packages -import RdrName -import GHC.Hs -import GHC.Hs.Dump -import CoreSyn -import StringBuffer -import Parser -import Lexer -import SrcLoc -import TcRnDriver -import GHC.IfaceToCore ( typecheckIface ) -import TcRnMonad -import TcHsSyn ( ZonkFlexi (DefaultFlexi) ) -import NameCache ( initNameCache ) -import GHC.Iface.Load ( ifaceStats, initExternalPackageState ) -import PrelInfo -import GHC.Iface.Utils -import GHC.HsToCore -import SimplCore -import GHC.Iface.Tidy -import GHC.CoreToStg.Prep -import GHC.CoreToStg ( coreToStg ) -import GHC.Stg.Syntax -import GHC.Stg.FVs ( annTopBindingsFreeVars ) -import GHC.Stg.Pipeline ( stg2stg ) -import qualified GHC.StgToCmm as StgToCmm ( codeGen ) -import CostCentre -import ProfInit -import TyCon -import Name -import NameSet -import GHC.Cmm -import GHC.Cmm.Parser ( parseCmmFile ) -import GHC.Cmm.Info.Build -import GHC.Cmm.Pipeline -import GHC.Cmm.Info -import CodeOutput -import InstEnv -import FamInstEnv -import Fingerprint ( Fingerprint ) -import Hooks -import TcEnv -import PrelNames -import Plugins -import GHC.Runtime.Loader ( initializePlugins ) - -import DynFlags -import ErrUtils - -import Outputable -import NameEnv -import HscStats ( ppSourceStats ) -import HscTypes -import FastString -import UniqSupply -import Bag -import Exception -import qualified Stream -import Stream (Stream) - -import Util - -import Data.List ( nub, isPrefixOf, partition ) -import Control.Monad -import Data.IORef -import System.FilePath as FilePath -import System.Directory -import System.IO (fixIO) -import qualified Data.Map as M -import qualified Data.Set as S -import Data.Set (Set) -import Data.Functor -import Control.DeepSeq (force) - -import GHC.Iface.Ext.Ast ( mkHieFile ) -import GHC.Iface.Ext.Types ( getAsts, hie_asts, hie_module ) -import GHC.Iface.Ext.Binary ( readHieFile, writeHieFile , hie_file_result) -import GHC.Iface.Ext.Debug ( diffFile, validateScopes ) - -#include "HsVersions.h" - - -{- ********************************************************************** -%* * - Initialisation -%* * -%********************************************************************* -} - -newHscEnv :: DynFlags -> IO HscEnv -newHscEnv dflags = do - eps_var <- newIORef initExternalPackageState - us <- mkSplitUniqSupply 'r' - nc_var <- newIORef (initNameCache us knownKeyNames) - fc_var <- newIORef emptyInstalledModuleEnv - iserv_mvar <- newMVar Nothing - emptyDynLinker <- uninitializedLinker - return HscEnv { hsc_dflags = dflags - , hsc_targets = [] - , hsc_mod_graph = emptyMG - , hsc_IC = emptyInteractiveContext dflags - , hsc_HPT = emptyHomePackageTable - , hsc_EPS = eps_var - , hsc_NC = nc_var - , hsc_FC = fc_var - , hsc_type_env_var = Nothing - , hsc_iserv = iserv_mvar - , hsc_dynLinker = emptyDynLinker - } - --- ----------------------------------------------------------------------------- - -getWarnings :: Hsc WarningMessages -getWarnings = Hsc $ \_ w -> return (w, w) - -clearWarnings :: Hsc () -clearWarnings = Hsc $ \_ _ -> return ((), emptyBag) - -logWarnings :: WarningMessages -> Hsc () -logWarnings w = Hsc $ \_ w0 -> return ((), w0 `unionBags` w) - -getHscEnv :: Hsc HscEnv -getHscEnv = Hsc $ \e w -> return (e, w) - -handleWarnings :: Hsc () -handleWarnings = do - dflags <- getDynFlags - w <- getWarnings - liftIO $ printOrThrowWarnings dflags w - clearWarnings - --- | log warning in the monad, and if there are errors then --- throw a SourceError exception. -logWarningsReportErrors :: Messages -> Hsc () -logWarningsReportErrors (warns,errs) = do - logWarnings warns - when (not $ isEmptyBag errs) $ throwErrors errs - --- | Log warnings and throw errors, assuming the messages --- contain at least one error (e.g. coming from PFailed) -handleWarningsThrowErrors :: Messages -> Hsc a -handleWarningsThrowErrors (warns, errs) = do - logWarnings warns - dflags <- getDynFlags - (wWarns, wErrs) <- warningsToMessages dflags <$> getWarnings - liftIO $ printBagOfErrors dflags wWarns - throwErrors (unionBags errs wErrs) - --- | Deal with errors and warnings returned by a compilation step --- --- 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 :: IO (Messages, Maybe a) -> Hsc a -ioMsgMaybe ioA = do - ((warns,errs), mb_r) <- liftIO ioA - logWarnings warns - case mb_r of - Nothing -> throwErrors errs - Just r -> ASSERT( isEmptyBag errs ) return r - --- | like ioMsgMaybe, except that we ignore error messages and return --- 'Nothing' instead. -ioMsgMaybe' :: IO (Messages, Maybe a) -> Hsc (Maybe a) -ioMsgMaybe' ioA = do - ((warns,_errs), mb_r) <- liftIO $ ioA - logWarnings warns - return mb_r - --- ----------------------------------------------------------------------------- --- | Lookup things in the compiler's environment - -hscTcRnLookupRdrName :: HscEnv -> Located RdrName -> IO [Name] -hscTcRnLookupRdrName hsc_env0 rdr_name - = runInteractiveHsc hsc_env0 $ - do { hsc_env <- getHscEnv - ; ioMsgMaybe $ tcRnLookupRdrName hsc_env rdr_name } - -hscTcRcLookupName :: HscEnv -> Name -> IO (Maybe TyThing) -hscTcRcLookupName hsc_env0 name = runInteractiveHsc hsc_env0 $ do - hsc_env <- getHscEnv - ioMsgMaybe' $ tcRnLookupName hsc_env name - -- ignore errors: the only error we're likely to get is - -- "name not found", and the Maybe in the return type - -- is used to indicate that. - -hscTcRnGetInfo :: HscEnv -> Name - -> IO (Maybe (TyThing, Fixity, [ClsInst], [FamInst], SDoc)) -hscTcRnGetInfo hsc_env0 name - = runInteractiveHsc hsc_env0 $ - do { hsc_env <- getHscEnv - ; ioMsgMaybe' $ tcRnGetInfo hsc_env name } - -hscIsGHCiMonad :: HscEnv -> String -> IO Name -hscIsGHCiMonad hsc_env name - = runHsc hsc_env $ ioMsgMaybe $ isGHCiMonad hsc_env name - -hscGetModuleInterface :: HscEnv -> Module -> IO ModIface -hscGetModuleInterface hsc_env0 mod = runInteractiveHsc hsc_env0 $ do - hsc_env <- getHscEnv - ioMsgMaybe $ getModuleInterface hsc_env mod - --- ----------------------------------------------------------------------------- --- | Rename some import declarations -hscRnImportDecls :: HscEnv -> [LImportDecl GhcPs] -> IO GlobalRdrEnv -hscRnImportDecls hsc_env0 import_decls = runInteractiveHsc hsc_env0 $ do - hsc_env <- getHscEnv - ioMsgMaybe $ tcRnImportDecls hsc_env import_decls - --- ----------------------------------------------------------------------------- --- | parse a file, returning the abstract syntax - -hscParse :: HscEnv -> ModSummary -> IO HsParsedModule -hscParse hsc_env mod_summary = runHsc hsc_env $ hscParse' mod_summary - --- internal version, that doesn't fail due to -Werror -hscParse' :: ModSummary -> Hsc HsParsedModule -hscParse' mod_summary - | Just r <- ms_parsed_mod mod_summary = return r - | otherwise = {-# SCC "Parser" #-} - withTimingD (text "Parser"<+>brackets (ppr $ ms_mod mod_summary)) - (const ()) $ do - dflags <- getDynFlags - let src_filename = ms_hspp_file mod_summary - maybe_src_buf = ms_hspp_buf mod_summary - - -------------------------- Parser ---------------- - -- sometimes we already have the buffer in memory, perhaps - -- because we needed to parse the imports out of it, or get the - -- module name. - buf <- case maybe_src_buf of - Just b -> return b - Nothing -> liftIO $ hGetStringBuffer src_filename - - let loc = mkRealSrcLoc (mkFastString src_filename) 1 1 - let parseMod | HsigFile == ms_hsc_src mod_summary - = parseSignature - | otherwise = parseModule - - case unP parseMod (mkPState dflags buf loc) of - PFailed pst -> - handleWarningsThrowErrors (getMessages pst dflags) - POk pst rdr_module -> do - let (warns, errs) = getMessages pst dflags - logWarnings warns - liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" - FormatHaskell (ppr rdr_module) - liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST" - FormatHaskell (showAstData NoBlankSrcSpan rdr_module) - liftIO $ dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics" - FormatText (ppSourceStats False rdr_module) - when (not $ isEmptyBag errs) $ throwErrors errs - - -- To get the list of extra source files, we take the list - -- that the parser gave us, - -- - eliminate files beginning with '<'. gcc likes to use - -- pseudo-filenames like "<built-in>" and "<command-line>" - -- - normalise them (eliminate differences between ./f and f) - -- - filter out the preprocessed source file - -- - filter out anything beginning with tmpdir - -- - remove duplicates - -- - filter out the .hs/.lhs source filename if we have one - -- - let n_hspp = FilePath.normalise src_filename - srcs0 = nub $ filter (not . (tmpDir dflags `isPrefixOf`)) - $ filter (not . (== n_hspp)) - $ map FilePath.normalise - $ filter (not . isPrefixOf "<") - $ map unpackFS - $ srcfiles pst - srcs1 = case ml_hs_file (ms_location mod_summary) of - Just f -> filter (/= FilePath.normalise f) srcs0 - Nothing -> srcs0 - - -- sometimes we see source files from earlier - -- preprocessing stages that cannot be found, so just - -- filter them out: - srcs2 <- liftIO $ filterM doesFileExist srcs1 - - let api_anns = ApiAnns { - apiAnnItems = M.fromListWith (++) $ annotations pst, - apiAnnEofPos = eof_pos pst, - apiAnnComments = M.fromList (annotations_comments pst), - apiAnnRogueComments = comment_q pst - } - res = HsParsedModule { - hpm_module = rdr_module, - hpm_src_files = srcs2, - hpm_annotations = api_anns - } - - -- apply parse transformation of plugins - let applyPluginAction p opts - = parsedResultAction p opts mod_summary - withPlugins dflags applyPluginAction res - - --- ----------------------------------------------------------------------------- --- | If the renamed source has been kept, extract it. Dump it if requested. -extract_renamed_stuff :: ModSummary -> TcGblEnv -> Hsc RenamedStuff -extract_renamed_stuff mod_summary tc_result = do - let rn_info = getRenamedStuff tc_result - - dflags <- getDynFlags - liftIO $ dumpIfSet_dyn dflags Opt_D_dump_rn_ast "Renamer" - FormatHaskell (showAstData NoBlankSrcSpan rn_info) - - -- Create HIE files - when (gopt Opt_WriteHie dflags) $ do - -- I assume this fromJust is safe because `-fwrite-hie-file` - -- enables the option which keeps the renamed source. - hieFile <- mkHieFile mod_summary tc_result (fromJust rn_info) - let out_file = ml_hie_file $ ms_location mod_summary - liftIO $ writeHieFile out_file hieFile - - -- Validate HIE files - when (gopt Opt_ValidateHie dflags) $ do - hs_env <- Hsc $ \e w -> return (e, w) - liftIO $ do - -- Validate Scopes - let mdl = hie_module hieFile - case validateScopes mdl $ getAsts $ hie_asts hieFile of - [] -> putMsg dflags $ text "Got valid scopes" - xs -> do - putMsg dflags $ text "Got invalid scopes" - mapM_ (putMsg dflags) xs - -- Roundtrip testing - nc <- readIORef $ hsc_NC hs_env - (file', _) <- readHieFile nc out_file - case diffFile hieFile (hie_file_result file') of - [] -> - putMsg dflags $ text "Got no roundtrip errors" - xs -> do - putMsg dflags $ text "Got roundtrip errors" - mapM_ (putMsg dflags) xs - return rn_info - - --- ----------------------------------------------------------------------------- --- | Rename and typecheck a module, additionally returning the renamed syntax -hscTypecheckRename :: HscEnv -> ModSummary -> HsParsedModule - -> IO (TcGblEnv, RenamedStuff) -hscTypecheckRename hsc_env mod_summary rdr_module = runHsc hsc_env $ - hsc_typecheck True mod_summary (Just rdr_module) - - --- | A bunch of logic piled around around @tcRnModule'@, concerning a) backpack --- b) concerning dumping rename info and hie files. It would be nice to further --- separate this stuff out, probably in conjunction better separating renaming --- and type checking (#17781). -hsc_typecheck :: Bool -- ^ Keep renamed source? - -> ModSummary -> Maybe HsParsedModule - -> Hsc (TcGblEnv, RenamedStuff) -hsc_typecheck keep_rn mod_summary mb_rdr_module = do - hsc_env <- getHscEnv - let hsc_src = ms_hsc_src mod_summary - dflags = hsc_dflags hsc_env - outer_mod = ms_mod mod_summary - mod_name = moduleName outer_mod - outer_mod' = mkModule (thisPackage dflags) mod_name - inner_mod = canonicalizeHomeModule dflags mod_name - src_filename = ms_hspp_file mod_summary - real_loc = realSrcLocSpan $ mkRealSrcLoc (mkFastString src_filename) 1 1 - keep_rn' = gopt Opt_WriteHie dflags || keep_rn - MASSERT( moduleUnitId outer_mod == thisPackage dflags ) - tc_result <- if hsc_src == HsigFile && not (isHoleModule inner_mod) - then ioMsgMaybe $ tcRnInstantiateSignature hsc_env outer_mod' real_loc - else - do hpm <- case mb_rdr_module of - Just hpm -> return hpm - Nothing -> hscParse' mod_summary - tc_result0 <- tcRnModule' mod_summary keep_rn' hpm - if hsc_src == HsigFile - then do (iface, _, _) <- liftIO $ hscSimpleIface hsc_env tc_result0 Nothing - ioMsgMaybe $ - tcRnMergeSignatures hsc_env hpm tc_result0 iface - else return tc_result0 - -- TODO are we extracting anything when we merely instantiate a signature? - -- If not, try to move this into the "else" case above. - rn_info <- extract_renamed_stuff mod_summary tc_result - return (tc_result, rn_info) - --- wrapper around tcRnModule to handle safe haskell extras -tcRnModule' :: ModSummary -> Bool -> HsParsedModule - -> Hsc TcGblEnv -tcRnModule' sum save_rn_syntax mod = do - hsc_env <- getHscEnv - dflags <- getDynFlags - - -- -Wmissing-safe-haskell-mode - when (not (safeHaskellModeEnabled dflags) - && wopt Opt_WarnMissingSafeHaskellMode dflags) $ - logWarnings $ unitBag $ - makeIntoWarning (Reason Opt_WarnMissingSafeHaskellMode) $ - mkPlainWarnMsg dflags (getLoc (hpm_module mod)) $ - warnMissingSafeHaskellMode - - tcg_res <- {-# SCC "Typecheck-Rename" #-} - ioMsgMaybe $ - tcRnModule hsc_env sum - save_rn_syntax mod - - -- See Note [Safe Haskell Overlapping Instances Implementation] - -- although this is used for more than just that failure case. - (tcSafeOK, whyUnsafe) <- liftIO $ readIORef (tcg_safeInfer tcg_res) - let allSafeOK = safeInferred dflags && tcSafeOK - - -- end of the safe haskell line, how to respond to user? - res <- if not (safeHaskellOn dflags) - || (safeInferOn dflags && not allSafeOK) - -- if safe Haskell off or safe infer failed, mark unsafe - then markUnsafeInfer tcg_res whyUnsafe - - -- module (could be) safe, throw warning if needed - else do - tcg_res' <- hscCheckSafeImports tcg_res - safe <- liftIO $ fst <$> readIORef (tcg_safeInfer tcg_res') - when safe $ do - case wopt Opt_WarnSafe dflags of - True - | safeHaskell dflags == Sf_Safe -> return () - | otherwise -> (logWarnings $ unitBag $ - makeIntoWarning (Reason Opt_WarnSafe) $ - mkPlainWarnMsg dflags (warnSafeOnLoc dflags) $ - errSafe tcg_res') - False | safeHaskell dflags == Sf_Trustworthy && - wopt Opt_WarnTrustworthySafe dflags -> - (logWarnings $ unitBag $ - makeIntoWarning (Reason Opt_WarnTrustworthySafe) $ - mkPlainWarnMsg dflags (trustworthyOnLoc dflags) $ - errTwthySafe tcg_res') - False -> return () - return tcg_res' - - -- apply plugins to the type checking result - - - return res - where - pprMod t = ppr $ moduleName $ tcg_mod t - errSafe t = quotes (pprMod t) <+> text "has been inferred as safe!" - errTwthySafe t = quotes (pprMod t) - <+> text "is marked as Trustworthy but has been inferred as safe!" - warnMissingSafeHaskellMode = ppr (moduleName (ms_mod sum)) - <+> text "is missing Safe Haskell mode" - --- | Convert a typechecked module to Core -hscDesugar :: HscEnv -> ModSummary -> TcGblEnv -> IO ModGuts -hscDesugar hsc_env mod_summary tc_result = - runHsc hsc_env $ hscDesugar' (ms_location mod_summary) tc_result - -hscDesugar' :: ModLocation -> TcGblEnv -> Hsc ModGuts -hscDesugar' mod_location tc_result = do - hsc_env <- getHscEnv - r <- ioMsgMaybe $ - {-# SCC "deSugar" #-} - deSugar hsc_env mod_location tc_result - - -- always check -Werror after desugaring, this is the last opportunity for - -- warnings to arise before the backend. - handleWarnings - return r - --- | Make a 'ModDetails' from the results of typechecking. Used when --- typechecking only, as opposed to full compilation. -makeSimpleDetails :: HscEnv -> TcGblEnv -> IO ModDetails -makeSimpleDetails hsc_env tc_result = mkBootModDetailsTc hsc_env tc_result - - -{- ********************************************************************** -%* * - The main compiler pipeline -%* * -%********************************************************************* -} - -{- - -------------------------------- - The compilation proper - -------------------------------- - -It's the task of the compilation proper to compile Haskell, hs-boot and core -files to either byte-code, hard-code (C, asm, LLVM, etc.) or to nothing at all -(the module is still parsed and type-checked. This feature is mostly used by -IDE's and the likes). Compilation can happen in either 'one-shot', 'batch', -'nothing', or 'interactive' mode. 'One-shot' mode targets hard-code, 'batch' -mode targets hard-code, 'nothing' mode targets nothing and 'interactive' mode -targets byte-code. - -The modes are kept separate because of their different types and meanings: - - * In 'one-shot' mode, we're only compiling a single file and can therefore - discard the new ModIface and ModDetails. This is also the reason it only - targets hard-code; compiling to byte-code or nothing doesn't make sense when - we discard the result. - - * 'Batch' mode is like 'one-shot' except that we keep the resulting ModIface - and ModDetails. 'Batch' mode doesn't target byte-code since that require us to - return the newly compiled byte-code. - - * 'Nothing' mode has exactly the same type as 'batch' mode but they're still - kept separate. This is because compiling to nothing is fairly special: We - don't output any interface files, we don't run the simplifier and we don't - generate any code. - - * 'Interactive' mode is similar to 'batch' mode except that we return the - compiled byte-code together with the ModIface and ModDetails. - -Trying to compile a hs-boot file to byte-code will result in a run-time error. -This is the only thing that isn't caught by the type-system. --} - - -type Messager = HscEnv -> (Int,Int) -> RecompileRequired -> ModSummary -> IO () - --- | This function runs GHC's frontend with recompilation --- avoidance. Specifically, it checks if recompilation is needed, --- and if it is, it parses and typechecks the input module. --- It does not write out the results of typechecking (See --- compileOne and hscIncrementalCompile). -hscIncrementalFrontend :: Bool -- always do basic recompilation check? - -> Maybe TcGblEnv - -> Maybe Messager - -> ModSummary - -> SourceModified - -> Maybe ModIface -- Old interface, if available - -> (Int,Int) -- (i,n) = module i of n (for msgs) - -> Hsc (Either ModIface (FrontendResult, Maybe Fingerprint)) - -hscIncrementalFrontend - always_do_basic_recompilation_check m_tc_result - mHscMessage mod_summary source_modified mb_old_iface mod_index - = do - hsc_env <- getHscEnv - - let msg what = case mHscMessage of - Just hscMessage -> hscMessage hsc_env mod_index what mod_summary - Nothing -> return () - - skip iface = do - liftIO $ msg UpToDate - return $ Left iface - - compile mb_old_hash reason = do - liftIO $ msg reason - (tc_result, _) <- hsc_typecheck False mod_summary Nothing - return $ Right (FrontendTypecheck tc_result, mb_old_hash) - - stable = case source_modified of - SourceUnmodifiedAndStable -> True - _ -> False - - case m_tc_result of - Just tc_result - | not always_do_basic_recompilation_check -> - return $ Right (FrontendTypecheck tc_result, Nothing) - _ -> do - (recomp_reqd, mb_checked_iface) - <- {-# SCC "checkOldIface" #-} - liftIO $ checkOldIface hsc_env mod_summary - source_modified mb_old_iface - -- save the interface that comes back from checkOldIface. - -- In one-shot mode we don't have the old iface until this - -- point, when checkOldIface reads it from the disk. - let mb_old_hash = fmap (mi_iface_hash . mi_final_exts) mb_checked_iface - - case mb_checked_iface of - Just iface | not (recompileRequired recomp_reqd) -> - -- If the module used TH splices when it was last - -- compiled, then the recompilation check is not - -- accurate enough (#481) and we must ignore - -- it. However, if the module is stable (none of - -- the modules it depends on, directly or - -- indirectly, changed), then we *can* skip - -- recompilation. This is why the SourceModified - -- type contains SourceUnmodifiedAndStable, and - -- it's pretty important: otherwise ghc --make - -- would always recompile TH modules, even if - -- nothing at all has changed. Stability is just - -- the same check that make is doing for us in - -- one-shot mode. - case m_tc_result of - Nothing - | mi_used_th iface && not stable -> - compile mb_old_hash (RecompBecause "TH") - _ -> - skip iface - _ -> - case m_tc_result of - Nothing -> compile mb_old_hash recomp_reqd - Just tc_result -> - return $ Right (FrontendTypecheck tc_result, mb_old_hash) - --------------------------------------------------------------- --- Compilers --------------------------------------------------------------- - --- | Used by both OneShot and batch mode. Runs the pipeline HsSyn and Core parts --- of the pipeline. --- We return a interface if we already had an old one around and recompilation --- was not needed. Otherwise it will be created during later passes when we --- run the compilation pipeline. -hscIncrementalCompile :: Bool - -> Maybe TcGblEnv - -> Maybe Messager - -> HscEnv - -> ModSummary - -> SourceModified - -> Maybe ModIface - -> (Int,Int) - -> IO (HscStatus, DynFlags) -hscIncrementalCompile always_do_basic_recompilation_check m_tc_result - mHscMessage hsc_env' mod_summary source_modified mb_old_iface mod_index - = do - dflags <- initializePlugins hsc_env' (hsc_dflags hsc_env') - let hsc_env'' = hsc_env' { hsc_dflags = dflags } - - -- One-shot mode needs a knot-tying mutable variable for interface - -- files. See TcRnTypes.TcGblEnv.tcg_type_env_var. - -- See also Note [hsc_type_env_var hack] - type_env_var <- newIORef emptyNameEnv - let mod = ms_mod mod_summary - hsc_env | isOneShot (ghcMode (hsc_dflags hsc_env'')) - = hsc_env'' { hsc_type_env_var = Just (mod, type_env_var) } - | otherwise - = hsc_env'' - - -- NB: enter Hsc monad here so that we don't bail out early with - -- -Werror on typechecker warnings; we also want to run the desugarer - -- to get those warnings too. (But we'll always exit at that point - -- because the desugarer runs ioMsgMaybe.) - runHsc hsc_env $ do - e <- hscIncrementalFrontend always_do_basic_recompilation_check m_tc_result mHscMessage - mod_summary source_modified mb_old_iface mod_index - case e of - -- We didn't need to do any typechecking; the old interface - -- file on disk was good enough. - Left iface -> do - -- Knot tying! See Note [Knot-tying typecheckIface] - details <- liftIO . fixIO $ \details' -> do - let hsc_env' = - hsc_env { - hsc_HPT = addToHpt (hsc_HPT hsc_env) - (ms_mod_name mod_summary) (HomeModInfo iface details' Nothing) - } - -- NB: This result is actually not that useful - -- in one-shot mode, since we're not going to do - -- any further typechecking. It's much more useful - -- in make mode, since this HMI will go into the HPT. - details <- genModDetails hsc_env' iface - return details - return (HscUpToDate iface details, dflags) - -- We finished type checking. (mb_old_hash is the hash of - -- the interface that existed on disk; it's possible we had - -- to retypecheck but the resulting interface is exactly - -- the same.) - Right (FrontendTypecheck tc_result, mb_old_hash) -> do - status <- finish mod_summary tc_result mb_old_hash - return (status, dflags) - --- Runs the post-typechecking frontend (desugar and simplify). We want to --- generate most of the interface as late as possible. This gets us up-to-date --- and good unfoldings and other info in the interface file. --- --- We might create a interface right away, in which case we also return the --- updated HomeModInfo. But we might also need to run the backend first. In the --- later case Status will be HscRecomp and we return a function from ModIface -> --- HomeModInfo. --- --- HscRecomp in turn will carry the information required to compute a interface --- when passed the result of the code generator. So all this can and is done at --- the call site of the backend code gen if it is run. -finish :: ModSummary - -> TcGblEnv - -> Maybe Fingerprint - -> Hsc HscStatus -finish summary tc_result mb_old_hash = do - hsc_env <- getHscEnv - let dflags = hsc_dflags hsc_env - target = hscTarget dflags - hsc_src = ms_hsc_src summary - - -- Desugar, if appropriate - -- - -- We usually desugar even when we are not generating code, otherwise we - -- would miss errors thrown by the desugaring (see #10600). The only - -- exceptions are when the Module is Ghc.Prim or when it is not a - -- HsSrcFile Module. - mb_desugar <- - if ms_mod summary /= gHC_PRIM && hsc_src == HsSrcFile - then Just <$> hscDesugar' (ms_location summary) tc_result - else pure Nothing - - -- Simplify, if appropriate, and (whether we simplified or not) generate an - -- interface file. - case mb_desugar of - -- Just cause we desugared doesn't mean we are generating code, see above. - Just desugared_guts | target /= HscNothing -> do - plugins <- liftIO $ readIORef (tcg_th_coreplugins tc_result) - simplified_guts <- hscSimplify' plugins desugared_guts - - (cg_guts, details) <- {-# SCC "CoreTidy" #-} - liftIO $ tidyProgram hsc_env simplified_guts - - let !partial_iface = - {-# SCC "HscMain.mkPartialIface" #-} - -- This `force` saves 2M residency in test T10370 - -- See Note [Avoiding space leaks in toIface*] for details. - force (mkPartialIface hsc_env details simplified_guts) - - return HscRecomp { hscs_guts = cg_guts, - hscs_mod_location = ms_location summary, - hscs_mod_details = details, - hscs_partial_iface = partial_iface, - hscs_old_iface_hash = mb_old_hash, - hscs_iface_dflags = dflags } - - -- We are not generating code, so we can skip simplification - -- and generate a simple interface. - _ -> do - (iface, mb_old_iface_hash, details) <- liftIO $ - hscSimpleIface hsc_env tc_result mb_old_hash - - liftIO $ hscMaybeWriteIface dflags iface mb_old_iface_hash (ms_location summary) - - return $ case (target, hsc_src) of - (HscNothing, _) -> HscNotGeneratingCode iface details - (_, HsBootFile) -> HscUpdateBoot iface details - (_, HsigFile) -> HscUpdateSig iface details - _ -> panic "finish" - -{- -Note [Writing interface files] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We write interface files in HscMain.hs and DriverPipeline.hs using -hscMaybeWriteIface, but only once per compilation (twice with dynamic-too). - -* If a compilation does NOT require (re)compilation of the hard code we call - hscMaybeWriteIface inside HscMain:finish. -* If we run in One Shot mode and target bytecode we write it in compileOne' -* Otherwise we must be compiling to regular hard code and require recompilation. - In this case we create the interface file inside RunPhase using the interface - generator contained inside the HscRecomp status. --} -hscMaybeWriteIface :: DynFlags -> ModIface -> Maybe Fingerprint -> ModLocation -> IO () -hscMaybeWriteIface dflags iface old_iface location = do - let force_write_interface = gopt Opt_WriteInterface dflags - write_interface = case hscTarget dflags of - HscNothing -> False - HscInterpreted -> False - _ -> True - no_change = old_iface == Just (mi_iface_hash (mi_final_exts iface)) - - when (write_interface || force_write_interface) $ - hscWriteIface dflags iface no_change location - --------------------------------------------------------------- --- NoRecomp handlers --------------------------------------------------------------- - --- NB: this must be knot-tied appropriately, see hscIncrementalCompile -genModDetails :: HscEnv -> ModIface -> IO ModDetails -genModDetails hsc_env old_iface - = do - new_details <- {-# SCC "tcRnIface" #-} - initIfaceLoad hsc_env (typecheckIface old_iface) - dumpIfaceStats hsc_env - return new_details - --------------------------------------------------------------- --- Progress displayers. --------------------------------------------------------------- - -oneShotMsg :: HscEnv -> RecompileRequired -> IO () -oneShotMsg hsc_env recomp = - case recomp of - UpToDate -> - compilationProgressMsg (hsc_dflags hsc_env) $ - "compilation IS NOT required" - _ -> - return () - -batchMsg :: Messager -batchMsg hsc_env mod_index recomp mod_summary = - case recomp of - MustCompile -> showMsg "Compiling " "" - UpToDate - | verbosity (hsc_dflags hsc_env) >= 2 -> showMsg "Skipping " "" - | otherwise -> return () - RecompBecause reason -> showMsg "Compiling " (" [" ++ reason ++ "]") - where - dflags = hsc_dflags hsc_env - showMsg msg reason = - compilationProgressMsg dflags $ - (showModuleIndex mod_index ++ - msg ++ showModMsg dflags (hscTarget dflags) - (recompileRequired recomp) mod_summary) - ++ reason - --------------------------------------------------------------- --- Safe Haskell --------------------------------------------------------------- - --- Note [Safe Haskell Trust Check] --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- Safe Haskell checks that an import is trusted according to the following --- rules for an import of module M that resides in Package P: --- --- * If M is recorded as Safe and all its trust dependencies are OK --- then M is considered safe. --- * If M is recorded as Trustworthy and P is considered trusted and --- all M's trust dependencies are OK then M is considered safe. --- --- By trust dependencies we mean that the check is transitive. So if --- a module M that is Safe relies on a module N that is trustworthy, --- importing module M will first check (according to the second case) --- that N is trusted before checking M is trusted. --- --- This is a minimal description, so please refer to the user guide --- for more details. The user guide is also considered the authoritative --- source in this matter, not the comments or code. - - --- Note [Safe Haskell Inference] --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- Safe Haskell does Safe inference on modules that don't have any specific --- safe haskell mode flag. The basic approach to this is: --- * When deciding if we need to do a Safe language check, treat --- an unmarked module as having -XSafe mode specified. --- * For checks, don't throw errors but return them to the caller. --- * Caller checks if there are errors: --- * For modules explicitly marked -XSafe, we throw the errors. --- * For unmarked modules (inference mode), we drop the errors --- and mark the module as being Unsafe. --- --- It used to be that we only did safe inference on modules that had no Safe --- Haskell flags, but now we perform safe inference on all modules as we want --- to allow users to set the `-Wsafe`, `-Wunsafe` and --- `-Wtrustworthy-safe` flags on Trustworthy and Unsafe modules so that a --- user can ensure their assumptions are correct and see reasons for why a --- module is safe or unsafe. --- --- This is tricky as we must be careful when we should throw an error compared --- to just warnings. For checking safe imports we manage it as two steps. First --- we check any imports that are required to be safe, then we check all other --- imports to see if we can infer them to be safe. - - --- | Check that the safe imports of the module being compiled are valid. --- If not we either issue a compilation error if the module is explicitly --- using Safe Haskell, or mark the module as unsafe if we're in safe --- inference mode. -hscCheckSafeImports :: TcGblEnv -> Hsc TcGblEnv -hscCheckSafeImports tcg_env = do - dflags <- getDynFlags - tcg_env' <- checkSafeImports tcg_env - checkRULES dflags tcg_env' - - where - checkRULES dflags tcg_env' = do - case safeLanguageOn dflags of - True -> do - -- XSafe: we nuke user written RULES - logWarnings $ warns dflags (tcg_rules tcg_env') - return tcg_env' { tcg_rules = [] } - False - -- SafeInferred: user defined RULES, so not safe - | safeInferOn dflags && not (null $ tcg_rules tcg_env') - -> markUnsafeInfer tcg_env' $ warns dflags (tcg_rules tcg_env') - - -- Trustworthy OR SafeInferred: with no RULES - | otherwise - -> return tcg_env' - - warns dflags rules = listToBag $ map (warnRules dflags) rules - - warnRules :: DynFlags -> GenLocated SrcSpan (RuleDecl GhcTc) -> ErrMsg - warnRules dflags (L loc (HsRule { rd_name = n })) = - mkPlainWarnMsg dflags loc $ - text "Rule \"" <> ftext (snd $ unLoc n) <> text "\" ignored" $+$ - text "User defined rules are disabled under Safe Haskell" - warnRules _ (L _ (XRuleDecl nec)) = noExtCon nec - --- | Validate that safe imported modules are actually safe. For modules in the --- HomePackage (the package the module we are compiling in resides) this just --- involves checking its trust type is 'Safe' or 'Trustworthy'. For modules --- that reside in another package we also must check that the external package --- is trusted. See the Note [Safe Haskell Trust Check] above for more --- information. --- --- The code for this is quite tricky as the whole algorithm is done in a few --- distinct phases in different parts of the code base. See --- GHC.Rename.Names.rnImportDecl for where package trust dependencies for a --- module are collected and unioned. Specifically see the Note [Tracking Trust --- Transitively] in GHC.Rename.Names and the Note [Trust Own Package] in --- GHC.Rename.Names. -checkSafeImports :: TcGblEnv -> Hsc TcGblEnv -checkSafeImports tcg_env - = do - dflags <- getDynFlags - imps <- mapM condense imports' - let (safeImps, regImps) = partition (\(_,_,s) -> s) imps - - -- We want to use the warning state specifically for detecting if safe - -- inference has failed, so store and clear any existing warnings. - oldErrs <- getWarnings - clearWarnings - - -- Check safe imports are correct - safePkgs <- S.fromList <$> mapMaybeM checkSafe safeImps - safeErrs <- getWarnings - clearWarnings - - -- Check non-safe imports are correct if inferring safety - -- See the Note [Safe Haskell Inference] - (infErrs, infPkgs) <- case (safeInferOn dflags) of - False -> return (emptyBag, S.empty) - True -> do infPkgs <- S.fromList <$> mapMaybeM checkSafe regImps - infErrs <- getWarnings - clearWarnings - return (infErrs, infPkgs) - - -- restore old errors - logWarnings oldErrs - - case (isEmptyBag safeErrs) of - -- Failed safe check - False -> liftIO . throwIO . mkSrcErr $ safeErrs - - -- Passed safe check - True -> do - let infPassed = isEmptyBag infErrs - tcg_env' <- case (not infPassed) of - True -> markUnsafeInfer tcg_env infErrs - False -> return tcg_env - when (packageTrustOn dflags) $ checkPkgTrust pkgReqs - let newTrust = pkgTrustReqs dflags safePkgs infPkgs infPassed - return tcg_env' { tcg_imports = impInfo `plusImportAvails` newTrust } - - where - impInfo = tcg_imports tcg_env -- ImportAvails - imports = imp_mods impInfo -- ImportedMods - imports1 = moduleEnvToList imports -- (Module, [ImportedBy]) - imports' = map (fmap importedByUser) imports1 -- (Module, [ImportedModsVal]) - pkgReqs = imp_trust_pkgs impInfo -- [UnitId] - - condense :: (Module, [ImportedModsVal]) -> Hsc (Module, SrcSpan, IsSafeImport) - condense (_, []) = panic "HscMain.condense: Pattern match failure!" - condense (m, x:xs) = do imv <- foldlM cond' x xs - return (m, imv_span imv, imv_is_safe imv) - - -- ImportedModsVal = (ModuleName, Bool, SrcSpan, IsSafeImport) - cond' :: ImportedModsVal -> ImportedModsVal -> Hsc ImportedModsVal - cond' v1 v2 - | imv_is_safe v1 /= imv_is_safe v2 - = do - dflags <- getDynFlags - throwOneError $ mkPlainErrMsg dflags (imv_span v1) - (text "Module" <+> ppr (imv_name v1) <+> - (text $ "is imported both as a safe and unsafe import!")) - | otherwise - = return v1 - - -- easier interface to work with - checkSafe :: (Module, SrcSpan, a) -> Hsc (Maybe InstalledUnitId) - checkSafe (m, l, _) = fst `fmap` hscCheckSafe' m l - - -- what pkg's to add to our trust requirements - pkgTrustReqs :: DynFlags -> Set InstalledUnitId -> Set InstalledUnitId -> - Bool -> ImportAvails - pkgTrustReqs dflags req inf infPassed | safeInferOn dflags - && not (safeHaskellModeEnabled dflags) && infPassed - = emptyImportAvails { - imp_trust_pkgs = req `S.union` inf - } - pkgTrustReqs dflags _ _ _ | safeHaskell dflags == Sf_Unsafe - = emptyImportAvails - pkgTrustReqs _ req _ _ = emptyImportAvails { imp_trust_pkgs = req } - --- | Check that a module is safe to import. --- --- We return True to indicate the import is safe and False otherwise --- although in the False case an exception may be thrown first. -hscCheckSafe :: HscEnv -> Module -> SrcSpan -> IO Bool -hscCheckSafe hsc_env m l = runHsc hsc_env $ do - dflags <- getDynFlags - pkgs <- snd `fmap` hscCheckSafe' m l - when (packageTrustOn dflags) $ checkPkgTrust pkgs - errs <- getWarnings - return $ isEmptyBag errs - --- | Return if a module is trusted and the pkgs it depends on to be trusted. -hscGetSafe :: HscEnv -> Module -> SrcSpan -> IO (Bool, Set InstalledUnitId) -hscGetSafe hsc_env m l = runHsc hsc_env $ do - (self, pkgs) <- hscCheckSafe' m l - good <- isEmptyBag `fmap` getWarnings - clearWarnings -- don't want them printed... - let pkgs' | Just p <- self = S.insert p pkgs - | otherwise = pkgs - return (good, pkgs') - --- | Is a module trusted? If not, throw or log errors depending on the type. --- Return (regardless of trusted or not) if the trust type requires the modules --- own package be trusted and a list of other packages required to be trusted --- (these later ones haven't been checked) but the own package trust has been. -hscCheckSafe' :: Module -> SrcSpan - -> Hsc (Maybe InstalledUnitId, Set InstalledUnitId) -hscCheckSafe' m l = do - dflags <- getDynFlags - (tw, pkgs) <- isModSafe m l - case tw of - False -> return (Nothing, pkgs) - True | isHomePkg dflags m -> return (Nothing, pkgs) - -- TODO: do we also have to check the trust of the instantiation? - -- Not necessary if that is reflected in dependencies - | otherwise -> return (Just $ toInstalledUnitId (moduleUnitId m), pkgs) - where - isModSafe :: Module -> SrcSpan -> Hsc (Bool, Set InstalledUnitId) - isModSafe m l = do - dflags <- getDynFlags - iface <- lookup' m - case iface of - -- can't load iface to check trust! - Nothing -> throwOneError $ mkPlainErrMsg dflags l - $ text "Can't load the interface file for" <+> ppr m - <> text ", to check that it can be safely imported" - - -- got iface, check trust - Just iface' -> - let trust = getSafeMode $ mi_trust iface' - trust_own_pkg = mi_trust_pkg iface' - -- check module is trusted - safeM = trust `elem` [Sf_Safe, Sf_SafeInferred, Sf_Trustworthy] - -- check package is trusted - safeP = packageTrusted dflags trust trust_own_pkg m - -- pkg trust reqs - pkgRs = S.fromList . map fst $ filter snd $ dep_pkgs $ mi_deps iface' - -- warn if Safe module imports Safe-Inferred module. - warns = if wopt Opt_WarnInferredSafeImports dflags - && safeLanguageOn dflags - && trust == Sf_SafeInferred - then inferredImportWarn - else emptyBag - -- General errors we throw but Safe errors we log - errs = case (safeM, safeP) of - (True, True ) -> emptyBag - (True, False) -> pkgTrustErr - (False, _ ) -> modTrustErr - in do - logWarnings warns - logWarnings errs - return (trust == Sf_Trustworthy, pkgRs) - - where - inferredImportWarn = unitBag - $ makeIntoWarning (Reason Opt_WarnInferredSafeImports) - $ mkErrMsg dflags l (pkgQual dflags) - $ sep - [ text "Importing Safe-Inferred module " - <> ppr (moduleName m) - <> text " from explicitly Safe module" - ] - pkgTrustErr = unitBag $ mkErrMsg dflags l (pkgQual dflags) $ - sep [ ppr (moduleName m) - <> text ": Can't be safely imported!" - , text "The package (" <> ppr (moduleUnitId m) - <> text ") the module resides in isn't trusted." - ] - modTrustErr = unitBag $ mkErrMsg dflags l (pkgQual dflags) $ - sep [ ppr (moduleName m) - <> text ": Can't be safely imported!" - , text "The module itself isn't safe." ] - - -- | Check the package a module resides in is trusted. Safe compiled - -- modules are trusted without requiring that their package is trusted. For - -- trustworthy modules, modules in the home package are trusted but - -- otherwise we check the package trust flag. - packageTrusted :: DynFlags -> SafeHaskellMode -> Bool -> Module -> Bool - packageTrusted _ Sf_None _ _ = False -- shouldn't hit these cases - packageTrusted _ Sf_Ignore _ _ = False -- shouldn't hit these cases - packageTrusted _ Sf_Unsafe _ _ = False -- prefer for completeness. - packageTrusted dflags _ _ _ - | not (packageTrustOn dflags) = True - packageTrusted _ Sf_Safe False _ = True - packageTrusted _ Sf_SafeInferred False _ = True - packageTrusted dflags _ _ m - | isHomePkg dflags m = True - | otherwise = trusted $ getPackageDetails dflags (moduleUnitId m) - - lookup' :: Module -> Hsc (Maybe ModIface) - lookup' m = do - hsc_env <- getHscEnv - hsc_eps <- liftIO $ hscEPS hsc_env - let pkgIfaceT = eps_PIT hsc_eps - homePkgT = hsc_HPT hsc_env - iface = lookupIfaceByModule homePkgT pkgIfaceT m - -- the 'lookupIfaceByModule' method will always fail when calling from GHCi - -- as the compiler hasn't filled in the various module tables - -- so we need to call 'getModuleInterface' to load from disk - iface' <- case iface of - Just _ -> return iface - Nothing -> snd `fmap` (liftIO $ getModuleInterface hsc_env m) - return iface' - - - isHomePkg :: DynFlags -> Module -> Bool - isHomePkg dflags m - | thisPackage dflags == moduleUnitId m = True - | otherwise = False - --- | Check the list of packages are trusted. -checkPkgTrust :: Set InstalledUnitId -> Hsc () -checkPkgTrust pkgs = do - dflags <- getDynFlags - let errors = S.foldr go [] pkgs - go pkg acc - | trusted $ getInstalledPackageDetails dflags pkg - = acc - | otherwise - = (:acc) $ mkErrMsg dflags noSrcSpan (pkgQual dflags) - $ text "The package (" <> ppr pkg <> text ") is required" <> - text " to be trusted but it isn't!" - case errors of - [] -> return () - _ -> (liftIO . throwIO . mkSrcErr . listToBag) errors - --- | Set module to unsafe and (potentially) wipe trust information. --- --- Make sure to call this method to set a module to inferred unsafe, it should --- be a central and single failure method. We only wipe the trust information --- when we aren't in a specific Safe Haskell mode. --- --- While we only use this for recording that a module was inferred unsafe, we --- may call it on modules using Trustworthy or Unsafe flags so as to allow --- warning flags for safety to function correctly. See Note [Safe Haskell --- Inference]. -markUnsafeInfer :: TcGblEnv -> WarningMessages -> Hsc TcGblEnv -markUnsafeInfer tcg_env whyUnsafe = do - dflags <- getDynFlags - - when (wopt Opt_WarnUnsafe dflags) - (logWarnings $ unitBag $ makeIntoWarning (Reason Opt_WarnUnsafe) $ - mkPlainWarnMsg dflags (warnUnsafeOnLoc dflags) (whyUnsafe' dflags)) - - liftIO $ writeIORef (tcg_safeInfer tcg_env) (False, whyUnsafe) - -- NOTE: Only wipe trust when not in an explicitly safe haskell mode. Other - -- times inference may be on but we are in Trustworthy mode -- so we want - -- to record safe-inference failed but not wipe the trust dependencies. - case not (safeHaskellModeEnabled dflags) of - True -> return $ tcg_env { tcg_imports = wiped_trust } - False -> return tcg_env - - where - wiped_trust = (tcg_imports tcg_env) { imp_trust_pkgs = S.empty } - pprMod = ppr $ moduleName $ tcg_mod tcg_env - whyUnsafe' df = vcat [ quotes pprMod <+> text "has been inferred as unsafe!" - , text "Reason:" - , nest 4 $ (vcat $ badFlags df) $+$ - (vcat $ pprErrMsgBagWithLoc whyUnsafe) $+$ - (vcat $ badInsts $ tcg_insts tcg_env) - ] - badFlags df = concatMap (badFlag df) unsafeFlagsForInfer - badFlag df (str,loc,on,_) - | on df = [mkLocMessage SevOutput (loc df) $ - text str <+> text "is not allowed in Safe Haskell"] - | otherwise = [] - badInsts insts = concatMap badInst insts - - checkOverlap (NoOverlap _) = False - checkOverlap _ = True - - badInst ins | checkOverlap (overlapMode (is_flag ins)) - = [mkLocMessage SevOutput (nameSrcSpan $ getName $ is_dfun ins) $ - ppr (overlapMode $ is_flag ins) <+> - text "overlap mode isn't allowed in Safe Haskell"] - | otherwise = [] - - --- | Figure out the final correct safe haskell mode -hscGetSafeMode :: TcGblEnv -> Hsc SafeHaskellMode -hscGetSafeMode tcg_env = do - dflags <- getDynFlags - liftIO $ finalSafeMode dflags tcg_env - --------------------------------------------------------------- --- Simplifiers --------------------------------------------------------------- - -hscSimplify :: HscEnv -> [String] -> ModGuts -> IO ModGuts -hscSimplify hsc_env plugins modguts = - runHsc hsc_env $ hscSimplify' plugins modguts - -hscSimplify' :: [String] -> ModGuts -> Hsc ModGuts -hscSimplify' plugins ds_result = do - hsc_env <- getHscEnv - let hsc_env_with_plugins = hsc_env - { hsc_dflags = foldr addPluginModuleName (hsc_dflags hsc_env) plugins - } - {-# SCC "Core2Core" #-} - liftIO $ core2core hsc_env_with_plugins ds_result - --------------------------------------------------------------- --- Interface generators --------------------------------------------------------------- - --- | Generate a striped down interface file, e.g. for boot files or when ghci --- generates interface files. See Note [simpleTidyPgm - mkBootModDetailsTc] -hscSimpleIface :: HscEnv - -> TcGblEnv - -> Maybe Fingerprint - -> IO (ModIface, Maybe Fingerprint, ModDetails) -hscSimpleIface hsc_env tc_result mb_old_iface - = runHsc hsc_env $ hscSimpleIface' tc_result mb_old_iface - -hscSimpleIface' :: TcGblEnv - -> Maybe Fingerprint - -> Hsc (ModIface, Maybe Fingerprint, ModDetails) -hscSimpleIface' tc_result mb_old_iface = do - hsc_env <- getHscEnv - details <- liftIO $ mkBootModDetailsTc hsc_env tc_result - safe_mode <- hscGetSafeMode tc_result - new_iface - <- {-# SCC "MkFinalIface" #-} - liftIO $ - mkIfaceTc hsc_env safe_mode details tc_result - -- And the answer is ... - liftIO $ dumpIfaceStats hsc_env - return (new_iface, mb_old_iface, details) - --------------------------------------------------------------- --- BackEnd combinators --------------------------------------------------------------- -{- -Note [Interface filename extensions] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -ModLocation only contains the base names, however when generating dynamic files -the actual extension might differ from the default. - -So we only load the base name from ModLocation and replace the actual extension -according to the information in DynFlags. - -If we generate a interface file right after running the core pipeline we will -have set -dynamic-too and potentially generate both interface files at the same -time. - -If we generate a interface file after running the backend then dynamic-too won't -be set, however then the extension will be contained in the dynflags instead so -things still work out fine. --} - -hscWriteIface :: DynFlags -> ModIface -> Bool -> ModLocation -> IO () -hscWriteIface dflags iface no_change mod_location = do - -- mod_location only contains the base name, so we rebuild the - -- correct file extension from the dynflags. - let ifaceBaseFile = ml_hi_file mod_location - unless no_change $ - let ifaceFile = buildIfName ifaceBaseFile (hiSuf dflags) - in {-# SCC "writeIface" #-} - writeIfaceFile dflags ifaceFile iface - whenGeneratingDynamicToo dflags $ do - -- TODO: We should do a no_change check for the dynamic - -- interface file too - -- When we generate iface files after core - let dynDflags = dynamicTooMkDynamicDynFlags dflags - -- dynDflags will have set hiSuf correctly. - dynIfaceFile = buildIfName ifaceBaseFile (hiSuf dynDflags) - - writeIfaceFile dynDflags dynIfaceFile iface - where - buildIfName :: String -> String -> String - buildIfName baseName suffix - | Just name <- outputHi dflags - = name - | otherwise - = let with_hi = replaceExtension baseName suffix - in addBootSuffix_maybe (mi_boot iface) with_hi - --- | Compile to hard-code. -hscGenHardCode :: HscEnv -> CgGuts -> ModLocation -> FilePath - -> IO (FilePath, Maybe FilePath, [(ForeignSrcLang, FilePath)], NameSet) - -- ^ @Just f@ <=> _stub.c is f -hscGenHardCode hsc_env cgguts location output_filename = do - let CgGuts{ -- This is the last use of the ModGuts in a compilation. - -- From now on, we just use the bits we need. - cg_module = this_mod, - cg_binds = core_binds, - cg_tycons = tycons, - cg_foreign = foreign_stubs0, - cg_foreign_files = foreign_files, - cg_dep_pkgs = dependencies, - cg_hpc_info = hpc_info } = cgguts - dflags = hsc_dflags hsc_env - data_tycons = filter isDataTyCon tycons - -- cg_tycons includes newtypes, for the benefit of External Core, - -- but we don't generate any code for newtypes - - ------------------- - -- PREPARE FOR CODE GENERATION - -- Do saturation and convert to A-normal form - (prepd_binds, local_ccs) <- {-# SCC "CorePrep" #-} - corePrepPgm hsc_env this_mod location - core_binds data_tycons - ----------------- Convert to STG ------------------ - (stg_binds, (caf_ccs, caf_cc_stacks)) - <- {-# SCC "CoreToStg" #-} - myCoreToStg dflags this_mod prepd_binds - - let cost_centre_info = - (S.toList local_ccs ++ caf_ccs, caf_cc_stacks) - prof_init = profilingInitCode this_mod cost_centre_info - foreign_stubs = foreign_stubs0 `appendStubC` prof_init - - ------------------ Code generation ------------------ - - -- The back-end is streamed: each top-level function goes - -- from Stg all the way to asm before dealing with the next - -- top-level function, so showPass isn't very useful here. - -- Hence we have one showPass for the whole backend, the - -- next showPass after this will be "Assembler". - withTiming dflags - (text "CodeGen"<+>brackets (ppr this_mod)) - (const ()) $ do - cmms <- {-# SCC "StgToCmm" #-} - doCodeGen hsc_env this_mod data_tycons - cost_centre_info - stg_binds hpc_info - - ------------------ Code output ----------------------- - rawcmms0 <- {-# SCC "cmmToRawCmm" #-} - lookupHook cmmToRawCmmHook - (\dflg _ -> cmmToRawCmm dflg) dflags dflags (Just this_mod) cmms - - let dump a = do - unless (null a) $ - dumpIfSet_dyn dflags Opt_D_dump_cmm_raw "Raw Cmm" FormatCMM (ppr a) - return a - rawcmms1 = Stream.mapM dump rawcmms0 - - (output_filename, (_stub_h_exists, stub_c_exists), foreign_fps, caf_infos) - <- {-# SCC "codeOutput" #-} - codeOutput dflags this_mod output_filename location - foreign_stubs foreign_files dependencies rawcmms1 - return (output_filename, stub_c_exists, foreign_fps, caf_infos) - - -hscInteractive :: HscEnv - -> CgGuts - -> ModLocation - -> IO (Maybe FilePath, CompiledByteCode, [SptEntry]) -hscInteractive hsc_env cgguts location = do - let dflags = hsc_dflags hsc_env - let CgGuts{ -- This is the last use of the ModGuts in a compilation. - -- From now on, we just use the bits we need. - cg_module = this_mod, - cg_binds = core_binds, - cg_tycons = tycons, - cg_foreign = foreign_stubs, - cg_modBreaks = mod_breaks, - cg_spt_entries = spt_entries } = cgguts - - data_tycons = filter isDataTyCon tycons - -- cg_tycons includes newtypes, for the benefit of External Core, - -- but we don't generate any code for newtypes - - ------------------- - -- PREPARE FOR CODE GENERATION - -- Do saturation and convert to A-normal form - (prepd_binds, _) <- {-# SCC "CorePrep" #-} - corePrepPgm hsc_env this_mod location core_binds data_tycons - ----------------- Generate byte code ------------------ - comp_bc <- byteCodeGen hsc_env this_mod prepd_binds data_tycons mod_breaks - ------------------ Create f-x-dynamic C-side stuff ----- - (_istub_h_exists, istub_c_exists) - <- outputForeignStubs dflags this_mod location foreign_stubs - return (istub_c_exists, comp_bc, spt_entries) - ------------------------------- - -hscCompileCmmFile :: HscEnv -> FilePath -> FilePath -> IO () -hscCompileCmmFile hsc_env filename output_filename = runHsc hsc_env $ do - let dflags = hsc_dflags hsc_env - cmm <- ioMsgMaybe $ parseCmmFile dflags filename - liftIO $ do - dumpIfSet_dyn dflags Opt_D_dump_cmm_verbose_by_proc "Parsed Cmm" FormatCMM (ppr cmm) - let -- Make up a module name to give the NCG. We can't pass bottom here - -- lest we reproduce #11784. - mod_name = mkModuleName $ "Cmm$" ++ FilePath.takeFileName filename - cmm_mod = mkModule (thisPackage dflags) mod_name - - -- Compile decls in Cmm files one decl at a time, to avoid re-ordering - -- them in SRT analysis. - -- - -- Re-ordering here causes breakage when booting with C backend because - -- in C we must declare before use, but SRT algorithm is free to - -- re-order [A, B] (B refers to A) when A is not CAFFY and return [B, A] - cmmgroup <- - concatMapM (\cmm -> snd <$> cmmPipeline hsc_env (emptySRT cmm_mod) [cmm]) cmm - - unless (null cmmgroup) $ - dumpIfSet_dyn dflags Opt_D_dump_cmm "Output Cmm" - FormatCMM (ppr cmmgroup) - rawCmms <- lookupHook cmmToRawCmmHook - (\dflgs _ -> cmmToRawCmm dflgs) dflags dflags Nothing (Stream.yield cmmgroup) - _ <- codeOutput dflags cmm_mod output_filename no_loc NoStubs [] [] - rawCmms - return () - where - no_loc = ModLocation{ ml_hs_file = Just filename, - ml_hi_file = panic "hscCompileCmmFile: no hi file", - ml_obj_file = panic "hscCompileCmmFile: no obj file", - ml_hie_file = panic "hscCompileCmmFile: no hie file"} - --------------------- Stuff for new code gen --------------------- - -{- -Note [Forcing of stg_binds] -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The two last steps in the STG pipeline are: - -* Sorting the bindings in dependency order. -* Annotating them with free variables. - -We want to make sure we do not keep references to unannotated STG bindings -alive, nor references to bindings which have already been compiled to Cmm. - -We explicitly force the bindings to avoid this. - -This reduces residency towards the end of the CodeGen phase significantly -(5-10%). --} - -doCodeGen :: HscEnv -> Module -> [TyCon] - -> CollectedCCs - -> [StgTopBinding] - -> HpcInfo - -> IO (Stream IO CmmGroupSRTs NameSet) - -- Note we produce a 'Stream' of CmmGroups, so that the - -- backend can be run incrementally. Otherwise it generates all - -- the C-- up front, which has a significant space cost. -doCodeGen hsc_env this_mod data_tycons - cost_centre_info stg_binds hpc_info = do - let dflags = hsc_dflags hsc_env - - let stg_binds_w_fvs = annTopBindingsFreeVars stg_binds - - dumpIfSet_dyn dflags Opt_D_dump_stg_final "Final STG:" FormatSTG (pprGenStgTopBindings stg_binds_w_fvs) - - let cmm_stream :: Stream IO CmmGroup () - -- See Note [Forcing of stg_binds] - cmm_stream = stg_binds_w_fvs `seqList` {-# SCC "StgToCmm" #-} - lookupHook stgToCmmHook StgToCmm.codeGen dflags dflags this_mod data_tycons - cost_centre_info stg_binds_w_fvs hpc_info - - -- codegen consumes a stream of CmmGroup, and produces a new - -- stream of CmmGroup (not necessarily synchronised: one - -- CmmGroup on input may produce many CmmGroups on output due - -- to proc-point splitting). - - let dump1 a = do - unless (null a) $ - dumpIfSet_dyn dflags Opt_D_dump_cmm_from_stg - "Cmm produced by codegen" FormatCMM (ppr a) - return a - - ppr_stream1 = Stream.mapM dump1 cmm_stream - - pipeline_stream = - {-# SCC "cmmPipeline" #-} - Stream.mapAccumL (cmmPipeline hsc_env) (emptySRT this_mod) ppr_stream1 - <&> (srtMapNonCAFs . moduleSRTMap) - - dump2 a = do - unless (null a) $ - dumpIfSet_dyn dflags Opt_D_dump_cmm "Output Cmm" FormatCMM (ppr a) - return a - - return (Stream.mapM dump2 pipeline_stream) - -myCoreToStg :: DynFlags -> Module -> CoreProgram - -> IO ( [StgTopBinding] -- output program - , CollectedCCs ) -- CAF cost centre info (declared and used) -myCoreToStg dflags this_mod prepd_binds = do - let (stg_binds, cost_centre_info) - = {-# SCC "Core2Stg" #-} - coreToStg dflags this_mod prepd_binds - - stg_binds2 - <- {-# SCC "Stg2Stg" #-} - stg2stg dflags this_mod stg_binds - - return (stg_binds2, cost_centre_info) - - -{- ********************************************************************** -%* * -\subsection{Compiling a do-statement} -%* * -%********************************************************************* -} - -{- -When the UnlinkedBCOExpr is linked you get an HValue of type *IO [HValue]* When -you run it you get a list of HValues that should be the same length as the list -of names; add them to the ClosureEnv. - -A naked expression returns a singleton Name [it]. The stmt is lifted into the -IO monad as explained in Note [Interactively-bound Ids in GHCi] in HscTypes --} - --- | Compile a stmt all the way to an HValue, but don't run it --- --- We return Nothing to indicate an empty statement (or comment only), not a --- parse error. -hscStmt :: HscEnv -> String -> IO (Maybe ([Id], ForeignHValue, FixityEnv)) -hscStmt hsc_env stmt = hscStmtWithLocation hsc_env stmt "<interactive>" 1 - --- | Compile a stmt all the way to an HValue, but don't run it --- --- We return Nothing to indicate an empty statement (or comment only), not a --- parse error. -hscStmtWithLocation :: HscEnv - -> String -- ^ The statement - -> String -- ^ The source - -> Int -- ^ Starting line - -> IO ( Maybe ([Id] - , ForeignHValue {- IO [HValue] -} - , FixityEnv)) -hscStmtWithLocation hsc_env0 stmt source linenumber = - runInteractiveHsc hsc_env0 $ do - maybe_stmt <- hscParseStmtWithLocation source linenumber stmt - case maybe_stmt of - Nothing -> return Nothing - - Just parsed_stmt -> do - hsc_env <- getHscEnv - liftIO $ hscParsedStmt hsc_env parsed_stmt - -hscParsedStmt :: HscEnv - -> GhciLStmt GhcPs -- ^ The parsed statement - -> IO ( Maybe ([Id] - , ForeignHValue {- IO [HValue] -} - , FixityEnv)) -hscParsedStmt hsc_env stmt = runInteractiveHsc hsc_env $ do - -- Rename and typecheck it - (ids, tc_expr, fix_env) <- ioMsgMaybe $ tcRnStmt hsc_env stmt - - -- Desugar it - ds_expr <- ioMsgMaybe $ deSugarExpr hsc_env tc_expr - liftIO (lintInteractiveExpr "desugar expression" hsc_env ds_expr) - handleWarnings - - -- Then code-gen, and link it - -- It's important NOT to have package 'interactive' as thisUnitId - -- for linking, else we try to link 'main' and can't find it. - -- Whereas the linker already knows to ignore 'interactive' - let src_span = srcLocSpan interactiveSrcLoc - hval <- liftIO $ hscCompileCoreExpr hsc_env src_span ds_expr - - return $ Just (ids, hval, fix_env) - --- | Compile a decls -hscDecls :: HscEnv - -> String -- ^ The statement - -> IO ([TyThing], InteractiveContext) -hscDecls hsc_env str = hscDeclsWithLocation hsc_env str "<interactive>" 1 - -hscParseDeclsWithLocation :: HscEnv -> String -> Int -> String -> IO [LHsDecl GhcPs] -hscParseDeclsWithLocation hsc_env source line_num str = do - L _ (HsModule{ hsmodDecls = decls }) <- - runInteractiveHsc hsc_env $ - hscParseThingWithLocation source line_num parseModule str - return decls - --- | Compile a decls -hscDeclsWithLocation :: HscEnv - -> String -- ^ The statement - -> String -- ^ The source - -> Int -- ^ Starting line - -> IO ([TyThing], InteractiveContext) -hscDeclsWithLocation hsc_env str source linenumber = do - L _ (HsModule{ hsmodDecls = decls }) <- - runInteractiveHsc hsc_env $ - hscParseThingWithLocation source linenumber parseModule str - hscParsedDecls hsc_env decls - -hscParsedDecls :: HscEnv -> [LHsDecl GhcPs] -> IO ([TyThing], InteractiveContext) -hscParsedDecls hsc_env decls = runInteractiveHsc hsc_env $ do - {- Rename and typecheck it -} - hsc_env <- getHscEnv - tc_gblenv <- ioMsgMaybe $ tcRnDeclsi hsc_env decls - - {- Grab the new instances -} - -- We grab the whole environment because of the overlapping that may have - -- been done. See the notes at the definition of InteractiveContext - -- (ic_instances) for more details. - let defaults = tcg_default tc_gblenv - - {- Desugar it -} - -- We use a basically null location for iNTERACTIVE - let iNTERACTIVELoc = ModLocation{ ml_hs_file = Nothing, - ml_hi_file = panic "hsDeclsWithLocation:ml_hi_file", - ml_obj_file = panic "hsDeclsWithLocation:ml_obj_file", - ml_hie_file = panic "hsDeclsWithLocation:ml_hie_file" } - ds_result <- hscDesugar' iNTERACTIVELoc tc_gblenv - - {- Simplify -} - simpl_mg <- liftIO $ do - plugins <- readIORef (tcg_th_coreplugins tc_gblenv) - hscSimplify hsc_env plugins ds_result - - {- Tidy -} - (tidy_cg, mod_details) <- liftIO $ tidyProgram hsc_env simpl_mg - - let !CgGuts{ cg_module = this_mod, - cg_binds = core_binds, - cg_tycons = tycons, - cg_modBreaks = mod_breaks } = tidy_cg - - !ModDetails { md_insts = cls_insts - , md_fam_insts = fam_insts } = mod_details - -- Get the *tidied* cls_insts and fam_insts - - data_tycons = filter isDataTyCon tycons - - {- Prepare For Code Generation -} - -- Do saturation and convert to A-normal form - (prepd_binds, _) <- {-# SCC "CorePrep" #-} - liftIO $ corePrepPgm hsc_env this_mod iNTERACTIVELoc core_binds data_tycons - - {- Generate byte code -} - cbc <- liftIO $ byteCodeGen hsc_env this_mod - prepd_binds data_tycons mod_breaks - - let src_span = srcLocSpan interactiveSrcLoc - liftIO $ linkDecls hsc_env src_span cbc - - {- Load static pointer table entries -} - liftIO $ hscAddSptEntries hsc_env (cg_spt_entries tidy_cg) - - let tcs = filterOut isImplicitTyCon (mg_tcs simpl_mg) - patsyns = mg_patsyns simpl_mg - - ext_ids = [ id | id <- bindersOfBinds core_binds - , isExternalName (idName id) - , not (isDFunId id || isImplicitId id) ] - -- We only need to keep around the external bindings - -- (as decided by GHC.Iface.Tidy), since those are the only ones - -- that might later be looked up by name. But we can exclude - -- - DFunIds, which are in 'cls_insts' (see Note [ic_tythings] in HscTypes - -- - Implicit Ids, which are implicit in tcs - -- c.f. TcRnDriver.runTcInteractive, which reconstructs the TypeEnv - - new_tythings = map AnId ext_ids ++ map ATyCon tcs ++ map (AConLike . PatSynCon) patsyns - ictxt = hsc_IC hsc_env - -- See Note [Fixity declarations in GHCi] - fix_env = tcg_fix_env tc_gblenv - new_ictxt = extendInteractiveContext ictxt new_tythings cls_insts - fam_insts defaults fix_env - return (new_tythings, new_ictxt) - --- | Load the given static-pointer table entries into the interpreter. --- See Note [Grand plan for static forms] in StaticPtrTable. -hscAddSptEntries :: HscEnv -> [SptEntry] -> IO () -hscAddSptEntries hsc_env entries = do - let add_spt_entry :: SptEntry -> IO () - add_spt_entry (SptEntry i fpr) = do - val <- getHValue hsc_env (idName i) - addSptEntry hsc_env fpr val - mapM_ add_spt_entry entries - -{- - Note [Fixity declarations in GHCi] - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - To support fixity declarations on types defined within GHCi (as requested - in #10018) we record the fixity environment in InteractiveContext. - When we want to evaluate something TcRnDriver.runTcInteractive pulls out this - fixity environment and uses it to initialize the global typechecker environment. - After the typechecker has finished its business, an updated fixity environment - (reflecting whatever fixity declarations were present in the statements we - passed it) will be returned from hscParsedStmt. This is passed to - updateFixityEnv, which will stuff it back into InteractiveContext, to be - used in evaluating the next statement. - --} - -hscImport :: HscEnv -> String -> IO (ImportDecl GhcPs) -hscImport hsc_env str = runInteractiveHsc hsc_env $ do - (L _ (HsModule{hsmodImports=is})) <- - hscParseThing parseModule str - case is of - [L _ i] -> return i - _ -> liftIO $ throwOneError $ - mkPlainErrMsg (hsc_dflags hsc_env) noSrcSpan $ - text "parse error in import declaration" - --- | Typecheck an expression (but don't run it) -hscTcExpr :: HscEnv - -> TcRnExprMode - -> String -- ^ The expression - -> IO Type -hscTcExpr hsc_env0 mode expr = runInteractiveHsc hsc_env0 $ do - hsc_env <- getHscEnv - parsed_expr <- hscParseExpr expr - ioMsgMaybe $ tcRnExpr hsc_env mode parsed_expr - --- | Find the kind of a type, after generalisation -hscKcType - :: HscEnv - -> Bool -- ^ Normalise the type - -> String -- ^ The type as a string - -> IO (Type, Kind) -- ^ Resulting type (possibly normalised) and kind -hscKcType hsc_env0 normalise str = runInteractiveHsc hsc_env0 $ do - hsc_env <- getHscEnv - ty <- hscParseType str - ioMsgMaybe $ tcRnType hsc_env DefaultFlexi normalise ty - -hscParseExpr :: String -> Hsc (LHsExpr GhcPs) -hscParseExpr expr = do - hsc_env <- getHscEnv - maybe_stmt <- hscParseStmt expr - case maybe_stmt of - Just (L _ (BodyStmt _ expr _ _)) -> return expr - _ -> throwOneError $ mkPlainErrMsg (hsc_dflags hsc_env) noSrcSpan - (text "not an expression:" <+> quotes (text expr)) - -hscParseStmt :: String -> Hsc (Maybe (GhciLStmt GhcPs)) -hscParseStmt = hscParseThing parseStmt - -hscParseStmtWithLocation :: String -> Int -> String - -> Hsc (Maybe (GhciLStmt GhcPs)) -hscParseStmtWithLocation source linenumber stmt = - hscParseThingWithLocation source linenumber parseStmt stmt - -hscParseType :: String -> Hsc (LHsType GhcPs) -hscParseType = hscParseThing parseType - -hscParseIdentifier :: HscEnv -> String -> IO (Located RdrName) -hscParseIdentifier hsc_env str = - runInteractiveHsc hsc_env $ hscParseThing parseIdentifier str - -hscParseThing :: (Outputable thing, Data thing) - => Lexer.P thing -> String -> Hsc thing -hscParseThing = hscParseThingWithLocation "<interactive>" 1 - -hscParseThingWithLocation :: (Outputable thing, Data thing) => String -> Int - -> Lexer.P thing -> String -> Hsc thing -hscParseThingWithLocation source linenumber parser str - = withTimingD - (text "Parser [source]") - (const ()) $ {-# SCC "Parser" #-} do - dflags <- getDynFlags - - let buf = stringToStringBuffer str - loc = mkRealSrcLoc (fsLit source) linenumber 1 - - case unP parser (mkPState dflags buf loc) of - PFailed pst -> do - handleWarningsThrowErrors (getMessages pst dflags) - - POk pst thing -> do - logWarningsReportErrors (getMessages pst dflags) - liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" - FormatHaskell (ppr thing) - liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST" - FormatHaskell (showAstData NoBlankSrcSpan thing) - return thing - - -{- ********************************************************************** -%* * - Desugar, simplify, convert to bytecode, and link an expression -%* * -%********************************************************************* -} - -hscCompileCoreExpr :: HscEnv -> SrcSpan -> CoreExpr -> IO ForeignHValue -hscCompileCoreExpr hsc_env = - lookupHook hscCompileCoreExprHook hscCompileCoreExpr' (hsc_dflags hsc_env) hsc_env - -hscCompileCoreExpr' :: HscEnv -> SrcSpan -> CoreExpr -> IO ForeignHValue -hscCompileCoreExpr' hsc_env srcspan ds_expr - = do { let dflags = hsc_dflags hsc_env - - {- Simplify it -} - ; simpl_expr <- simplifyExpr hsc_env ds_expr - - {- Tidy it (temporary, until coreSat does cloning) -} - ; let tidy_expr = tidyExpr emptyTidyEnv simpl_expr - - {- Prepare for codegen -} - ; prepd_expr <- corePrepExpr dflags hsc_env tidy_expr - - {- Lint if necessary -} - ; lintInteractiveExpr "hscCompileExpr" hsc_env prepd_expr - - {- Convert to BCOs -} - ; bcos <- coreExprToBCOs hsc_env - (icInteractiveModule (hsc_IC hsc_env)) prepd_expr - - {- link it -} - ; hval <- linkExpr hsc_env srcspan bcos - - ; return hval } - - -{- ********************************************************************** -%* * - Statistics on reading interfaces -%* * -%********************************************************************* -} - -dumpIfaceStats :: HscEnv -> IO () -dumpIfaceStats hsc_env = do - eps <- readIORef (hsc_EPS hsc_env) - dumpIfSet dflags (dump_if_trace || dump_rn_stats) - "Interface statistics" - (ifaceStats eps) - where - dflags = hsc_dflags hsc_env - dump_rn_stats = dopt Opt_D_dump_rn_stats dflags - dump_if_trace = dopt Opt_D_dump_if_trace dflags - - -{- ********************************************************************** -%* * - Progress Messages: Module i of n -%* * -%********************************************************************* -} - -showModuleIndex :: (Int, Int) -> String -showModuleIndex (i,n) = "[" ++ padded ++ " of " ++ n_str ++ "] " - where - n_str = show n - i_str = show i - padded = replicate (length n_str - length i_str) ' ' ++ i_str |