@@ -99,7 +99,7 @@ import Data.Tuple.Extra
9999import Development.IDE.Core.Compile
100100import Development.IDE.Core.FileExists hiding (LogShake , Log )
101101import Development.IDE.Core.FileStore (getFileContents ,
102- resetInterfaceStore )
102+ getModTime )
103103import Development.IDE.Core.IdeConfiguration
104104import Development.IDE.Core.OfInterest hiding (LogShake , Log )
105105import Development.IDE.Core.PositionMapping
@@ -135,7 +135,7 @@ import Ide.Plugin.Config
135135import qualified Language.LSP.Server as LSP
136136import Language.LSP.Types (SMethod (SCustomMethod , SWindowShowMessage ), ShowMessageParams (ShowMessageParams ), MessageType (MtInfo ))
137137import Language.LSP.VFS
138- import System.Directory (makeAbsolute )
138+ import System.Directory (makeAbsolute , doesFileExist )
139139import Data.Default (def , Default )
140140import Ide.Plugin.Properties (HasProperty ,
141141 KeyNameProxy ,
@@ -154,6 +154,9 @@ import qualified Development.IDE.Core.Shake as Shake
154154import qualified Development.IDE.GHC.ExactPrint as ExactPrint hiding (LogShake )
155155import qualified Development.IDE.Types.Logger as Logger
156156import qualified Development.IDE.Types.Shake as Shake
157+ import Development.IDE.GHC.CoreFile
158+ import Data.Time.Clock.POSIX (posixSecondsToUTCTime , utcTimeToPOSIXSeconds )
159+ import Control.Monad.IO.Unlift
157160
158161data Log
159162 = LogShake Shake. Log
@@ -673,9 +676,13 @@ typeCheckRuleDefinition hsc pm = do
673676 setPriority priorityTypeCheck
674677 IdeOptions { optDefer = defer } <- getIdeOptions
675678
676- linkables_to_keep <- currentLinkables
679+ unlift <- askUnliftIO
680+ let dets = TypecheckHelpers
681+ { getLinkablesToKeep = unliftIO unlift $ currentLinkables
682+ , getLinkables = unliftIO unlift . uses_ GetLinkable
683+ }
677684 addUsageDependencies $ liftIO $
678- typecheckModule defer hsc linkables_to_keep pm
685+ typecheckModule defer hsc dets pm
679686 where
680687 addUsageDependencies :: Action (a , Maybe TcModuleResult ) -> Action (a , Maybe TcModuleResult )
681688 addUsageDependencies a = do
@@ -752,7 +759,7 @@ ghcSessionDepsDefinition fullModSummary GhcSessionDepsConfig{..} env file = do
752759 depSessions <- map hscEnv <$> uses_ (GhcSessionDeps_ fullModSummary) deps
753760 ifaces <- uses_ GetModIface deps
754761
755- let inLoadOrder = map hirHomeMod ifaces
762+ let inLoadOrder = map ( \ HiFileResult { .. } -> HomeModInfo hirModIface hirModDetails Nothing ) ifaces
756763 session' <- liftIO $ mergeEnvs hsc mss inLoadOrder depSessions
757764
758765 Just <$> liftIO (newHscEnvEqWithImportPaths (envImportPaths env) session' [] )
@@ -768,7 +775,7 @@ getModIfaceFromDiskRule recorder = defineEarlyCutoff (cmapWithPrio LogShake reco
768775 Just session -> do
769776 linkableType <- getLinkableType f
770777 ver <- use_ GetModificationTime f
771- se @ ShakeExtras {ideNc} <- getShakeExtras
778+ ShakeExtras {ideNc} <- getShakeExtras
772779 let m_old = case old of
773780 Shake. Succeeded (Just old_version) v -> Just (v, old_version)
774781 Shake. Stale _ (Just old_version) v -> Just (v, old_version)
@@ -777,9 +784,10 @@ getModIfaceFromDiskRule recorder = defineEarlyCutoff (cmapWithPrio LogShake reco
777784 { source_version = ver
778785 , old_value = m_old
779786 , get_file_version = use GetModificationTime_ {missingFileDiagnostics = False }
787+ , get_linkable_hashes = \ fs -> map linkableHash <$> uses_ GetLinkable fs
780788 , regenerate = regenerateHiFile session f ms
781789 }
782- r <- loadInterface se (hscEnv session) ms linkableType recompInfo
790+ r <- loadInterface (hscEnv session) ms linkableType recompInfo
783791 case r of
784792 (diags, Nothing ) -> return (Nothing , (diags, Nothing ))
785793 (diags, Just x) -> do
@@ -899,7 +907,7 @@ getModIfaceRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $
899907 hsc <- hscEnv <$> use_ GhcSessionDeps f
900908 let compile = fmap ([] ,) $ use GenerateCore f
901909 se <- getShakeExtras
902- (diags, ! hiFile) <- compileToObjCodeIfNeeded se hsc linkableType compile tmr
910+ (diags, ! hiFile) <- writeCoreFileIfNeeded se hsc linkableType compile tmr
903911 let fp = hiFileFingerPrint <$> hiFile
904912 hiDiags <- case hiFile of
905913 Just hiFile
@@ -912,10 +920,6 @@ getModIfaceRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $
912920 let fp = hiFileFingerPrint <$> hiFile
913921 return (fp, ([] , hiFile))
914922
915- -- Record the linkable so we know not to unload it
916- whenJust (hm_linkable . hirHomeMod =<< mhmi) $ \ (LM time mod _) -> do
917- compiledLinkables <- getCompiledLinkables <$> getIdeGlobalAction
918- liftIO $ void $ modifyVar' compiledLinkables $ \ old -> extendModuleEnv old mod time
919923 pure res
920924
921925-- | Count of total times we asked GHC to recompile
@@ -960,13 +964,12 @@ regenerateHiFile sess f ms compNeeded = do
960964 Nothing -> pure (diags', Nothing )
961965 Just tmr -> do
962966
963- -- compile writes .o file
964967 let compile = liftIO $ compileModule (RunSimplifier True ) hsc (pm_mod_summary pm) $ tmrTypechecked tmr
965968
966969 se <- getShakeExtras
967970
968971 -- Bang pattern is important to avoid leaking 'tmr'
969- (diags'', ! res) <- compileToObjCodeIfNeeded se hsc compNeeded compile tmr
972+ (diags'', ! res) <- writeCoreFileIfNeeded se hsc compNeeded compile tmr
970973
971974 -- Write hi file
972975 hiDiags <- case res of
@@ -994,18 +997,20 @@ regenerateHiFile sess f ms compNeeded = do
994997
995998
996999-- | HscEnv should have deps included already
997- compileToObjCodeIfNeeded :: ShakeExtras -> HscEnv -> Maybe LinkableType -> Action (IdeResult ModGuts ) -> TcModuleResult -> Action (IdeResult HiFileResult )
998- compileToObjCodeIfNeeded _ hsc Nothing _ tmr = do
1000+ -- This writes the core file if a linkable is required
1001+ -- The actual linkable will be generated on demand when required by `GetLinkable`
1002+ writeCoreFileIfNeeded :: ShakeExtras -> HscEnv -> Maybe LinkableType -> Action (IdeResult ModGuts ) -> TcModuleResult -> Action (IdeResult HiFileResult )
1003+ writeCoreFileIfNeeded _ hsc Nothing _ tmr = do
9991004 incrementRebuildCount
10001005 res <- liftIO $ mkHiFileResultNoCompile hsc tmr
10011006 pure ([] , Just $! res)
1002- compileToObjCodeIfNeeded se hsc (Just linkableType ) getGuts tmr = do
1007+ writeCoreFileIfNeeded se hsc (Just _ ) getGuts tmr = do
10031008 incrementRebuildCount
10041009 (diags, mguts) <- getGuts
10051010 case mguts of
10061011 Nothing -> pure (diags, Nothing )
10071012 Just guts -> do
1008- (diags', ! res) <- liftIO $ mkHiFileResultCompile se hsc tmr guts linkableType
1013+ (diags', ! res) <- liftIO $ mkHiFileResultCompile se hsc tmr guts
10091014 pure (diags++ diags', res)
10101015
10111016getClientSettingsRule :: Recorder (WithPriority Log ) -> Rules ()
@@ -1037,6 +1042,48 @@ usePropertyAction kn plId p = do
10371042
10381043-- ---------------------------------------------------------------------
10391044
1045+ getLinkableRule :: Recorder (WithPriority Log ) -> Rules ()
1046+ getLinkableRule recorder =
1047+ defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \ GetLinkable f -> do
1048+ ModSummaryResult {msrModSummary = ms} <- use_ GetModSummary f
1049+ HiFileResult {hirModIface, hirModDetails, hirCoreFp} <- use_ GetModIface f
1050+ let obj_file = ml_obj_file (ms_location ms)
1051+ core_file = ml_core_file (ms_location ms)
1052+ -- Can't use `GetModificationTime` rule because the core file was possibly written in this
1053+ -- very session, so the results aren't reliable
1054+ core_t <- liftIO $ getModTime core_file
1055+ case hirCoreFp of
1056+ Nothing -> error " called GetLinkable for a file without a linkable"
1057+ Just (bin_core, hash) -> do
1058+ session <- use_ GhcSessionDeps f
1059+ ShakeExtras {ideNc} <- getShakeExtras
1060+ let namecache_updater = mkUpdater ideNc
1061+ linkableType <- getLinkableType f >>= \ case
1062+ Nothing -> error " called GetLinkable for a file which doesn't need compilation"
1063+ Just t -> pure t
1064+ (warns, hmi) <- case linkableType of
1065+ -- Bytecode needs to be regenerated from the core file
1066+ BCOLinkable -> liftIO $ coreFileToLinkable linkableType (hscEnv session) ms hirModIface hirModDetails bin_core (posixSecondsToUTCTime core_t)
1067+ -- Object code can be read from the disk
1068+ ObjectLinkable -> do
1069+ -- object file is up to date if it is newer than the core file
1070+ -- Can't use a rule like 'GetModificationTime' or 'GetFileExists' because 'coreFileToLinkable' will write the object file, and
1071+ -- thus bump its modification time, forcing this rule to be rerun every time.
1072+ exists <- liftIO $ doesFileExist obj_file
1073+ mobj_time <- liftIO $
1074+ if exists
1075+ then Just <$> getModTime obj_file
1076+ else pure Nothing
1077+ case mobj_time of
1078+ Just obj_t
1079+ | obj_t >= core_t -> pure ([] , Just $ HomeModInfo hirModIface hirModDetails (Just $ LM (posixSecondsToUTCTime obj_t) (ms_mod ms) [DotO obj_file]))
1080+ _ -> liftIO $ coreFileToLinkable linkableType (hscEnv session) ms hirModIface hirModDetails bin_core (error " object doesn't have time" )
1081+ -- Record the linkable so we know not to unload it
1082+ whenJust (hm_linkable =<< hmi) $ \ (LM time mod _) -> do
1083+ compiledLinkables <- getCompiledLinkables <$> getIdeGlobalAction
1084+ liftIO $ void $ modifyVar' compiledLinkables $ \ old -> extendModuleEnv old mod time
1085+ return (hash <$ hmi, (warns, LinkableResult <$> hmi <*> pure hash))
1086+
10401087-- | For now we always use bytecode unless something uses unboxed sums and tuples along with TH
10411088getLinkableType :: NormalizedFilePath -> Action (Maybe LinkableType )
10421089getLinkableType f = use_ NeedsCompilation f
@@ -1069,7 +1116,6 @@ needsCompilationRule file = do
10691116 (,) (map (fmap (msrModSummary . fst )) <$> usesWithStale GetModSummaryWithoutTimestamps revdeps)
10701117 (uses NeedsCompilation revdeps)
10711118 pure $ computeLinkableType ms modsums (map join needsComps)
1072-
10731119 pure (Just $ encodeLinkableType res, Just res)
10741120 where
10751121 computeLinkableType :: ModSummary -> [Maybe ModSummary ] -> [Maybe LinkableType ] -> Maybe LinkableType
@@ -1170,3 +1216,4 @@ mainRule recorder RulesConfig{..} = do
11701216 persistentHieFileRule recorder
11711217 persistentDocMapRule
11721218 persistentImportMapRule
1219+ getLinkableRule recorder
0 commit comments