Skip to content

Commit 08c3bb6

Browse files
committed
Improve handling of specialTarget
1 parent 477cf79 commit 08c3bb6

File tree

3 files changed

+44
-38
lines changed

3 files changed

+44
-38
lines changed

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

+35-37
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import qualified Data.HashMap.Strict as HM
4242
import Data.IORef
4343
import qualified Data.Set as OS
4444
import Data.List
45+
import Data.List.Extra as L
4546
import qualified Data.List.NonEmpty as NE
4647
import qualified Data.Map.Strict as Map
4748
import Data.Maybe
@@ -501,7 +502,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
501502
packageSetup (hieYaml, cfp, opts, libDir) = do
502503
-- Parse DynFlags for the newly discovered component
503504
hscEnv <- emptyHscEnv ideNc libDir
504-
newTargetDfs <- evalGhcEnv hscEnv $ setOptions opts (hsc_dflags hscEnv)
505+
newTargetDfs <- evalGhcEnv hscEnv $ setOptions cfp opts (hsc_dflags hscEnv)
505506
let deps = componentDependencies opts ++ maybeToList hieYaml
506507
dep_info <- getDependencyInfo deps
507508
-- Now lookup to see whether we are combining with an existing HscEnv
@@ -575,7 +576,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
575576
let this_flags_map = HM.fromList (concatMap toFlagsMap all_targets)
576577

577578
void $ modifyVar' fileToFlags $
578-
Map.insertWith HM.union hieYaml this_flags_map
579+
Map.insert hieYaml this_flags_map
579580
void $ modifyVar' filesMap $
580581
flip HM.union (HM.fromList (zip (map fst $ concatMap toFlagsMap all_targets) (repeat hieYaml)))
581582

@@ -756,7 +757,10 @@ fromTargetId is exts (GHC.TargetModule modName) env dep = do
756757
-- For a 'TargetFile' we consider all the possible module names
757758
fromTargetId _ _ (GHC.TargetFile f _) env deps = do
758759
nf <- toNormalizedFilePath' <$> makeAbsolute f
759-
return [TargetDetails (TargetFile nf) env deps [nf]]
760+
let other
761+
| "-boot" `isSuffixOf` f = toNormalizedFilePath' (L.dropEnd 5 $ fromNormalizedFilePath nf)
762+
| otherwise = toNormalizedFilePath' (fromNormalizedFilePath nf ++ "-boot")
763+
return [TargetDetails (TargetFile nf) env deps [nf, other]]
760764

761765
toFlagsMap :: TargetDetails -> [(NormalizedFilePath, (IdeResult HscEnvEq, DependencyInfo))]
762766
toFlagsMap TargetDetails{..} =
@@ -781,8 +785,13 @@ newComponentCache
781785
-> [ComponentInfo]
782786
-> IO [ ([TargetDetails], (IdeResult HscEnvEq, DependencyInfo))]
783787
newComponentCache recorder exts cradlePath cfp hsc_env old_cis new_cis = do
784-
let cis = Map.union (mkMap new_cis) (mkMap old_cis) -- Left biased so prefer new components over old ones
785-
mkMap = Map.fromList . map (\ci -> (componentUnitId ci, ci))
788+
let cis = Map.unionWith unionCIs (mkMap new_cis) (mkMap old_cis)
789+
-- When we have multiple components with the same uid,
790+
-- prefer the new one over the old.
791+
-- However, we might have added some targets to the old unit
792+
-- (see special target), so preserve those
793+
unionCIs new_ci old_ci = new_ci { componentTargets = componentTargets new_ci ++ componentTargets old_ci }
794+
mkMap = Map.fromListWith unionCIs . map (\ci -> (componentUnitId ci, ci))
786795
let dfs = map componentDynFlags $ Map.elems cis
787796
uids = Map.keys cis
788797
hscEnv' <- -- Set up a multi component session with the other units on GHC 9.4
@@ -825,7 +834,7 @@ newComponentCache recorder exts cradlePath cfp hsc_env old_cis new_cis = do
825834
Nothing -> pure ()
826835
Just err -> logWith recorder Error $ LogDLLLoadError err
827836

828-
fmap (addSpecial cfp) $ forM (Map.elems cis) $ \ci -> do
837+
forM (Map.elems cis) $ \ci -> do
829838
let df = componentDynFlags ci
830839
let newFunc = maybe newHscEnvEqPreserveImportPaths newHscEnvEq cradlePath
831840
thisEnv <- do
@@ -859,34 +868,7 @@ newComponentCache recorder exts cradlePath cfp hsc_env old_cis new_cis = do
859868
let mk t = fromTargetId (importPaths df) exts (targetId t) targetEnv targetDepends
860869
ctargets <- concatMapM mk (componentTargets ci)
861870

862-
return (ctargets, res)
863-
where
864-
-- A special target for the file which caused this wonderful
865-
-- component to be created. In case the cradle doesn't list all the targets for
866-
-- the component, in which case things will be horribly broken anyway.
867-
-- Otherwise, we will immediately attempt to reload this module which
868-
-- causes an infinite loop and high CPU usage.
869-
addSpecial cfp xs
870-
| alreadyIncluded = xs
871-
| otherwise = let (as,bs) = break inIncludePath xs
872-
in case bs of
873-
[] ->
874-
-- There is no appropriate target to add the file to, so pick one randomly
875-
case as of
876-
[] -> []
877-
((ctargets,res@(targetEnv, targetDepends)):xs) ->
878-
let x = (TargetDetails (TargetFile cfp) targetEnv targetDepends [cfp] : ctargets, res)
879-
in x:xs
880-
-- There is a component which could have this file in its include path
881-
-- pick one of these components
882-
((ctargets,res@(targetEnv, targetDepends)):bs) ->
883-
let b = (TargetDetails (TargetFile cfp) targetEnv targetDepends [cfp] : ctargets, res)
884-
in as ++ (b:bs)
885-
where
886-
alreadyIncluded = any (any (cfp ==) . concatMap targetLocations . fst) xs
887-
inIncludePath (_,((_, Just env),_)) = any (isParent $ fromNormalizedFilePath cfp) $ maybe [] OS.toList $ envImportPaths env
888-
where
889-
isParent fp parent = any (equalFilePath parent) (map (foldr (</>) "") $ inits $ splitPath fp)
871+
return (L.nubOrdOn targetTarget ctargets, res)
890872

891873
{- Note [Avoiding bad interface files]
892874
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1068,12 +1050,28 @@ addUnit unit_str = liftEwM $ do
10681050
putCmdLineState (unit_str : units)
10691051

10701052
-- | Throws if package flags are unsatisfiable
1071-
setOptions :: GhcMonad m => ComponentOptions -> DynFlags -> m (NE.NonEmpty (DynFlags, [GHC.Target]))
1072-
setOptions (ComponentOptions theOpts compRoot _) dflags = do
1053+
setOptions :: GhcMonad m => NormalizedFilePath -> ComponentOptions -> DynFlags -> m (NE.NonEmpty (DynFlags, [GHC.Target]))
1054+
setOptions cfp (ComponentOptions theOpts compRoot _) dflags = do
10731055
((theOpts',errs,warns),units) <- processCmdLineP unit_flags [] (map noLoc theOpts)
10741056
case NE.nonEmpty units of
10751057
Just us -> initMulti us
1076-
Nothing -> (NE.:| []) <$> initOne (map unLoc theOpts')
1058+
Nothing -> do
1059+
(df, targets) <- initOne (map unLoc theOpts')
1060+
-- A special target for the file which caused this wonderful
1061+
-- component to be created. In case the cradle doesn't list all the targets for
1062+
-- the component, in which case things will be horribly broken anyway.
1063+
-- Otherwise, we will immediately attempt to reload this module which
1064+
-- causes an infinite loop and high CPU usage.
1065+
--
1066+
-- We don't do this when we have multiple components, because each
1067+
-- component better list all targets or there will be anarchy.
1068+
-- It is difficult to know which component to add our file to in
1069+
-- that case.
1070+
-- Multi unit arguments are likely to come from cabal, which
1071+
-- does list all targets.
1072+
abs_fp <- liftIO $ makeAbsolute (fromNormalizedFilePath cfp)
1073+
let special_target = Compat.mkSimpleTarget df abs_fp
1074+
pure $ (df, special_target : targets) NE.:| []
10771075
where
10781076
initMulti unitArgFiles =
10791077
forM unitArgFiles $ \f -> do

ghcide/src/Development/IDE/GHC/Compat/Core.hs

+8
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ module Development.IDE.GHC.Compat.Core (
282282
-- * Driver-Make
283283
Target(..),
284284
TargetId(..),
285+
mkSimpleTarget,
285286
mkModuleGraph,
286287
-- * GHCi
287288
initObjLinker,
@@ -971,3 +972,10 @@ homeModInfoObject = hm_linkable
971972
field_label :: a -> a
972973
field_label = id
973974
#endif
975+
976+
mkSimpleTarget :: DynFlags -> FilePath -> Target
977+
#if MIN_VERSION_ghc(9,3,0)
978+
mkSimpleTarget df fp = Target (TargetFile fp Nothing) True (homeUnitId_ df) Nothing
979+
#else
980+
mkSimpleTarget _ fp = Target (TargetFile fp Nothing) True Nothing
981+
#endif

ghcide/src/Development/IDE/Types/KnownTargets.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import GHC.Generics
1717
type KnownTargets = HashMap Target (HashSet NormalizedFilePath)
1818

1919
data Target = TargetModule ModuleName | TargetFile NormalizedFilePath
20-
deriving ( Eq, Generic, Show )
20+
deriving ( Eq, Ord, Generic, Show )
2121
deriving anyclass (Hashable, NFData)
2222

2323
toKnownFiles :: KnownTargets -> HashSet NormalizedFilePath

0 commit comments

Comments
 (0)