diff --git a/.gitlab/ci.sh b/.gitlab/ci.sh index 52106e0787a95f7f8234b930b891a39661140cc3..0d21d33885c3fc2ea9ee305482380f310cd5de09 100755 --- a/.gitlab/ci.sh +++ b/.gitlab/ci.sh @@ -714,11 +714,11 @@ function cabal_abi_test() { start_section "Cabal test: $OUT" mkdir -p "$OUT" - run "$HC" \ + "$HC" \ -hidir tmp -odir tmp -fforce-recomp -haddock \ -iCabal/Cabal/src -XNoPolyKinds Distribution.Simple -j"$cores" \ -fobject-determinism \ - "$@" 2>&1 | tee $OUT/log + "$@" 2>&1 | sed '1d' | tee $OUT/log summarise_hi_files summarise_o_files popd diff --git a/compiler/GHC/Hs/Doc.hs b/compiler/GHC/Hs/Doc.hs index 0dac7789bedb1db1d855481c06c3dccd6a1b0f99..46ce16feba1c70a073f57f2cbeb04c3015f11f0b 100644 --- a/compiler/GHC/Hs/Doc.hs +++ b/compiler/GHC/Hs/Doc.hs @@ -124,7 +124,7 @@ data DocStructureItem = DsiSectionHeading !Int !(HsDoc GhcRn) | DsiDocChunk !(HsDoc GhcRn) | DsiNamedChunkRef !String - | DsiExports !Avails + | DsiExports !DetOrdAvails | DsiModExport !(NonEmpty ModuleName) -- ^ We might re-export avails from multiple -- modules with a single export declaration. E.g. @@ -136,7 +136,7 @@ data DocStructureItem -- -- Invariant: This list of ModuleNames must be -- sorted to guarantee interface file determinism. - !Avails + !DetOrdAvails -- ^ Invariant: This list of Avails must be sorted -- to guarantee interface file determinism. diff --git a/compiler/GHC/HsToCore/Docs.hs b/compiler/GHC/HsToCore/Docs.hs index fcb62fd82a01c546eb650d0f193bc392d0405199..da73bfd1ebc7341455dcbc369cd7555951f6dff2 100644 --- a/compiler/GHC/HsToCore/Docs.hs +++ b/compiler/GHC/HsToCore/Docs.hs @@ -160,7 +160,11 @@ mkDocStructureFromExportList mdl import_avails export_list = (IEGroup _ level doc, _) -> DsiSectionHeading level (unLoc doc) (IEDoc _ doc, _) -> DsiDocChunk (unLoc doc) (IEDocNamed _ name, _) -> DsiNamedChunkRef name - (_, avails) -> DsiExports (nubAvails avails) + (IEThingWith{}, avails) -> + DsiExports $ + {- For explicit export lists, use the explicit order. It is deterministic by construction -} + DefinitelyDeterministicAvails (nubAvails avails) + (_, avails) -> DsiExports (sortAvails (nubAvails avails)) moduleExport :: ModuleName -- Alias -> Avails @@ -201,10 +205,10 @@ mkDocStructureFromDecls env all_exports decls = avails :: [Located DocStructureItem] avails = flip fmap all_exports $ \avail -> case M.lookup (availName avail) name_locs of - Just loc -> L loc (DsiExports [avail]) + Just loc -> L loc (DsiExports (sortAvails [avail])) -- FIXME: This is just a workaround that we use when handling e.g. -- associated data families like in the html-test Instances.hs. - Nothing -> noLoc (DsiExports []) + Nothing -> noLoc (DsiExports (sortAvails [])) -- This causes the associated data family to be incorrectly documented -- separately from its class: diff --git a/compiler/GHC/Iface/Make.hs b/compiler/GHC/Iface/Make.hs index fdbea6a9b4f2bae4041b08749120139f225c96b8..41132433947e5b7e47baf5402755e5365aadd1cd 100644 --- a/compiler/GHC/Iface/Make.hs +++ b/compiler/GHC/Iface/Make.hs @@ -518,8 +518,8 @@ mkIfaceImports = map go go (ImpUserSpec decl (ImpUserExplicit env)) = IfaceImport decl (ImpIfaceExplicit (forceGlobalRdrEnv env)) go (ImpUserSpec decl (ImpUserEverythingBut ns)) = IfaceImport decl (ImpIfaceEverythingBut ns) -mkIfaceExports :: [AvailInfo] -> [IfaceExport] -- Sort to make canonical -mkIfaceExports = sortAvails +mkIfaceExports :: [AvailInfo] -> [IfaceExport] -- Sort to make canonical +mkIfaceExports as = case sortAvails as of DefinitelyDeterministicAvails sas -> sas {- Note [Original module] diff --git a/compiler/GHC/Types/Avail.hs b/compiler/GHC/Types/Avail.hs index a71e497cafb156fbc8f2d7307926ae712640e567..2970bf34fb0a4fc4dadaa56a46ca011a044569fc 100644 --- a/compiler/GHC/Types/Avail.hs +++ b/compiler/GHC/Types/Avail.hs @@ -1,5 +1,7 @@ {-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE PatternSynonyms #-} -- -- (c) The University of Glasgow -- @@ -20,6 +22,7 @@ module GHC.Types.Avail ( filterAvails, nubAvails, sortAvails, + DetOrdAvails(DetOrdAvails, DefinitelyDeterministicAvails) ) where import GHC.Prelude @@ -65,6 +68,20 @@ data AvailInfo -- | A collection of 'AvailInfo' - several things that are \"available\" type Avails = [AvailInfo] +-- | Occurrences of Avails in interface files must be deterministically ordered +-- to guarantee interface file determinism. +-- +-- We guarantee a deterministic order by either using the order explicitly +-- given by the user (e.g. in an explicit constructor export list) or instead +-- by sorting the avails with 'sortAvails'. +newtype DetOrdAvails = DefinitelyDeterministicAvails Avails + deriving newtype (Binary, Outputable, NFData) + +-- | It's always safe to match on 'DetOrdAvails' +pattern DetOrdAvails :: Avails -> DetOrdAvails +pattern DetOrdAvails x <- DefinitelyDeterministicAvails x +{-# COMPLETE DetOrdAvails #-} + {- Note [Representing pattern synonym fields in AvailInfo] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Record pattern synonym fields cannot be represented using AvailTC like fields of @@ -133,8 +150,8 @@ availSubordinateNames avail@(AvailTC _ ns) | otherwise = ns -- | Sort 'Avails'/'AvailInfo's -sortAvails :: Avails -> Avails -sortAvails = sortBy stableAvailCmp . map sort_subs +sortAvails :: Avails -> DetOrdAvails +sortAvails = DefinitelyDeterministicAvails . sortBy stableAvailCmp . map sort_subs where sort_subs :: AvailInfo -> AvailInfo sort_subs (Avail n) = Avail n diff --git a/testsuite/tests/determinism/T25304/A.hs b/testsuite/tests/determinism/T25304/A.hs new file mode 100644 index 0000000000000000000000000000000000000000..3f164c44a12ae91b5df8fc44f582508342501939 --- /dev/null +++ b/testsuite/tests/determinism/T25304/A.hs @@ -0,0 +1,84 @@ +module A + ( MyType(..) + ) where + +data MyType + = A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | X + | Y + | Z + | AA + | AB + | AC + | AD + | AE + | AF + | AG + | AH + | AI + | AJ + | AK + | AL + | AM + | AN + | AO + | AP + | AQ + | AR + | AS + | AT + | AU + | AV + | AW + | AX + | AY + | AZ + | BA + | BB + | BC + | BD + | BE + | BF + | BG + | BH + | BI + | BJ + | BK + | BL + | BM + | BN + | BO + | BP + | BQ + | BR + | BS + | BT + | BU + | BV + | BW + | BX + | BY + | BZ + | CA diff --git a/testsuite/tests/determinism/T25304/B.hs b/testsuite/tests/determinism/T25304/B.hs new file mode 100644 index 0000000000000000000000000000000000000000..2f961f66644931796f599c9760e89aee238fe92d --- /dev/null +++ b/testsuite/tests/determinism/T25304/B.hs @@ -0,0 +1,86 @@ +module B +( MyType + ( BA + , BB + , BC + , BD + , BE + , BF + , BG + , BH + , BI + , BJ + , BK + , BL + , BM + , BN + , BO + , BP + , BQ + , BR + , BS + , BT + , BU + , BV + , BW + , BX + , BY + , BZ + , CA + , AA + , AB + , AC + , AD + , AE + , AF + , AG + , AH + , AI + , AJ + , AK + , AL + , AM + , AN + , AO + , AP + , AQ + , AR + , AS + , AT + , AU + , AV + , AW + , AX + , AY + , AZ + , A + , B + , C + , D + , E + , F + , G + , H + , I + , J + , K + , L + , M + , N + , O + , P + , Q + , R + , S + , T + , U + , V + , W + , X + , Y + , Z + ) +) where + +import A + diff --git a/testsuite/tests/determinism/T25304/Makefile b/testsuite/tests/determinism/T25304/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cd29342e8a007266d3cfa8b8c728c18dd3e105ae --- /dev/null +++ b/testsuite/tests/determinism/T25304/Makefile @@ -0,0 +1,25 @@ +TOP=../../.. +include $(TOP)/mk/boilerplate.mk +include $(TOP)/mk/test.mk + +T25304: + $(RM) A.hi A.o B.hi B.o + # Use -haddock to get docs: output in the interface file + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -haddock B.hs + '$(TEST_HC)' --show-iface A.hi > A_clean_iface + '$(TEST_HC)' --show-iface B.hi > B_clean_iface + '$(TEST_HC)' $(TEST_HC_OPTS) -dinitial-unique=16777215 -dunique-increment=-1 -v0 -haddock A.hs B.hs -fforce-recomp + '$(TEST_HC)' --show-iface A.hi > A_dirty_iface + '$(TEST_HC)' --show-iface B.hi > B_dirty_iface + diff A_clean_iface A_dirty_iface + diff B_clean_iface B_dirty_iface + +T25304a: + $(RM) A.hi A.o B.hi B.o + # Use -haddock to get docs: output in the interface file + '$(TEST_HC)' $(TEST_HC_OPTS) -v0 -haddock B.hs + '$(TEST_HC)' --show-iface B.hi > B_clean_iface + # The goal is to see the export list in the documentation structure of the + # interface file preserves the order used in the source + cat B_clean_iface | grep -A7 "documentation structure" + diff --git a/testsuite/tests/determinism/T25304/T25304a.stdout b/testsuite/tests/determinism/T25304/T25304a.stdout new file mode 100644 index 0000000000000000000000000000000000000000..b92d2b33a853d507911a54f4783879666fb8564a --- /dev/null +++ b/testsuite/tests/determinism/T25304/T25304a.stdout @@ -0,0 +1,8 @@ + documentation structure: + avails: + [A.MyType{A.MyType, A.BA, A.BB, A.BC, A.BD, A.BE, A.BF, A.BG, A.BH, + A.BI, A.BJ, A.BK, A.BL, A.BM, A.BN, A.BO, A.BP, A.BQ, A.BR, A.BS, + A.BT, A.BU, A.BV, A.BW, A.BX, A.BY, A.BZ, A.CA, A.AA, A.AB, A.AC, + A.AD, A.AE, A.AF, A.AG, A.AH, A.AI, A.AJ, A.AK, A.AL, A.AM, A.AN, + A.AO, A.AP, A.AQ, A.AR, A.AS, A.AT, A.AU, A.AV, A.AW, A.AX, A.AY, + A.AZ, A.A, A.B, A.C, A.D, A.E, A.F, A.G, A.H, A.I, A.J, A.K, A.L, diff --git a/testsuite/tests/determinism/T25304/all.T b/testsuite/tests/determinism/T25304/all.T new file mode 100644 index 0000000000000000000000000000000000000000..7d7f21f5f24699acca0bb9ac03c6db78832aa987 --- /dev/null +++ b/testsuite/tests/determinism/T25304/all.T @@ -0,0 +1,2 @@ +test('T25304', [extra_files(['A.hs', 'B.hs'])], makefile_test, ['T25304']) +test('T25304a', [extra_files(['A.hs', 'B.hs'])], makefile_test, ['T25304a']) diff --git a/testsuite/tests/showIface/DocsInHiFileTH.stdout b/testsuite/tests/showIface/DocsInHiFileTH.stdout index 650829d4de6fd6ee73ec487b636b894a7b235edb..58f75a5846889f21f2a7dc527a773ab910e60f03 100644 --- a/testsuite/tests/showIface/DocsInHiFileTH.stdout +++ b/testsuite/tests/showIface/DocsInHiFileTH.stdout @@ -187,7 +187,7 @@ docs: avails: [i] avails: - [WD11{WD11, WD11Bool, WD11Int, WD11Foo}] + [WD11{WD11, WD11Bool, WD11Foo, WD11Int}] avails: [WD13{WD13}] avails: @@ -221,11 +221,11 @@ docs: avails: [Pretty{Pretty, prettyPrint}] avails: - [Corge{Corge, runCorge, Corge}] + [Corge{Corge, Corge, runCorge}] avails: - [Quuz{Quuz, quuz1_a, Quuz}] + [Quuz{Quuz, Quuz, quuz1_a}] avails: - [Quux{Quux, Quux2, Quux1}] + [Quux{Quux, Quux1, Quux2}] avails: [Tup2] avails: diff --git a/testsuite/tests/showIface/NoExportList.stdout b/testsuite/tests/showIface/NoExportList.stdout index 83fd28fa68d7c578ef80422ffc8bcf12efb8f443..aed34318ebb55beb34751ed7f889de0cdc7f31b1 100644 --- a/testsuite/tests/showIface/NoExportList.stdout +++ b/testsuite/tests/showIface/NoExportList.stdout @@ -32,7 +32,7 @@ docs: -- Actually we have only one type. identifiers: avails: - [R{R, fβ, fα, R}] + [R{R, R, fα, fβ}] section heading, level 1: text: -- * Functions diff --git a/utils/haddock/haddock-api/src/Haddock/Interface/Create.hs b/utils/haddock/haddock-api/src/Haddock/Interface/Create.hs index 2fb1003ac727338bb2164820454bca57aae9c702..bf384e1b44c73aea36013d9be3f6e38f6192b096 100644 --- a/utils/haddock/haddock-api/src/Haddock/Interface/Create.hs +++ b/utils/haddock/haddock-api/src/Haddock/Interface/Create.hs @@ -201,7 +201,15 @@ createInterface1' flags unit_state dflags hie_file mod_iface ifaces inst_ifaces -- See Note [Exporting built-in items] let builtinTys = DsiSectionHeading 1 (WithHsDocIdentifiers (mkGeneratedHsDocString "Builtin syntax") []) bonus_ds mods - | mdl == gHC_PRIM = [builtinTys, DsiExports funAvail] <> mods + | mdl == gHC_PRIM = + [ builtinTys + , DsiExports $ + {- Haddock does not want to sort avails, the order should be + deterministically /derived from the source/. + In this particular case, sorting funAvail would be a no-op anyway. -} + DefinitelyDeterministicAvails + funAvail + ] <> mods | otherwise = mods let @@ -461,11 +469,11 @@ mkExportItems Just hsDoc' -> do doc <- processDocStringParas parserOpts sDocContext pkgName hsDoc' pure [ExportDoc doc] - DsiExports avails -> + DsiExports (DetOrdAvails avails) -> -- TODO: We probably don't need nubAvails here. -- mkDocStructureFromExportList already uses it. concat <$> traverse availExport (nubAvails avails) - DsiModExport mod_names avails -> do + DsiModExport mod_names (DetOrdAvails avails) -> do -- only consider exporting a module if we are sure we are really -- exporting the whole module and not some subset. (unrestricted_mods, remaining_avails) <- unrestrictedModExports sDocContext thisMod modMap instIfaceMap avails (NE.toList mod_names) diff --git a/utils/haddock/html-test/ref/BundledPatterns2.html b/utils/haddock/html-test/ref/BundledPatterns2.html index 68261f3945bee97bef18b555e09f7f468e9b9968..6d71e0a7aa1413cae6f87ba55f560ba1bfc7bddd 100644 --- a/utils/haddock/html-test/ref/BundledPatterns2.html +++ b/utils/haddock/html-test/ref/BundledPatterns2.html @@ -96,14 +96,6 @@ >where</span ><ul class="subs" ><li - ><span class="keyword" - >pattern</span - > <a href="#" - >LR</a - > :: a -> <a href="#" title="BundledPatterns2" - >RTree</a - > 0 a</li - ><li ><span class="keyword" >pattern</span > <a href="#" @@ -117,6 +109,14 @@ > (d <a href="#" title="GHC.TypeLits" >+</a > 1) a</li + ><li + ><span class="keyword" + >pattern</span + > <a href="#" + >LR</a + > :: a -> <a href="#" title="BundledPatterns2" + >RTree</a + > 0 a</li ></ul ></li ></ul @@ -318,28 +318,34 @@ ><td class="src" ><span class="keyword" >pattern</span - > <a id="v:LR" class="def" - >LR</a - > :: a -> <a href="#" title="BundledPatterns2" + > <a id="v:BR" class="def" + >BR</a + > :: <a href="#" title="BundledPatterns2" >RTree</a - > 0 a</td + > d a -> <a href="#" title="BundledPatterns2" + >RTree</a + > d a -> <a href="#" title="BundledPatterns2" + >RTree</a + > (d <a href="#" title="GHC.TypeLits" + >+</a + > 1) a</td ><td class="doc" ><p - >Leaf of a perfect depth tree</p + >Branch of a perfect depth tree</p ><pre class="screen" ><code class="prompt" >>>> </code ><strong class="userinput" ><code - >LR 1 + >BR (LR 1) (LR 2) </code ></strong - >1 + ><1,2> <code class="prompt" >>>> </code ><strong class="userinput" ><code - >let x = LR 1 + >let x = BR (LR 1) (LR 2) </code ></strong ><code class="prompt" @@ -349,16 +355,16 @@ >:t x </code ></strong - >x :: Num a => RTree 0 a + >x :: Num a => RTree 1 a </pre ><p - >Can be used as a pattern:</p + >Case be used a pattern:</p ><pre class="screen" ><code class="prompt" >>>> </code ><strong class="userinput" ><code - >let f (LR a) (LR b) = a + b + >let f (BR (LR a) (LR b)) = LR (a + b) </code ></strong ><code class="prompt" @@ -368,12 +374,12 @@ >:t f </code ></strong - >f :: Num a => RTree 0 a -> RTree 0 a -> a + >f :: Num a => RTree 1 a -> RTree 0 a <code class="prompt" >>>> </code ><strong class="userinput" ><code - >f (LR 1) (LR 2) + >f (BR (LR 1) (LR 2)) </code ></strong >3 @@ -384,34 +390,28 @@ ><td class="src" ><span class="keyword" >pattern</span - > <a id="v:BR" class="def" - >BR</a - > :: <a href="#" title="BundledPatterns2" - >RTree</a - > d a -> <a href="#" title="BundledPatterns2" - >RTree</a - > d a -> <a href="#" title="BundledPatterns2" + > <a id="v:LR" class="def" + >LR</a + > :: a -> <a href="#" title="BundledPatterns2" >RTree</a - > (d <a href="#" title="GHC.TypeLits" - >+</a - > 1) a</td + > 0 a</td ><td class="doc" ><p - >Branch of a perfect depth tree</p + >Leaf of a perfect depth tree</p ><pre class="screen" ><code class="prompt" >>>> </code ><strong class="userinput" ><code - >BR (LR 1) (LR 2) + >LR 1 </code ></strong - ><1,2> + >1 <code class="prompt" >>>> </code ><strong class="userinput" ><code - >let x = BR (LR 1) (LR 2) + >let x = LR 1 </code ></strong ><code class="prompt" @@ -421,16 +421,16 @@ >:t x </code ></strong - >x :: Num a => RTree 1 a + >x :: Num a => RTree 0 a </pre ><p - >Case be used a pattern:</p + >Can be used as a pattern:</p ><pre class="screen" ><code class="prompt" >>>> </code ><strong class="userinput" ><code - >let f (BR (LR a) (LR b)) = LR (a + b) + >let f (LR a) (LR b) = a + b </code ></strong ><code class="prompt" @@ -440,12 +440,12 @@ >:t f </code ></strong - >f :: Num a => RTree 1 a -> RTree 0 a + >f :: Num a => RTree 0 a -> RTree 0 a -> a <code class="prompt" >>>> </code ><strong class="userinput" ><code - >f (BR (LR 1) (LR 2)) + >f (LR 1) (LR 2) </code ></strong >3 diff --git a/utils/haddock/latex-test/ref/ConstructorArgs/ConstructorArgs.tex b/utils/haddock/latex-test/ref/ConstructorArgs/ConstructorArgs.tex index b7870fa99a23229b27d76458e9b33ff5e71ce70e..b919b272209be1bcf053c628fc71e9a1dcc0098c 100644 --- a/utils/haddock/latex-test/ref/ConstructorArgs/ConstructorArgs.tex +++ b/utils/haddock/latex-test/ref/ConstructorArgs/ConstructorArgs.tex @@ -3,7 +3,7 @@ \haddockbeginheader {\haddockverb\begin{verbatim} module ConstructorArgs ( - Foo((:|), Rec, x, y, Baz, Boa, (:*)), Boo(Foo, Foa, Fo, Fo'), pattern Bo, + Foo((:*), (:|), Baz, Boa, Rec, x, y), Boo(Foo, Foa, Fo, Fo'), pattern Bo, pattern Bo' ) where\end{verbatim}} \haddockendheader diff --git a/utils/haddock/latex-test/ref/DefaultSignatures/DefaultSignatures.tex b/utils/haddock/latex-test/ref/DefaultSignatures/DefaultSignatures.tex index 161320835d59bf716a159259781cc10557216198..674b25bffcfe1f983e5ffc4007544d0e9603ff66 100644 --- a/utils/haddock/latex-test/ref/DefaultSignatures/DefaultSignatures.tex +++ b/utils/haddock/latex-test/ref/DefaultSignatures/DefaultSignatures.tex @@ -3,7 +3,7 @@ \haddockbeginheader {\haddockverb\begin{verbatim} module DefaultSignatures ( - Foo(baz', baz, bar) + Foo(bar, baz, baz') ) where\end{verbatim}} \haddockendheader diff --git a/utils/haddock/latex-test/ref/GadtConstructorArgs/GadtConstructorArgs.tex b/utils/haddock/latex-test/ref/GadtConstructorArgs/GadtConstructorArgs.tex index e5b2123df106f3ac78b3033bff47f9e686218b0b..d53cd410b67150cf7db3428a5aa1376ef310d47f 100644 --- a/utils/haddock/latex-test/ref/GadtConstructorArgs/GadtConstructorArgs.tex +++ b/utils/haddock/latex-test/ref/GadtConstructorArgs/GadtConstructorArgs.tex @@ -3,7 +3,7 @@ \haddockbeginheader {\haddockverb\begin{verbatim} module GadtConstructorArgs ( - Boo(Fot, x, y, Fob, w, z) + Boo(Fob, Fot, w, x, y, z) ) where\end{verbatim}} \haddockendheader diff --git a/utils/haddock/latex-test/ref/TypeFamilies3/TypeFamilies3.tex b/utils/haddock/latex-test/ref/TypeFamilies3/TypeFamilies3.tex index 6ceb36864af0a1601d7cdc7b1826375b01b09c81..2881b14b9273fe0eb1e48e2ade157b6c337e32c8 100644 --- a/utils/haddock/latex-test/ref/TypeFamilies3/TypeFamilies3.tex +++ b/utils/haddock/latex-test/ref/TypeFamilies3/TypeFamilies3.tex @@ -3,7 +3,7 @@ \haddockbeginheader {\haddockverb\begin{verbatim} module TypeFamilies3 ( - Foo, Bar, Baz(Baz3, Baz2, Baz1) + Foo, Bar, Baz(Baz1, Baz2, Baz3) ) where\end{verbatim}} \haddockendheader