Skip to content

Commit ae6ea9b

Browse files
committed
Two recompilation avoidance related bugs
1. Recompilation avoidance regresses in GHC 9.4 due to interactions between GHC and HLS's implementations. Avoid this by filtering out the information that causes the conflict See https://gitlab.haskell.org/ghc/ghc/-/issues/22744. 2. The recompilation avoidance info GHC stores in interfaces can blow up to be extremely large when deserialised from disk. See https://gitlab.haskell.org/ghc/ghc/-/issues/22744 Deduplicate these filepaths.
1 parent ddc67b2 commit ae6ea9b

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

.hlint.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
within:
5656
- Development.IDE.Core.Shake
5757
- Development.IDE.GHC.Util
58+
- Development.IDE.Core.FileStore
5859
- Development.IDE.Plugin.CodeAction.Util
5960
- Development.IDE.Graph.Internal.Database
6061
- Development.IDE.Graph.Internal.Paths

ghcide/src/Development/IDE/Core/Compile.hs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ import Data.Time (UTCTime (..))
7070
import Data.Tuple.Extra (dupe)
7171
import Data.Unique as Unique
7272
import Debug.Trace
73-
import Development.IDE.Core.FileStore (resetInterfaceStore)
73+
import Development.IDE.Core.FileStore (resetInterfaceStore, shareFilePath)
7474
import Development.IDE.Core.Preprocessor
7575
import Development.IDE.Core.RuleTypes
7676
import Development.IDE.Core.Shake
@@ -435,6 +435,30 @@ tcRnModule hsc_env tc_helpers pmod = do
435435
-- anywhere. So we zero it out.
436436
-- The field is not serialized or deserialised from disk, so we don't need to remove it
437437
-- while reading an iface from disk, only if we just generated an iface in memory
438+
--
439+
440+
441+
442+
-- | See https://github.com/haskell/haskell-language-server/issues/3450
443+
-- GHC's recompilation avoidance in the presense of TH is less precise than
444+
-- HLS. To avoid GHC from pessimising HLS, we filter out certain dependency information
445+
-- that we track ourselves. See also Note [Recompilation avoidance in the presence of TH]
446+
filterUsages :: [Usage] -> [Usage]
447+
#if MIN_VERSION_ghc(9,3,0)
448+
filterUsages = filter $ \case UsageHomeModuleInterface{} -> False
449+
_ -> True
450+
#else
451+
filterUsages = id
452+
#endif
453+
454+
-- | Mitigation for https://gitlab.haskell.org/ghc/ghc/-/issues/22744
455+
shareUsages :: ModIface -> ModIface
456+
shareUsages iface = iface {mi_usages = usages}
457+
where usages = map go (mi_usages iface)
458+
go usg@UsageFile{} = usg {usg_file_path = fp}
459+
where !fp = shareFilePath (usg_file_path usg)
460+
go usg = usg
461+
438462

439463
mkHiFileResultNoCompile :: HscEnv -> TcModuleResult -> IO HiFileResult
440464
mkHiFileResultNoCompile session tcm = do
@@ -444,7 +468,7 @@ mkHiFileResultNoCompile session tcm = do
444468
details <- makeSimpleDetails hsc_env_tmp tcGblEnv
445469
sf <- finalSafeMode (ms_hspp_opts ms) tcGblEnv
446470
iface' <- mkIfaceTc hsc_env_tmp sf details ms tcGblEnv
447-
let iface = iface' { mi_globals = Nothing } -- See Note [Clearing mi_globals after generating an iface]
471+
let iface = iface' { mi_globals = Nothing, mi_usages = filterUsages (mi_usages iface') } -- See Note [Clearing mi_globals after generating an iface]
448472
pure $! mkHiFileResult ms iface details (tmrRuntimeModules tcm) Nothing
449473

450474
mkHiFileResultCompile
@@ -486,7 +510,7 @@ mkHiFileResultCompile se session' tcm simplified_guts = catchErrs $ do
486510
let !partial_iface = force (mkPartialIface session details simplified_guts)
487511
final_iface' <- mkFullIface session partial_iface
488512
#endif
489-
let final_iface = final_iface' {mi_globals = Nothing} -- See Note [Clearing mi_globals after generating an iface]
513+
let final_iface = final_iface' {mi_globals = Nothing, mi_usages = filterUsages (mi_usages final_iface')} -- See Note [Clearing mi_globals after generating an iface]
490514

491515
-- Write the core file now
492516
core_file <- case mguts of
@@ -1462,7 +1486,8 @@ loadInterface session ms linkableNeeded RecompilationInfo{..} = do
14621486
regenerate linkableNeeded
14631487

14641488
case (mb_checked_iface, recomp_iface_reqd) of
1465-
(Just iface, UpToDate) -> do
1489+
(Just iface', UpToDate) -> do
1490+
let iface = shareUsages iface'
14661491
details <- liftIO $ mkDetailsFromIface sessionWithMsDynFlags iface
14671492
-- parse the runtime dependencies from the annotations
14681493
let runtime_deps

ghcide/src/Development/IDE/Core/FileStore.hs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module Development.IDE.Core.FileStore(
1818
getModTime,
1919
isWatchSupported,
2020
registerFileWatches,
21+
shareFilePath,
2122
Log(..)
2223
) where
2324

@@ -28,6 +29,8 @@ import Control.Exception
2829
import Control.Monad.Extra
2930
import Control.Monad.IO.Class
3031
import qualified Data.ByteString as BS
32+
import qualified Data.HashMap.Strict as HashMap
33+
import Data.IORef
3134
import qualified Data.Text as T
3235
import qualified Data.Text.Utf16.Rope as Rope
3336
import Data.Time
@@ -76,6 +79,7 @@ import qualified Language.LSP.Types as LSP
7679
import qualified Language.LSP.Types.Capabilities as LSP
7780
import Language.LSP.VFS
7881
import System.FilePath
82+
import System.IO.Unsafe
7983

8084
data Log
8185
= LogCouldNotIdentifyReverseDeps !NormalizedFilePath
@@ -297,3 +301,17 @@ isWatchSupported = do
297301
, Just True <- _dynamicRegistration
298302
-> True
299303
| otherwise -> False
304+
305+
filePathMap :: IORef (HashMap.HashMap FilePath FilePath)
306+
filePathMap = unsafePerformIO $ newIORef HashMap.empty
307+
{-# NOINLINE filePathMap #-}
308+
309+
shareFilePath :: FilePath -> FilePath
310+
shareFilePath k = unsafePerformIO $ do
311+
atomicModifyIORef' filePathMap $ \km ->
312+
let new_key = HashMap.lookup k km
313+
in case new_key of
314+
Just v -> (km, v)
315+
Nothing -> (HashMap.insert k k km, k)
316+
{-# NOINLINE shareFilePath #-}
317+

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ module Development.IDE.GHC.Compat(
4343
myCoreToStgExpr,
4444
#endif
4545

46+
Usage(..),
47+
4648
FastStringCompat,
4749
bytesFS,
4850
mkFastStringByteString,
@@ -167,9 +169,9 @@ import GHC.Runtime.Context (icInteractiveModule)
167169
import GHC.Unit.Home.ModInfo (HomePackageTable,
168170
lookupHpt)
169171
#if MIN_VERSION_ghc(9,3,0)
170-
import GHC.Unit.Module.Deps (Dependencies(dep_direct_mods))
172+
import GHC.Unit.Module.Deps (Dependencies(dep_direct_mods), Usage(..))
171173
#else
172-
import GHC.Unit.Module.Deps (Dependencies(dep_mods))
174+
import GHC.Unit.Module.Deps (Dependencies(dep_mods), Usage(..))
173175
#endif
174176
#else
175177
import GHC.CoreToByteCode (coreExprToBCOs)

0 commit comments

Comments
 (0)