[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 4 commits: Add `rethrowSTM` and improve STM-related documentation
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC Commits: d1d01fa5 by Wolfgang Jeltsch at 2026-08-27T13:17:59+03:00 Add `rethrowSTM` and improve STM-related documentation Adding `rethrowSTM` resolves #26758. The implementation of `rethrowSTM` is completely analogous to the one of `rethrowIO`. The following is established for the documentation of `throwSTM` and `catchSTM`: * Both operations are directly described as analogs of their `IO` counterparts. * There is no reference to `throw` in the documentation of `throwSTM`, because, although such a reference is great in the documentation of `throwIO`, it is somewhat out of place in the documentation of `throwSTM`. * Instead of repeating part of `throwIO`’s documentation, the documentation of `throwSTM` just recommends using `throwSTM` instead of `throw` and references the corresponding arguments in the documentation of `throwIO`. - - - - - 3826e69b by fendor at 2026-08-27T20:35:29-04:00 GHCi: Fix order of `PackageDBFlag`s for interactive home unit `PackageDBFlag`s are stored in reverse order of cli specification. When sorting the `PackageDBFlag`s by longest common prefix, we need thus to reverse the package db stacks before calculating the prefix. We make sure to reverse the package db stack for the interactive home unit to uphold that later specified package dbs overwrite earlier ones. Resolved and adds regression test for #27640 - - - - - bc45cf7d by fendor at 2026-08-27T20:35:29-04:00 Reuse the UnitIndexCache after initialising multiple home units - - - - - 07be45d3 by Alan Zimmerman at 2026-08-27T20:35:30-04:00 EPA: Some Haddock processing tweaks These changes to the Haddock postprocessing should not change behaviour, but just bring it more closely in line with the original, changed at 44309cd377f And add some haddock exactprint tests to show they work. - - - - - 23 changed files: - changelog.d/T27202 - + changelog.d/rethrow-stm - changelog.d/unit-index - compiler/GHC/Driver/Session/Units.hs - compiler/GHC/Parser/PostProcess/Haddock.hs - ghc/GHCi/UI.hs - libraries/base/src/GHC/Conc.hs - libraries/ghc-internal/src/GHC/Internal/STM.hs - + testsuite/tests/ghci/prog-mhu007/Makefile - + testsuite/tests/ghci/prog-mhu007/a/A.hs - + testsuite/tests/ghci/prog-mhu007/all.T - + testsuite/tests/ghci/prog-mhu007/b/B.hs - + testsuite/tests/ghci/prog-mhu007/prog-mhu007.script - + testsuite/tests/ghci/prog-mhu007/prog-mhu007.stdout - + testsuite/tests/ghci/prog-mhu007/testpkg-bar/Bar.hs - + testsuite/tests/ghci/prog-mhu007/testpkg-bar/testpkg-bar.pkg - + testsuite/tests/ghci/prog-mhu007/testpkg-foo/Foo.hs - + testsuite/tests/ghci/prog-mhu007/testpkg-foo/testpkg-foo.pkg - + testsuite/tests/ghci/prog-mhu007/unitA - + testsuite/tests/ghci/prog-mhu007/unitB - + testsuite/tests/printer/Haddock1.hs - testsuite/tests/printer/Makefile - testsuite/tests/printer/all.T Changes: ===================================== changelog.d/T27202 ===================================== @@ -1,7 +1,7 @@ section: ghci synopsis: Fix regression to honour module targets in nested directories into GHCi after startup. -issues: #27202 -mrs: !15980 +issues: #27202 #27640 +mrs: !15980 !16591 description: { Fix a regression that made it impossible to import modules using `:load <Mod>` and `:add <Mod>` after GHCi startup. ===================================== changelog.d/rethrow-stm ===================================== @@ -0,0 +1,4 @@ +section: ghc-internal +synopsis: Add `rethrowSTM`, an `STM` analog of `rethrowIO` +issues: #26758 +mrs: !16501 ===================================== changelog.d/unit-index ===================================== @@ -1,7 +1,7 @@ section: compiler synopsis: Use global ``UnitIndex`` to deduplicate ``UnitInfo``s over multiple home units -issues: #27500 #26423 -mrs: !16115 +issues: #27500 #26423 #27748 +mrs: !16115 !16598 description: { The ``UnitState`` used to be duplicated for all ``HomeUnitEnv``, not sharing any of the ``UnitInfo``s. ===================================== compiler/GHC/Driver/Session/Units.hs ===================================== @@ -145,8 +145,15 @@ initMulti unitArgsFiles lintDynFlagsAndSrcs = do checkUnitCycles initial_dflags home_unit_graph let dflags = homeUnitEnv_dflags $ HUG.unitEnv_lookup mainUnitId home_unit_graph - unitEnv <- assertUnitEnvInvariant <$> (liftIO $ initUnitEnv mainUnitId home_unit_graph (ghcNameVersion dflags) (targetPlatform dflags)) - let final_hsc_env = hsc_env { hsc_unit_env = unitEnv } + newUnitEnv <- do + env <- liftIO $ initUnitEnv mainUnitId home_unit_graph (ghcNameVersion dflags) (targetPlatform dflags) + -- We need to reuse the 'UnitIndexCache' as we used it above in 'initUnits'. + -- See Note [Sharing 'UnitInfo's across the 'UnitEnv'] why this must be shared. + pure $ assertUnitEnvInvariant $ env + { ue_uic = hscUIC hsc_env + } + + let final_hsc_env = hsc_env { hsc_unit_env = newUnitEnv } GHC.setSession final_hsc_env ===================================== compiler/GHC/Parser/PostProcess/Haddock.hs ===================================== @@ -265,12 +265,14 @@ instance HasHaddock (Located (HsModule GhcPs)) where -- ) where -- -- Only do this when the export list exists. - let (_, close_paren, _) = am_exports mod_anns + let + (open_paren, close_paren, _) = am_exports mod_anns + l_exports = combineSrcSpans (getEpTokenSrcSpan open_paren) (getEpTokenSrcSpan close_paren) hsmodExports' <- traverse @Maybe (\exports -> - extendHdkA (getEpTokenSrcSpan close_paren) $ do + extendHdkA l_exports $ do exports' <- addHaddockInterleaveItems EpNoLayout mkDocIE exports - registerEpTokenHdkA close_paren -- ) position, not end-of-last-item + registerEpTokenHdkA close_paren -- Do not consume comments after the closing parenthesis pure exports') (hsmodExports mod) ===================================== ghc/GHCi/UI.hs ===================================== @@ -763,7 +763,7 @@ installInteractiveHomeUnits dflags = do -- However, in the case of multiple home units, initialised via @ghci -unit ... -unit ...@, there -- are not @-package-db@ arguments in the base 'DynFlags'... -- To fix this, we look at the home units and merge their package dbs stacks. - -- We assume, that many package db stacks look almost identical, and only differ in view elements. + -- We assume, that many package db stacks look almost identical, and only differ in few unit databases. -- Thus, we try to extract a common package db stack (i.e., longest common prefix), and then concat -- the rest of the package db stacks. At last, we add the two result package db stacks. -- This should work reliably with cabal and stack, but it is hacky. @@ -864,8 +864,14 @@ installInteractiveHomeUnits dflags = do pure (HUG.mkHomeUnitEnv unit_state dflags hpt (Just home_unit)) concatPackageDbStacksUsingLongestCommonPrefix :: [[PackageDBFlag]] -> [PackageDBFlag] - concatPackageDbStacksUsingLongestCommonPrefix stacks = + concatPackageDbStacksUsingLongestCommonPrefix stacks' = let + -- Package DB stacks are accumulated from the cli right to left. + -- E.g., @-clear-package-db -global-package-db@ is stored as + -- @[PackageDB GlobalPkgDb, ClearPackageDBs]@. + -- Hence, we reverse the stacks, before computing the longest common prefix, + -- otherwise the prefix won't match at all. + stacks = map List.reverse stacks' -- O (m * n) -- m ... Number of PackageDBFlag stacks -- n ... Size of the stacks @@ -873,8 +879,21 @@ installInteractiveHomeUnits dflags = do map List.head . List.takeWhile ((List.all . (==) . List.head) <*> List.tail) . List.transpose prefix = longestCommonPrefix stacks + + -- We reverse each individual stack segment to maintain the relative order within in a package + -- db stack. + -- There should be no 'ClearPackageDBs' in here, otherwise we are going to overwrite + -- the longest common prefix stacks. + -- + -- @nubOrd@ can silently change precedence of package db stack merging. + -- This is not trivially avoidable right now, since multiple home units could simply + -- have package db stacks that cannot be unified. + unmergeableStack = + nubOrd (concatMap (List.reverse . List.drop (length prefix)) stacks) in - prefix ++ nubOrd (concatMap (List.drop (length prefix)) stacks) + -- We reverse the final common package db stack again to match the expectation of 'packageDBFlags' that they are + -- stord in reverse order. + unmergeableStack ++ reverse prefix reportError :: GhciMonad m => GhciCommandMessage -> m () reportError err = do ===================================== libraries/base/src/GHC/Conc.hs ===================================== @@ -79,6 +79,9 @@ module GHC.Conc , retry , orElse , throwSTM +#if __GLASGOW_HASKELL__ >= 1002 + , rethrowSTM +#endif , catchSTM , TVar(..) , newTVar ===================================== libraries/ghc-internal/src/GHC/Internal/STM.hs ===================================== @@ -5,6 +5,11 @@ {-# LANGUAGE RankNTypes #-} {-# OPTIONS_HADDOCK not-home #-} +-- Make unused imports warnings instead of errors, because there are seemingly +-- unused imports of `throw`, `throwIO`, and `rethrowIO`, which are actually +-- used for documentation hyperlinking. +{-# OPTIONS_GHC -Wwarn=unused-imports #-} + module GHC.Internal.STM ( -- * the 'STM' monad @@ -13,6 +18,7 @@ module GHC.Internal.STM , retry , orElse , throwSTM + , rethrowSTM , catchSTM , unsafeIOToSTM -- * TVars @@ -28,7 +34,9 @@ import qualified GHC.Internal.Stack.Types as Rebindable import GHC.Internal.Base import GHC.Internal.Exception (Exception, toExceptionWithBacktrace, fromException, addExceptionContext) import GHC.Internal.Exception.Context (ExceptionAnnotation) -import GHC.Internal.Exception.Type (WhileHandling(..)) +import GHC.Internal.Exception.Type ( + WhileHandling(..), ExceptionWithContext, NoBacktrace (NoBacktrace), + ) import GHC.Internal.Maybe (Maybe(..)) import GHC.Internal.Prim ( RealWorld, State#, TVar#, atomically#, catchRetry#, catchSTM#, @@ -37,6 +45,10 @@ import GHC.Internal.Prim ( import GHC.Internal.Prim.PtrEq (sameTVar#) import GHC.Internal.Stack (HasCallStack, withFrozenCallStack) +-- Imports for documentation hyperlinking +import GHC.Internal.Exception (throw) +import GHC.Internal.IO (throwIO, rethrowIO) + -- TVars are shared memory locations which support atomic memory -- transactions. @@ -166,7 +178,7 @@ retry = STM $ \s# -> retry# s# orElse :: STM a -> STM a -> STM a orElse (STM m) e = STM $ \s -> catchRetry# m (unSTM e) s --- | A variant of 'throw' that can only be used within the 'STM' monad. +-- | The 'STM' analog of 'throwIO'. -- -- Throwing an exception in @STM@ aborts the transaction and propagates the -- exception. If the exception is caught via 'catchSTM', only the changes @@ -176,19 +188,8 @@ orElse (STM m) e = STM $ \s -> catchRetry# m (unSTM e) s -- If the exception is not caught inside of the 'STM', it is re-thrown by -- 'atomically', and the entire 'STM' is rolled back. -- --- Although 'throwSTM' has a type that is an instance of the type of 'throw', the --- two functions are subtly different: --- --- > throw e `seq` x ===> throw e --- > throwSTM e `seq` x ===> x --- --- The first example will cause the exception @e@ to be raised, --- whereas the second one won\'t. In fact, 'throwSTM' will only cause --- an exception to be raised when it is used within the 'STM' monad. --- The 'throwSTM' variant should be used in preference to 'throw' to --- raise an exception within the 'STM' monad because it guarantees --- ordering with respect to other 'STM' operations, whereas 'throw' --- does not. +-- Note that 'throwSTM' is preferable to 'throw', for the same reasons that +-- 'throwIO' is preferable to 'throw'. throwSTM :: (HasCallStack, Exception e) => e -> STM a throwSTM e = do -- N.B. Typically use of unsafeIOToSTM is very much frowned upon as this @@ -197,7 +198,11 @@ throwSTM e = do se <- unsafeIOToSTM (withFrozenCallStack $ toExceptionWithBacktrace e) STM $ raiseIO# se --- | Exception handling within STM actions. +-- | The 'STM' analog of 'rethrowIO'. +rethrowSTM :: Exception e => ExceptionWithContext e -> STM a +rethrowSTM e = throwSTM (NoBacktrace e) + +-- | The 'STM' analog of 'catch'. -- -- @'catchSTM' m f@ catches any exception thrown by @m@ using 'throwSTM', -- using the function @f@ to handle the exception. If an exception is ===================================== testsuite/tests/ghci/prog-mhu007/Makefile ===================================== @@ -0,0 +1,33 @@ +TOP=../../.. +include $(TOP)/mk/boilerplate.mk +include $(TOP)/mk/test.mk + +PKGCONF_FOO=local-foo.package.conf +PKGCONF_BAR=local-bar.package.conf +LOCAL_GHC_PKG_FOO = '$(GHC_PKG)' --no-user-package-db -f $(PKGCONF_FOO) +LOCAL_GHC_PKG_BAR = '$(GHC_PKG)' --no-user-package-db -f $(PKGCONF_BAR) + +# Finds both packages in different unit databases +.PHONY: prog-mhu007 +prog-mhu007: + cd testpkg-foo && \ + '$(TEST_HC)' $(TEST_HC_OPTS) $(WAY_FLAGS) -hisuf=$(ghciWayExt) $(ghciWayFlags) \ + -v0 -fno-code -fwrite-interface -hidir dist-testpkg-foo-0.1.0.0 -this-unit-id testpkg-foo-0.1.0.0-XXX \ + -i. Foo + cd testpkg-bar && \ + '$(TEST_HC)' $(TEST_HC_OPTS) $(WAY_FLAGS) -hisuf=$(ghciWayExt) $(ghciWayFlags) \ + -v0 -fno-code -fwrite-interface -hidir dist-testpkg-bar-0.1.0.0 -this-unit-id testpkg-bar-0.1.0.0-XXX \ + -i. Bar + + $(LOCAL_GHC_PKG_FOO) init $(PKGCONF_FOO) 2>/dev/null + $(LOCAL_GHC_PKG_FOO) register --force testpkg-foo/testpkg-foo.pkg 2>/dev/null + $(LOCAL_GHC_PKG_FOO) hide testpkg-foo + $(LOCAL_GHC_PKG_FOO) list + + $(LOCAL_GHC_PKG_BAR) init $(PKGCONF_BAR) 2>/dev/null + $(LOCAL_GHC_PKG_BAR) register --force testpkg-bar/testpkg-bar.pkg 2>/dev/null + $(LOCAL_GHC_PKG_BAR) hide testpkg-bar + $(LOCAL_GHC_PKG_BAR) list + + '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) $(WAY_FLAGS) $(ghciWayFlags) \ + -no-user-package-db -fno-code -unit @unitA -unit @unitB < prog-mhu007.script ===================================== testsuite/tests/ghci/prog-mhu007/a/A.hs ===================================== @@ -0,0 +1,3 @@ +module A where + +import Bar ===================================== testsuite/tests/ghci/prog-mhu007/all.T ===================================== @@ -0,0 +1,8 @@ + +proj_files = extra_files(['a/', 'b/', 'unitA', 'unitB', 'testpkg-bar/', 'testpkg-foo/']) + +test('prog-mhu007', + [proj_files, + cmd_prefix('ghciWayFlags=' + config.ghci_way_flags), + req_interp], + makefile_test, ['prog-mhu007']) ===================================== testsuite/tests/ghci/prog-mhu007/b/B.hs ===================================== @@ -0,0 +1,3 @@ +module B where + +import Foo ===================================== testsuite/tests/ghci/prog-mhu007/prog-mhu007.script ===================================== @@ -0,0 +1,5 @@ +:m + A B +"Loaded A and B" +import Foo +import Bar +"Loaded dependencies Foo and Bar" ===================================== testsuite/tests/ghci/prog-mhu007/prog-mhu007.stdout ===================================== @@ -0,0 +1,10 @@ +Reading package info from "testpkg-foo/testpkg-foo.pkg" ... done. +local-foo.package.conf + (testpkg-foo-0.1.0.0) + +Reading package info from "testpkg-bar/testpkg-bar.pkg" ... done. +local-bar.package.conf + (testpkg-bar-0.1.0.0) + +"Loaded A and B" +"Loaded dependencies Foo and Bar" ===================================== testsuite/tests/ghci/prog-mhu007/testpkg-bar/Bar.hs ===================================== @@ -0,0 +1 @@ +module Bar where ===================================== testsuite/tests/ghci/prog-mhu007/testpkg-bar/testpkg-bar.pkg ===================================== @@ -0,0 +1,11 @@ +name: testpkg-bar +version: 0.1.0.0 +id: testpkg-bar-0.1.0.0-XXX +key: testpkg-bar-0.1.0.0-XXX +exposed: True +exposed-modules: Bar +hidden-modules: +import-dirs: ${pkgroot}/testpkg-bar/dist-testpkg-bar-0.1.0.0 +library-dirs: +include-dirs: +hs-libraries: ===================================== testsuite/tests/ghci/prog-mhu007/testpkg-foo/Foo.hs ===================================== @@ -0,0 +1 @@ +module Foo where ===================================== testsuite/tests/ghci/prog-mhu007/testpkg-foo/testpkg-foo.pkg ===================================== @@ -0,0 +1,11 @@ +name: testpkg-foo +version: 0.1.0.0 +id: testpkg-foo-0.1.0.0-XXX +key: testpkg-foo-0.1.0.0-XXX +exposed: True +exposed-modules: Foo +hidden-modules: +import-dirs: ${pkgroot}/testpkg-foo/dist-testpkg-foo-0.1.0.0 +library-dirs: +include-dirs: +hs-libraries: ===================================== testsuite/tests/ghci/prog-mhu007/unitA ===================================== @@ -0,0 +1,11 @@ +-i +-ia/ +A +-this-unit-id a-0.0.0 +-this-package-name a +-clear-package-db +-global-package-db +-no-user-package-db +-package-db local-bar.package.conf +-package base +-package-id testpkg-bar-0.1.0.0-XXX ===================================== testsuite/tests/ghci/prog-mhu007/unitB ===================================== @@ -0,0 +1,11 @@ +-i +-ib/ +B +-this-unit-id b-0.0.0 +-this-package-name b +-clear-package-db +-global-package-db +-no-user-package-db +-package-db local-foo.package.conf +-package base +-package-id testpkg-foo-0.1.0.0-XXX ===================================== testsuite/tests/printer/Haddock1.hs ===================================== @@ -0,0 +1,36 @@ +{-# OPTIONS_GHC -fno-warn-redundant-constraints -haddock #-} +-- | Haddock comment, +-- coming before the module +module Haddock1 ( + + -- | This is some inline documentation in the export list + -- + -- > a code block using bird-tracks + -- > each line must begin with > (which isn't significant unless it + -- > is at the beginning of the line). + f + + {-| nested-style doc comments -} + , g + + -- * A section + -- and without an intervening comma: + -- ** A subsection + ) where + +-- | Haddock before imports +import Data.List + +-- | Haddock before decl +f = undefined +g = undefined + +-- | This comment applies to the /following/ declaration +-- and it continues until the next non-comment line +data T a b + = A Int (Maybe Float) -- ^ This comment describes the 'A' constructor + | -- | This comment describes the 'B' constructor + B (T a b, T Int Float) -- ^ abcd + +-- | An abstract data declaration +data T2 a b = T2 a b ===================================== testsuite/tests/printer/Makefile ===================================== @@ -932,3 +932,8 @@ PprModifiers: PprQualifiedStrings: $(CHECK_PPR) $(LIBDIR) PprQualifiedStrings.hs $(CHECK_EXACT) $(LIBDIR) PprQualifiedStrings.hs + +.PHONY: Haddock1 +Haddock1: + # $(CHECK_PPR) $(LIBDIR) Haddock1.hs + $(CHECK_EXACT) $(LIBDIR) Haddock1.hs ===================================== testsuite/tests/printer/all.T ===================================== @@ -223,3 +223,4 @@ test('TestLevelImports', [ignore_stderr, req_ppr_deps], makefile_test, ['TestLev test('TestNamedDefaults', [ignore_stderr, req_ppr_deps], makefile_test, ['TestNamedDefaults']) test('PprModifiers', [ignore_stderr,req_ppr_deps], makefile_test, ['PprModifiers']) test('PprQualifiedStrings', [ignore_stderr,req_ppr_deps], makefile_test, ['PprQualifiedStrings']) +test('Haddock1', [ignore_stderr,req_ppr_deps], makefile_test, ['Haddock1']) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b6bc865eb74325ebe4dd4c82eb1d020... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b6bc865eb74325ebe4dd4c82eb1d020... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Marge Bot (@marge-bot)