-
Notifications
You must be signed in to change notification settings - Fork 97
Use stale information if it's available to answer requests quickly #624
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks reasonably plausible. I'll take a more detailed look after @cocreature weighs in on the concept of whether this is the right thing to do or not.
Splitting off the benchmark stuff would let us land this in two phases, and decouple things that aren't very related at all.
bench/Main.hs
Outdated
@@ -218,14 +218,16 @@ runBenchmarks benchmarks = do | |||
putStrLn $ intercalate ", " $ map (showDuration . snd) results |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How big a deal would it be to send the benchmark changes in via a different PR? Seems totally unrelated to the rest of it, and one for @pepeiborra to review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. I've got a number of changes for the benchmark suite myself, so a separate PR that can be reviewed and merged quickly would be much appreciated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've pushed my benchmarks changes in #625
bench/Main.hs
Outdated
@@ -218,14 +218,16 @@ runBenchmarks benchmarks = do | |||
putStrLn $ intercalate ", " $ map (showDuration . snd) results | |||
|
|||
runBench :: HasConfig => Bench -> IO Seconds | |||
runBench Bench {..} = handleAny (\e -> print e >> return (-1)) | |||
runBench Bench {..} = handleAny (\e -> print e >> return (-2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having -1 as a special case was odd, but just on the edge of tolerable. Now we're having two magic negative seconds I think an enum would be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please!
bench/Main.hs
Outdated
return $ if res then t else -1 | ||
where | ||
cmd = | ||
unwords $ | ||
[ "ghcide", | ||
"--lsp", | ||
"--test", | ||
"--verbose", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why pass verbose? Why not take this as an argument to get passed onward?
bench/Main.hs
Outdated
return $ if res then t else -1 | ||
where | ||
cmd = | ||
unwords $ | ||
[ "ghcide", | ||
"--lsp", | ||
"--test", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/Development/IDE/Core/Service.hs
Outdated
@@ -50,7 +47,7 @@ initialise :: LSP.ClientCapabilities | |||
-> IdeOptions | |||
-> VFSHandle | |||
-> IO IdeState | |||
initialise caps mainRule getLspId toDiags logger debouncer options vfs = | |||
initialise caps mainRule getLspId toDiags logger debouncer options vfs = do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this change for?
src/Development/IDE/Core/Shake.hs
Outdated
data DelayedActionX a = DelayedActionX { actionName :: String -- Name we show to the user | ||
-- The queue only contrains entries for | ||
-- unique key values. | ||
, actionPriority :: Logger.Priority |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we using log priorities here?
src/Development/IDE/Core/Shake.hs
Outdated
liftIO $ logPriority l (actionPriority d) $ T.pack $ | ||
"finish: " ++ (actionName d) ++ " (took " ++ showDuration runTime ++ ")" | ||
|
||
freshId :: Var Int -> IO Int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just reuse Data.Unique?
src/Development/IDE/Core/Shake.hs
Outdated
|
||
freshId :: Var Int -> IO Int | ||
freshId qcount = do | ||
modifyVar qcount (\n -> return (n + 1, n)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a potential space leak.
@@ -395,7 +395,6 @@ getCompletions ideOpts CC { allModNamesAsNS, unqualCompls, qualCompls, importabl | |||
= filtModNameCompls ++ map (toggleSnippets caps withSnippets | |||
. mkCompl ideOpts . stripAutoGenerated) filtCompls | |||
++ filtKeywordCompls | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why delete one line in this file?
Benchmarks please! |
Benchmarks are vacuous now but anyway.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summarizing my understanding, this change:
- Introduces
useWithStaleFast
andIdeAction
, which are instant access to possibly obsolete data - Moves completions, hover, get-definition and outline to
IdeAction
, but importantly not code actions - Moves some rules to
IdeAction
, concretely the ones for.hie
files. - Makes
kick
ask forSpanInfo
instead of justTypeCheck
, and only on the file that changed - Introduces
DelayedAction
To me 1,2, and 4 make sense, I have questions about 5 and concerns about 3.
About DelayedAction
s:
- What in these actions is delayed?
- Why are they needed?
- I like that they add metadata, improving logging, but what are the ids used for?
About moving rules to In fact, I would prefer if there was no reference to IdeAction
, I know it's only the .hie
rules and you have plans down the road for those, but I would rather postpone the change until those plans materialize.IdeAction
in the Rules
module, and instead all the IdeAction
computations were moved to a separate module for clarity.
src/Development/IDE/Core/Shake.hs
Outdated
-- been modified, basically any use of shakeRun which is not blocking (ie | ||
-- which is not called via runAction). | ||
shakeRunInternal :: IdeState -> [DelayedAction a] -> IO () | ||
shakeRunInternal ide as = void $ shakeRunUser ide as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot of ways of running things now:
shakeRunUser
shakeRunInternal
delay
delayedAction
Assuming all are needed, is there a naming that makes things clearer? e.g.runUserIO
, runUserAction
, runInternalIO
, runInternalAction
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shakeRunUser
and shakeRunInternal
sound very different but then the latter just calls the former. Are you planning to differentiate them further in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make things more confusing, shakeRunUser
is literally only called from shakeRunInternal
.
-- A (maybe) stale result now, and an up to date one later | ||
data FastResult a = FastResult { stale :: Maybe (a,PositionMapping), uptoDate :: IO (Maybe a) } | ||
|
||
useWithStaleFast :: IdeRule k v => k -> NormalizedFilePath -> IdeAction (Maybe (v, PositionMapping)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doc comment needed
src/Development/IDE/Core/Service.hs
Outdated
runAction :: IdeState -> Action a -> IO a | ||
runAction ide action = join $ shakeEnqueue ide action | ||
runAction :: String -> IdeState -> Action a -> IO a | ||
runAction = runActionSync |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get rid of either runAction
or runActionSync
? They are the same...
|
||
mbHieTimestamp <- either (\(_ :: IOException) -> Nothing) Just <$> (liftIO $ try $ getModificationTime hie_f) | ||
srcTimestamp <- MaybeT (either (\(_ :: IOException) -> Nothing) Just <$> (liftIO $ try $ getModificationTime $ fromNormalizedFilePath f)) | ||
liftIO $ print (mbHieTimestamp, srcTimestamp, hie_f, normal_hie_f) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving rules out of the Shake graph doesn't seem like a good idea. Action
and IdeAction
sound alike but they have very different semantics, in that the former is backed by a recalculation graph and a cache, whereas the second is not.
For instance, the body of this new version getHomeHieFile
will run in full every time it's called, hitting the disk for timestamps and reloading the .hie
file every time. That doesn't seem right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was not a Rule
in the first place, so the semantics should remain sufficiently similar, since it uses
proper Rules just like before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I was under the impression that it was a rule for some reason. Maybe it should be, but that's a question for another PR
src/Development/IDE/Core/Shake.hs
Outdated
|
||
data DelayedActionX a = DelayedActionX { actionName :: String -- Name we show to the user | ||
-- The queue only contrains entries for | ||
-- unique key values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment seems out of place
46be3ff
to
3030195
Compare
I am taking a week break so probably won't get back to this until after that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the PR!
A couple of comments:
- I’m broadly happy to make actions explicitly triggered by users like hover and completions rely on stale results. I still very much dislike the fact that hovering twice without making any change can now give you different results but I don’t see a way to avoid this.
- I’m less happy to do the same for things not triggered by users even if they are triggered by their editor. This includes things like codelenses, document outline and so on. There are two reasons why I don’t like it here:
- One I simply don’t think the benefits are as big. This is usually not something users are actively waiting for since they didn’t trigger it so they don’t need to be as fast.
- As a user, I have no obvious way to trigger those actions again. Admittedly VSCode is fairly keen on sending these requests but e.g. I don’t know a nice way for refreshing code lenses without modifying my file which will again change those results so they are still not up2date.
- The names of the various
use*
functions are a mess now and they behave pretty inconsistently. - I’m slightly worried about the fact that we switch to a different codepath for testing in
useWithStaleFast'
. I understand why but it still makes it easy for things to creep in that aren’t covered by testing.
bench/Main.hs
Outdated
@@ -218,14 +218,16 @@ runBenchmarks benchmarks = do | |||
putStrLn $ intercalate ", " $ map (showDuration . snd) results | |||
|
|||
runBench :: HasConfig => Bench -> IO Seconds | |||
runBench Bench {..} = handleAny (\e -> print e >> return (-1)) | |||
runBench Bench {..} = handleAny (\e -> print e >> return (-2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please!
src/Development/IDE/Core/Shake.hs
Outdated
GlobalIdeOptions x <- getIdeGlobalExtras ide | ||
return x | ||
|
||
-- | The result of an IDE operation. Warnings and errors are in the Diagnostic, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment doesn’t really seem to belong to anything its surroundings. I think this got moved when IdeResult
got moved and probably got messed up in a rebase.
src/Development/IDE/Core/Shake.hs
Outdated
-- been modified, basically any use of shakeRun which is not blocking (ie | ||
-- which is not called via runAction). | ||
shakeRunInternal :: IdeState -> [DelayedAction a] -> IO () | ||
shakeRunInternal ide as = void $ shakeRunUser ide as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shakeRunUser
and shakeRunInternal
sound very different but then the latter just calls the former. Are you planning to differentiate them further in the future?
src/Development/IDE/Core/Shake.hs
Outdated
-- been modified, basically any use of shakeRun which is not blocking (ie | ||
-- which is not called via runAction). | ||
shakeRunInternal :: IdeState -> [DelayedAction a] -> IO () | ||
shakeRunInternal ide as = void $ shakeRunUser ide as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make things more confusing, shakeRunUser
is literally only called from shakeRunInternal
.
src/Development/IDE/Core/Shake.hs
Outdated
liftIO $ case r of | ||
Nothing -> do | ||
IdeTesting testing <- optTesting <$> getIdeOptionsIO s | ||
if testing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m slightly worried about having this so deep in the internals. That makes it easy to mess up something and not have tests catch it. Not quite sure what a better solution is here.
src/Development/IDE/Core/Shake.hs
Outdated
-- | Actions with an ID for tracing purposes | ||
data DelayedActionExtra | ||
= DelayedActionExtra | ||
{ _actionInternalId :: Unique |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You aren’t using this unique anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it is meant to be used for tracing purposes, maybe it will be helpful with the work @mpardalos is going to do.
src/Development/IDE/Core/Shake.hs
Outdated
type DelayedActionInternal = DelayedActionX DelayedActionExtra | ||
|
||
{-# COMPLETE DelayedActionInternal#-} | ||
pattern DelayedActionInternal :: String -> Logger.Priority -> Action () -> Unique -> DelayedActionX DelayedActionExtra |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might just be me but I find that those pattern synonyms here just make things more confusing. I’d prefer either having two separate types or actually pass around the polymorphic version.
src/Development/IDE/Core/Shake.hs
Outdated
mkDelayedAction = DelayedAction | ||
|
||
data DelayedActionX a = DelayedActionX | ||
{ actionName :: String -- ^ Name we show to the user |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
user
is the IDE dev right? I couldn’t find anything where this is used for non-debugging purposes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we clarify the doc comment here please?
@@ -87,11 +91,11 @@ toIdeResult = either (, Nothing) (([],) . Just) | |||
|
|||
-- | useE is useful to implement functions that aren’t rules but need shortcircuiting | |||
-- e.g. getDefinition. | |||
useE :: IdeRule k v => k -> NormalizedFilePath -> MaybeT Action v | |||
useE k = MaybeT . use k | |||
useE :: IdeRule k v => k -> NormalizedFilePath -> MaybeT IdeAction (v, PositionMapping) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afaict use
and useE
are very different now. use
will block until you get the result. useE
will return without blocking. use
on the other hand still block. useE
also will give you stale results. useWithStale
also blocks but gives you the last result if the rule fails. Currently you somewhat rely on the fact that useE
is called outside of rules.
I think this could do with some new function names, e.g., (very happy if you come up with better names)
use
useWithStale
useWithStaleNonBlocking
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also usesE
is still blocking afaict. That seems wrong.
I would like to follow the codepath we follow for tests even when not testing, but @mpickering disagrees. I think it is OK to block on the first request when no results have been computed. Otherwise you get some very weird behavior. For example, suppose you have an |
One problem with this is that vscode does not send any new requests until it gets a response for these. To the user, this looks the server blocking on hover, go to definition etc. This means that in practice, a lot of the gains of this PR will be negated. For instance, on modification, vscode will send these requests. Then when the user tries to hover on something, vscode will refuse to send any new requests until the code lenses etc. triggered by the modification return. I don't really have a problem with this though since I don't use vscode and my editor only sends outline requests when I ask it to. |
Are you positive that it is VSCode who doesn't send the requests concurrently? |
I think so, since I got frustrated by this once and checked the logs. |
Do you mean the logs printed by ghcide? There's every chance that those would be single-threaded too |
I'm not sure now, they might have been the haskell-lsp logs. I will check again when I'm at my computer. |
As suggested in #617. Taken fron haskell#624
As suggested in #617. Taken fron haskell#624
f314ba4
to
0835fb6
Compare
* Write a cabal.project file As suggested in #617. Taken fron #624 * Write a cabal.project.local Otherwise Cabal still errors out * Override default hie dir Otherwise .hi and .hie files end up in different locations, which causes the getDefinition experiment to fail the second time it's run. This is because we assume in ghcide that .hi and .hie files have the same lifetimes, which is not true when the ..hie files are wiped but the .hi files aren't.
As suggested in #617. Taken fron haskell#624
0835fb6
to
7a498e5
Compare
I have simplified the API somewhat by removing Now we have |
96ece92
to
3a064ee
Compare
I believe this is ready for another look. I think I've addressed most of the comments here. |
Did you have a chance to check whether the lsp-client is able to send requests concurrently? |
Since this branch has performance impacting changes, could you run and share differential benchmarks following the guidelines below https://github.com/digital-asset/ghcide/blame/master/README.md#L313-L321 |
Given that this PR splits requests into a fast path and a slow path, we must be careful in analysing any performance graphs we produce. |
Ah, I meant code lens. Code action doesn't use |
This introduces a new function `useWithStaleFast` which returns with stale information WITHOUT checking freshness like `use` and `useWithStale`. Greatly improve debug logging All actions triggered by shakeRun now also pass an identifier which means that the debug logging shows which actions are starting/finishing We also distinguish between internal and external events. By default external events are ones triggered by runAction and the debug output is displayed to the user in command line and --lsp mode. In order to see internal logging statements, there is a new flag called --verbose which also prints out internal events such as file modification flushes. Cleaner variant using runAfter Step 1: Do not run actions with shakeRun Queue implementation, living, breathing Use a priority queue to schedule shake actions. Most user actions are answered immediately with a cache but also spawn a shake action to check the cached value we consulted was up to date.
48349ec
to
84aac45
Compare
Benchmark results:
|
Here is the entire output of the benchmark tool:
As we can see, for the results returning stale information, there is a pause for the initial run. Subsequent requests return instantaneously. |
84aac45
to
68d8dfe
Compare
Here are the differential results: http://78.47.113.11/results/ |
I think the questions that remain are:
|
|
Addressed both points. |
Very nice!! That's much better than the optimisation in #670, which is bottle-necked a bit by Shake |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Sorry for the delay. Two small requests for doc fixes before merging.
src/Development/IDE/Core/Shake.hs
Outdated
|
||
-- | Lookup value in the database and return with the stale value immediately | ||
-- Will queue an action to refresh the value. | ||
-- Never blocks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is no longer accurate. You block the first time (which is a good idea imho so just update the docs).
src/Development/IDE/Core/Shake.hs
Outdated
mkDelayedAction = DelayedAction | ||
|
||
data DelayedActionX a = DelayedActionX | ||
{ actionName :: String -- ^ Name we show to the user |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we clarify the doc comment here please?
Fixed! |
* Write a cabal.project file As suggested in haskell/ghcide#617. Taken fron haskell/ghcide#624 * Write a cabal.project.local Otherwise Cabal still errors out * Override default hie dir Otherwise .hi and .hie files end up in different locations, which causes the getDefinition experiment to fail the second time it's run. This is because we assume in ghcide that .hi and .hie files have the same lifetimes, which is not true when the ..hie files are wiped but the .hi files aren't.
…askell/ghcide#624) * Use stale information for hover and completions This introduces a new function `useWithStaleFast` which returns with stale information WITHOUT checking freshness like `use` and `useWithStale`. Greatly improve debug logging All actions triggered by shakeRun now also pass an identifier which means that the debug logging shows which actions are starting/finishing We also distinguish between internal and external events. By default external events are ones triggered by runAction and the debug output is displayed to the user in command line and --lsp mode. In order to see internal logging statements, there is a new flag called --verbose which also prints out internal events such as file modification flushes. Cleaner variant using runAfter Step 1: Do not run actions with shakeRun Queue implementation, living, breathing Use a priority queue to schedule shake actions. Most user actions are answered immediately with a cache but also spawn a shake action to check the cached value we consulted was up to date. * Remove DelayedActionExtra * hlint * Fix progress * Always block instead of fail on initial computation * Can block for code lens * Update docs Co-authored-by: Zubin Duggal <[email protected]>
* Write a cabal.project file As suggested in haskell/ghcide#617. Taken fron haskell/ghcide#624 * Write a cabal.project.local Otherwise Cabal still errors out * Override default hie dir Otherwise .hi and .hie files end up in different locations, which causes the getDefinition experiment to fail the second time it's run. This is because we assume in ghcide that .hi and .hie files have the same lifetimes, which is not true when the ..hie files are wiped but the .hi files aren't.
…askell/ghcide#624) * Use stale information for hover and completions This introduces a new function `useWithStaleFast` which returns with stale information WITHOUT checking freshness like `use` and `useWithStale`. Greatly improve debug logging All actions triggered by shakeRun now also pass an identifier which means that the debug logging shows which actions are starting/finishing We also distinguish between internal and external events. By default external events are ones triggered by runAction and the debug output is displayed to the user in command line and --lsp mode. In order to see internal logging statements, there is a new flag called --verbose which also prints out internal events such as file modification flushes. Cleaner variant using runAfter Step 1: Do not run actions with shakeRun Queue implementation, living, breathing Use a priority queue to schedule shake actions. Most user actions are answered immediately with a cache but also spawn a shake action to check the cached value we consulted was up to date. * Remove DelayedActionExtra * hlint * Fix progress * Always block instead of fail on initial computation * Can block for code lens * Update docs Co-authored-by: Zubin Duggal <[email protected]>
* Write a cabal.project file As suggested in haskell/ghcide#617. Taken fron haskell/ghcide#624 * Write a cabal.project.local Otherwise Cabal still errors out * Override default hie dir Otherwise .hi and .hie files end up in different locations, which causes the getDefinition experiment to fail the second time it's run. This is because we assume in ghcide that .hi and .hie files have the same lifetimes, which is not true when the ..hie files are wiped but the .hi files aren't.
…askell/ghcide#624) * Use stale information for hover and completions This introduces a new function `useWithStaleFast` which returns with stale information WITHOUT checking freshness like `use` and `useWithStale`. Greatly improve debug logging All actions triggered by shakeRun now also pass an identifier which means that the debug logging shows which actions are starting/finishing We also distinguish between internal and external events. By default external events are ones triggered by runAction and the debug output is displayed to the user in command line and --lsp mode. In order to see internal logging statements, there is a new flag called --verbose which also prints out internal events such as file modification flushes. Cleaner variant using runAfter Step 1: Do not run actions with shakeRun Queue implementation, living, breathing Use a priority queue to schedule shake actions. Most user actions are answered immediately with a cache but also spawn a shake action to check the cached value we consulted was up to date. * Remove DelayedActionExtra * hlint * Fix progress * Always block instead of fail on initial computation * Can block for code lens * Update docs Co-authored-by: Zubin Duggal <[email protected]>
With this patch whenever any request made by the user is dealt with by an
IdeAction
which has the implicit guarantee to never block for an unbounded amount of time.Stale information is used if it's available to answer all requests. Information should usually be up-to-date because the
FileStore.hs
rule requests up-to-date information whenver a file changes.Do not review the changes to the hover/completions etc code too closely because that is all rewritten on another branch by Zubin anyway to use HieDb.
This patch also lays the way for removing
kick
and more fine grained control over which files are typechecked.