@@ -85,6 +85,9 @@ import Database.SQLite.Simple
85
85
import HieDb.Create
86
86
import HieDb.Types
87
87
import HieDb.Utils
88
+ import Ide.Types (dynFlagsModifyGlobal )
89
+ import Data.List.NonEmpty (NonEmpty )
90
+ import qualified Data.List.NonEmpty as NE
88
91
89
92
-- | Bump this version number when making changes to the format of the data stored in hiedb
90
93
hiedbDataVersion :: String
@@ -230,7 +233,9 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
230
233
filesMap <- newVar HM. empty :: IO (Var FilesMap )
231
234
-- Version of the mappings above
232
235
version <- newVar 0
233
- let returnWithVersion fun = IdeGhcSession fun <$> liftIO (readVar version)
236
+ let returnWithVersion :: (FilePath -> IO (IdeResult HscEnvEq , [FilePath ]))
237
+ -> Action IdeGhcSession
238
+ returnWithVersion fun = (IdeGhcSession fun) <$> liftIO (readVar version)
234
239
-- This caches the mapping from Mod.hs -> hie.yaml
235
240
cradleLoc <- liftIO $ memoIO $ \ v -> do
236
241
res <- findCradle v
@@ -277,9 +282,9 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
277
282
-- If the hieYaml file already has an HscEnv, the new component is
278
283
-- combined with the components in the old HscEnv into a new HscEnv
279
284
-- which contains the union.
280
- let packageSetup :: (Maybe FilePath , NormalizedFilePath , ComponentOptions , FilePath )
281
- -> IO (HscEnv , ComponentInfo , [ComponentInfo ])
282
- packageSetup (hieYaml, cfp, opts , libDir) = do
285
+ let packageSetup :: (Maybe FilePath , NormalizedFilePath , NonEmpty ComponentOptions , FilePath )
286
+ -> IO [ (HscEnv , ComponentInfo , [ComponentInfo ])]
287
+ packageSetup (hieYaml, cfp, allOpts , libDir) = concatForM ( NE. toList allOpts) $ \ opts -> do
283
288
-- Parse DynFlags for the newly discovered component
284
289
hscEnv <- emptyHscEnv ideNc libDir
285
290
(df, targets) <- evalGhcEnv hscEnv $ setOptions opts (hsc_dflags hscEnv)
@@ -289,7 +294,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
289
294
-- or making a new one. The lookup returns the HscEnv and a list of
290
295
-- information about other components loaded into the HscEnv
291
296
-- (unitId, DynFlag, Targets)
292
- modifyVar hscEnvs $ \ m -> do
297
+ r <- modifyVar hscEnvs $ \ m -> do
293
298
-- Just deps if there's already an HscEnv
294
299
-- Nothing is it's the first time we are making an HscEnv
295
300
let oldDeps = Map. lookup hieYaml m
@@ -343,12 +348,13 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
343
348
-- . The modified information (without -inplace flags) for
344
349
-- existing packages
345
350
pure (Map. insert hieYaml (newHscEnv, new_deps) m, (newHscEnv, head new_deps', tail new_deps'))
351
+ pure [r]
346
352
347
353
348
- let session :: (Maybe FilePath , NormalizedFilePath , ComponentOptions , FilePath )
354
+ let session :: (Maybe FilePath , NormalizedFilePath , NonEmpty ComponentOptions , FilePath )
349
355
-> IO (IdeResult HscEnvEq ,[FilePath ])
350
- session args@ (hieYaml, _cfp , _opts, _libDir) = do
351
- (hscEnv , new, old_deps) <- packageSetup args
356
+ session args@ (hieYaml, cfp , _opts, _libDir) = do
357
+ setupInfos <- packageSetup args -- (hscEnvs , new, old_deps)
352
358
353
359
-- Whenever we spin up a session on Linux, dynamically load libm.so.6
354
360
-- in. We need this in case the binary is statically linked, in which
@@ -358,58 +364,73 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
358
364
-- some code. If the binary is dynamically linked, then this will have
359
365
-- no effect.
360
366
-- See https://github.com/haskell/haskell-language-server/issues/221
361
- when (os == " linux" ) $ do
362
- initObjLinker hscEnv
363
- res <- loadDLL hscEnv " libm.so.6"
364
- case res of
365
- Nothing -> pure ()
366
- Just err -> hPutStrLn stderr $
367
- " Error dynamically loading libm.so.6:\n " <> err
368
-
369
- -- Make a map from unit-id to DynFlags, this is used when trying to
370
- -- resolve imports. (especially PackageImports)
371
- let uids = map (\ ci -> (componentUnitId ci, componentDynFlags ci)) (new : old_deps)
372
-
373
- -- For each component, now make a new HscEnvEq which contains the
374
- -- HscEnv for the hie.yaml file but the DynFlags for that component
375
-
376
- -- New HscEnv for the component in question, returns the new HscEnvEq and
377
- -- a mapping from FilePath to the newly created HscEnvEq.
378
- let new_cache = newComponentCache logger optExtensions hieYaml _cfp hscEnv uids
379
- (cs, res) <- new_cache new
380
- -- Modified cache targets for everything else in the hie.yaml file
381
- -- which now uses the same EPS and so on
382
- cached_targets <- concatMapM (fmap fst . new_cache) old_deps
383
-
384
- let all_targets = cs ++ cached_targets
385
-
386
- void $ modifyVar' fileToFlags $
387
- Map. insert hieYaml (HM. fromList (concatMap toFlagsMap all_targets))
388
- void $ modifyVar' filesMap $
389
- flip HM. union (HM. fromList (zip (map fst $ concatMap toFlagsMap all_targets) (repeat hieYaml)))
390
-
391
- void $ extendKnownTargets all_targets
392
-
393
- -- Invalidate all the existing GhcSession build nodes by restarting the Shake session
394
- invalidateShakeCache
395
- restartShakeSession []
396
-
397
- -- Typecheck all files in the project on startup
398
- checkProject <- getCheckProject
399
- unless (null cs || not checkProject) $ do
400
- cfps' <- liftIO $ filterM (IO. doesFileExist . fromNormalizedFilePath) (concatMap targetLocations cs)
401
- void $ shakeEnqueue extras $ mkDelayedAction " InitialLoad" Debug $ void $ do
402
- mmt <- uses GetModificationTime cfps'
403
- let cs_exist = catMaybes (zipWith (<$) cfps' mmt)
404
- modIfaces <- uses GetModIface cs_exist
405
- -- update exports map
406
- extras <- getShakeExtras
407
- let ! exportsMap' = createExportsMap $ mapMaybe (fmap hirModIface) modIfaces
408
- liftIO $ modifyVar_ (exportsMap extras) $ evaluate . (exportsMap' <> )
409
-
410
- return (second Map. keys res)
411
-
412
- let consultCradle :: Maybe FilePath -> FilePath -> IO (IdeResult HscEnvEq , [FilePath ])
367
+ forM_ setupInfos $ \ (hscEnv, new, old_deps) -> do
368
+ when (os == " linux" ) $ do
369
+ initObjLinker hscEnv
370
+ res <- loadDLL hscEnv " libm.so.6"
371
+ case res of
372
+ Nothing -> pure ()
373
+ Just err -> hPutStrLn stderr $
374
+ " Error dynamically loading libm.so.6:\n " <> err
375
+
376
+ -- Make a map from unit-id to DynFlags, this is used when trying to
377
+ -- resolve imports. (especially PackageImports)
378
+ let uids = map (\ ci -> (componentUnitId ci, componentDynFlags ci)) (new : old_deps)
379
+
380
+ -- For each component, now make a new HscEnvEq which contains the
381
+ -- HscEnv for the hie.yaml file but the DynFlags for that component
382
+
383
+ -- New HscEnv for the component in question, returns the new HscEnvEq and
384
+ -- a mapping from FilePath to the newly created HscEnvEq.
385
+ let new_cache = newComponentCache logger optExtensions hieYaml cfp hscEnv uids
386
+ (cs, _res) <- new_cache new
387
+ -- Modified cache targets for everything else in the hie.yaml file
388
+ -- which now uses the same EPS and so on
389
+ cached_targets <- concatMapM (fmap fst . new_cache) old_deps
390
+
391
+ let all_targets = cs ++ cached_targets
392
+
393
+ void $ modifyVar' fileToFlags $
394
+ Map. insert hieYaml (HM. fromList (concatMap toFlagsMap all_targets))
395
+ void $ modifyVar' filesMap $
396
+ flip HM. union (HM. fromList (zip (map fst $ concatMap toFlagsMap all_targets) (repeat hieYaml)))
397
+
398
+ void $ extendKnownTargets all_targets
399
+
400
+ -- Invalidate all the existing GhcSession build nodes by restarting the Shake session
401
+ invalidateShakeCache
402
+ restartShakeSession []
403
+
404
+ -- Typecheck all files in the project on startup
405
+ checkProject <- getCheckProject
406
+ unless (null cs || not checkProject) $ do
407
+ cfps' <- liftIO $ filterM (IO. doesFileExist . fromNormalizedFilePath) (concatMap targetLocations cs)
408
+ void $ shakeEnqueue extras $ mkDelayedAction " InitialLoad" Debug $ void $ do
409
+ mmt <- uses GetModificationTime cfps'
410
+ let cs_exist = catMaybes (zipWith (<$) cfps' mmt)
411
+ modIfaces <- uses GetModIface cs_exist
412
+ -- update exports map
413
+ extras <- getShakeExtras
414
+ let ! exportsMap' = createExportsMap $ mapMaybe (fmap hirModIface) modIfaces
415
+ liftIO $ modifyVar_ (exportsMap extras) $ evaluate . (exportsMap' <> )
416
+
417
+ yamlMap <- readVar fileToFlags
418
+ let (hscEnvEq, depInfo) = (yamlMap Map. ! hieYaml) HM. ! cfp
419
+ pure (hscEnvEq, Map. keys depInfo)
420
+
421
+ -- Let's be insanely hacky!
422
+ -- Go through all new components and find the one that the given fp most likely
423
+ -- belongs to.
424
+ -- Since all ComponentInfo's carry a proof for which file caused their creation,
425
+ -- and add this file to their targets, we need to do some post-processing.
426
+ -- It is an implementation detail that the first known target is the normalized
427
+ -- filepath of the proof file.
428
+ -- Let's strip it away and let's see whether the targets still contain 'cfp'!
429
+ -- If they do, it must be the home component of cfp.
430
+ -- If we find it, remove it as a target from all other 'HscEnvEq' to avoid recompilation
431
+ -- issues.
432
+
433
+ let consultCradle :: Maybe FilePath -> FilePath -> IO (IdeResult HscEnvEq ,[FilePath ])
413
434
consultCradle hieYaml cfp = do
414
435
lfp <- flip makeRelative cfp <$> getCurrentDirectory
415
436
logInfo logger $ T. pack (" Consulting the cradle for " <> show lfp)
@@ -441,7 +462,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
441
462
InstallationMismatch {.. } ->
442
463
return (([renderPackageSetupException cfp GhcVersionMismatch {.. }], Nothing ),[] )
443
464
InstallationChecked _compileTime _ghcLibCheck ->
444
- session (hieYaml, toNormalizedFilePath' cfp, opts, libDir)
465
+ session (hieYaml, toNormalizedFilePath' cfp, opts, libDir)
445
466
-- Failure case, either a cradle error or the none cradle
446
467
Left err -> do
447
468
dep_info <- getDependencyInfo (maybeToList hieYaml)
@@ -498,7 +519,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
498
519
-- GHC options/dynflags needed for the session and the GHC library directory
499
520
500
521
cradleToOptsAndLibDir :: Show a => Cradle a -> FilePath
501
- -> IO (Either [CradleError ] (ComponentOptions , FilePath ))
522
+ -> IO (Either [CradleError ] (NonEmpty ComponentOptions , FilePath ))
502
523
cradleToOptsAndLibDir cradle file = do
503
524
-- Start off by getting the session options
504
525
hPutStrLn stderr $ " Output from setting up the cradle " <> show cradle
@@ -574,7 +595,7 @@ newComponentCache
574
595
-> [(InstalledUnitId , DynFlags )]
575
596
-> ComponentInfo
576
597
-> IO ( [TargetDetails ], (IdeResult HscEnvEq , DependencyInfo ))
577
- newComponentCache logger exts cradlePath cfp hsc_env uids ci = do
598
+ newComponentCache logger exts cradlePath _cfp hsc_env uids ci = do
578
599
let df = componentDynFlags ci
579
600
let hscEnv' = hsc_env { hsc_dflags = df
580
601
, hsc_IC = (hsc_IC hsc_env) { ic_dflags = df } }
@@ -594,8 +615,9 @@ newComponentCache logger exts cradlePath cfp hsc_env uids ci = do
594
615
-- the component, in which case things will be horribly broken anyway.
595
616
-- Otherwise, we will immediately attempt to reload this module which
596
617
-- causes an infinite loop and high CPU usage.
597
- let special_target = TargetDetails (TargetFile cfp) targetEnv targetDepends [componentFP ci]
598
- return (special_target: ctargets, res)
618
+ -- let special_target = TargetDetails (TargetFile cfp) targetEnv targetDepends [componentFP ci]
619
+ -- return (special_target:ctargets, res)
620
+ return (ctargets, res)
599
621
600
622
{- Note [Avoiding bad interface files]
601
623
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 commit comments