@@ -95,8 +95,11 @@ import System.Info
9595import Control.Applicative (Alternative ((<|>) ))
9696import 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 )
100103import Control.Concurrent.STM.TQueue
101104import Control.DeepSeq
102105import 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
164169deriving instance Show Log
165170
166171
167172instance 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
240249hiedbDataVersion :: 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