@@ -99,7 +99,7 @@ import Data.Tuple.Extra
99
99
import Development.IDE.Core.Compile
100
100
import Development.IDE.Core.FileExists hiding (LogShake , Log )
101
101
import Development.IDE.Core.FileStore (getFileContents ,
102
- resetInterfaceStore )
102
+ getModTime )
103
103
import Development.IDE.Core.IdeConfiguration
104
104
import Development.IDE.Core.OfInterest hiding (LogShake , Log )
105
105
import Development.IDE.Core.PositionMapping
@@ -135,7 +135,7 @@ import Ide.Plugin.Config
135
135
import qualified Language.LSP.Server as LSP
136
136
import Language.LSP.Types (SMethod (SCustomMethod , SWindowShowMessage ), ShowMessageParams (ShowMessageParams ), MessageType (MtInfo ))
137
137
import Language.LSP.VFS
138
- import System.Directory (makeAbsolute )
138
+ import System.Directory (makeAbsolute , doesFileExist )
139
139
import Data.Default (def , Default )
140
140
import Ide.Plugin.Properties (HasProperty ,
141
141
KeyNameProxy ,
@@ -154,6 +154,9 @@ import qualified Development.IDE.Core.Shake as Shake
154
154
import qualified Development.IDE.GHC.ExactPrint as ExactPrint hiding (LogShake )
155
155
import qualified Development.IDE.Types.Logger as Logger
156
156
import 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
157
160
158
161
data Log
159
162
= LogShake Shake. Log
@@ -673,9 +676,13 @@ typeCheckRuleDefinition hsc pm = do
673
676
setPriority priorityTypeCheck
674
677
IdeOptions { optDefer = defer } <- getIdeOptions
675
678
676
- linkables_to_keep <- currentLinkables
679
+ unlift <- askUnliftIO
680
+ let dets = TypecheckHelpers
681
+ { getLinkablesToKeep = unliftIO unlift $ currentLinkables
682
+ , getLinkables = unliftIO unlift . uses_ GetLinkable
683
+ }
677
684
addUsageDependencies $ liftIO $
678
- typecheckModule defer hsc linkables_to_keep pm
685
+ typecheckModule defer hsc dets pm
679
686
where
680
687
addUsageDependencies :: Action (a , Maybe TcModuleResult ) -> Action (a , Maybe TcModuleResult )
681
688
addUsageDependencies a = do
@@ -752,7 +759,7 @@ ghcSessionDepsDefinition fullModSummary GhcSessionDepsConfig{..} env file = do
752
759
depSessions <- map hscEnv <$> uses_ (GhcSessionDeps_ fullModSummary) deps
753
760
ifaces <- uses_ GetModIface deps
754
761
755
- let inLoadOrder = map hirHomeMod ifaces
762
+ let inLoadOrder = map ( \ HiFileResult { .. } -> HomeModInfo hirModIface hirModDetails Nothing ) ifaces
756
763
session' <- liftIO $ mergeEnvs hsc mss inLoadOrder depSessions
757
764
758
765
Just <$> liftIO (newHscEnvEqWithImportPaths (envImportPaths env) session' [] )
@@ -768,7 +775,7 @@ getModIfaceFromDiskRule recorder = defineEarlyCutoff (cmapWithPrio LogShake reco
768
775
Just session -> do
769
776
linkableType <- getLinkableType f
770
777
ver <- use_ GetModificationTime f
771
- se @ ShakeExtras {ideNc} <- getShakeExtras
778
+ ShakeExtras {ideNc} <- getShakeExtras
772
779
let m_old = case old of
773
780
Shake. Succeeded (Just old_version) v -> Just (v, old_version)
774
781
Shake. Stale _ (Just old_version) v -> Just (v, old_version)
@@ -777,9 +784,10 @@ getModIfaceFromDiskRule recorder = defineEarlyCutoff (cmapWithPrio LogShake reco
777
784
{ source_version = ver
778
785
, old_value = m_old
779
786
, get_file_version = use GetModificationTime_ {missingFileDiagnostics = False }
787
+ , get_linkable_hashes = \ fs -> map linkableHash <$> uses_ GetLinkable fs
780
788
, regenerate = regenerateHiFile session f ms
781
789
}
782
- r <- loadInterface se (hscEnv session) ms linkableType recompInfo
790
+ r <- loadInterface (hscEnv session) ms linkableType recompInfo
783
791
case r of
784
792
(diags, Nothing ) -> return (Nothing , (diags, Nothing ))
785
793
(diags, Just x) -> do
@@ -899,7 +907,7 @@ getModIfaceRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $
899
907
hsc <- hscEnv <$> use_ GhcSessionDeps f
900
908
let compile = fmap ([] ,) $ use GenerateCore f
901
909
se <- getShakeExtras
902
- (diags, ! hiFile) <- compileToObjCodeIfNeeded se hsc linkableType compile tmr
910
+ (diags, ! hiFile) <- writeCoreFileIfNeeded se hsc linkableType compile tmr
903
911
let fp = hiFileFingerPrint <$> hiFile
904
912
hiDiags <- case hiFile of
905
913
Just hiFile
@@ -912,10 +920,6 @@ getModIfaceRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $
912
920
let fp = hiFileFingerPrint <$> hiFile
913
921
return (fp, ([] , hiFile))
914
922
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
919
923
pure res
920
924
921
925
-- | Count of total times we asked GHC to recompile
@@ -960,13 +964,12 @@ regenerateHiFile sess f ms compNeeded = do
960
964
Nothing -> pure (diags', Nothing )
961
965
Just tmr -> do
962
966
963
- -- compile writes .o file
964
967
let compile = liftIO $ compileModule (RunSimplifier True ) hsc (pm_mod_summary pm) $ tmrTypechecked tmr
965
968
966
969
se <- getShakeExtras
967
970
968
971
-- 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
970
973
971
974
-- Write hi file
972
975
hiDiags <- case res of
@@ -994,18 +997,20 @@ regenerateHiFile sess f ms compNeeded = do
994
997
995
998
996
999
-- | 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
999
1004
incrementRebuildCount
1000
1005
res <- liftIO $ mkHiFileResultNoCompile hsc tmr
1001
1006
pure ([] , Just $! res)
1002
- compileToObjCodeIfNeeded se hsc (Just linkableType ) getGuts tmr = do
1007
+ writeCoreFileIfNeeded se hsc (Just _ ) getGuts tmr = do
1003
1008
incrementRebuildCount
1004
1009
(diags, mguts) <- getGuts
1005
1010
case mguts of
1006
1011
Nothing -> pure (diags, Nothing )
1007
1012
Just guts -> do
1008
- (diags', ! res) <- liftIO $ mkHiFileResultCompile se hsc tmr guts linkableType
1013
+ (diags', ! res) <- liftIO $ mkHiFileResultCompile se hsc tmr guts
1009
1014
pure (diags++ diags', res)
1010
1015
1011
1016
getClientSettingsRule :: Recorder (WithPriority Log ) -> Rules ()
@@ -1037,6 +1042,46 @@ usePropertyAction kn plId p = do
1037
1042
1038
1043
-- ---------------------------------------------------------------------
1039
1044
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
+
1040
1085
-- | For now we always use bytecode unless something uses unboxed sums and tuples along with TH
1041
1086
getLinkableType :: NormalizedFilePath -> Action (Maybe LinkableType )
1042
1087
getLinkableType f = use_ NeedsCompilation f
@@ -1069,7 +1114,6 @@ needsCompilationRule file = do
1069
1114
(,) (map (fmap (msrModSummary . fst )) <$> usesWithStale GetModSummaryWithoutTimestamps revdeps)
1070
1115
(uses NeedsCompilation revdeps)
1071
1116
pure $ computeLinkableType ms modsums (map join needsComps)
1072
-
1073
1117
pure (Just $ encodeLinkableType res, Just res)
1074
1118
where
1075
1119
computeLinkableType :: ModSummary -> [Maybe ModSummary ] -> [Maybe LinkableType ] -> Maybe LinkableType
@@ -1170,3 +1214,4 @@ mainRule recorder RulesConfig{..} = do
1170
1214
persistentHieFileRule recorder
1171
1215
persistentDocMapRule
1172
1216
persistentImportMapRule
1217
+ getLinkableRule recorder
0 commit comments