Skip to content

Commit 64e9525

Browse files
Catch GHC errors in listing module names (#1367)
* Catch GHC errors in listing module names * Move visible module names to HscEnvEq * Make envVisibleModuleNames lazy Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent ad0a154 commit 64e9525

File tree

3 files changed

+35
-12
lines changed

3 files changed

+35
-12
lines changed

ghcide/src/Development/IDE/Plugin/Completions.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ produceCompletions = do
8383
case (global, inScope) of
8484
((_, Just globalEnv), (_, Just inScopeEnv)) -> do
8585
let uri = fromNormalizedUri $ normalizedFilePathToUri file
86-
cdata <- liftIO $ cacheDataProducer uri env (ms_mod ms) globalEnv inScopeEnv imps parsedDeps
86+
cdata <- liftIO $ cacheDataProducer uri sess (ms_mod ms) globalEnv inScopeEnv imps parsedDeps
8787
return ([], Just cdata)
8888
(_diag, _) ->
8989
return ([], Nothing)

ghcide/src/Development/IDE/Plugin/Completions/Logic.hs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import HscTypes
2727
import Name
2828
import RdrName
2929
import Type
30-
import Packages
3130
#if MIN_GHC_API_VERSION(8,10,0)
3231
import Predicate (isDictTy)
3332
import Pair
@@ -59,6 +58,7 @@ import Data.Functor
5958
import Ide.PluginUtils (mkLspCommand)
6059
import Ide.Types (CommandId (..), PluginId, WithSnippets (..))
6160
import Control.Monad
61+
import Development.IDE.Types.HscEnvEq
6262

6363
-- From haskell-ide-engine/hie-plugin-api/Haskell/Ide/Engine/Context.hs
6464

@@ -294,9 +294,10 @@ mkPragmaCompl label insertText =
294294
Nothing Nothing Nothing Nothing Nothing
295295

296296

297-
cacheDataProducer :: Uri -> HscEnv -> Module -> GlobalRdrEnv-> GlobalRdrEnv -> [LImportDecl GhcPs] -> [ParsedModule] -> IO CachedCompletions
298-
cacheDataProducer uri packageState curMod globalEnv inScopeEnv limports deps = do
299-
let dflags = hsc_dflags packageState
297+
cacheDataProducer :: Uri -> HscEnvEq -> Module -> GlobalRdrEnv-> GlobalRdrEnv -> [LImportDecl GhcPs] -> [ParsedModule] -> IO CachedCompletions
298+
cacheDataProducer uri env curMod globalEnv inScopeEnv limports deps = do
299+
let
300+
packageState = hscEnv env
300301
curModName = moduleName curMod
301302

302303
importMap = Map.fromList [ (getLoc imp, imp) | imp <- limports ]
@@ -309,8 +310,6 @@ cacheDataProducer uri packageState curMod globalEnv inScopeEnv limports deps = d
309310
-- Full canonical names of imported modules
310311
importDeclerations = map unLoc limports
311312

312-
-- The list of all importable Modules from all packages
313-
moduleNames = map showModName (listVisibleModuleNames dflags)
314313

315314
-- The given namespaces for the imported modules (ie. full name, or alias if used)
316315
allModNamesAsNS = map (showModName . asNamespace) importDeclerations
@@ -366,6 +365,9 @@ cacheDataProducer uri packageState curMod globalEnv inScopeEnv limports deps = d
366365

367366
(unquals,quals) <- getCompls rdrElts
368367

368+
-- The list of all importable Modules from all packages
369+
moduleNames <- maybe [] (map showModName) <$> envVisibleModuleNames env
370+
369371
return $ CC
370372
{ allModNamesAsNS = allModNamesAsNS
371373
, unqualCompls = unquals

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

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Development.IDE.Types.HscEnvEq
66
newHscEnvEqWithImportPaths,
77
envImportPaths,
88
envPackageExports,
9+
envVisibleModuleNames,
910
deps
1011
) where
1112

@@ -16,7 +17,7 @@ import Development.Shake.Classes
1617
import Module (InstalledUnitId)
1718
import System.Directory (canonicalizePath)
1819
import Development.IDE.GHC.Compat
19-
import GhcPlugins(HscEnv (hsc_dflags), PackageState (explicitPackages), InstalledPackageInfo (exposedModules), Module(..), packageConfigId)
20+
import GhcPlugins(HscEnv (hsc_dflags), PackageState (explicitPackages), InstalledPackageInfo (exposedModules), Module(..), packageConfigId, listVisibleModuleNames)
2021
import System.FilePath
2122
import Development.IDE.GHC.Util (lookupPackageConfig)
2223
import Control.Monad.IO.Class
@@ -27,7 +28,10 @@ import OpenTelemetry.Eventlog (withSpan)
2728
import Control.Monad.Extra (mapMaybeM, join, eitherM)
2829
import Control.Concurrent.Extra (newVar, modifyVar)
2930
import Control.Concurrent.Async (Async, async, waitCatch)
30-
import Control.Exception (throwIO, mask)
31+
import Control.Exception (throwIO, mask, evaluate)
32+
import Development.IDE.GHC.Error (catchSrcErrors)
33+
import Control.DeepSeq (force)
34+
import Data.Either (fromRight)
3135

3236
-- | An 'HscEnv' with equality. Two values are considered equal
3337
-- if they are created with the same call to 'newHscEnvEq'.
@@ -42,6 +46,11 @@ data HscEnvEq = HscEnvEq
4246
-- ^ If Just, import dirs originally configured in this env
4347
-- If Nothing, the env import dirs are unaltered
4448
, envPackageExports :: IO ExportsMap
49+
, envVisibleModuleNames :: IO (Maybe [ModuleName])
50+
-- ^ 'listVisibleModuleNames' is a pure function,
51+
-- but it could panic due to a ghc bug: https://github.com/haskell/haskell-language-server/issues/1365
52+
-- So it's wrapped in IO here for error handling
53+
-- If Nothing, 'listVisibleModuleNames' panic
4554
}
4655

4756
-- | Wrap an 'HscEnv' into an 'HscEnvEq'.
@@ -58,12 +67,15 @@ newHscEnvEq cradlePath hscEnv0 deps = do
5867

5968
newHscEnvEqWithImportPaths :: Maybe [String] -> HscEnv -> [(InstalledUnitId, DynFlags)] -> IO HscEnvEq
6069
newHscEnvEqWithImportPaths envImportPaths hscEnv deps = do
70+
71+
let dflags = hsc_dflags hscEnv
72+
6173
envUnique <- newUnique
6274

6375
-- it's very important to delay the package exports computation
6476
envPackageExports <- onceAsync $ withSpan "Package Exports" $ \_sp -> do
6577
-- compute the package imports
66-
let pkgst = pkgState (hsc_dflags hscEnv)
78+
let pkgst = pkgState dflags
6779
depends = explicitPackages pkgst
6880
targets =
6981
[ (pkg, mn)
@@ -82,6 +94,15 @@ newHscEnvEqWithImportPaths envImportPaths hscEnv deps = do
8294
Maybes.Succeeded mi -> Just mi
8395
modIfaces <- mapMaybeM doOne targets
8496
return $ createExportsMap modIfaces
97+
98+
-- similar to envPackageExports, evaluated lazily
99+
envVisibleModuleNames <- onceAsync $
100+
fromRight Nothing
101+
<$> catchSrcErrors
102+
dflags
103+
"listVisibleModuleNames"
104+
(evaluate . force . Just $ listVisibleModuleNames dflags)
105+
85106
return HscEnvEq{..}
86107

87108
-- | Wrap an 'HscEnv' into an 'HscEnvEq'.
@@ -108,8 +129,8 @@ instance Eq HscEnvEq where
108129
a == b = envUnique a == envUnique b
109130

110131
instance NFData HscEnvEq where
111-
rnf (HscEnvEq a b c d _) =
112-
-- deliberately skip the package exports map
132+
rnf (HscEnvEq a b c d _ _) =
133+
-- deliberately skip the package exports map and visible module names
113134
rnf (hashUnique a) `seq` b `seq` c `seq` rnf d
114135

115136
instance Hashable HscEnvEq where

0 commit comments

Comments
 (0)