-
-
Notifications
You must be signed in to change notification settings - Fork 368
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix a wingman bug caused by mismanaged stale data (#1657)
* Start tracking provenance of stale data It's amazing how wrong this code used to be * Add some machinery for automagically updating the age * Add an applicative instance * Tracked ages makes everything much easier to reason about * Formatting * Haddock and small changes * Update haddock on IdeAction * Update to lsp-1.2 (#1631) * Update to lsp-1.2 * fix stack * fix splice plugin tests * fix tactic plugin tests * fix some tests * fix some tests * fix outline tests * hlint * fix func-test * Avoid reordering plugins (#1629) * Avoid reordering plugins Order of execution matters for notification plugins, so lets avoid unnecessary reorderings * remove duplicate plugins * fix tests * Civilized indexing progress reporting (#1633) * Civilized indexing progress reporting * optProgressStyle * Consistency: Indexing references ==> Indexing * Fix progress tests * Do not override custom user commands (#1650) Co-authored-by: Potato Hatsue <[email protected]> * Shut the Shake session on exit, instead of restarting it (#1655) Restarting the session will result in progress reporting and other messages being sent to the client, which might have already closed the stream Co-authored-by: Potato Hatsue <[email protected]> * Fix importing type operators (#1644) * Fix importing type operators * Update test * Add expected failure tests * log exceptions before killing the server (#1651) * log hiedb exceptions before killing the server * This is not the hiedb thread - fix message * Fix handler - either an error or success * additional .gitignore entries (#1659) * Fix ignore paths (#1656) * Skip individual steps * Skip individual steps * And needs pre_job * Add bounds for Diff (#1665) * Replace Barrier with MVar in lsp main (#1668) * Port UseStale to ghcide * Use the new ghcide UseStale machinery * Fix hlint complaints Co-authored-by: wz1000 <[email protected]> Co-authored-by: Pepe Iborra <[email protected]> Co-authored-by: Potato Hatsue <[email protected]> Co-authored-by: Javier Neira <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
- Loading branch information
1 parent
334f185
commit c6421fd
Showing
11 changed files
with
305 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
{-# LANGUAGE DerivingVia #-} | ||
{-# LANGUAGE GADTs #-} | ||
{-# LANGUAGE KindSignatures #-} | ||
{-# LANGUAGE RankNTypes #-} | ||
|
||
module Development.IDE.Core.UseStale | ||
( Age(..) | ||
, Tracked | ||
, unTrack | ||
, PositionMap | ||
, TrackedStale (..) | ||
, unsafeMkStale | ||
, unsafeMkCurrent | ||
, unsafeCopyAge | ||
, MapAge (..) | ||
, dualPositionMap | ||
, useWithStale | ||
, useWithStale_ | ||
) where | ||
|
||
import Control.Arrow | ||
import Control.Category (Category) | ||
import qualified Control.Category as C | ||
import Control.DeepSeq (NFData) | ||
import Data.Aeson | ||
import Data.Coerce (coerce) | ||
import Data.Functor ((<&>)) | ||
import Data.Functor.Identity (Identity(Identity)) | ||
import Data.Kind (Type) | ||
import Data.String (fromString) | ||
import Development.IDE (NormalizedFilePath, IdeRule, Action, Range, rangeToRealSrcSpan, realSrcSpanToRange) | ||
import qualified Development.IDE.Core.PositionMapping as P | ||
import qualified Development.IDE.Core.Shake as IDE | ||
import qualified FastString as FS | ||
import SrcLoc | ||
|
||
|
||
------------------------------------------------------------------------------ | ||
-- | A data kind for 'Tracked'. | ||
data Age = Current | Stale Type | ||
|
||
|
||
------------------------------------------------------------------------------ | ||
-- | Some value, tagged with its age. All 'Current' ages are considered to be | ||
-- the same thing, but 'Stale' values are protected by an untouchable variable | ||
-- to ensure they can't be unified. | ||
newtype Tracked (age :: Age) a = UnsafeTracked | ||
{ unTrack :: a | ||
} | ||
deriving stock (Functor, Foldable, Traversable) | ||
deriving newtype (Eq, Ord, Show, Read, ToJSON, FromJSON, NFData) | ||
deriving (Applicative, Monad) via Identity | ||
|
||
|
||
------------------------------------------------------------------------------ | ||
-- | Like 'P.PositionMapping', but with annotated ages for how 'Tracked' values | ||
-- change. Use the 'Category' instance to compose 'PositionMapping's in order | ||
-- to transform between values of different stale ages. | ||
newtype PositionMap (from :: Age) (to :: Age) = PositionMap | ||
{ getPositionMapping :: P.PositionMapping | ||
} | ||
|
||
instance Category PositionMap where | ||
id = coerce P.zeroMapping | ||
(.) = coerce P.composeDelta | ||
|
||
|
||
------------------------------------------------------------------------------ | ||
-- | Get a 'PositionMap' that runs in the opposite direction. | ||
dualPositionMap :: PositionMap from to -> PositionMap to from | ||
dualPositionMap (PositionMap (P.PositionMapping (P.PositionDelta from to))) = | ||
PositionMap $ P.PositionMapping $ P.PositionDelta to from | ||
|
||
|
||
------------------------------------------------------------------------------ | ||
-- | A pair containing a @'Tracked' 'Stale'@ value, as well as | ||
-- a 'PositionMapping' that will fast-forward values to the current age. | ||
data TrackedStale a where | ||
TrackedStale | ||
:: Tracked (Stale s) a | ||
-> PositionMap (Stale s) Current | ||
-> TrackedStale a | ||
|
||
instance Functor TrackedStale where | ||
fmap f (TrackedStale t pm) = TrackedStale (fmap f t) pm | ||
|
||
|
||
------------------------------------------------------------------------------ | ||
-- | A class for which 'Tracked' values can be run across a 'PositionMapping' | ||
-- to change their ages. | ||
class MapAge a where | ||
{-# MINIMAL mapAgeFrom | mapAgeTo #-} | ||
mapAgeFrom :: PositionMap from to -> Tracked to a -> Maybe (Tracked from a) | ||
mapAgeFrom = mapAgeTo . dualPositionMap | ||
|
||
mapAgeTo :: PositionMap from to -> Tracked from a -> Maybe (Tracked to a) | ||
mapAgeTo = mapAgeFrom . dualPositionMap | ||
|
||
|
||
instance MapAge Range where | ||
mapAgeFrom = coerce P.fromCurrentRange | ||
mapAgeTo = coerce P.toCurrentRange | ||
|
||
|
||
instance MapAge RealSrcSpan where | ||
mapAgeFrom = | ||
invMapAge (\fs -> rangeToRealSrcSpan (fromString $ FS.unpackFS fs)) | ||
(srcSpanFile &&& realSrcSpanToRange) | ||
. mapAgeFrom | ||
|
||
|
||
------------------------------------------------------------------------------ | ||
-- | Helper function for deriving 'MapAge' for values in terms of other | ||
-- instances. | ||
invMapAge | ||
:: (c -> a -> b) | ||
-> (b -> (c, a)) | ||
-> (Tracked from a -> Maybe (Tracked to a)) | ||
-> Tracked from b | ||
-> Maybe (Tracked to b) | ||
invMapAge to from f t = | ||
let (c, t') = unTrack $ fmap from t | ||
in fmap (fmap $ to c) $ f $ UnsafeTracked t' | ||
|
||
|
||
unsafeMkCurrent :: age -> Tracked 'Current age | ||
unsafeMkCurrent = coerce | ||
|
||
|
||
unsafeMkStale :: age -> Tracked (Stale s) age | ||
unsafeMkStale = coerce | ||
|
||
|
||
unsafeCopyAge :: Tracked age a -> b -> Tracked age b | ||
unsafeCopyAge _ = coerce | ||
|
||
|
||
-- | Request a Rule result, it not available return the last computed result, if any, which may be stale | ||
useWithStale :: IdeRule k v | ||
=> k -> NormalizedFilePath -> Action (Maybe (TrackedStale v)) | ||
useWithStale key file = do | ||
x <- IDE.useWithStale key file | ||
pure $ x <&> \(v, pm) -> | ||
TrackedStale (coerce v) (coerce pm) | ||
|
||
-- | Request a Rule result, it not available return the last computed result which may be stale. | ||
-- Errors out if none available. | ||
useWithStale_ :: IdeRule k v | ||
=> k -> NormalizedFilePath -> Action (TrackedStale v) | ||
useWithStale_ key file = do | ||
(v, pm) <- IDE.useWithStale_ key file | ||
pure $ TrackedStale (coerce v) (coerce pm) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.