Clean up hie-core (#1992)

* Split off addRelativeImport from modifying the session

* Switch located imports to adding their own relative imports

* Delete the unused getGhcDynFlags

* Make runGhcEnv no longer need to consult import paths

* Call runGhcEnv directly

* Move getSrcSpanInfos out to Spans

* Remove a redundant import

* Make findImports in Either rather than ExceptT

* Move getImports over to the right place

* Switch to liftEither
This commit is contained in:
Neil Mitchell 2019-07-03 16:38:57 +01:00 committed by mergify[bot]
parent a2ba883092
commit 4dc9cd0020
4 changed files with 63 additions and 83 deletions

View File

@ -9,24 +9,21 @@
-- Given a list of paths to find libraries, and a file to compile, produce a list of 'CoreModule' values. -- Given a list of paths to find libraries, and a file to compile, produce a list of 'CoreModule' values.
module Development.IDE.Core.Compile module Development.IDE.Core.Compile
( TcModuleResult(..) ( TcModuleResult(..)
, getGhcDynFlags
, compileModule , compileModule
, getSrcSpanInfos
, parseModule , parseModule
, parseFileContents
, typecheckModule , typecheckModule
, computePackageDeps , computePackageDeps
, addRelativeImport
) where ) where
import Development.IDE.GHC.Warnings import Development.IDE.GHC.Warnings
import Development.IDE.GHC.CPP import Development.IDE.GHC.CPP
import Development.IDE.Types.Diagnostics import Development.IDE.Types.Diagnostics
import qualified Development.IDE.Import.FindImports as FindImports
import Development.IDE.GHC.Error import Development.IDE.GHC.Error
import Development.IDE.Spans.Calculate
import Development.IDE.GHC.Orphans() import Development.IDE.GHC.Orphans()
import Development.IDE.GHC.Util import Development.IDE.GHC.Util
import Development.IDE.GHC.Compat import Development.IDE.GHC.Compat
import qualified GHC.LanguageExtensions.Type as GHC
import Development.IDE.Types.Options import Development.IDE.Types.Options
import Development.IDE.Types.Location import Development.IDE.Types.Location
@ -47,6 +44,7 @@ import qualified GHC.LanguageExtensions as LangExt
import Control.DeepSeq import Control.DeepSeq
import Control.Monad.Extra import Control.Monad.Extra
import Control.Monad.Except
import Control.Monad.Trans.Except import Control.Monad.Trans.Except
import qualified Data.Text as T import qualified Data.Text as T
import Data.IORef import Data.IORef
@ -54,7 +52,6 @@ import Data.List.Extra
import Data.Maybe import Data.Maybe
import Data.Tuple.Extra import Data.Tuple.Extra
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import Development.IDE.Spans.Type
import System.FilePath import System.FilePath
import System.Directory import System.Directory
import System.IO.Extra import System.IO.Extra
@ -74,19 +71,6 @@ instance NFData TcModuleResult where
rnf = rwhnf rnf = rwhnf
-- | Get source span info, used for e.g. AtPoint and Goto Definition.
getSrcSpanInfos
:: ParsedModule
-> HscEnv
-> [(Located ModuleName, Maybe NormalizedFilePath)]
-> TcModuleResult
-> IO [SpanInfo]
getSrcSpanInfos mod env imports tc =
runGhcSession (Just mod) env
. getSpanInfo imports
$ tmrModule tc
-- | Given a string buffer, return a pre-processed @ParsedModule@. -- | Given a string buffer, return a pre-processed @ParsedModule@.
parseModule parseModule
:: IdeOptions :: IdeOptions
@ -97,7 +81,7 @@ parseModule
parseModule IdeOptions{..} env file = parseModule IdeOptions{..} env file =
fmap (either (, Nothing) (second Just)) . fmap (either (, Nothing) (second Just)) .
-- We need packages since imports fail to resolve otherwise. -- We need packages since imports fail to resolve otherwise.
runGhcSession Nothing env . runExceptT . parseFileContents optPreprocessor file runGhcEnv env . runExceptT . parseFileContents optPreprocessor file
-- | Given a package identifier, what packages does it depend on -- | Given a package identifier, what packages does it depend on
@ -122,7 +106,7 @@ typecheckModule
-> IO ([FileDiagnostic], Maybe TcModuleResult) -> IO ([FileDiagnostic], Maybe TcModuleResult)
typecheckModule opt packageState deps pm = typecheckModule opt packageState deps pm =
fmap (either (, Nothing) (second Just)) $ fmap (either (, Nothing) (second Just)) $
runGhcSession (Just pm) packageState $ runGhcEnv packageState $
catchSrcErrors $ do catchSrcErrors $ do
setupEnv deps setupEnv deps
(warnings, tcm) <- withWarnings $ \tweak -> (warnings, tcm) <- withWarnings $ \tweak ->
@ -133,14 +117,13 @@ typecheckModule opt packageState deps pm =
-- | Compile a single type-checked module to a 'CoreModule' value, or -- | Compile a single type-checked module to a 'CoreModule' value, or
-- provide errors. -- provide errors.
compileModule compileModule
:: ParsedModule :: HscEnv
-> HscEnv
-> [TcModuleResult] -> [TcModuleResult]
-> TcModuleResult -> TcModuleResult
-> IO ([FileDiagnostic], Maybe CoreModule) -> IO ([FileDiagnostic], Maybe CoreModule)
compileModule mod packageState deps tmr = compileModule packageState deps tmr =
fmap (either (, Nothing) (second Just)) $ fmap (either (, Nothing) (second Just)) $
runGhcSession (Just mod) packageState $ runGhcEnv packageState $
catchSrcErrors $ do catchSrcErrors $ do
setupEnv (deps ++ [tmr]) setupEnv (deps ++ [tmr])
@ -164,21 +147,9 @@ compileModule mod packageState deps tmr =
return (warnings, core) return (warnings, core)
getGhcDynFlags :: ParsedModule -> HscEnv -> IO DynFlags addRelativeImport :: ParsedModule -> DynFlags -> DynFlags
getGhcDynFlags mod pkg = runGhcSession (Just mod) pkg getSessionDynFlags addRelativeImport modu dflags = dflags
{importPaths = nubOrd $ maybeToList (moduleImportPaths modu) ++ importPaths dflags}
-- | Evaluate a GHC session using a new environment constructed with
-- the supplied options.
runGhcSession
:: Maybe ParsedModule
-> HscEnv
-> Ghc a
-> IO a
runGhcSession modu env act = runGhcEnv env $ do
modifyDynFlags $ \x -> x
{importPaths = nubOrd $ maybeToList (moduleImportPaths =<< modu) ++ importPaths x}
act
moduleImportPaths :: GHC.ParsedModule -> Maybe FilePath moduleImportPaths :: GHC.ParsedModule -> Maybe FilePath
moduleImportPaths pm moduleImportPaths pm
@ -258,6 +229,35 @@ loadModuleHome tmr = modifySession $ \e ->
mod_info = tmrModInfo tmr mod_info = tmrModInfo tmr
mod = ms_mod_name ms mod = ms_mod_name ms
-- | GhcMonad function to chase imports of a module given as a StringBuffer. Returns given module's
-- name and its imports.
getImportsParsed :: DynFlags ->
GHC.ParsedSource ->
Either [FileDiagnostic] (GHC.ModuleName, [(Maybe FastString, Located GHC.ModuleName)])
getImportsParsed dflags (L loc parsed) = do
let modName = maybe (GHC.mkModuleName "Main") GHC.unLoc $ GHC.hsmodName parsed
-- refuse source imports
let srcImports = filter (ideclSource . GHC.unLoc) $ GHC.hsmodImports parsed
when (not $ null srcImports) $ Left $
concat
[ diagFromString mloc ("Illegal source import of " <> GHC.moduleNameString (GHC.unLoc $ GHC.ideclName i))
| L mloc i <- srcImports ]
-- most of these corner cases are also present in https://hackage.haskell.org/package/ghc-8.6.1/docs/src/HeaderInfo.html#getImports
-- but we want to avoid parsing the module twice
let implicit_prelude = xopt GHC.ImplicitPrelude dflags
implicit_imports = Hdr.mkPrelImports modName loc implicit_prelude $ GHC.hsmodImports parsed
-- filter out imports that come from packages
return (modName, [(fmap sl_fs $ ideclPkgQual i, ideclName i)
| i <- map GHC.unLoc $ implicit_imports ++ GHC.hsmodImports parsed
, GHC.moduleNameString (GHC.unLoc $ ideclName i) /= "GHC.Prim"
])
-- | Produce a module summary from a StringBuffer. -- | Produce a module summary from a StringBuffer.
getModSummaryFromBuffer getModSummaryFromBuffer
:: GhcMonad m :: GhcMonad m
@ -267,7 +267,7 @@ getModSummaryFromBuffer
-> GHC.ParsedSource -> GHC.ParsedSource
-> ExceptT [FileDiagnostic] m ModSummary -> ExceptT [FileDiagnostic] m ModSummary
getModSummaryFromBuffer fp contents dflags parsed = do getModSummaryFromBuffer fp contents dflags parsed = do
(modName, imports) <- FindImports.getImportsParsed dflags parsed (modName, imports) <- liftEither $ getImportsParsed dflags parsed
let modLoc = ModLocation let modLoc = ModLocation
{ ml_hs_file = Just fp { ml_hs_file = Just fp

View File

@ -30,6 +30,7 @@ import Control.Monad.Except
import Control.Monad.Trans.Maybe import Control.Monad.Trans.Maybe
import qualified Development.IDE.Core.Compile as Compile import qualified Development.IDE.Core.Compile as Compile
import qualified Development.IDE.Types.Options as Compile import qualified Development.IDE.Types.Options as Compile
import qualified Development.IDE.Spans.Calculate as Compile
import Development.IDE.Import.DependencyInformation import Development.IDE.Import.DependencyInformation
import Development.IDE.Import.FindImports import Development.IDE.Import.FindImports
import Development.IDE.Core.FileStore import Development.IDE.Core.FileStore
@ -50,6 +51,7 @@ import GHC
import Development.IDE.GHC.Compat import Development.IDE.GHC.Compat
import UniqSupply import UniqSupply
import NameCache import NameCache
import HscTypes
import qualified Development.IDE.Spans.AtPoint as AtPoint import qualified Development.IDE.Spans.AtPoint as AtPoint
import Development.IDE.Core.Service import Development.IDE.Core.Service
@ -143,8 +145,8 @@ getLocatedImportsRule =
pm <- use_ GetParsedModule file pm <- use_ GetParsedModule file
let ms = pm_mod_summary pm let ms = pm_mod_summary pm
let imports = ms_textual_imps ms let imports = ms_textual_imps ms
packageState <- use_ GhcSession "" env <- use_ GhcSession ""
dflags <- liftIO $ Compile.getGhcDynFlags pm packageState let dflags = Compile.addRelativeImport pm $ hsc_dflags env
opt <- getIdeOptions opt <- getIdeOptions
xs <- forM imports $ \(mbPkgName, modName) -> xs <- forM imports $ \(mbPkgName, modName) ->
(modName, ) <$> locateModule dflags (Compile.optExtensions opt) getFileExists modName mbPkgName (modName, ) <$> locateModule dflags (Compile.optExtensions opt) getFileExists modName mbPkgName
@ -229,11 +231,10 @@ getDependenciesRule =
getSpanInfoRule :: Rules () getSpanInfoRule :: Rules ()
getSpanInfoRule = getSpanInfoRule =
define $ \GetSpanInfo file -> do define $ \GetSpanInfo file -> do
pm <- use_ GetParsedModule file
tc <- use_ TypeCheck file tc <- use_ TypeCheck file
imports <- use_ GetLocatedImports file imports <- use_ GetLocatedImports file
packageState <- use_ GhcSession "" packageState <- use_ GhcSession ""
x <- liftIO $ Compile.getSrcSpanInfos pm packageState (fileImports imports) tc x <- liftIO $ Compile.getSrcSpanInfos packageState (fileImports imports) tc
return ([], Just x) return ([], Just x)
-- Typechecks a module. -- Typechecks a module.
@ -254,10 +255,9 @@ generateCoreRule =
define $ \GenerateCore file -> do define $ \GenerateCore file -> do
deps <- use_ GetDependencies file deps <- use_ GetDependencies file
(tm:tms) <- uses_ TypeCheck (file:transitiveModuleDeps deps) (tm:tms) <- uses_ TypeCheck (file:transitiveModuleDeps deps)
let pm = tm_parsed_module . Compile.tmrModule $ tm
setPriority priorityGenerateCore setPriority priorityGenerateCore
packageState <- use_ GhcSession "" packageState <- use_ GhcSession ""
liftIO $ Compile.compileModule pm packageState tms tm liftIO $ Compile.compileModule packageState tms tm
loadGhcSession :: Rules () loadGhcSession :: Rules ()
loadGhcSession = loadGhcSession =

View File

@ -4,8 +4,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module Development.IDE.Import.FindImports module Development.IDE.Import.FindImports
( getImportsParsed ( locateModule
, locateModule
, Import(..) , Import(..)
) where ) where
@ -14,13 +13,10 @@ import Development.IDE.GHC.Orphans()
import Development.IDE.Types.Diagnostics import Development.IDE.Types.Diagnostics
import Development.IDE.Types.Location import Development.IDE.Types.Location
-- GHC imports -- GHC imports
import BasicTypes (StringLiteral(..))
import DynFlags import DynFlags
import FastString import FastString
import GHC import GHC
import qualified HeaderInfo as Hdr
import qualified Module as M import qualified Module as M
import qualified GHC.LanguageExtensions.Type as GHC
import Packages import Packages
import Outputable (showSDoc, ppr, pprPanic) import Outputable (showSDoc, ppr, pprPanic)
import Finder import Finder
@ -29,7 +25,6 @@ import Control.DeepSeq
-- standard imports -- standard imports
import Control.Monad.Extra import Control.Monad.Extra
import Control.Monad.IO.Class import Control.Monad.IO.Class
import qualified Control.Monad.Trans.Except as Ex
import System.FilePath import System.FilePath
data Import data Import
@ -42,35 +37,6 @@ instance NFData Import where
rnf (PackageImport x) = rnf x rnf (PackageImport x) = rnf x
-- | GhcMonad function to chase imports of a module given as a StringBuffer. Returns given module's
-- name and its imports.
getImportsParsed :: Monad m =>
DynFlags ->
GHC.ParsedSource ->
Ex.ExceptT [FileDiagnostic] m
(M.ModuleName, [(Maybe FastString, Located M.ModuleName)])
getImportsParsed dflags (L loc parsed) = do
let modName = maybe (GHC.mkModuleName "Main") GHC.unLoc $ GHC.hsmodName parsed
-- refuse source imports
let srcImports = filter (ideclSource . GHC.unLoc) $ GHC.hsmodImports parsed
when (not $ null srcImports) $ Ex.throwE $
concat
[ diagFromString mloc ("Illegal source import of " <> GHC.moduleNameString (GHC.unLoc $ GHC.ideclName i))
| L mloc i <- srcImports ]
-- most of these corner cases are also present in https://hackage.haskell.org/package/ghc-8.6.1/docs/src/HeaderInfo.html#getImports
-- but we want to avoid parsing the module twice
let implicit_prelude = xopt GHC.ImplicitPrelude dflags
implicit_imports = Hdr.mkPrelImports modName loc implicit_prelude $ GHC.hsmodImports parsed
-- filter out imports that come from packages
return (modName, [(fmap sl_fs $ ideclPkgQual i, ideclName i)
| i <- map GHC.unLoc $ implicit_imports ++ GHC.hsmodImports parsed
, GHC.moduleNameString (GHC.unLoc $ ideclName i) /= "GHC.Prim"
])
-- | locate a module in the file system. Where we go from *daml to Haskell -- | locate a module in the file system. Where we go from *daml to Haskell
locateModuleFile :: MonadIO m locateModuleFile :: MonadIO m
=> DynFlags => DynFlags

View File

@ -7,7 +7,7 @@
-- | Get information on modules, identifiers, etc. -- | Get information on modules, identifiers, etc.
module Development.IDE.Spans.Calculate(getSpanInfo,listifyAllSpans) where module Development.IDE.Spans.Calculate(getSrcSpanInfos,listifyAllSpans) where
import ConLike import ConLike
import Control.Monad import Control.Monad
@ -27,6 +27,20 @@ import Development.IDE.GHC.Error (zeroSpan)
import Prelude hiding (mod) import Prelude hiding (mod)
import TcHsSyn import TcHsSyn
import Var import Var
import Development.IDE.Core.Compile
import Development.IDE.GHC.Util
-- | Get source span info, used for e.g. AtPoint and Goto Definition.
getSrcSpanInfos
:: HscEnv
-> [(Located ModuleName, Maybe NormalizedFilePath)]
-> TcModuleResult
-> IO [SpanInfo]
getSrcSpanInfos env imports tc =
runGhcEnv env
. getSpanInfo imports
$ tmrModule tc
-- | Get ALL source spans in the module. -- | Get ALL source spans in the module.
getSpanInfo :: GhcMonad m getSpanInfo :: GhcMonad m