1
1
-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2
2
-- SPDX-License-Identifier: Apache-2.0
3
+ {-# LANGUAGE CPP #-} -- To get precise GHC version
4
+ {-# LANGUAGE TemplateHaskell #-}
3
5
{-# OPTIONS_GHC -Wno-dodgy-imports #-} -- GHC no longer exports def in GHC 8.6 and above
4
6
{-# LANGUAGE DeriveGeneric #-}
5
7
{-# LANGUAGE OverloadedStrings #-}
@@ -28,6 +30,7 @@ import qualified Data.Map.Strict as Map
28
30
import Data.Maybe
29
31
import qualified Data.Text as T
30
32
import qualified Data.Text.IO as T
33
+ import Data.Time.Clock (UTCTime )
31
34
-- import Data.Version
32
35
-- import Development.GitRev
33
36
import Development.IDE.Core.Debouncer
@@ -50,7 +53,7 @@ import DynFlags (gopt_set, gopt_unset,
50
53
updOptLevel )
51
54
import DynFlags (PackageFlag (.. ), PackageArg (.. ))
52
55
import GHC hiding (def )
53
- -- import qualified GHC.Paths
56
+ import GHC.Check ( runTimeVersion , compileTimeVersionFromLibdir )
54
57
-- import GhcMonad
55
58
import HIE.Bios.Cradle
56
59
import HIE.Bios.Environment (addCmdOpts )
@@ -243,10 +246,10 @@ showEvent lock (EventFileDiagnostics (toNormalizedFilePath' -> file) diags) =
243
246
showEvent lock e = withLock lock $ print e
244
247
245
248
246
- cradleToSessionOpts :: Lock -> Cradle a -> FilePath -> IO ComponentOptions
247
- cradleToSessionOpts lock cradle file = do
249
+ cradleToSessionOpts :: Cradle a -> FilePath -> IO ComponentOptions
250
+ cradleToSessionOpts cradle file = do
248
251
let showLine s = putStrLn (" > " ++ s)
249
- cradleRes <- withLock lock $ mask $ \ _ -> runCradle (cradleOptsProg cradle) showLine file
252
+ cradleRes <- runCradle (cradleOptsProg cradle) showLine file
250
253
opts <- case cradleRes of
251
254
CradleSuccess r -> pure r
252
255
CradleFail err -> throwIO err
@@ -271,7 +274,7 @@ targetToFile :: [FilePath] -> TargetId -> IO [NormalizedFilePath]
271
274
targetToFile is (TargetModule mod ) = do
272
275
let fps = [i </> (moduleNameSlashes mod ) -<.> ext | ext <- exts, i <- is ]
273
276
exts = [" hs" , " hs-boot" , " lhs" ]
274
- mapM (fmap ( toNormalizedFilePath') . canonicalizePath) fps
277
+ mapM (fmap toNormalizedFilePath' . canonicalizePath) fps
275
278
targetToFile _ (TargetFile f _) = do
276
279
f' <- canonicalizePath f
277
280
return [(toNormalizedFilePath' f')]
@@ -288,6 +291,7 @@ loadSession dir = liftIO $ do
288
291
hscEnvs <- newVar Map. empty
289
292
-- Mapping from a filepath to HscEnv
290
293
fileToFlags <- newVar Map. empty
294
+
291
295
-- This caches the mapping from Mod.hs -> hie.yaml
292
296
cradleLoc <- memoIO $ \ v -> do
293
297
res <- findCradle v
@@ -301,11 +305,12 @@ loadSession dir = liftIO $ do
301
305
-- If the hieYaml file already has an HscEnv, the new component is
302
306
-- combined with the components in the old HscEnv into a new HscEnv
303
307
-- which contains both.
304
- packageSetup <- return $ \ (hieYaml, opts) -> do
308
+ packageSetup <- return $ \ (hieYaml, cfp, opts) -> do
305
309
-- Parse DynFlags for the newly discovered component
306
310
hscEnv <- emptyHscEnv
307
311
(df, targets) <- evalGhcEnv hscEnv $ do
308
312
setOptions opts (hsc_dflags hscEnv)
313
+ dep_info <- getDependencyInfo (componentDependencies opts)
309
314
-- Now lookup to see whether we are combining with an exisiting HscEnv
310
315
-- or making a new one. The lookup returns the HscEnv and a list of
311
316
-- information about other components loaded into the HscEnv
@@ -318,13 +323,13 @@ loadSession dir = liftIO $ do
318
323
-- We will modify the unitId and DynFlags used for
319
324
-- compilation but these are the true source of
320
325
-- information.
321
- new_deps = (thisInstalledUnitId df, df, targets) : maybe [] snd oldDeps
326
+ new_deps = (thisInstalledUnitId df, df, targets, cfp, dep_info ) : maybe [] snd oldDeps
322
327
-- Get all the unit-ids for things in this component
323
- inplace = map (\ (a, _, _) -> a) new_deps
328
+ inplace = map (\ (a, _, _, _, _ ) -> a) new_deps
324
329
-- Remove all inplace dependencies from package flags for
325
330
-- components in this HscEnv
326
- rearrange (uid, (df, uids), ts) = (uid, (df, uids, ts))
327
- do_one (uid,df, ts) = rearrange (uid, removeInplacePackages inplace df, ts)
331
+ rearrange (uid, (df, uids), ts, cfp, di ) = (uid, (df, uids, ts, cfp, di ))
332
+ do_one (uid,df, ts, cfp, di ) = rearrange (uid, removeInplacePackages inplace df, ts, cfp, di )
328
333
-- All deps, but without any packages which are also loaded
329
334
-- into memory
330
335
new_deps' = map do_one new_deps
@@ -352,62 +357,106 @@ loadSession dir = liftIO $ do
352
357
pure (Map. insert hieYaml (newHscEnv, new_deps) m, (newHscEnv, head new_deps', tail new_deps'))
353
358
354
359
355
- session <- return $ \ (hieYaml, opts) -> do
356
- (hscEnv, new, old_deps) <- packageSetup (hieYaml, opts)
360
+ session <- return $ \ (hieYaml, cfp, opts) -> do
361
+ (hscEnv, new, old_deps) <- packageSetup (hieYaml, cfp, opts)
357
362
-- TODO Handle the case where there is no hie.yaml
358
363
-- Make a map from unit-id to DynFlags, this is used when trying to
359
364
-- resolve imports.
360
- let uids = map (\ (iuid, (df, _uis, _targets)) -> (iuid, df)) (new : old_deps)
365
+ let uids = map (\ (iuid, (df, _uis, _targets, _cfp, _di )) -> (iuid, df)) (new : old_deps)
361
366
362
367
-- For each component, now make a new HscEnvEq which contains the
363
368
-- HscEnv for the hie.yaml file but the DynFlags for that component
364
369
--
365
370
-- Then look at the targets for each component and create a map
366
371
-- from FilePath to the HscEnv
367
- let new_cache (_iuid, (df, _uis, targets)) = do
372
+ let new_cache (_iuid, (df, _uis, targets, cfp, di )) = do
368
373
let hscEnv' = hscEnv { hsc_dflags = df
369
374
, hsc_IC = (hsc_IC hscEnv) { ic_dflags = df } }
370
375
371
- res <- newHscEnvEq hscEnv' uids
376
+ versionMismatch <- evalGhcEnv hscEnv' checkGhcVersion
377
+ henv <- case versionMismatch of
378
+ Just mismatch -> return mismatch
379
+ Nothing -> newHscEnvEq hscEnv' uids
380
+ let res = (henv, di)
381
+ print res
372
382
373
383
let is = importPaths df
374
384
ctargets <- concatMapM (targetToFile is . targetId) targets
385
+ -- A special target for the file which caused this wonderful
386
+ -- component to be created.
387
+ let special_target = (cfp, res)
375
388
-- pprTraceM "TARGETS" (ppr (map (text . show) ctargets))
376
389
let xs = map (,res) ctargets
377
- return (xs, res)
390
+ return (special_target : xs, res)
378
391
379
392
-- New HscEnv for the component in question
380
393
(cs, res) <- new_cache new
381
394
-- Modified cache targets for everything else in the hie.yaml file
382
395
-- which now uses the same EPS and so on
383
396
cached_targets <- concatMapM (fmap fst . new_cache) old_deps
384
397
modifyVar_ fileToFlags $ \ var -> do
385
- pure $ Map. insert hieYaml (HM. fromList (cs ++ cached_targets))var
398
+ pure $ Map. insert hieYaml (HM. fromList (cs ++ cached_targets)) var
399
+
386
400
return res
387
401
388
402
lock <- newLock
389
403
cradle_lock <- newLock
390
404
391
405
-- This caches the mapping from hie.yaml + Mod.hs -> [String]
392
406
sessionOpts <- return $ \ (hieYaml, file) -> do
407
+
408
+
393
409
fm <- readVar fileToFlags
394
410
let mv = Map. lookup hieYaml fm
395
411
let v = fromMaybe HM. empty mv
396
412
cfp <- liftIO $ canonicalizePath file
413
+ case HM. lookup (toNormalizedFilePath' cfp) v of
414
+ Just (_, old_di) -> do
415
+ deps_ok <- checkDependencyInfo old_di
416
+ unless deps_ok $ do
417
+ modifyVar_ fileToFlags (const (return Map. empty))
418
+ -- Keep the same name cache
419
+ modifyVar_ hscEnvs (return . Map. adjust (\ (h, _) -> (h, [] )) hieYaml )
420
+ Nothing -> return ()
397
421
-- We sort so exact matches come first.
398
422
case HM. lookup (toNormalizedFilePath' cfp) v of
399
423
Just opts -> do
400
424
-- putStrLn $ "Cached component of " <> show file
401
- pure opts
425
+ pure ( fst opts)
402
426
Nothing -> do
403
- putStrLn $ " Shelling out to cabal " <> show file
404
- cradle <- maybe (loadImplicitCradle $ addTrailingPathSeparator dir) loadCradle hieYaml
405
- opts <- cradleToSessionOpts cradle_lock cradle file
406
- print opts
407
- session (hieYaml, opts)
408
- return $ \ file -> liftIO $ withLock lock $ do
409
- hieYaml <- cradleLoc file
410
- sessionOpts (hieYaml, file)
427
+ finished_barrier <- newBarrier
428
+ -- fork a new thread here which won't be killed by shake
429
+ -- throwing an async exception
430
+ void $ forkIO $ withLock cradle_lock $ do
431
+ putStrLn $ " Shelling out to cabal " <> show file
432
+ cradle <- maybe (loadImplicitCradle $ addTrailingPathSeparator dir) loadCradle hieYaml
433
+ opts <- cradleToSessionOpts cradle cfp
434
+ print opts
435
+ res <- fst <$> session (hieYaml, toNormalizedFilePath' cfp, opts)
436
+ signalBarrier finished_barrier res
437
+ waitBarrier finished_barrier
438
+ return $ \ file -> liftIO $ mask_ $ withLock lock $ do
439
+ hieYaml <- cradleLoc file
440
+ sessionOpts (hieYaml, file)
441
+
442
+ checkDependencyInfo :: Map. Map FilePath (Maybe UTCTime ) -> IO Bool
443
+ checkDependencyInfo old_di = do
444
+ di <- getDependencyInfo (Map. keys old_di)
445
+ return (di == old_di)
446
+
447
+
448
+
449
+ getDependencyInfo :: [FilePath ] -> IO (Map. Map FilePath (Maybe UTCTime ))
450
+ getDependencyInfo fs = Map. fromList <$> mapM do_one fs
451
+
452
+ where
453
+ do_one fp = do
454
+ exists <- IO. doesFileExist fp
455
+ if exists
456
+ then do
457
+ mtime <- getModificationTime fp
458
+ return (fp, Just mtime)
459
+ else return (fp, Nothing )
411
460
412
461
-- This function removes all the -package flags which refer to packages we
413
462
-- are going to deal with ourselves. For example, if a executable depends
@@ -497,3 +546,13 @@ getCacheDir opts = IO.getXdgDirectory IO.XdgCache (cacheDir </> opts_hash)
497
546
-- Prefix for the cache path
498
547
cacheDir :: String
499
548
cacheDir = " ghcide"
549
+
550
+ compileTimeGhcVersion :: Version
551
+ compileTimeGhcVersion = $$ (compileTimeVersionFromLibdir getLibdir)
552
+
553
+ checkGhcVersion :: Ghc (Maybe HscEnvEq )
554
+ checkGhcVersion = do
555
+ v <- runTimeVersion
556
+ return $ if v == Just compileTimeGhcVersion
557
+ then Nothing
558
+ else Just GhcVersionMismatch {compileTime = compileTimeGhcVersion, runTime = v}
0 commit comments