Skip to content

Commit d38af0d

Browse files
wz1000fendormichaelpj
authored
session-loader: Don't loop forever when we don't find a file in any multi component (#4096)
* session-loader: Don't loop forever when we don't find a file in any multi component We add a check for if the current file is a target we know about, and emit a diagnostic if that is the case, refusing to load the file in. This doesn't change the implicit adding of the current file as a target for a single component case, as we need the old behaviour to support bare GHC/Direct cradles where not all targets may be listed. * Update ghcide/session-loader/Development/IDE/Session.hs Co-authored-by: fendor <[email protected]> --------- Co-authored-by: fendor <[email protected]> Co-authored-by: Michael Peyton Jones <[email protected]>
1 parent c3b0b37 commit d38af0d

File tree

1 file changed

+26
-10
lines changed

1 file changed

+26
-10
lines changed

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

+26-10
Original file line numberDiff line numberDiff line change
@@ -585,9 +585,21 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
585585
let new_cache = newComponentCache recorder optExtensions hieYaml _cfp hscEnv
586586
all_target_details <- new_cache old_deps new_deps
587587

588-
let all_targets = concatMap fst all_target_details
589-
590-
let this_flags_map = HM.fromList (concatMap toFlagsMap all_targets)
588+
this_dep_info <- getDependencyInfo $ maybeToList hieYaml
589+
let (all_targets, this_flags_map, this_options)
590+
= case HM.lookup _cfp flags_map' of
591+
Just this -> (all_targets', flags_map', this)
592+
Nothing -> (this_target_details : all_targets', HM.insert _cfp this_flags flags_map', this_flags)
593+
where all_targets' = concat all_target_details
594+
flags_map' = HM.fromList (concatMap toFlagsMap all_targets')
595+
this_target_details = TargetDetails (TargetFile _cfp) this_error_env this_dep_info [_cfp]
596+
this_flags = (this_error_env, this_dep_info)
597+
this_error_env = ([this_error], Nothing)
598+
this_error = ideErrorWithSource (Just "cradle") (Just DiagnosticSeverity_Error) _cfp
599+
$ T.unlines
600+
[ "No cradle target found. Is this file listed in the targets of your cradle?"
601+
, "If you are using a .cabal file, please ensure that this module is listed in either the exposed-modules or other-modules section"
602+
]
591603

592604
void $ modifyVar' fileToFlags $
593605
Map.insert hieYaml this_flags_map
@@ -615,7 +627,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
615627
let !exportsMap' = createExportsMap $ mapMaybe (fmap hirModIface) modIfaces
616628
liftIO $ atomically $ modifyTVar' (exportsMap shakeExtras) (exportsMap' <>)
617629

618-
return $ second Map.keys $ this_flags_map HM.! _cfp
630+
return $ second Map.keys this_options
619631

620632
let consultCradle :: Maybe FilePath -> FilePath -> IO (IdeResult HscEnvEq, [FilePath])
621633
consultCradle hieYaml cfp = do
@@ -810,7 +822,7 @@ newComponentCache
810822
-> HscEnv -- ^ An empty HscEnv
811823
-> [ComponentInfo] -- ^ New components to be loaded
812824
-> [ComponentInfo] -- ^ old, already existing components
813-
-> IO [ ([TargetDetails], (IdeResult HscEnvEq, DependencyInfo))]
825+
-> IO [ [TargetDetails] ]
814826
newComponentCache recorder exts cradlePath _cfp hsc_env old_cis new_cis = do
815827
let cis = Map.unionWith unionCIs (mkMap new_cis) (mkMap old_cis)
816828
-- When we have multiple components with the same uid,
@@ -882,14 +894,13 @@ newComponentCache recorder exts cradlePath _cfp hsc_env old_cis new_cis = do
882894
henv <- createHscEnvEq thisEnv (zip uids dfs)
883895
let targetEnv = (if isBad ci then multi_errs else [], Just henv)
884896
targetDepends = componentDependencyInfo ci
885-
res = ( targetEnv, targetDepends)
886-
logWith recorder Debug $ LogNewComponentCache res
897+
logWith recorder Debug $ LogNewComponentCache (targetEnv, targetDepends)
887898
evaluate $ liftRnf rwhnf $ componentTargets ci
888899

889900
let mk t = fromTargetId (importPaths df) exts (targetId t) targetEnv targetDepends
890901
ctargets <- concatMapM mk (componentTargets ci)
891902

892-
return (L.nubOrdOn targetTarget ctargets, res)
903+
return (L.nubOrdOn targetTarget ctargets)
893904

894905
{- Note [Avoiding bad interface files]
895906
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1081,15 +1092,20 @@ setOptions cfp (ComponentOptions theOpts compRoot _) dflags = do
10811092
-- A special target for the file which caused this wonderful
10821093
-- component to be created. In case the cradle doesn't list all the targets for
10831094
-- the component, in which case things will be horribly broken anyway.
1084-
-- Otherwise, we will immediately attempt to reload this module which
1085-
-- causes an infinite loop and high CPU usage.
1095+
--
1096+
-- When we have a single component that is caused to be loaded due to a
1097+
-- file, we assume the file is part of that component. This is useful
1098+
-- for bare GHC sessions, such as many of the ones used in the testsuite
10861099
--
10871100
-- We don't do this when we have multiple components, because each
10881101
-- component better list all targets or there will be anarchy.
10891102
-- It is difficult to know which component to add our file to in
10901103
-- that case.
10911104
-- Multi unit arguments are likely to come from cabal, which
10921105
-- does list all targets.
1106+
--
1107+
-- If we don't end up with a target for the current file in the end, then
1108+
-- we will report it as an error for that file
10931109
abs_fp <- liftIO $ makeAbsolute (fromNormalizedFilePath cfp)
10941110
let special_target = Compat.mkSimpleTarget df abs_fp
10951111
pure $ (df, special_target : targets) :| []

0 commit comments

Comments
 (0)