Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 34 additions & 5 deletions haskell-debugger/GHC/Debugger/Monad.hs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ import GHC.Platform.Ways
import GHC.Data.FastString.Env (emptyFsEnv)
#endif

import GHC.Unit.Home.Graph

-- | A debugger action.
newtype Debugger a = Debugger { unDebugger :: ReaderT DebuggerState GHC.Ghc a }
deriving ( Functor, Applicative, Monad, MonadIO
Expand Down Expand Up @@ -428,11 +430,13 @@ runDebugger l rootDir compDir libdir units ghcInvocation' extraGhcArgs mainFp co
let preludeImp = GHC.IIDecl . GHC.simpleImportDecl $ GHC.mkModuleName "Prelude"
-- dbgView should always be available, either because we manually loaded it
-- or because it's in the transitive closure.
hug <- hsc_HUG <$> getSession
let dbgViewImps
-- Using in-memory hs-dbg-view. It's a home-unit, so refer to it directly
| hdv_uid == hsDebuggerViewInMemoryUnitId
-- If hs-dbg-view is a home-unit, refer to it directly
-- See Note [Do not package-qualify imports for home units]
| memberHugUnitId hdv_uid hug
= map (GHC.IIModule . mkModule (RealUnit (Definite hdv_uid))) loadedBuiltinModNames
-- It's available in a unit in the transitive closure. Resolve it.
-- It's available in an exposed unit in the transitive closure. Resolve it
| otherwise
= map (\mn ->
GHC.IIDecl (GHC.simpleImportDecl mn)
Expand Down Expand Up @@ -507,9 +511,7 @@ add our own `MC.finally cleanupInterp` call which sends the `Shutdown` message
to the external interpreter before propagating the exception further (to GHC's
`withCleanupSession`, which will now do Nothing because we set `InterpPending`,
and beyond).
-}

{-
Note [Must explicitly expose module graph units]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
`interactiveGhcDebugger` is our "current home unit", so its
Expand All @@ -533,6 +535,33 @@ An alternative, closer to what ghci does, would be to copy the `packageFlags`
from the debuggee units, however doing so doesn't take care of fixing a unitId
for dependencies of dependencies.

Note [Do not package-qualify imports for home units]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A package-qualified module import will be looked up directly in the exposed
packages, IGNORING the home units modules.

This can lead to two scenarios:

1) a package-import of a loaded unit fails, because that unit, despite being
loaded, is not installed

2) a package-import of a loaded unit succeeds, because a unit with the same
name (but not necessarily the same unit-id!), is installed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe clarify that you mean import "haskell-debugger-view" ... can be ambiguous, at it's not a full unitId. But we use the full unitIdString in the RawPkgQual which sould be unambiguous?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's us, but a user can use a package-qualified import without it being the specific unit-id.

Sorry, I missed this comment before merging.


The second case can result in subtly wrong interactive sessions, where the
package-qualified imported module shadows the loaded module. Perhaps GHC could
warn about this. Cabal-repl and ghci also suffer from this subtle interaction.

In light of this, when the debugger imports the `haskell-debugger-view` modules,
it is imperative that if the `haskell-debugger-view` unit is in the home units
(e.g. if `haskell-debugger-view` is listed in the cabal.project, like it is in
the debugger tree), we do not use a package-qualified import.

On the other hand, if the `haskell-debugger-view` package is not in the
home-units, we *should* package-qualify it to make sure we reference the right
one.

See also #283
-}

-- | See Note [Shutting down the external interpreter]
Expand Down
18 changes: 18 additions & 0 deletions test/golden/T283/T283.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
cabal-version: 3.16
name: T283
version: 0.1.0.0
license: NONE
author: Rodrigo Mesquita
maintainer: rodrigo.m.mesquita@gmail.com
build-type: Simple
extra-doc-files: CHANGELOG.md

common warnings
ghc-options: -Wall

executable T283
import: warnings
main-is: Main.hs
build-depends: base
hs-source-dirs: app
default-language: Haskell2010
10 changes: 10 additions & 0 deletions test/golden/T283/T283.ghc-914.hdb-stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[1 of 3] Compiling GHC.Debugger.View.Class ( in-memory:GHC.Debugger.View.Class, interpreted )[haskell-debugger-view-in-memory]
[2 of 3] Compiling Main ( <TEMPORARY-DIRECTORY>/app/Main.hs, interpreted )[T283-0.1.0.0-inplace-T283]
(hdb)
(hdb) THIS IS A PACKAGE
()
(hdb) Aborted: <interactive>:1:1: error: [GHC-35235]
Could not find module `Main'.
It is not a module in the current program, or in any known package.
(hdb) "If an older version of T283 was installed, we'd now shadow the home-unit Main with the outdated installed Main!"
(hdb) Exiting...
4 changes: 4 additions & 0 deletions test/golden/T283/T283.hdb-stdin
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
p import Main
p main
p import "T283" Main
p "If an older version of T283 was installed, we'd now shadow the home-unit Main with the outdated installed Main!"
4 changes: 4 additions & 0 deletions test/golden/T283/T283.hdb-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh

# Witnesses that package-qualified imports bypass home units (#283)
$HDB -v0 app/Main.hs 2>&1 < T283.hdb-stdin
4 changes: 4 additions & 0 deletions test/golden/T283/app/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Main (main) where

main :: IO ()
main = putStrLn "THIS IS A PACKAGE"
2 changes: 1 addition & 1 deletion test/haskell/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import Test.Utils
main :: IO ()
main = do
env <- getEnvironment
let mkTest = mkGoldenTest False env
let mkTest = mkGoldenTest (maybe False read (lookup "KEEP_TEMP_DIRS" env)) env
golden_tests_paths <- findByExtension [".hdb-test"] "test/golden"
`catch` \(e::IOException) -> do
hPutStrLn stderr "-- !! ERROR !! -----------------------------------------------------------------"
Expand Down
Loading