Skip to content

Commit 89ae61a

Browse files
committed
Merge branch 'master' into soulomoon/shake-rebouncer
2 parents 5d77f61 + 3084c7f commit 89ae61a

File tree

4 files changed

+35
-6
lines changed

4 files changed

+35
-6
lines changed

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -615,10 +615,9 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
615615
void $ modifyVar' filesMap $ flip HM.union (HM.fromList (map ((,hieYaml) . fst) $ concatMap toFlagsMap all_targets))
616616
-- The VFS doesn't change on cradle edits, re-use the old one.
617617
-- Invalidate all the existing GhcSession build nodes by restarting the Shake session
618-
restartShakeSession VFSUnmodified "new component" [] $ do
619-
key1 <- extendKnownTargets all_targets
620-
key2 <- invalidateShakeCache
621-
return [key1, key2]
618+
invalidateShakeCache
619+
-- The VFS doesn't change on cradle edits, re-use the old one.
620+
restartShakeSession VFSUnmodified "new component" []
622621

623622
-- Typecheck all files in the project on startup
624623
checkProject <- getCheckProject

ghcide/src/Development/IDE/Core/FileExists.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ getFileExistsMapUntracked = do
106106
FileExistsMapVar v <- getIdeGlobalAction
107107
return v
108108

109-
-- | Modify the global store of file exists and return the keys that need to be mark as dirty
109+
-- | Modify the global store of file exists and return the keys that need to be marked as dirty
110110
modifyFileExists :: IdeState -> [(NormalizedFilePath, FileChangeType)] -> IO [Key]
111111
modifyFileExists state changes = do
112112
FileExistsMapVar var <- getIdeGlobalState state

ghcide/src/Development/IDE/Core/Shake.hs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,7 @@ setValues state key file val diags =
576576

577577

578578
-- | Delete the value stored for a given ide build key
579+
-- and return the key that was deleted.
579580
deleteValue
580581
:: Shake.ShakeValue k
581582
=> ShakeExtras
@@ -1324,6 +1325,8 @@ defineEarlyCutoff' doDiagnostics cmp key file mbOld mode action = do
13241325
(if eq then ChangedRecomputeSame else ChangedRecomputeDiff)
13251326
(encodeShakeValue bs)
13261327
(A res) $ do
1328+
-- this hook needs to be run in the same transaction as the key is marked clean
1329+
-- see Note [Housekeeping rule cache and dirty key outside of hls-graph]
13271330
setValues state key file res (Vector.fromList diags)
13281331
modifyTVar' dirtyKeys (deleteKeySet $ toKey key file)
13291332
return res
@@ -1349,6 +1352,32 @@ defineEarlyCutoff' doDiagnostics cmp key file mbOld mode action = do
13491352
-- * creating bogus "file does not exists" diagnostics
13501353
| otherwise = useWithoutDependency (GetModificationTime_ False) fp
13511354

1355+
-- Note [Housekeeping rule cache and dirty key outside of hls-graph]
1356+
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1357+
-- Hls-graph contains its own internal running state for each key in the shakeDatabase.
1358+
-- ShakeExtras contains `state` field (rule result cache) and `dirtyKeys` (keys that became
1359+
-- dirty in between build sessions) that is not visible to the hls-graph
1360+
-- Essentially, we need to keep the rule cache and dirty key and hls-graph's internal state
1361+
-- in sync.
1362+
1363+
-- 1. A dirty key collected in a session should not be removed from dirty keys in the same session.
1364+
-- Since if we clean out the dirty key in the same session,
1365+
-- 1.1. we will lose the chance to dirty its reverse dependencies. Since it only happens during session restart.
1366+
-- 1.2. a key might be marked as dirty in ShakeExtras while it's being recomputed by hls-graph which could lead to it's premature removal from dirtyKeys.
1367+
-- See issue https://github.com/haskell/haskell-language-server/issues/4093 for more details.
1368+
1369+
-- 2. When a key is marked clean in the hls-graph's internal running
1370+
-- state, the rule cache and dirty keys are updated in the same transaction.
1371+
-- otherwise, some situations like the following can happen:
1372+
-- thread 1: hls-graph session run a key
1373+
-- thread 1: defineEarlyCutoff' run the action for the key
1374+
-- thread 1: the action is done, rule cache and dirty key are updated
1375+
-- thread 2: we restart the hls-graph session, thread 1 is killed, the
1376+
-- hls-graph's internal state is not updated.
1377+
-- This is problematic with early cut off because we are having a new rule cache matching the
1378+
-- old hls-graph's internal state, which might case it's reverse dependency to skip the recomputation.
1379+
-- See https://github.com/haskell/haskell-language-server/issues/4194 for more details.
1380+
13521381
traceA :: A v -> String
13531382
traceA (A Failed{}) = "Failed"
13541383
traceA (A Stale{}) = "Stale"

hls-graph/src/Development/IDE/Graph/Internal/Types.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ data RunResult value = RunResult
204204
,runValue :: value
205205
-- ^ The value to return from 'Development.Shake.Rule.apply'.
206206
,runHook :: STM ()
207-
-- ^ The hook to run after the rule completes.
207+
-- ^ The hook to run at the end of the build in the same transaction
208+
-- when the key is marked as clean.
208209
} deriving Functor
209210

210211
---------------------------------------------------------------------

0 commit comments

Comments
 (0)