Skip to content

Commit 27223eb

Browse files
committed
implement restriction to transitive deps for module graph
1 parent 2a63484 commit 27223eb

File tree

4 files changed

+71
-21
lines changed

4 files changed

+71
-21
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,12 @@ typecheckParents :: Recorder (WithPriority Log) -> IdeState -> NormalizedFilePat
262262
typecheckParents recorder state nfp = void $ shakeEnqueue (shakeExtras state) parents
263263
where parents = mkDelayedAction "ParentTC" L.Debug (typecheckParentsAction recorder nfp)
264264

265+
266+
useReverseTransDeps :: NormalizedFilePath -> Action (Maybe [NormalizedFilePath])
267+
useReverseTransDeps file = transitiveReverseDependencies file <$> useWithSeparateFingerprintRule_ GetModuleGraphTransDepsFingerprints GetModuleGraph file
265268
typecheckParentsAction :: Recorder (WithPriority Log) -> NormalizedFilePath -> Action ()
266269
typecheckParentsAction recorder nfp = do
267-
revs <- transitiveReverseDependencies nfp <$> useWithSeparateFingerprintRule_ GetModuleGraphTransReverseDepsFingerprints GetModuleGraph nfp
270+
revs <- useReverseTransDeps nfp
268271
case revs of
269272
Nothing -> logWith recorder Info $ LogCouldNotIdentifyReverseDeps nfp
270273
Just rs -> do

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

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module Development.IDE.Core.Rules(
1212
-- * Types
1313
IdeState, GetParsedModule(..), TransitiveDependencies(..),
1414
GhcSessionIO(..), GetClientSettings(..),
15+
useTransDepModuleGraph,
1516
-- * Functions
1617
runAction,
1718
toIdeResult,
@@ -472,7 +473,7 @@ rawDependencyInformation fs = do
472473
reportImportCyclesRule :: Recorder (WithPriority Log) -> Rules ()
473474
reportImportCyclesRule recorder =
474475
defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \ReportImportCycles file -> fmap (\errs -> if null errs then (Just "1",([], Just ())) else (Nothing, (errs, Nothing))) $ do
475-
DependencyInformation{..} <- useWithSeparateFingerprintRule_ GetModuleGraphTransDepsFingerprints GetModuleGraph file
476+
DependencyInformation {depErrorNodes, depPathIdMap} <- useTransDepModuleGraph file
476477
case pathToId depPathIdMap file of
477478
-- The header of the file does not parse, so it can't be part of any import cycles.
478479
Nothing -> pure []
@@ -633,17 +634,17 @@ dependencyInfoForFiles fs = do
633634
(rawDepInfo, bm) <- rawDependencyInformation fs
634635
let (all_fs, _all_ids) = unzip $ HM.toList $ pathToIdMap $ rawPathIdMap rawDepInfo
635636
msrs <- uses GetModSummaryWithoutTimestamps all_fs
636-
let mss = map (fmap msrModSummary) msrs
637+
let mss = zip _all_ids $ map (fmap msrModSummary) msrs
637638
let deps = map (\i -> IM.lookup (getFilePathId i) (rawImports rawDepInfo)) _all_ids
638-
nodeKeys = IM.fromList $ catMaybes $ zipWith (\fi mms -> (getFilePathId fi,) . NodeKey_Module . msKey <$> mms) _all_ids mss
639+
nodeKeys = IM.fromList $ catMaybes $ zipWith (\fi (_, mms) -> (getFilePathId fi,) . NodeKey_Module . msKey <$> mms) _all_ids mss
639640
mns = catMaybes $ zipWith go mss deps
640-
go (Just ms) (Just (Right (ModuleImports xs))) = Just $ ModuleNode this_dep_keys ms
641+
go (pid,Just ms) (Just (Right (ModuleImports xs))) = Just $ (pid, ModuleNode this_dep_keys ms)
641642
where this_dep_ids = mapMaybe snd xs
642643
this_dep_keys = mapMaybe (\fi -> IM.lookup (getFilePathId fi) nodeKeys) this_dep_ids
643-
go (Just ms) _ = Just $ ModuleNode [] ms
644+
go (pid, Just ms) _ = Just $ (pid, ModuleNode [] ms)
644645
go _ _ = Nothing
645-
mg = mkModuleGraph mns
646-
let shallowFingers = IntMap.fromList $ foldr' (\(i, m) acc -> case m of
646+
mg = IntMap.fromList $ map (first getFilePathId) mns
647+
let shallowFingers = IntMap.fromList $! foldr' (\(i, m) acc -> case m of
647648
Just x -> (getFilePathId i,msrFingerprint x):acc
648649
Nothing -> acc) [] $ zip _all_ids msrs
649650
pure (fingerprintToBS $ Util.fingerprintFingerprints $ map (maybe fingerprint0 msrFingerprint) msrs, processDependencyInformation rawDepInfo bm mg shallowFingers)
@@ -663,7 +664,7 @@ typeCheckRuleDefinition hsc pm fp = do
663664
unlift <- askUnliftIO
664665
let dets = TypecheckHelpers
665666
{ getLinkables = unliftIO unlift . uses_ GetLinkable
666-
, getModuleGraph = unliftIO unlift $ useWithSeparateFingerprintRule_ GetModuleGraphTransDepsFingerprints GetModuleGraph fp
667+
, getModuleGraph = unliftIO unlift $ useTransDepModuleGraph fp
667668
}
668669
addUsageDependencies $ liftIO $
669670
typecheckModule defer hsc dets pm
@@ -735,6 +736,11 @@ instance Default GhcSessionDepsConfig where
735736
{ fullModuleGraph = True
736737
}
737738

739+
useTransDepModuleGraph :: NormalizedFilePath -> Action DependencyInformation
740+
useTransDepModuleGraph file = filterDependencyInformationReachable file <$> useWithSeparateFingerprintRule_ GetModuleGraphTransDepsFingerprints GetModuleGraph file
741+
useImmediateDepsModuleGraph :: NormalizedFilePath -> Action (Maybe DependencyInformation)
742+
useImmediateDepsModuleGraph file = useWithSeparateFingerprintRule GetModuleGraphTransDepsFingerprints GetModuleGraph file
743+
738744
-- | Note [GhcSessionDeps]
739745
-- ~~~~~~~~~~~~~~~~~~~~~
740746
-- For a file 'Foo', GhcSessionDeps "Foo.hs" results in an HscEnv which includes
@@ -760,10 +766,10 @@ ghcSessionDepsDefinition fullModSummary GhcSessionDepsConfig{..} env file = do
760766
depSessions <- map hscEnv <$> uses_ (GhcSessionDeps_ fullModSummary) deps
761767
ifaces <- uses_ GetModIface deps
762768
let inLoadOrder = map (\HiFileResult{..} -> HomeModInfo hirModIface hirModDetails emptyHomeModInfoLinkable) ifaces
763-
de <- useWithSeparateFingerprintRule_ GetModuleGraphTransDepsFingerprints GetModuleGraph file
764-
mg <- do
769+
de <- useTransDepModuleGraph file
770+
mg <- mkModuleGraph <$> do
765771
if fullModuleGraph
766-
then return $ depModuleGraph de
772+
then return $ IntMap.elems $ depModuleGraph de
767773
else do
768774
let mgs = map hsc_mod_graph depSessions
769775
-- On GHC 9.4+, the module graph contains not only ModSummary's but each `ModuleNode` in the graph
@@ -775,7 +781,7 @@ ghcSessionDepsDefinition fullModSummary GhcSessionDepsConfig{..} env file = do
775781
let module_graph_nodes =
776782
nubOrdOn mkNodeKey (ModuleNode final_deps ms : concatMap mgModSummaries' mgs)
777783
liftIO $ evaluate $ liftRnf rwhnf module_graph_nodes
778-
return $ mkModuleGraph module_graph_nodes
784+
return module_graph_nodes
779785
session' <- liftIO $ mergeEnvs hsc mg de ms inLoadOrder depSessions
780786

781787
-- Here we avoid a call to to `newHscEnvEqWithImportPaths`, which creates a new
@@ -805,7 +811,7 @@ getModIfaceFromDiskRule recorder = defineEarlyCutoff (cmapWithPrio LogShake reco
805811
, old_value = m_old
806812
, get_file_version = use GetModificationTime_{missingFileDiagnostics = False}
807813
, get_linkable_hashes = \fs -> map (snd . fromJust . hirCoreFp) <$> uses_ GetModIface fs
808-
, get_module_graph = useWithSeparateFingerprintRule_ GetModuleGraphTransDepsFingerprints GetModuleGraph f
814+
, get_module_graph = useTransDepModuleGraph f
809815
, regenerate = regenerateHiFile session f ms
810816
}
811817
hsc_env' <- setFileCacheHook (hscEnv session)
@@ -1139,7 +1145,7 @@ needsCompilationRule file
11391145
| "boot" `isSuffixOf` fromNormalizedFilePath file =
11401146
pure (Just $ encodeLinkableType Nothing, Just Nothing)
11411147
needsCompilationRule file = do
1142-
graph <- useWithSeparateFingerprintRule GetModuleGraphImmediateReverseDepsFingerprints GetModuleGraph file
1148+
graph <- useImmediateDepsModuleGraph file
11431149
res <- case graph of
11441150
-- Treat as False if some reverse dependency header fails to parse
11451151
Nothing -> pure Nothing

ghcide/src/Development/IDE/Import/DependencyInformation.hs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
module Development.IDE.Import.DependencyInformation
66
( DependencyInformation(..)
7+
, filterDependencyInformationReachable
78
, ModuleImports(..)
89
, RawDependencyInformation(..)
910
, NodeError(..)
@@ -137,6 +138,26 @@ data RawDependencyInformation = RawDependencyInformation
137138
, rawModuleMap :: !(FilePathIdMap ShowableModule)
138139
} deriving Show
139140

141+
filterFilePathIdMap :: (IntMap.Key -> Bool) -> FilePathIdMap a -> FilePathIdMap a
142+
filterFilePathIdMap p = IntMap.filterWithKey (\k _ -> p k)
143+
144+
filterDependencyInformationReachable :: NormalizedFilePath -> DependencyInformation -> DependencyInformation
145+
filterDependencyInformationReachable fileId depInfo@DependencyInformation{..} =
146+
let reachableIds = transitiveDepIds depInfo fileId
147+
curId = getFilePathId <$> lookupPathToId depPathIdMap fileId
148+
isReachable k = IntSet.member k reachableIds || Just k == curId
149+
filterMap = filterFilePathIdMap isReachable
150+
rawModDeps = filterMap depModules
151+
in depInfo {
152+
depErrorNodes = filterMap depErrorNodes
153+
, depModules = rawModDeps
154+
, depModuleDeps = filterMap depModuleDeps
155+
, depReverseModuleDeps = filterMap depReverseModuleDeps
156+
, depBootMap = filterMap depBootMap
157+
, depModuleGraph = filterMap depModuleGraph
158+
, depModuleFiles = ShowableModuleEnv $ mkModuleEnv $ map (\(i,sm) -> (showableModule sm, FilePathId i)) $ IntMap.toList rawModDeps
159+
}
160+
140161
data DependencyInformation =
141162
DependencyInformation
142163
{ depErrorNodes :: !(FilePathIdMap (NonEmpty NodeError))
@@ -153,7 +174,7 @@ data DependencyInformation =
153174
-- ^ Map from hs-boot file to the corresponding hs file
154175
, depModuleFiles :: !(ShowableModuleEnv FilePathId)
155176
-- ^ Map from Module to the corresponding non-boot hs file
156-
, depModuleGraph :: !ModuleGraph
177+
, depModuleGraph :: !(FilePathIdMap ModuleGraphNode)
157178
, depTransDepsFingerprints :: !(FilePathIdMap Fingerprint)
158179
-- ^ Map from Module to fingerprint of the transitive dependencies of the module.
159180
, depTransReverseDepsFingerprints :: !(FilePathIdMap Fingerprint)
@@ -187,7 +208,10 @@ reachableModules DependencyInformation{..} =
187208
map (idToPath depPathIdMap . FilePathId) $ IntMap.keys depErrorNodes <> IntMap.keys depModuleDeps
188209

189210
instance NFData DependencyInformation
190-
211+
instance NFData ModuleGraphNode where
212+
rnf = rwhnf
213+
instance Show (ModuleGraphNode) where
214+
show (_) = "ModuleGraphNode"
191215
-- | This does not contain the actual parse error as that is already reported by GetParsedModule.
192216
data ModuleParseError = ModuleParseError
193217
deriving (Show, Generic)
@@ -243,7 +267,7 @@ instance Semigroup NodeResult where
243267
SuccessNode _ <> ErrorNode errs = ErrorNode errs
244268
SuccessNode a <> SuccessNode _ = SuccessNode a
245269

246-
processDependencyInformation :: RawDependencyInformation -> BootIdMap -> ModuleGraph -> FilePathIdMap Fingerprint -> DependencyInformation
270+
processDependencyInformation :: RawDependencyInformation -> BootIdMap -> FilePathIdMap ModuleGraphNode -> FilePathIdMap Fingerprint -> DependencyInformation
247271
processDependencyInformation RawDependencyInformation{..} rawBootMap mg shallowFingerMap =
248272
DependencyInformation
249273
{ depErrorNodes = IntMap.fromList errorNodes
@@ -359,6 +383,23 @@ immediateReverseDependencies file DependencyInformation{..} = do
359383
FilePathId cur_id <- lookupPathToId depPathIdMap file
360384
return $ map (idToPath depPathIdMap . FilePathId) (maybe mempty IntSet.toList (IntMap.lookup cur_id depReverseModuleDeps))
361385

386+
-- | returns all transitive dependencies ids
387+
transitiveDepIds :: DependencyInformation -> NormalizedFilePath -> IntSet.IntSet
388+
transitiveDepIds DependencyInformation{..} file = fromMaybe mempty $ do
389+
!fileId <- pathToId depPathIdMap file
390+
reachableVs <-
391+
-- Delete the starting node
392+
IntSet.delete (getFilePathId fileId) .
393+
IntSet.fromList . map (fst3 . fromVertex) .
394+
reachable g <$> toVertex (getFilePathId fileId)
395+
let transitiveModuleDepIds = IntSet.fromList $ filter (\v -> v `IntSet.member` reachableVs) $ map (fst3 . fromVertex) vs
396+
return transitiveModuleDepIds
397+
where
398+
(g, fromVertex, toVertex) = graphFromEdges edges
399+
edges = map (\(f, fs) -> (f, f, IntSet.toList fs ++ boot_edge f)) $ IntMap.toList depModuleDeps
400+
boot_edge f = [getFilePathId f' | Just f' <- [IntMap.lookup f depBootMap]]
401+
vs = vertices g
402+
362403
-- | returns all transitive dependencies in topological order.
363404
transitiveDeps :: DependencyInformation -> NormalizedFilePath -> Maybe TransitiveDependencies
364405
transitiveDeps DependencyInformation{..} file = do
@@ -372,7 +413,7 @@ transitiveDeps DependencyInformation{..} file = do
372413
filter (\v -> v `IntSet.member` reachableVs) $ map (fst3 . fromVertex) vs
373414
let transitiveModuleDeps =
374415
map (idToPath depPathIdMap . FilePathId) transitiveModuleDepIds
375-
pure TransitiveDependencies {..}
416+
pure TransitiveDependencies {transitiveModuleDeps}
376417
where
377418
(g, fromVertex, toVertex) = graphFromEdges edges
378419
edges = map (\(f, fs) -> (f, f, IntSet.toList fs ++ boot_edge f)) $ IntMap.toList depModuleDeps

plugins/hls-eval-plugin/src/Ide/Plugin/Eval/Handlers.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import qualified Data.Text as T
4343
import qualified Data.Text.Utf16.Rope.Mixed as Rope
4444
import Development.IDE.Core.FileStore (getUriContents, setSomethingModified)
4545
import Development.IDE.Core.Rules (IdeState,
46-
runAction)
46+
runAction, useTransDepModuleGraph)
4747
import Development.IDE.Core.Shake (use_, uses_, VFSModified (VFSUnmodified), useWithSeparateFingerprintRule_)
4848
import Development.IDE.GHC.Compat hiding (typeKind,
4949
unitState)
@@ -253,7 +253,7 @@ initialiseSessionForEval needs_quickcheck st nfp = do
253253
ms <- msrModSummary <$> use_ GetModSummary nfp
254254
deps_hsc <- hscEnv <$> use_ GhcSessionDeps nfp
255255

256-
linkables_needed <- transitiveDeps <$> useWithSeparateFingerprintRule_ GetModuleGraphTransDepsFingerprints GetModuleGraph nfp <*> pure nfp
256+
linkables_needed <- transitiveDeps <$> useTransDepModuleGraph nfp <*> pure nfp
257257
linkables <- uses_ GetLinkable (nfp : maybe [] transitiveModuleDeps linkables_needed)
258258
-- We unset the global rdr env in mi_globals when we generate interfaces
259259
-- See Note [Clearing mi_globals after generating an iface]

0 commit comments

Comments
 (0)