Skip to content

Commit 66cf400

Browse files
authored
Merge pull request #3893 from fendor/fix/boot-modules
Generate FileTarget for all possible targetLocations
2 parents bcb83e9 + 86fb77b commit 66cf400

File tree

2 files changed

+60
-15
lines changed

2 files changed

+60
-15
lines changed

ghcide/session-loader/Development/IDE/Session.hs

+32-15
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ import Data.Hashable hiding (hash)
4141
import qualified Data.HashMap.Strict as HM
4242
import Data.IORef
4343
import Data.List
44-
import Data.List.NonEmpty (NonEmpty (..))
4544
import Data.List.Extra as L
45+
import Data.List.NonEmpty (NonEmpty (..))
4646
import qualified Data.List.NonEmpty as NE
4747
import qualified Data.Map.Strict as Map
4848
import Data.Maybe
@@ -113,22 +113,23 @@ import System.Random (RandomGen)
113113

114114
import qualified Development.IDE.Session.Implicit as GhcIde
115115

116-
import Development.IDE.GHC.Compat.CmdLine
116+
import Development.IDE.GHC.Compat.CmdLine
117117

118118

119119
-- See Note [Guidelines For Using CPP In GHCIDE Import Statements]
120120
#if MIN_VERSION_ghc(9,3,0)
121121
import qualified Data.Set as OS
122122

123-
import GHC.Driver.Errors.Types
124-
import GHC.Driver.Env (hscSetActiveUnitId, hsc_all_home_unit_ids)
125-
import GHC.Driver.Make (checkHomeUnitsClosed)
126-
import GHC.Unit.State
127-
import GHC.Types.Error (errMsgDiagnostic)
128-
import GHC.Data.Bag
123+
import GHC.Data.Bag
124+
import GHC.Driver.Env (hscSetActiveUnitId,
125+
hsc_all_home_unit_ids)
126+
import GHC.Driver.Errors.Types
127+
import GHC.Driver.Make (checkHomeUnitsClosed)
128+
import GHC.Types.Error (errMsgDiagnostic)
129+
import GHC.Unit.State
129130
#endif
130131

131-
import GHC.ResponseFile
132+
import GHC.ResponseFile
132133

133134
data Log
134135
= LogSettingInitialDynFlags
@@ -479,12 +480,28 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
479480
-- files in the project so that `knownFiles` can learn about them and
480481
-- we can generate a complete module graph
481482
let extendKnownTargets newTargets = do
482-
knownTargets <- forM newTargets $ \TargetDetails{..} ->
483+
knownTargets <- concatForM newTargets $ \TargetDetails{..} ->
483484
case targetTarget of
484-
TargetFile f -> pure (targetTarget, [f])
485+
TargetFile f -> do
486+
-- If a target file has multiple possible locations, then we
487+
-- assume they are all separate file targets.
488+
-- This happens with '.hs-boot' files if they are in the root directory of the project.
489+
-- GHC reports options such as '-i. A' as 'TargetFile A.hs' instead of 'TargetModule A'.
490+
-- In 'fromTargetId', we dutifully look for '.hs-boot' files and add them to the
491+
-- targetLocations of the TargetDetails. Then we add everything to the 'knownTargetsVar'.
492+
-- However, when we look for a 'Foo.hs-boot' file in 'FindImports.hs', we look for either
493+
--
494+
-- * TargetFile Foo.hs-boot
495+
-- * TargetModule Foo
496+
--
497+
-- If we don't generate a TargetFile for each potential location, we will only have
498+
-- 'TargetFile Foo.hs' in the 'knownTargetsVar', thus not find 'TargetFile Foo.hs-boot'
499+
-- and also not find 'TargetModule Foo'.
500+
fs <- filterM (IO.doesFileExist . fromNormalizedFilePath) targetLocations
501+
pure $ map (\fp -> (TargetFile fp, [fp])) (nubOrd (f:fs))
485502
TargetModule _ -> do
486503
found <- filterM (IO.doesFileExist . fromNormalizedFilePath) targetLocations
487-
return (targetTarget, found)
504+
return [(targetTarget, found)]
488505
hasUpdate <- join $ atomically $ do
489506
known <- readTVar knownTargetsVar
490507
let known' = flip mapHashed known $ \k ->
@@ -975,13 +992,13 @@ data ComponentInfo = ComponentInfo
975992
-- | Internal units, such as local libraries, that this component
976993
-- is loaded with. These have been extracted from the original
977994
-- ComponentOptions.
978-
, componentInternalUnits :: [UnitId]
995+
, componentInternalUnits :: [UnitId]
979996
-- | All targets of this components.
980997
, componentTargets :: [GHC.Target]
981998
-- | Filepath which caused the creation of this component
982999
, componentFP :: NormalizedFilePath
9831000
-- | Component Options used to load the component.
984-
, componentCOptions :: ComponentOptions
1001+
, componentCOptions :: ComponentOptions
9851002
-- | Maps cradle dependencies, such as `stack.yaml`, or `.cabal` file
9861003
-- to last modification time. See Note [Multi Cradle Dependency Info]
9871004
, componentDependencyInfo :: DependencyInfo
@@ -1106,7 +1123,7 @@ setOptions cfp (ComponentOptions theOpts compRoot _) dflags = do
11061123

11071124
let targets = makeTargetsAbsolute root targets'
11081125
root = case workingDirectory dflags'' of
1109-
Nothing -> compRoot
1126+
Nothing -> compRoot
11101127
Just wdir -> compRoot </> wdir
11111128
let dflags''' =
11121129
setWorkingDirectory root $

ghcide/test/exe/DiagnosticTests.hs

+28
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,34 @@ tests = testGroup "diagnostics"
232232
_ <- createDoc "ModuleB.hs" "haskell" contentB
233233
_ <- createDoc "ModuleB.hs-boot" "haskell" contentBboot
234234
expectDiagnostics [("ModuleB.hs", [(DiagnosticSeverity_Warning, (3,0), "Top-level binding")])]
235+
, testSession' "bidirectional module dependency with hs-boot" $ \path -> do
236+
let cradle = unlines
237+
[ "cradle:"
238+
, " direct: {arguments: [ModuleA, ModuleB]}"
239+
]
240+
let contentA = T.unlines
241+
[ "module ModuleA where"
242+
, "import {-# SOURCE #-} ModuleB"
243+
]
244+
let contentB = T.unlines
245+
[ "{-# OPTIONS -Wmissing-signatures#-}"
246+
, "module ModuleB where"
247+
, "import {-# SOURCE #-} ModuleA"
248+
-- introduce an artificial diagnostic
249+
, "foo = ()"
250+
]
251+
let contentBboot = T.unlines
252+
[ "module ModuleB where"
253+
]
254+
let contentAboot = T.unlines
255+
[ "module ModuleA where"
256+
]
257+
liftIO $ writeFile (path </> "hie.yaml") cradle
258+
_ <- createDoc "ModuleA.hs" "haskell" contentA
259+
_ <- createDoc "ModuleA.hs-boot" "haskell" contentAboot
260+
_ <- createDoc "ModuleB.hs" "haskell" contentB
261+
_ <- createDoc "ModuleB.hs-boot" "haskell" contentBboot
262+
expectDiagnostics [("ModuleB.hs", [(DiagnosticSeverity_Warning, (3,0), "Top-level binding")])]
235263
, testSessionWait "correct reference used with hs-boot" $ do
236264
let contentB = T.unlines
237265
[ "module ModuleB where"

0 commit comments

Comments
 (0)