[Git][ghc/ghc][wip/T13869] GHCi: Improve response to unloading, loading and reloading modules

Jade (@Jade) gitlab at gitlab.haskell.org
Tue Feb 20 18:03:49 UTC 2024



Jade pushed to branch wip/T13869 at Glasgow Haskell Compiler / GHC


Commits:
5e0aa927 by Jade at 2024-02-20T19:07:51+01:00
GHCi: Improve response to unloading, loading and reloading modules

Fixes #13869

- - - - -


17 changed files:

- docs/users_guide/9.10.1-notes.rst
- ghc/GHCi/UI.hs
- testsuite/tests/driver/T8526/T8526.stdout
- testsuite/tests/ghci/prog018/prog018.stdout
- + testsuite/tests/ghci/scripts/T13869.script
- + testsuite/tests/ghci/scripts/T13869.stdout
- + testsuite/tests/ghci/scripts/T13869a.hs
- + testsuite/tests/ghci/scripts/T13869b.hs
- testsuite/tests/ghci/scripts/T13997.stdout
- testsuite/tests/ghci/scripts/T17669.stdout
- testsuite/tests/ghci/scripts/T1914.stdout
- testsuite/tests/ghci/scripts/T20217.stdout
- testsuite/tests/ghci/scripts/T20587.stdout
- testsuite/tests/ghci/scripts/T6105.stdout
- testsuite/tests/ghci/scripts/T8042.stdout
- testsuite/tests/ghci/scripts/all.T
- testsuite/tests/ghci/should_run/all.T


Changes:

=====================================
docs/users_guide/9.10.1-notes.rst
=====================================
@@ -132,6 +132,10 @@ Compiler
 GHCi
 ~~~~
 
+- GHCi now differentiates between adding, unadding, loading, unloading and reloading
+  in its responses to using the respective commands. The output with `-fshow-loaded-modules`
+  is not changed to keep backwards compatibility for tooling.
+
 Runtime system
 ~~~~~~~~~~~~~~
 


=====================================
ghc/GHCi/UI.hs
=====================================
@@ -1702,8 +1702,7 @@ changeDirectory dir = do
 trySuccess :: GhciMonad m => m SuccessFlag -> m SuccessFlag
 trySuccess act =
     handleSourceError (\e -> do printErrAndMaybeExit e -- immediately exit fith failure if in ghc -e
-                                return Failed) $ do
-      act
+                                pure Failed) act
 
 -----------------------------------------------------------------------------
 -- :edit
@@ -1901,7 +1900,7 @@ checkModule m = do
                         (text "local  names: " <+> ppr loc)
              _ -> empty
           return True
-  afterLoad (successIf ok) False
+  afterLoad (successIf ok) Check
 
 -----------------------------------------------------------------------------
 -- :doc
@@ -2006,6 +2005,13 @@ instancesCmd s = do
 -----------------------------------------------------------------------------
 -- :load, :add, :unadd, :reload
 
+-- these are mainly used for displaying a more informative response
+data LoadType = Add !Int | Unadd !Int | Load | Reload | Check
+
+isReload :: LoadType -> Bool
+isReload Reload = True
+isReload _      = False
+
 -- | Sets '-fdefer-type-errors' if 'defer' is true, executes 'load' and unsets
 -- '-fdefer-type-errors' again if it has not been set before.
 wrapDeferTypeErrors :: GHC.GhcMonad m => m a -> m a
@@ -2053,7 +2059,7 @@ loadModule' files = do
         clearCaches
 
         GHC.setTargets targets
-        doLoadAndCollectInfo False LoadAllTargets
+        doLoadAndCollectInfo Load LoadAllTargets
 
   if gopt Opt_GhciLeakCheck dflags
     then do
@@ -2076,7 +2082,7 @@ addModule files = do
   -- remove old targets with the same id; e.g. for :add *M
   mapM_ GHC.removeTarget [ tid | Target { targetId = tid } <- targets' ]
   mapM_ GHC.addTarget targets'
-  _ <- doLoadAndCollectInfo False LoadAllTargets
+  _ <- doLoadAndCollectInfo (Add $ length targets') LoadAllTargets
   return ()
   where
     checkTarget :: GhciMonad m => Target -> m Bool
@@ -2108,8 +2114,9 @@ unAddModule :: GhciMonad m => [FilePath] -> m ()
 unAddModule files = do
   files' <- mapM expandPath files
   targets <- mapM (\m -> GHC.guessTarget m Nothing Nothing) files'
-  mapM_ GHC.removeTarget [ tid | Target { targetId = tid } <- targets ]
-  _ <- doLoadAndCollectInfo False LoadAllTargets
+  let removals = [ tid | Target { targetId = tid } <- targets ]
+  mapM_ GHC.removeTarget removals
+  _ <- doLoadAndCollectInfo (Unadd $ length removals) LoadAllTargets
   return ()
 
 -- | @:reload@ command
@@ -2117,7 +2124,7 @@ reloadModule :: GhciMonad m => String -> m ()
 reloadModule m = do
   session <- GHC.getSession
   let home_unit = homeUnitId (hsc_home_unit session)
-  ok <- doLoadAndCollectInfo True (loadTargets home_unit)
+  ok <- doLoadAndCollectInfo Reload (loadTargets home_unit)
   when (failed ok) failIfExprEvalMode
   where
     loadTargets hu | null m    = LoadAllTargets
@@ -2138,11 +2145,11 @@ reloadModuleDefer = wrapDeferTypeErrors . reloadModule
 -- since those commands are designed to be used by editors and
 -- tooling, it's useless to collect this data for normal GHCi
 -- sessions.
-doLoadAndCollectInfo :: GhciMonad m => Bool -> LoadHowMuch -> m SuccessFlag
-doLoadAndCollectInfo retain_context howmuch = do
+doLoadAndCollectInfo :: GhciMonad m => LoadType -> LoadHowMuch -> m SuccessFlag
+doLoadAndCollectInfo load_type howmuch = do
   doCollectInfo <- isOptionSet CollectInfo
 
-  doLoad retain_context howmuch >>= \case
+  doLoad load_type howmuch >>= \case
     Succeeded | doCollectInfo -> do
       mod_summaries <- GHC.mgModSummaries <$> getModuleGraph
       -- MP: :set +c code path only works in single package mode atm, hence
@@ -2152,11 +2159,11 @@ doLoadAndCollectInfo retain_context howmuch = do
       v <- mod_infos <$> getGHCiState
       !newInfos <- collectInfo v loaded
       modifyGHCiState (\st -> st { mod_infos = newInfos })
-      return Succeeded
-    flag -> return flag
+      pure Succeeded
+    flag -> pure flag
 
-doLoad :: GhciMonad m => Bool -> LoadHowMuch -> m SuccessFlag
-doLoad retain_context howmuch = do
+doLoad :: GhciMonad m => LoadType -> LoadHowMuch -> m SuccessFlag
+doLoad load_type howmuch = do
   -- turn off breakpoints before we load: we can't turn them off later, because
   -- the ModBreaks will have gone away.
   discardActiveBreakPoints
@@ -2165,31 +2172,31 @@ doLoad retain_context howmuch = do
   -- Enable buffering stdout and stderr as we're compiling. Keeping these
   -- handles unbuffered will just slow the compilation down, especially when
   -- compiling in parallel.
-  MC.bracket (liftIO $ do hSetBuffering stdout LineBuffering
-                          hSetBuffering stderr LineBuffering)
-             (\_ ->
-              liftIO $ do hSetBuffering stdout NoBuffering
-                          hSetBuffering stderr NoBuffering) $ \_ -> do
+  let setBuffering t = liftIO $ do
+        hSetBuffering stdout t
+        hSetBuffering stderr t
+  MC.bracket_ (setBuffering LineBuffering) (setBuffering NoBuffering) $ do
       hmis <- ifaceCache <$> getGHCiState
       -- If GHCi message gets its own configuration at some stage then this will need to be
       -- modified to 'embedUnknownDiagnostic'.
       ok <- trySuccess $ GHC.loadWithCache (Just hmis) (mkUnknownDiagnostic . GHCiMessage) howmuch
-      afterLoad ok retain_context
-      return ok
+      afterLoad ok load_type
+      pure ok
+
 
 
 afterLoad
   :: GhciMonad m
   => SuccessFlag
-  -> Bool   -- keep the remembered_ctx, as far as possible (:reload)
+  -> LoadType
   -> m ()
-afterLoad ok retain_context = do
+afterLoad ok load_type = do
   revertCAFs  -- always revert CAFs on load.
   discardTickArrays
   loaded_mods <- getLoadedModules
-  modulesLoadedMsg ok loaded_mods
+  modulesLoadedMsg ok loaded_mods load_type
   graph <- GHC.getModuleGraph
-  setContextAfterLoad retain_context (Just graph)
+  setContextAfterLoad (isReload load_type) (Just graph)
 
 setContextAfterLoad :: GhciMonad m => Bool -> Maybe GHC.ModuleGraph -> m ()
 setContextAfterLoad keep_ctxt Nothing = do
@@ -2273,35 +2280,49 @@ keepPackageImports = filterM is_pkg_import
 
 
 
-modulesLoadedMsg :: GHC.GhcMonad m => SuccessFlag -> [GHC.ModSummary] -> m ()
-modulesLoadedMsg ok mods = do
+modulesLoadedMsg :: GHC.GhcMonad m => SuccessFlag -> [GHC.ModSummary] -> LoadType -> m ()
+modulesLoadedMsg ok mods load_type = do
   dflags <- getDynFlags
-  msg <- if gopt Opt_ShowLoadedModules dflags
-         then do
-               mod_names <- mapM mod_name mods
-               let mod_commas
-                     | null mods = text "none."
-                     | otherwise = hsep (punctuate comma mod_names) <> text "."
-               return $ status <> text ", modules loaded:" <+> mod_commas
-         else do
-               return $ status <> text ","
-                    <+> speakNOf (length mods) (text "module") <+> "loaded."
-
   when (verbosity dflags > 0) $ do
-     rendered_msg <- showSDocForUser' msg
+     mod_names <- mapM mod_name mods
+     rendered_msg <- showSDocForUser' $
+       if gopt Opt_ShowLoadedModules dflags
+         then loaded_msg mod_names
+         else msg
      liftIO $ putStrLn rendered_msg
   where
-    status = case ok of
-                  Failed    -> text "Failed"
-                  Succeeded -> text "Ok"
+    num_mods = length mods
+    none_loaded = num_mods == 0
+
+    loaded_msg names =
+      let mod_commas
+           | null mods = text "none."
+           | otherwise = hsep (punctuate comma names) <> text "."
+      in status <> text ", modules loaded:" <+> mod_commas
+
+    msg  = status <> comma <+> msg' <> dot
+    msg' = case load_type of
+      Reload  -> if none_loaded
+                   then "no modules to be reloaded"
+                   else n_mods num_mods "reloaded"
+      Load    -> if none_loaded
+                   then "unloaded all modules"
+                   else n_mods num_mods "loaded"
+      Check   -> n_mods 1 "checked"
+      Add   n -> n_mods n "added"
+      Unadd n -> n_mods n "unadded"
+    n_mods amount action = speakNOf amount "module" <+> action
+
+    status | Succeeded <- ok = "Ok"
+           | otherwise       = "Failed"
 
     mod_name mod = do
         is_interpreted <- GHC.moduleIsBootOrNotObjectLinkable mod
-        return $ if is_interpreted
-                 then ppr (GHC.ms_mod mod)
-                 else ppr (GHC.ms_mod mod)
-                      <+> parens (text $ normalise $ msObjFilePath mod)
-                      -- Fix #9887
+        pure $ if is_interpreted
+               then ppr (GHC.ms_mod mod)
+               else ppr (GHC.ms_mod mod)
+                    <+> parens (text $ normalise $ msObjFilePath mod)
+                    -- Fix #9887
 
 -- | Run an 'ExceptT' wrapped 'GhcMonad' while handling source errors
 -- and printing 'throwE' strings to 'stderr'. If in expression


=====================================
testsuite/tests/driver/T8526/T8526.stdout
=====================================
@@ -2,5 +2,5 @@
 Ok, one module loaded.
 True
 [1 of 1] Compiling A                ( A.hs, interpreted )
-Ok, one module loaded.
+Ok, one module reloaded.
 False


=====================================
testsuite/tests/ghci/prog018/prog018.stdout
=====================================
@@ -22,4 +22,4 @@ Failed, two modules loaded.
 
 C.hs:6:7: error: [GHC-88464]
     Variable not in scope: variableNotInScope :: ()
-Failed, two modules loaded.
+Failed, two modules reloaded.


=====================================
testsuite/tests/ghci/scripts/T13869.script
=====================================
@@ -0,0 +1,13 @@
+:set -v1
+:load T13869a.hs
+:reload
+
+:load
+:reload
+
+:load T13869a.hs
+:add T13869b.hs
+:reload
+
+:load T13869a.hs T13869b.hs
+:unadd T13869.hs


=====================================
testsuite/tests/ghci/scripts/T13869.stdout
=====================================
@@ -0,0 +1,14 @@
+[1 of 1] Compiling T13869A          ( T13869a.hs, interpreted )
+Ok, one module loaded.
+Ok, one module reloaded.
+Ok, unloaded all modules.
+Ok, no modules to be reloaded.
+[1 of 1] Compiling T13869A          ( T13869a.hs, interpreted )
+Ok, one module loaded.
+[2 of 2] Compiling T13869B          ( T13869b.hs, interpreted )
+Ok, one module added.
+Ok, two modules reloaded.
+[1 of 2] Compiling T13869A          ( T13869a.hs, interpreted )
+[2 of 2] Compiling T13869B          ( T13869b.hs, interpreted )
+Ok, two modules loaded.
+Ok, one module unadded.


=====================================
testsuite/tests/ghci/scripts/T13869a.hs
=====================================
@@ -0,0 +1 @@
+module T13869A where


=====================================
testsuite/tests/ghci/scripts/T13869b.hs
=====================================
@@ -0,0 +1 @@
+module T13869B where


=====================================
testsuite/tests/ghci/scripts/T13997.stdout
=====================================
@@ -4,5 +4,5 @@ Ok, two modules loaded.
 [1 of 3] Compiling New              ( New.hs, New.o )
 [2 of 3] Compiling Bug2             ( Bug2.hs, Bug2.o ) [Source file changed]
 [3 of 3] Compiling Bug              ( Bug.hs, Bug.o ) [Bug2 changed]
-Ok, three modules loaded.
+Ok, three modules reloaded.
 True


=====================================
testsuite/tests/ghci/scripts/T17669.stdout
=====================================
@@ -2,5 +2,5 @@
 Ok, one module loaded.
 this
 [1 of 1] Compiling T17669           ( T17669.hs, T17669.o ) [Source file changed]
-Ok, one module loaded.
+Ok, one module reloaded.
 that


=====================================
testsuite/tests/ghci/scripts/T1914.stdout
=====================================
@@ -2,6 +2,6 @@
 [2 of 2] Compiling T1914A           ( T1914A.hs, interpreted )
 Ok, two modules loaded.
 [2 of 2] Compiling T1914A           ( T1914A.hs, interpreted ) [Source file changed]
-Failed, one module loaded.
+Failed, one module reloaded.
 [2 of 2] Compiling T1914A           ( T1914A.hs, interpreted )
-Ok, two modules loaded.
+Ok, two modules reloaded.


=====================================
testsuite/tests/ghci/scripts/T20217.stdout
=====================================
@@ -2,4 +2,4 @@
 [2 of 3] Compiling T20217A          ( T20217A.hs, nothing )
 [3 of 3] Compiling T20217           ( T20217.hs, nothing )
 Ok, three modules loaded.
-Ok, three modules loaded.
+Ok, three modules reloaded.


=====================================
testsuite/tests/ghci/scripts/T20587.stdout
=====================================
@@ -1,4 +1,4 @@
 [1 of 1] Compiling B
 Ok, one module loaded.
 [1 of 1] Compiling B [Source file changed]
-Ok, one module loaded.
+Ok, one module reloaded.


=====================================
testsuite/tests/ghci/scripts/T6105.stdout
=====================================
@@ -1,4 +1,4 @@
 [1 of 1] Compiling T6105            ( T6105.hs, interpreted )
 Ok, one module loaded.
 [1 of 1] Compiling T6105            ( T6105.hs, interpreted )
-Ok, one module loaded.
+Ok, one module reloaded.


=====================================
testsuite/tests/ghci/scripts/T8042.stdout
=====================================
@@ -3,7 +3,7 @@
 [3 of 3] Compiling T8042A           ( T8042A.hs, interpreted )
 Ok, three modules loaded.
 [3 of 3] Compiling T8042A           ( T8042A.hs, T8042A.o ) [Source file changed]
-Ok, three modules loaded.
+Ok, three modules reloaded.
 [2 of 3] Compiling T8042C           ( T8042C.hs, interpreted )
 [3 of 3] Compiling T8042A           ( T8042A.hs, interpreted )
 Ok, three modules loaded.


=====================================
testsuite/tests/ghci/scripts/all.T
=====================================
@@ -380,4 +380,5 @@ test('T22817', normal, ghci_script, ['T22817.script'])
 test('T22908', normal, ghci_script, ['T22908.script'])
 test('T23062', normal, ghci_script, ['T23062.script'])
 test('T16468', normal, ghci_script, ['T16468.script'])
-test('T23686', normal, ghci_script, ['T23686.script'])
\ No newline at end of file
+test('T23686', normal, ghci_script, ['T23686.script'])
+test('T13869', extra_files(['T13869a.hs', 'T13869b.hs']), ghci_script, ['T13869.script'])


=====================================
testsuite/tests/ghci/should_run/all.T
=====================================
@@ -94,4 +94,3 @@ test('GhciMainIs', just_ghci, compile_and_run, ['-main-is otherMain'])
 test('LargeBCO', [extra_files(['LargeBCO_A.hs']), req_interp, extra_hc_opts("-O -fbyte-code-and-object-code -fprefer-byte-code")], compile_and_run, [''])
 
 test('T24115', just_ghci + [extra_run_opts("-e ':add T24115.hs'")], ghci_script, ['T24115.script'])
-



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/5e0aa927389dbe8a5d5c1c7571e63c839bb67ec4

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/5e0aa927389dbe8a5d5c1c7571e63c839bb67ec4
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20240220/80223a8d/attachment-0001.html>


More information about the ghc-commits mailing list