@@ -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,46 @@ 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+ core_t <- liftIO $ getModTime core_file
1053+ case hirCoreFp of
1054+ Nothing -> error " called GetLinkable for a file without a linkable"
1055+ Just (bin_core, hash) -> do
1056+ session <- use_ GhcSessionDeps f
1057+ ShakeExtras {ideNc} <- getShakeExtras
1058+ let namecache_updater = mkUpdater ideNc
1059+ linkableType <- getLinkableType f >>= \ case
1060+ Nothing -> error " called GetLinkable for a file which doesn't need compilation"
1061+ Just t -> pure t
1062+ (warns, hmi) <- case linkableType of
1063+ -- Bytecode needs to be regenerated from the core file
1064+ BCOLinkable -> liftIO $ coreFileToLinkable linkableType (hscEnv session) ms hirModIface hirModDetails bin_core (posixSecondsToUTCTime core_t)
1065+ -- Object code can be read from the disk
1066+ ObjectLinkable -> do
1067+ -- object file is up to date if it is newer than the core file
1068+ -- Can't use a rule like 'GetModificationTime' or 'GetFileExists' because 'coreFileToLinkable' will write the object file, and
1069+ -- thus bump its modification time, forcing this rule to be rerun every time.
1070+ exists <- liftIO $ doesFileExist obj_file
1071+ mobj_time <- liftIO $
1072+ if exists
1073+ then Just <$> getModTime obj_file
1074+ else pure Nothing
1075+ case mobj_time of
1076+ Just obj_t
1077+ | obj_t >= core_t -> pure ([] , Just $ HomeModInfo hirModIface hirModDetails (Just $ LM (posixSecondsToUTCTime obj_t) (ms_mod ms) [DotO obj_file]))
1078+ _ -> liftIO $ coreFileToLinkable linkableType (hscEnv session) ms hirModIface hirModDetails bin_core (error " object doesn't have time" )
1079+ -- Record the linkable so we know not to unload it
1080+ whenJust (hm_linkable =<< hmi) $ \ (LM time mod _) -> do
1081+ compiledLinkables <- getCompiledLinkables <$> getIdeGlobalAction
1082+ liftIO $ void $ modifyVar' compiledLinkables $ \ old -> extendModuleEnv old mod time
1083+ return (hash <$ hmi, (warns, LinkableResult <$> hmi <*> pure hash))
1084+
10401085-- | For now we always use bytecode unless something uses unboxed sums and tuples along with TH
10411086getLinkableType :: NormalizedFilePath -> Action (Maybe LinkableType )
10421087getLinkableType f = use_ NeedsCompilation f
@@ -1069,7 +1114,6 @@ needsCompilationRule file = do
10691114 (,) (map (fmap (msrModSummary . fst )) <$> usesWithStale GetModSummaryWithoutTimestamps revdeps)
10701115 (uses NeedsCompilation revdeps)
10711116 pure $ computeLinkableType ms modsums (map join needsComps)
1072-
10731117 pure (Just $ encodeLinkableType res, Just res)
10741118 where
10751119 computeLinkableType :: ModSummary -> [Maybe ModSummary ] -> [Maybe LinkableType ] -> Maybe LinkableType
@@ -1170,3 +1214,4 @@ mainRule recorder RulesConfig{..} = do
11701214 persistentHieFileRule recorder
11711215 persistentDocMapRule
11721216 persistentImportMapRule
1217+ getLinkableRule recorder
0 commit comments