1
1
-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2
2
-- SPDX-License-Identifier: Apache-2.0
3
3
4
+ {-# LANGUAGE AllowAmbiguousTypes #-}
4
5
{-# LANGUAGE CPP #-}
5
6
{-# LANGUAGE DerivingStrategies #-}
6
7
{-# LANGUAGE DuplicateRecordFields #-}
@@ -121,6 +122,7 @@ import Data.Vector (Vector)
121
122
import qualified Data.Vector as Vector
122
123
import Development.IDE.Core.Debouncer
123
124
import Development.IDE.Core.FileUtils (getModTime )
125
+ import Development.IDE.Core.InputPath (InputPath (unInputPath , InputPath ))
124
126
import Development.IDE.Core.PositionMapping
125
127
import Development.IDE.Core.ProgressReporting
126
128
import Development.IDE.Core.RuleTypes
@@ -179,6 +181,7 @@ import System.FilePath hiding (makeRelative)
179
181
import System.IO.Unsafe (unsafePerformIO )
180
182
import System.Time.Extra
181
183
import UnliftIO (MonadUnliftIO (withRunInIO ))
184
+ import Development.IDE.Graph.Internal.RuleInput (RuleInput , HasInput )
182
185
183
186
184
187
data Log
@@ -342,7 +345,7 @@ type WithProgressFunc = forall a.
342
345
type WithIndefiniteProgressFunc = forall a .
343
346
T. Text -> LSP. ProgressCancellable -> IO a -> IO a
344
347
345
- type GetStalePersistent = NormalizedFilePath -> IdeAction (Maybe (Dynamic ,PositionDelta ,Maybe Int32 ))
348
+ type GetStalePersistent = InputPath i -> IdeAction (Maybe (Dynamic ,PositionDelta ,Maybe Int32 ))
346
349
347
350
getShakeExtras :: Action ShakeExtras
348
351
getShakeExtras = do
@@ -384,7 +387,7 @@ getPluginConfigAction plId = do
384
387
-- This is called when we don't already have a result, or computing the rule failed.
385
388
-- The result of this function will always be marked as 'stale', and a 'proper' rebuild of the rule will
386
389
-- be queued if the rule hasn't run before.
387
- addPersistentRule :: IdeRule k v => k -> (NormalizedFilePath -> IdeAction (Maybe (v ,PositionDelta ,Maybe Int32 ))) -> Rules ()
390
+ addPersistentRule :: IdeRule k i is v => k -> (InputPath i -> IdeAction (Maybe (v ,PositionDelta ,Maybe Int32 ))) -> Rules ()
388
391
addPersistentRule k getVal = do
389
392
ShakeExtras {persistentKeys} <- getShakeExtrasRules
390
393
void $ liftIO $ atomically $ modifyTVar' persistentKeys $ insertKeyMap (newKey k) (fmap (fmap (first3 toDyn)) . getVal)
@@ -452,7 +455,7 @@ getIdeOptionsIO ide = do
452
455
453
456
-- | Return the most recent, potentially stale, value and a PositionMapping
454
457
-- for the version of that value.
455
- lastValueIO :: IdeRule k v => ShakeExtras -> k -> NormalizedFilePath -> IO (Maybe (v , PositionMapping ))
458
+ lastValueIO :: IdeRule k i is v => ShakeExtras -> k -> InputPath i -> IO (Maybe (v , PositionMapping ))
456
459
lastValueIO s@ ShakeExtras {positionMapping,persistentKeys,state} k file = do
457
460
458
461
let readPersistent
@@ -498,7 +501,7 @@ lastValueIO s@ShakeExtras{positionMapping,persistentKeys,state} k file = do
498
501
499
502
-- | Return the most recent, potentially stale, value and a PositionMapping
500
503
-- for the version of that value.
501
- lastValue :: IdeRule k v => k -> NormalizedFilePath -> Action (Maybe (v , PositionMapping ))
504
+ lastValue :: IdeRule k i is v => k -> InputPath i -> Action (Maybe (v , PositionMapping ))
502
505
lastValue key file = do
503
506
s <- getShakeExtras
504
507
liftIO $ lastValueIO s key file
@@ -513,9 +516,11 @@ mappingForVersion allMappings file (Just (VFSVersion ver)) = do
513
516
return $ maybe zeroMapping snd $ EM. lookup ver =<< mapping
514
517
mappingForVersion _ _ _ = pure zeroMapping
515
518
516
- type IdeRule k v =
519
+ type IdeRule k i is v =
517
520
( Shake. RuleResult k ~ v
518
521
, Shake. ShakeValue k
522
+ , RuleInput k ~ is
523
+ , HasInput i is
519
524
, Show v
520
525
, Typeable v
521
526
, NFData v
@@ -581,10 +586,10 @@ shakeDatabaseProfileIO mbProfileDir = do
581
586
shakeProfileDatabase shakeDb $ dir </> file
582
587
return (dir </> file)
583
588
584
- setValues :: IdeRule k v
589
+ setValues :: IdeRule k i is v
585
590
=> Values
586
591
-> k
587
- -> NormalizedFilePath
592
+ -> InputPath i
588
593
-> Value v
589
594
-> Vector FileDiagnostic
590
595
-> STM ()
@@ -607,11 +612,11 @@ deleteValue ShakeExtras{state} key file = do
607
612
608
613
-- | We return Nothing if the rule has not run and Just Failed if it has failed to produce a value.
609
614
getValues ::
610
- forall k v .
611
- IdeRule k v =>
615
+ forall k i is v .
616
+ IdeRule k i is v =>
612
617
Values ->
613
618
k ->
614
- NormalizedFilePath ->
619
+ InputPath i ->
615
620
STM (Maybe (Value v , Vector FileDiagnostic ))
616
621
getValues state key file = do
617
622
STM. lookup (toKey key file) state >>= \ case
@@ -1010,23 +1015,23 @@ preservedKeys checkParents = HSet.fromList $
1010
1015
1011
1016
-- | Define a new Rule without early cutoff
1012
1017
define
1013
- :: IdeRule k v
1014
- => Recorder (WithPriority Log ) -> (k -> NormalizedFilePath -> Action (IdeResult v )) -> Rules ()
1018
+ :: IdeRule k i is v
1019
+ => Recorder (WithPriority Log ) -> (k -> InputPath i -> Action (IdeResult v )) -> Rules ()
1015
1020
define recorder op = defineEarlyCutoff recorder $ Rule $ \ k v -> (Nothing ,) <$> op k v
1016
1021
1017
1022
defineNoDiagnostics
1018
- :: IdeRule k v
1019
- => Recorder (WithPriority Log ) -> (k -> NormalizedFilePath -> Action (Maybe v )) -> Rules ()
1023
+ :: IdeRule k i is v
1024
+ => Recorder (WithPriority Log ) -> (k -> InputPath i -> Action (Maybe v )) -> Rules ()
1020
1025
defineNoDiagnostics recorder op = defineEarlyCutoff recorder $ RuleNoDiagnostics $ \ k v -> (Nothing ,) <$> op k v
1021
1026
1022
1027
-- | Request a Rule result if available
1023
- use :: IdeRule k v
1024
- => k -> NormalizedFilePath -> Action (Maybe v )
1028
+ use :: IdeRule k i is v
1029
+ => k -> InputPath i -> Action (Maybe v )
1025
1030
use key file = runIdentity <$> uses key (Identity file)
1026
1031
1027
1032
-- | Request a Rule result, it not available return the last computed result, if any, which may be stale
1028
- useWithStale :: IdeRule k v
1029
- => k -> NormalizedFilePath -> Action (Maybe (v , PositionMapping ))
1033
+ useWithStale :: IdeRule k i is v
1034
+ => k -> InputPath i -> Action (Maybe (v , PositionMapping ))
1030
1035
useWithStale key file = runIdentity <$> usesWithStale key (Identity file)
1031
1036
1032
1037
-- | Request a Rule result, it not available return the last computed result
@@ -1036,8 +1041,8 @@ useWithStale key file = runIdentity <$> usesWithStale key (Identity file)
1036
1041
-- none available.
1037
1042
--
1038
1043
-- WARNING: Not suitable for PluginHandlers. Use `useWithStaleE` instead.
1039
- useWithStale_ :: IdeRule k v
1040
- => k -> NormalizedFilePath -> Action (v , PositionMapping )
1044
+ useWithStale_ :: IdeRule k i is v
1045
+ => k -> InputPath i -> Action (v , PositionMapping )
1041
1046
useWithStale_ key file = runIdentity <$> usesWithStale_ key (Identity file)
1042
1047
1043
1048
-- | Plural version of 'useWithStale_'
@@ -1046,7 +1051,7 @@ useWithStale_ key file = runIdentity <$> usesWithStale_ key (Identity file)
1046
1051
-- none available.
1047
1052
--
1048
1053
-- WARNING: Not suitable for PluginHandlers.
1049
- usesWithStale_ :: (Traversable f , IdeRule k v ) => k -> f NormalizedFilePath -> Action (f (v , PositionMapping ))
1054
+ usesWithStale_ :: (Traversable f , IdeRule k i is v ) => k -> f ( InputPath i ) -> Action (f (v , PositionMapping ))
1050
1055
usesWithStale_ key files = do
1051
1056
res <- usesWithStale key files
1052
1057
case sequence res of
@@ -1077,11 +1082,11 @@ data FastResult a = FastResult { stale :: Maybe (a,PositionMapping), uptoDate ::
1077
1082
-- | Lookup value in the database and return with the stale value immediately
1078
1083
-- Will queue an action to refresh the value.
1079
1084
-- Might block the first time the rule runs, but never blocks after that.
1080
- useWithStaleFast :: IdeRule k v => k -> NormalizedFilePath -> IdeAction (Maybe (v , PositionMapping ))
1085
+ useWithStaleFast :: IdeRule k i is v => k -> InputPath i -> IdeAction (Maybe (v , PositionMapping ))
1081
1086
useWithStaleFast key file = stale <$> useWithStaleFast' key file
1082
1087
1083
1088
-- | Same as useWithStaleFast but lets you wait for an up to date result
1084
- useWithStaleFast' :: IdeRule k v => k -> NormalizedFilePath -> IdeAction (FastResult v )
1089
+ useWithStaleFast' :: IdeRule k i is v => k -> InputPath i -> IdeAction (FastResult v )
1085
1090
useWithStaleFast' key file = do
1086
1091
-- This lookup directly looks up the key in the shake database and
1087
1092
-- returns the last value that was computed for this key without
@@ -1108,7 +1113,7 @@ useWithStaleFast' key file = do
1108
1113
res <- lastValueIO s key file
1109
1114
pure $ FastResult res waitValue
1110
1115
1111
- useNoFile :: IdeRule k v => k -> Action (Maybe v )
1116
+ useNoFile :: IdeRule k i is v => k -> Action (Maybe v )
1112
1117
useNoFile key = use key emptyFilePath
1113
1118
1114
1119
-- Requests a rule if available.
@@ -1117,10 +1122,10 @@ useNoFile key = use key emptyFilePath
1117
1122
-- none available.
1118
1123
--
1119
1124
-- WARNING: Not suitable for PluginHandlers. Use `useE` instead.
1120
- use_ :: IdeRule k v => k -> NormalizedFilePath -> Action v
1125
+ use_ :: IdeRule k i is v => k -> InputPath i -> Action v
1121
1126
use_ key file = runIdentity <$> uses_ key (Identity file)
1122
1127
1123
- useNoFile_ :: IdeRule k v => k -> Action v
1128
+ useNoFile_ :: IdeRule k i is v => k -> Action v
1124
1129
useNoFile_ key = use_ key emptyFilePath
1125
1130
1126
1131
-- | Plural version of `use_`
@@ -1129,47 +1134,47 @@ useNoFile_ key = use_ key emptyFilePath
1129
1134
-- none available.
1130
1135
--
1131
1136
-- WARNING: Not suitable for PluginHandlers. Use `usesE` instead.
1132
- uses_ :: (Traversable f , IdeRule k v ) => k -> f NormalizedFilePath -> Action (f v )
1137
+ uses_ :: (Traversable f , IdeRule k i is v ) => k -> f ( InputPath i ) -> Action (f v )
1133
1138
uses_ key files = do
1134
1139
res <- uses key files
1135
1140
case sequence res of
1136
1141
Nothing -> liftIO $ throwIO $ BadDependency (show key)
1137
1142
Just v -> return v
1138
1143
1139
1144
-- | Plural version of 'use'
1140
- uses :: (Traversable f , IdeRule k v )
1141
- => k -> f NormalizedFilePath -> Action (f (Maybe v ))
1145
+ uses :: (Traversable f , IdeRule k i is v )
1146
+ => k -> f ( InputPath i ) -> Action (f (Maybe v ))
1142
1147
uses key files = fmap (\ (A value) -> currentValue value) <$> apply (fmap (Q . (key,)) files)
1143
1148
1144
1149
-- | Return the last computed result which might be stale.
1145
- usesWithStale :: (Traversable f , IdeRule k v )
1146
- => k -> f NormalizedFilePath -> Action (f (Maybe (v , PositionMapping )))
1150
+ usesWithStale :: (Traversable f , IdeRule k i is v )
1151
+ => k -> f ( InputPath i ) -> Action (f (Maybe (v , PositionMapping )))
1147
1152
usesWithStale key files = do
1148
1153
_ <- apply (fmap (Q . (key,)) files)
1149
1154
-- We don't look at the result of the 'apply' since 'lastValue' will
1150
1155
-- return the most recent successfully computed value regardless of
1151
1156
-- whether the rule succeeded or not.
1152
1157
traverse (lastValue key) files
1153
1158
1154
- useWithoutDependency :: IdeRule k v
1155
- => k -> NormalizedFilePath -> Action (Maybe v )
1159
+ useWithoutDependency :: IdeRule k i is v
1160
+ => k -> InputPath i -> Action (Maybe v )
1156
1161
useWithoutDependency key file =
1157
1162
(\ (Identity (A value)) -> currentValue value) <$> applyWithoutDependency (Identity (Q (key, file)))
1158
1163
1159
- data RuleBody k v
1160
- = Rule (k -> NormalizedFilePath -> Action (Maybe BS. ByteString , IdeResult v ))
1161
- | RuleNoDiagnostics (k -> NormalizedFilePath -> Action (Maybe BS. ByteString , Maybe v ))
1164
+ data RuleBody k i v
1165
+ = Rule (k -> InputPath i -> Action (Maybe BS. ByteString , IdeResult v ))
1166
+ | RuleNoDiagnostics (k -> InputPath i -> Action (Maybe BS. ByteString , Maybe v ))
1162
1167
| RuleWithCustomNewnessCheck
1163
1168
{ newnessCheck :: BS. ByteString -> BS. ByteString -> Bool
1164
- , build :: k -> NormalizedFilePath -> Action (Maybe BS. ByteString , Maybe v )
1169
+ , build :: k -> InputPath i -> Action (Maybe BS. ByteString , Maybe v )
1165
1170
}
1166
- | RuleWithOldValue (k -> NormalizedFilePath -> Value v -> Action (Maybe BS. ByteString , IdeResult v ))
1171
+ | RuleWithOldValue (k -> InputPath i -> Value v -> Action (Maybe BS. ByteString , IdeResult v ))
1167
1172
1168
1173
-- | Define a new Rule with early cutoff
1169
1174
defineEarlyCutoff
1170
- :: IdeRule k v
1175
+ :: IdeRule k i is v
1171
1176
=> Recorder (WithPriority Log )
1172
- -> RuleBody k v
1177
+ -> RuleBody k i v
1173
1178
-> Rules ()
1174
1179
defineEarlyCutoff recorder (Rule op) = addRule $ \ (Q (key, file)) (old :: Maybe BS. ByteString ) mode -> otTracedAction key file mode traceA $ \ traceDiagnostics -> do
1175
1180
extras <- getShakeExtras
@@ -1197,32 +1202,33 @@ defineEarlyCutoff recorder (RuleWithOldValue op) = addRule $ \(Q (key, file)) (o
1197
1202
updateFileDiagnostics recorder file ver (newKey key) extras . map (\ (_,y,z) -> (y,z)) $ diags
1198
1203
defineEarlyCutoff' diagnostics (==) key file old mode $ op key file
1199
1204
1200
- defineNoFile :: IdeRule k v => Recorder (WithPriority Log ) -> (k -> Action v ) -> Rules ()
1205
+ defineNoFile :: IdeRule k i is v => Recorder (WithPriority Log ) -> (k -> Action v ) -> Rules ()
1201
1206
defineNoFile recorder f = defineNoDiagnostics recorder $ \ k file -> do
1202
1207
if file == emptyFilePath then do res <- f k; return (Just res) else
1203
1208
fail $ " Rule " ++ show k ++ " should always be called with the empty string for a file"
1204
1209
1205
- defineEarlyCutOffNoFile :: IdeRule k v => Recorder (WithPriority Log ) -> (k -> Action (BS. ByteString , v )) -> Rules ()
1206
- defineEarlyCutOffNoFile recorder f = defineEarlyCutoff recorder $ RuleNoDiagnostics $ \ k file -> do
1210
+ defineEarlyCutOffNoFile :: IdeRule k i is v => Recorder (WithPriority Log ) -> (k -> Action (BS. ByteString , v )) -> Rules ()
1211
+ defineEarlyCutOffNoFile recorder f = defineEarlyCutoff recorder $ RuleNoDiagnostics $ \ k ( InputPath file) -> do
1207
1212
if file == emptyFilePath then do (hashString, res) <- f k; return (Just hashString, Just res) else
1208
1213
fail $ " Rule " ++ show k ++ " should always be called with the empty string for a file"
1209
1214
1210
1215
defineEarlyCutoff'
1211
- :: forall k v . IdeRule k v
1216
+ :: forall k i is v . IdeRule k i is v
1212
1217
=> (Maybe Int32 -> [FileDiagnostic ] -> Action () ) -- ^ update diagnostics
1213
1218
-- | compare current and previous for freshness
1214
1219
-> (BS. ByteString -> BS. ByteString -> Bool )
1215
1220
-> k
1216
- -> NormalizedFilePath
1221
+ -> InputPath i
1217
1222
-> Maybe BS. ByteString
1218
1223
-> RunMode
1219
1224
-> (Value v -> Action (Maybe BS. ByteString , IdeResult v ))
1220
1225
-> Action (RunResult (A (RuleResult k )))
1221
1226
defineEarlyCutoff' doDiagnostics cmp key file mbOld mode action = do
1227
+ let rawFile = unInputPath file
1222
1228
ShakeExtras {state, progress, dirtyKeys} <- getShakeExtras
1223
1229
options <- getIdeOptions
1224
1230
let trans g x = withRunInIO $ \ run -> g (run x)
1225
- (if optSkipProgress options key then id else trans (inProgress progress file )) $ do
1231
+ (if optSkipProgress options key then id else trans (inProgress progress rawFile )) $ do
1226
1232
val <- case mbOld of
1227
1233
Just old | mode == RunDependenciesSame -> do
1228
1234
mbValue <- liftIO $ atomicallyNamed " define - read 1" $ getValues state key file
@@ -1249,7 +1255,7 @@ defineEarlyCutoff' doDiagnostics cmp key file mbOld mode action = do
1249
1255
(mbBs, (diags, mbRes)) <- actionCatch
1250
1256
(do v <- action staleV; liftIO $ evaluate $ force v) $
1251
1257
\ (e :: SomeException ) -> do
1252
- pure (Nothing , ([ideErrorText file $ T. pack $ show e | not $ isBadDependency e],Nothing ))
1258
+ pure (Nothing , ([ideErrorText rawFile $ T. pack $ show e | not $ isBadDependency e],Nothing ))
1253
1259
1254
1260
ver <- estimateFileVersionUnsafely key mbRes file
1255
1261
(bs, res) <- case mbRes of
@@ -1270,7 +1276,7 @@ defineEarlyCutoff' doDiagnostics cmp key file mbOld mode action = do
1270
1276
-- this hook needs to be run in the same transaction as the key is marked clean
1271
1277
-- see Note [Housekeeping rule cache and dirty key outside of hls-graph]
1272
1278
setValues state key file res (Vector. fromList diags)
1273
- modifyTVar' dirtyKeys (deleteKeySet $ toKey key file )
1279
+ modifyTVar' dirtyKeys (deleteKeySet $ toKey key rawFile )
1274
1280
return res
1275
1281
where
1276
1282
-- Highly unsafe helper to compute the version of a file
@@ -1279,10 +1285,10 @@ defineEarlyCutoff' doDiagnostics cmp key file mbOld mode action = do
1279
1285
estimateFileVersionUnsafely
1280
1286
:: k
1281
1287
-> Maybe v
1282
- -> NormalizedFilePath
1288
+ -> InputPath i
1283
1289
-> Action (Maybe FileVersion )
1284
1290
estimateFileVersionUnsafely _k v fp
1285
- | fp == emptyFilePath = pure Nothing
1291
+ | unInputPath fp == emptyFilePath = pure Nothing
1286
1292
| Just Refl <- eqT @ k @ GetModificationTime = pure v
1287
1293
-- GetModificationTime depends on these rules, so avoid creating a cycle
1288
1294
| Just Refl <- eqT @ k @ AddWatchedFile = pure Nothing
@@ -1457,9 +1463,10 @@ kickSignal testing lspEnv files msg = when testing $ liftIO $ mRunLspT lspEnv $
1457
1463
toJSON $ map fromNormalizedFilePath files
1458
1464
1459
1465
-- | Add kick start/done signal to rule
1460
- runWithSignal :: (KnownSymbol s0 , KnownSymbol s1 , IdeRule k v ) => Proxy s0 -> Proxy s1 -> [NormalizedFilePath ] -> k -> Action ()
1461
- runWithSignal msgStart msgEnd files rule = do
1466
+ runWithSignal :: (KnownSymbol s0 , KnownSymbol s1 , IdeRule k i is v ) => Proxy s0 -> Proxy s1 -> [InputPath i ] -> k -> Action ()
1467
+ runWithSignal msgStart msgEnd inputFiles rule = do
1468
+ let files = map unInputPath inputFiles
1462
1469
ShakeExtras {ideTesting = Options. IdeTesting testing, lspEnv} <- getShakeExtras
1463
1470
kickSignal testing lspEnv files msgStart
1464
- void $ uses rule files
1471
+ void $ uses rule inputFiles
1465
1472
kickSignal testing lspEnv files msgEnd
0 commit comments