Skip to content

Commit 4c31646

Browse files
committed
fix
1 parent 83140cf commit 4c31646

File tree

1 file changed

+88
-55
lines changed

1 file changed

+88
-55
lines changed

ghcide/session-loader/Development/IDE/Session.hs

+88-55
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,11 @@ import System.Info
9595
import Control.Applicative (Alternative ((<|>)))
9696
import Data.Void
9797

98-
import Control.Concurrent.STM.Stats (atomically, modifyTVar',
99-
readTVar, writeTVar)
98+
import Control.Concurrent.STM.Stats (TVar, atomically,
99+
modifyTVar', newTVar,
100+
newTVarIO, readTVar,
101+
readTVarIO, stateTVar,
102+
swapTVar, writeTVar)
100103
import Control.Concurrent.STM.TQueue
101104
import Control.DeepSeq
102105
import Control.Exception (evaluate)
@@ -161,11 +164,15 @@ data Log
161164
| LogNewComponentCache !(([FileDiagnostic], Maybe HscEnvEq), DependencyInfo)
162165
| LogHieBios HieBios.Log
163166
| LogSessionLoadingChanged
167+
| LogCacheVersion NormalizedFilePath !Int
168+
| LogClearingCache !NormalizedFilePath
164169
deriving instance Show Log
165170

166171

167172
instance Pretty Log where
168173
pretty = \case
174+
LogClearingCache path ->
175+
"Clearing cache for" <+> pretty (fromNormalizedFilePath path)
169176
LogNoneCradleFound path ->
170177
"None cradle found for" <+> pretty path <+> ", ignoring the file"
171178
LogSettingInitialDynFlags ->
@@ -235,6 +242,8 @@ instance Pretty Log where
235242
LogSessionLoadingChanged ->
236243
"Session Loading config changed, reloading the full session."
237244
LogShake msg -> pretty msg
245+
LogCacheVersion path version ->
246+
"Cache version for" <+> pretty (fromNormalizedFilePath path) <+> "is" <+> pretty version
238247

239248
-- | Bump this version number when making changes to the format of the data stored in hiedb
240249
hiedbDataVersion :: String
@@ -460,31 +469,34 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir = do
460469
-- Mapping from hie.yaml file to HscEnv, one per hie.yaml file
461470
hscEnvs <- newVar Map.empty :: IO (Var HieMap)
462471
-- Mapping from a Filepath to HscEnv
463-
fileToFlags <- newVar Map.empty :: IO (Var FlagsMap)
472+
fileToFlags <- newTVarIO Map.empty :: IO (TVar FlagsMap)
464473
-- Mapping from a Filepath to its 'hie.yaml' location.
465474
-- Should hold the same Filepaths as 'fileToFlags', otherwise
466475
-- they are inconsistent. So, everywhere you modify 'fileToFlags',
467476
-- you have to modify 'filesMap' as well.
468-
filesMap <- newVar HM.empty :: IO (Var FilesMap)
477+
filesMap <- newTVarIO HM.empty :: IO (TVar FilesMap)
469478

470479
-- Version of the mappings above
471480
version <- newVar 0
472481

482+
483+
restartKeys <- newTVarIO []
484+
targetFiles <- newTVarIO []
473485
-- version of the whole rebuild
474-
cacheVersion <- newVar 0
475-
lastRestartVersion <- newVar 0
486+
cacheVersion <- newTVarIO 0
476487
cradleLock <- newMVar ()
477-
-- putMVar cradleLock ()
478488
biosSessionLoadingVar <- newVar Nothing :: IO (Var (Maybe SessionLoadingPreferenceConfig))
479489

480490
let returnWithVersion fun = IdeGhcSession fun <$> liftIO (readVar version)
481491

482492

483493
let clearCache = do
484-
modifyVar_ cacheVersion $ pure . succ
485-
modifyVar_ hscEnvs $ \_ -> pure Map.empty
486-
modifyVar_ fileToFlags $ \_ -> pure Map.empty
487-
modifyVar_ filesMap $ \_ -> pure HM.empty
494+
atomically $ modifyTVar' restartKeys ([toNoFileKey SessionCacheVersion] ++)
495+
atomically $ modifyTVar' cacheVersion succ
496+
void $ modifyVar' hscEnvs $ \_ -> Map.empty
497+
-- modifyTVar' hscEnvs $ \_ -> Map.empty
498+
atomically $ modifyTVar' fileToFlags $ \_ -> Map.empty
499+
atomically $ modifyTVar' filesMap $ \_ -> HM.empty
488500
let
489501
-- | We allow users to specify a loading strategy.
490502
-- Check whether this config was changed since the last time we have loaded
@@ -546,8 +558,8 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir = do
546558
, "If you are using a .cabal file, please ensure that this module is listed in either the exposed-modules or other-modules section"
547559
]
548560

549-
liftIO $ void $ modifyVar' fileToFlags $ Map.insert hieYaml this_flags_map
550-
liftIO $ void $ modifyVar' filesMap $ flip HM.union (HM.fromList (map ((,hieYaml) . fst) $ concatMap toFlagsMap all_targets))
561+
liftIO $ void $ atomically $ modifyTVar' fileToFlags $ Map.insert hieYaml this_flags_map
562+
liftIO $ void $ atomically $ modifyTVar' filesMap $ flip HM.union (HM.fromList (map ((,hieYaml) . fst) $ concatMap toFlagsMap all_targets))
551563
-- The VFS doesn't change on cradle edits, re-use the old one.
552564
-- Invalidate all the existing GhcSession build nodes by restarting the Shake session
553565
keys2 <- liftIO invalidateShakeCache
@@ -667,7 +679,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir = do
667679
ShakeExtras{lspEnv } <- getShakeExtras
668680
IdeOptions{ optTesting = IdeTesting optTesting } <- getIdeOptions
669681
hieYamlOld <- use_ CradleLoc cfp
670-
cachedHieYamlLocation <- join <$> liftIO (HM.lookup cfp <$> readVar filesMap)
682+
cachedHieYamlLocation <- join <$> liftIO (HM.lookup cfp <$> readTVarIO filesMap)
671683
let hieYaml = fromMaybe cachedHieYamlLocation (Just hieYamlOld)
672684
let lfpLog = makeRelative rootDir (fromNormalizedFilePath cfp)
673685
logWith recorder Info $ LogCradlePath lfpLog
@@ -706,49 +718,66 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir = do
706718
Left err -> do
707719
dep_info <- liftIO $ getDependencyInfo (maybeToList hieYaml)
708720
let res = (map (\err' -> renderCradleError err' cradle cfp) err, Nothing)
709-
liftIO $ void $ modifyVar' fileToFlags $
721+
liftIO $ atomically $ modifyTVar' fileToFlags $
710722
Map.insertWith HM.union hieYaml (HM.singleton cfp (res, dep_info))
711-
liftIO $ void $ modifyVar' filesMap $ HM.insert cfp hieYaml
723+
liftIO $ atomically $ modifyTVar' filesMap $ HM.insert cfp hieYaml
712724
return (res, maybe [] pure hieYaml ++ concatMap cradleErrorDependencies err,[],[])
713725

714726
sessionCacheVersionRule :: Rules ()
715727
sessionCacheVersionRule = defineNoFile (cmapWithPrio LogShake recorder) $ \SessionCacheVersion -> do
716-
v <- liftIO $ readVar cacheVersion
728+
alwaysRerun
729+
v <- liftIO $ readTVarIO cacheVersion
717730
pure v
718731

719732
hieYamlRule :: Rules ()
720-
hieYamlRule = defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \HieYaml file ->
721-
-- only one cradle consult at a time
722-
UnliftIO.withMVar cradleLock $ const $ do
733+
hieYamlRule = defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \HieYaml file -> do
723734
hieYaml <- use_ CradleLoc file
724735
-- check the reason we are called
725-
v <- Map.findWithDefault HM.empty hieYaml <$> (liftIO$readVar fileToFlags)
726-
case HM.lookup file v of
736+
v <- Map.findWithDefault HM.empty hieYaml <$> (liftIO$readTVarIO fileToFlags)
737+
someThing <- case HM.lookup file v of
727738
-- we already have the cache but it is still called, it must be deps changed
728739
-- clear the cache and reconsult
729740
-- we bump the version of the cache to inform others
730-
Just _ -> do
731-
liftIO clearCache
732-
-- we don't have the cache, consult
733-
Nothing -> pure ()
734-
-- install cache version check to avoid recompilation
735-
_ <- useNoFile_ SessionCacheVersion
736-
catchError file hieYaml $ do
737-
result@(_, deps, _, _) <- consultCradle file
738-
-- add the deps to the Shake graph
739-
mapM_ addDependency deps
740-
return $ Just result
741-
where
742-
catchError file hieYaml f =
743-
f `Safe.catch` \e -> do
744-
-- install dep so it can be recorvered
745-
mapM_ addDependency hieYaml
746-
return $ Just (([renderPackageSetupException file e], Nothing), maybe [] pure hieYaml, [], [])
747-
addDependency fp = do
748-
-- VSCode uses absolute paths in its filewatch notifications
749-
let nfp = toNormalizedFilePath' fp
750-
itExists <- getFileExists nfp
751-
when itExists $ void $ do use_ GetModificationTime nfp
741+
Just (opts, old_di) -> do
742+
-- need to differ two kinds of invocation, one is the file is changed
743+
-- other is the cache version bumped
744+
deps_ok <- liftIO $ checkDependencyInfo old_di
745+
if not deps_ok
746+
then do
747+
logWith recorder Debug $ LogClearingCache file
748+
liftIO clearCache
749+
return Nothing
750+
else return $ Just (opts, Map.keys old_di, [], [])
751+
Nothing -> return Nothing
752+
-- install cache version check to get notified when the cache is changed
753+
-- todo but some how it is informing other, then other inform us, causing a loop
754+
case someThing of
755+
Just result@(_, deps, _files, _keys) -> do
756+
mapM_ addDependency deps
757+
return $ Just result
758+
Nothing -> do
759+
v <- useNoFile_ SessionCacheVersion
760+
logWith recorder Debug $ LogCacheVersion file v
761+
762+
catchError file hieYaml $ do
763+
result@(_, deps, files, keys) <- consultCradle file
764+
-- add the deps to the Shake graph
765+
liftIO $ atomically $ do
766+
modifyTVar' targetFiles (files ++ )
767+
modifyTVar' restartKeys (keys ++)
768+
mapM_ addDependency deps
769+
return $ Just result
770+
where
771+
catchError file hieYaml f =
772+
f `Safe.catch` \e -> do
773+
-- install dep so it can be recorvered
774+
mapM_ addDependency hieYaml
775+
return $ Just (([renderPackageSetupException file e], Nothing), maybe [] pure hieYaml, [], [])
776+
addDependency fp = do
777+
-- VSCode uses absolute paths in its filewatch notifications
778+
let nfp = toNormalizedFilePath' fp
779+
itExists <- getFileExists nfp
780+
when itExists $ void $ do use_ GetModificationTime nfp
752781

753782
cradleLocRule :: Rules ()
754783
cradleLocRule = defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \CradleLoc file -> do
@@ -769,18 +798,22 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir = do
769798
-- before attempting to do so.
770799
ShakeExtras{restartShakeSession } <- getShakeExtras
771800
IdeOptions{ optCheckProject = getCheckProject} <- getIdeOptions
772-
returnWithVersion $ \file -> do
773-
_opts@(a, b, files, keys) <- use_ HieYaml file
774-
-- wait for the restart
775-
lastRestartVersion' <- liftIO $ readVar lastRestartVersion
776-
cacheVersion' <- liftIO $ readVar cacheVersion
777-
liftIO $ when ((notNull files || notNull keys) && lastRestartVersion' /= cacheVersion') $ do
778-
liftIO $ writeVar lastRestartVersion cacheVersion'
779-
checkProject <- getCheckProject
780-
-- think of not to restart a second time
781-
async <- UnliftIO.async $ restartShakeSession VFSUnmodified "new component" (if checkProject then return (typecheckAll files) else mempty) $ pure keys
801+
returnWithVersion $ \file ->
802+
-- only one cradle consult at a time
803+
UnliftIO.withMVar cradleLock $ const $ do
804+
-- we need to find a way to get rid of the (files, keys)
805+
_opts@(a, b, _files, _keys) <- use_ HieYaml file
806+
-- _opts@(a, b, _files, _keys) <- getOptions file
807+
async <- UnliftIO.async $ do
808+
files <- liftIO $ atomically $ swapTVar targetFiles []
809+
keys <- liftIO $ atomically $ swapTVar restartKeys []
810+
_ <- useNoFile_ SessionCacheVersion
811+
liftIO $ when (notNull files || notNull keys) $ do
812+
checkProject <- getCheckProject
813+
-- think of not to restart a second time
814+
restartShakeSession VFSUnmodified "new component" (if checkProject then return (typecheckAll files) else mempty) $ pure keys
782815
UnliftIO.wait async
783-
pure $ (fmap . fmap) toAbsolutePath (a, b))
816+
pure $ (fmap . fmap) toAbsolutePath (a, b))
784817

785818

786819
-- | Run the specific cradle on a specific FilePath via hie-bios.

0 commit comments

Comments
 (0)