Skip to content

Commit eac0326

Browse files
committed
Qualify modules with their pkg, but unambiguous
1 parent cea40af commit eac0326

3 files changed

Lines changed: 76 additions & 18 deletions

File tree

haskell-debugger/GHC/Debugger/Monad.hs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ import GHC.Runtime.Interpreter as GHCi
6161
import GHC.Runtime.Loader as GHC
6262
import GHC.Runtime.Context as GHCi
6363
import GHC.Types.Error
64-
import GHC.Types.PkgQual
6564
import GHC.Types.SourceError
66-
import GHC.Types.SourceText
6765
import GHC.Types.Unique.Supply as GHC
6866
import GHC.Unit.Module.Graph
6967
import GHC.Unit.State
@@ -416,32 +414,36 @@ runDebuggerAction l rootDir extraGhcArgs conf loadHomeUnit (Debugger action) = f
416414

417415
-- Set interactive context to import all loaded modules
418416
let preludeImp = GHC.IIDecl . GHC.simpleImportDecl $ GHC.mkModuleName "Prelude"
417+
418+
hu_dflags <- home_unit_dflags <$> getSession
419+
420+
hug <- hsc_HUG <$> getSession
421+
419422
-- dbgView should always be available, either because we manually loaded it
420423
-- or because it's in the transitive closure.
421-
hug <- hsc_HUG <$> getSession
422424
let dbgViewImps
423425
-- If hs-dbg-view is a home-unit, refer to it directly
424426
-- See Note [Do not package-qualify imports for home units]
425427
| memberHugUnitId hdv_uid hug
426428
= map (GHC.IIModule . mkModule (RealUnit (Definite hdv_uid))) loadedBuiltinModNames
427429
-- It's available in an exposed unit in the transitive closure. Resolve it
428430
| otherwise
429-
= map (\mn ->
430-
GHC.IIDecl (GHC.simpleImportDecl mn)
431-
{ ideclPkgQual = RawPkgQual
432-
StringLiteral
433-
{ sl_st = NoSourceText
434-
, sl_fs = mkFastString (unitIdString hdv_uid)
435-
, sl_tc = Nothing
436-
}
437-
}) loadedBuiltinModNames
431+
= map (packageImportDecl hvd_pkgName) loadedBuiltinModNames
432+
where
433+
hvd_pkgName = maybe (unitIdFS hdv_uid) mkFastString
434+
$ thisPackageName $ hu_dflags hdv_uid
438435

439436
mss <- getAllLoadedModules
440437

441438
GHC.setContext
442439
(preludeImp :
443440
dbgViewImps ++
444-
map (GHC.IIModule . GHC.ms_mod) mss)
441+
[ packageImportDecl pkgName (moduleName modl)
442+
| modl <- map GHC.ms_mod mss
443+
, let uid = moduleUnitId modl
444+
, let pkgName = maybe (unitIdFS uid) mkFastString . thisPackageName $ hu_dflags uid
445+
]
446+
)
445447

446448
-- See Note [External interpreter buffering]
447449
setBufferings <- compileExprRemote """

haskell-debugger/GHC/Debugger/Session.hs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@ module GHC.Debugger.Session (
3333
setExposedInUnit,
3434
graphUnits,
3535
compileModuleWithDepsInHpt,
36+
home_unit_dflags,
37+
packageImportDecl,
3638
)
3739
where
3840

3941
#if MIN_VERSION_ghc(9,14,2)
4042
import Data.Function ((&))
4143
#endif
44+
import Control.Exception (assert)
4245
import Control.Monad
4346
import Control.Monad.IO.Class
4447
import qualified Crypto.Hash.SHA1 as H
@@ -75,7 +78,7 @@ import qualified GHC.Unit.Home.Graph as HUG
7578
import qualified Data.Set as Set
7679
import Data.Maybe
7780
import GHC.Types.Target (InputFileBuffer)
78-
import GHC (SingleStep, ExecResult, ModSummary (ms_hspp_opts))
81+
import GHC (SingleStep, ExecResult, ModSummary (ms_hspp_opts), ideclPkgQual)
7982
import Data.Set (Set)
8083
import qualified GHC.Unit as GHC
8184
import GHC.Unit.Module.Graph (mg_mss, ModuleGraphNode (..), mnKey)
@@ -89,7 +92,9 @@ import GHC.Driver.Pipeline (compileOne)
8992
import qualified GHC.Unit.Home.ModInfo as GHC
9093
import GHC.Utils.TmpFs
9194
import Data.Foldable (for_)
92-
import GHC.Plugins (SourceError, try)
95+
import GHC.Plugins (SourceError, try, RawPkgQual (..))
96+
import GHC.Types.SourceText (StringLiteral(..), SourceText (..))
97+
import qualified GHC.Data.FastString
9398

9499
-- | Throws if package flags are unsatisfiable
95100
parseHomeUnitArguments :: GhcMonad m
@@ -161,13 +166,21 @@ setupHomeUnitGraph flagsAndTargets = do
161166
-- | Set up the 'HomeUnitGraph' with empty 'HomeUnitEnv's.
162167
-- The first 'DynFlags' are the 'DynFlags' for the interactive session.
163168
createHomeUnitGraph :: GHC.Logger -> [DynFlags] -> IO HomeUnitGraph
164-
createHomeUnitGraph logger unitDflags = do
169+
createHomeUnitGraph logger unitDflags0 = do
170+
-- See Note [ Ambiguous Package Qualified Imports Workaround ]
171+
let unitDflags = fixPackageNames unitDflags0
165172
let home_units = Set.fromList $ map homeUnitId_ unitDflags
166173
unitEnvList <- flip traverse unitDflags $ \ dflags -> do
174+
let uid = homeUnitId_ dflags
167175
hue <- setupNewHomeUnitEnv logger dflags Nothing home_units
168-
pure (homeUnitId_ dflags, hue)
176+
assert (homeUnitId_ (homeUnitEnv_dflags hue) == uid) $
177+
pure (uid, hue)
169178

170179
pure $ unitEnv_new (Map.fromList unitEnvList)
180+
where
181+
fixPackageNames [df] | Just{} <- thisPackageName df = [df]
182+
-- TODO #288: pick more user-friendly names.
183+
fixPackageNames dfss = map (\ dflags -> dflags { thisPackageName = Just (unitIdString (homeUnitId_ dflags))}) dfss
171184

172185
setupNewHomeUnitEnv :: GHC.Logger -> DynFlags -> Maybe [GHC.UnitDatabase UnitId] -> Set UnitId -> IO HomeUnitEnv
173186
setupNewHomeUnitEnv logger dflags cached_dbs other_home_units = do
@@ -356,6 +369,29 @@ fromTargetId _ _ unitId (GHC.TargetFile f _) ctts = do
356369
| otherwise = (f ++ "-boot")
357370
return [TargetDetails (TargetFile f) [f, other] unitId ctts]
358371

372+
{-
373+
Note [ Ambiguous Package Qualified Imports Workaround ]
374+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
375+
376+
Source level package qualified imports `import "foo" A` interpret "foo" as a package name.
377+
378+
When one manually builds a `RawPkgQual` for an `InteractiveImportDecl` one can get away with using a unit-id, but only for external (i.e. not home) units.
379+
That it works does not seem entirely intended (see quoted snippet below), the code is in `renamePkgQual`: If a package qualifier is not found among packages it's looked up as an external unit. This is already in the code path for `OtherPkg` though, which is why Home Units are excluded.
380+
```
381+
| otherwise
382+
-> OtherPkg (UnitId pkg_fs)
383+
-- not really correct as pkg_fs is unlikely to be a valid unit-id but
384+
-- we will report the failure later...
385+
```
386+
387+
Home units will only be found if the qualifier matches their dflags' `thisPackageName`. However that's bugged because the lookup doesn't bother considering there can be multiple units in the same package (library, sublibraries and exe units), and just picks the first found, leading to an import error if e.g. the library unit is picked but the module was in the exe one.
388+
TODO: report this upstream.
389+
390+
Turns out that the package name of a home unit is pretty meaningless though, so we can update the dflags to replace it with anything that's actually unique so we can dodge the bug.
391+
392+
See issue #288 for what can we do for users at the repl.
393+
-}
394+
359395
-- ----------------------------------------------------------------------------
360396
-- GHC Utils that should likely be exposed by GHC
361397
-- ----------------------------------------------------------------------------
@@ -366,6 +402,23 @@ mkSimpleTarget df fp = GHC.Target (GHC.TargetFile fp Nothing) True (homeUnitId_
366402
hscSetUnitEnv :: UnitEnv -> HscEnv -> HscEnv
367403
hscSetUnitEnv ue env = env { hsc_unit_env = ue }
368404

405+
home_unit_dflags :: HscEnv -> UnitId -> DynFlags
406+
home_unit_dflags hsc_env uid
407+
= homeUnitEnv_dflags
408+
. ue_findHomeUnitEnv uid
409+
. hsc_unit_env
410+
$ hsc_env
411+
412+
packageImportDecl :: GHC.Data.FastString.FastString -> ModuleName -> GHC.InteractiveImport
413+
packageImportDecl pkgName mn =
414+
GHC.IIDecl (GHC.simpleImportDecl $ mn)
415+
{ ideclPkgQual = RawPkgQual
416+
StringLiteral
417+
{ sl_st = NoSourceText
418+
, sl_fs = pkgName
419+
, sl_tc = Nothing
420+
}
421+
}
369422
-- ----------------------------------------------------------------------------
370423
-- Session cache directory
371424
-- ----------------------------------------------------------------------------

hdb-dap/Development/Debug/Session/Setup.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ data HieBiosFlags = HieBiosFlags
8686
-- Important for multi-package cabal projects, as packages are not in the
8787
-- root of the cradle, but in some sub-directory.
8888
}
89+
deriving Show
8990

9091
-- | Prepare a GHC session using hie-bios from scratch
9192
hieBiosSetup :: LogAction IO (WithSeverity SessionSetupLog)
@@ -208,7 +209,9 @@ hieDebugRunner l (DebugRunnerConf projectRoot entryFile extraGhcArgs) = runExcep
208209
r <- hieBiosSetup l projectRoot entryFile
209210
HieBiosFlags{..} <- case r of
210211
Left e -> throwError e
211-
Right f -> return f
212+
Right f -> do
213+
liftIO $ print r
214+
return f
212215
let absEntryFile = normalise $ projectRoot </> entryFile
213216
let
214217
pure $ Debugger.withProjectDebugSession ProjectDebugSpec{..}

0 commit comments

Comments
 (0)