11-- Copyright (c) 2019 The DAML Authors. All rights reserved.
22-- SPDX-License-Identifier: Apache-2.0
3+ {-# LANGUAGE CPP #-} -- To get precise GHC version
4+ {-# LANGUAGE TemplateHaskell #-}
35{-# OPTIONS_GHC -Wno-dodgy-imports #-} -- GHC no longer exports def in GHC 8.6 and above
46{-# LANGUAGE DeriveGeneric #-}
57{-# LANGUAGE OverloadedStrings #-}
@@ -28,6 +30,7 @@ import qualified Data.Map.Strict as Map
2830import Data.Maybe
2931import qualified Data.Text as T
3032import qualified Data.Text.IO as T
33+ import Data.Time.Clock (UTCTime )
3134-- import Data.Version
3235-- import Development.GitRev
3336import Development.IDE.Core.Debouncer
@@ -50,7 +53,7 @@ import DynFlags (gopt_set, gopt_unset,
5053 updOptLevel )
5154import DynFlags (PackageFlag (.. ), PackageArg (.. ))
5255import GHC hiding (def )
53- -- import qualified GHC.Paths
56+ import GHC.Check ( runTimeVersion , compileTimeVersionFromLibdir )
5457-- import GhcMonad
5558import HIE.Bios.Cradle
5659import HIE.Bios.Environment (addCmdOpts )
@@ -243,10 +246,10 @@ showEvent lock (EventFileDiagnostics (toNormalizedFilePath' -> file) diags) =
243246showEvent lock e = withLock lock $ print e
244247
245248
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
248251 let showLine s = putStrLn (" > " ++ s)
249- cradleRes <- withLock lock $ mask $ \ _ -> runCradle (cradleOptsProg cradle) showLine file
252+ cradleRes <- runCradle (cradleOptsProg cradle) showLine file
250253 opts <- case cradleRes of
251254 CradleSuccess r -> pure r
252255 CradleFail err -> throwIO err
@@ -271,7 +274,7 @@ targetToFile :: [FilePath] -> TargetId -> IO [NormalizedFilePath]
271274targetToFile is (TargetModule mod ) = do
272275 let fps = [i </> (moduleNameSlashes mod ) -<.> ext | ext <- exts, i <- is ]
273276 exts = [" hs" , " hs-boot" , " lhs" ]
274- mapM (fmap ( toNormalizedFilePath') . canonicalizePath) fps
277+ mapM (fmap toNormalizedFilePath' . canonicalizePath) fps
275278targetToFile _ (TargetFile f _) = do
276279 f' <- canonicalizePath f
277280 return [(toNormalizedFilePath' f')]
@@ -288,6 +291,7 @@ loadSession dir = liftIO $ do
288291 hscEnvs <- newVar Map. empty
289292 -- Mapping from a filepath to HscEnv
290293 fileToFlags <- newVar Map. empty
294+
291295 -- This caches the mapping from Mod.hs -> hie.yaml
292296 cradleLoc <- memoIO $ \ v -> do
293297 res <- findCradle v
@@ -301,11 +305,12 @@ loadSession dir = liftIO $ do
301305 -- If the hieYaml file already has an HscEnv, the new component is
302306 -- combined with the components in the old HscEnv into a new HscEnv
303307 -- which contains both.
304- packageSetup <- return $ \ (hieYaml, opts) -> do
308+ packageSetup <- return $ \ (hieYaml, cfp, opts) -> do
305309 -- Parse DynFlags for the newly discovered component
306310 hscEnv <- emptyHscEnv
307311 (df, targets) <- evalGhcEnv hscEnv $ do
308312 setOptions opts (hsc_dflags hscEnv)
313+ dep_info <- getDependencyInfo (componentDependencies opts)
309314 -- Now lookup to see whether we are combining with an exisiting HscEnv
310315 -- or making a new one. The lookup returns the HscEnv and a list of
311316 -- information about other components loaded into the HscEnv
@@ -318,13 +323,13 @@ loadSession dir = liftIO $ do
318323 -- We will modify the unitId and DynFlags used for
319324 -- compilation but these are the true source of
320325 -- information.
321- new_deps = (thisInstalledUnitId df, df, targets) : maybe [] snd oldDeps
326+ new_deps = (thisInstalledUnitId df, df, targets, cfp, dep_info ) : maybe [] snd oldDeps
322327 -- Get all the unit-ids for things in this component
323- inplace = map (\ (a, _, _) -> a) new_deps
328+ inplace = map (\ (a, _, _, _, _ ) -> a) new_deps
324329 -- Remove all inplace dependencies from package flags for
325330 -- 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 )
328333 -- All deps, but without any packages which are also loaded
329334 -- into memory
330335 new_deps' = map do_one new_deps
@@ -352,62 +357,106 @@ loadSession dir = liftIO $ do
352357 pure (Map. insert hieYaml (newHscEnv, new_deps) m, (newHscEnv, head new_deps', tail new_deps'))
353358
354359
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)
357362 -- TODO Handle the case where there is no hie.yaml
358363 -- Make a map from unit-id to DynFlags, this is used when trying to
359364 -- 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)
361366
362367 -- For each component, now make a new HscEnvEq which contains the
363368 -- HscEnv for the hie.yaml file but the DynFlags for that component
364369 --
365370 -- Then look at the targets for each component and create a map
366371 -- 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
368373 let hscEnv' = hscEnv { hsc_dflags = df
369374 , hsc_IC = (hsc_IC hscEnv) { ic_dflags = df } }
370375
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
372382
373383 let is = importPaths df
374384 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)
375388 -- pprTraceM "TARGETS" (ppr (map (text . show) ctargets))
376389 let xs = map (,res) ctargets
377- return (xs, res)
390+ return (special_target : xs, res)
378391
379392 -- New HscEnv for the component in question
380393 (cs, res) <- new_cache new
381394 -- Modified cache targets for everything else in the hie.yaml file
382395 -- which now uses the same EPS and so on
383396 cached_targets <- concatMapM (fmap fst . new_cache) old_deps
384397 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+
386400 return res
387401
388402 lock <- newLock
389403 cradle_lock <- newLock
390404
391405 -- This caches the mapping from hie.yaml + Mod.hs -> [String]
392406 sessionOpts <- return $ \ (hieYaml, file) -> do
407+
408+
393409 fm <- readVar fileToFlags
394410 let mv = Map. lookup hieYaml fm
395411 let v = fromMaybe HM. empty mv
396412 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 ()
397421 -- We sort so exact matches come first.
398422 case HM. lookup (toNormalizedFilePath' cfp) v of
399423 Just opts -> do
400424 -- putStrLn $ "Cached component of " <> show file
401- pure opts
425+ pure ( fst opts)
402426 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 )
411460
412461-- This function removes all the -package flags which refer to packages we
413462-- 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)
497546-- Prefix for the cache path
498547cacheDir :: String
499548cacheDir = " 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