[Git][ghc/ghc][master] ghci: fix module name string lifetime in hs_hpc_module invocation
by Marge Bot (@marge-bot) 28 May '26
by Marge Bot (@marge-bot) 28 May '26
28 May '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
8ab506ff by Cheng Shao at 2026-05-27T21:42:47-04:00
ghci: fix module name string lifetime in hs_hpc_module invocation
This patch makes hpcAddModule pass a properly malloced module name
string to hs_hpc_module, instead of using useAsCString which causes
use-after-free of module name string. Fixes #27297.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
4 changed files:
- + libraries/ghc-boot/GHC/Data/ShortByteString.hs
- libraries/ghc-boot/ghc-boot.cabal.in
- libraries/ghci/GHCi/Coverage.hs
- libraries/ghci/GHCi/Run.hs
Changes:
=====================================
libraries/ghc-boot/GHC/Data/ShortByteString.hs
=====================================
@@ -0,0 +1,17 @@
+module GHC.Data.ShortByteString
+ ( newCStringFromSBS
+ ) where
+
+import Prelude
+
+import qualified Data.ByteString.Short as SBS
+import Foreign
+import Foreign.C
+
+newCStringFromSBS :: SBS.ShortByteString -> IO CString
+newCStringFromSBS sbs =
+ SBS.useAsCStringLen sbs $ \(src, len) -> do
+ dst <- mallocBytes (len + 1)
+ copyBytes dst src len
+ pokeByteOff dst len (0 :: Word8)
+ pure dst
=====================================
libraries/ghc-boot/ghc-boot.cabal.in
=====================================
@@ -51,6 +51,7 @@ Library
exposed-modules:
GHC.BaseDir
+ GHC.Data.ShortByteString
GHC.Data.ShortText
GHC.Data.SizedSeq
GHC.Data.SmallArray
=====================================
libraries/ghci/GHCi/Coverage.hs
=====================================
@@ -9,9 +9,9 @@ import Prelude -- See note [Why do we import Prelude here?]
import Control.Exception
import Data.ByteString.Short (ShortByteString)
-import qualified Data.ByteString.Short as SBS
import Data.Word
import Foreign
+import GHC.Data.ShortByteString
import GHC.Foreign (CString)
import GHC.Utils.Encoding.UTF8 (utf8DecodeShortByteString)
import GHCi.ObjLink (lookupSymbol)
@@ -31,17 +31,19 @@ hpcAddModule ::
-- ^ Name of the ticks array found in the c-stub.
IO ()
hpcAddModule modlName ticks hash tickboxes = do
- SBS.useAsCString modlName $ \modlNameLiteral -> do
- -- we need to find the reference to the ticks array.
- lookupSymbol tickboxes >>= \ case
- Nothing -> do
- -- the symbol is not found, this is a bug!
- throwIO $ ErrorCall $ "hpcAddModule: failed to find symbol " <> utf8DecodeShortByteString tickboxes
- Just tickBoxRef -> do
- -- Calling 'hs_hpc_module' multiple times is safe, it will add the module only once.
- hpc_register_module modlNameLiteral (fromIntegral ticks) (fromIntegral hash) (castPtr tickBoxRef)
- -- calling 'hpc_startup' multiple times is safe, it will only be initialised once.
- hpc_startup
+ -- we need to find the reference to the ticks array.
+ lookupSymbol tickboxes >>= \ case
+ Nothing -> do
+ -- the symbol is not found, this is a bug!
+ throwIO $ ErrorCall $ "hpcAddModule: failed to find symbol " <> utf8DecodeShortByteString tickboxes
+ Just tickBoxRef -> do
+ -- hs_hpc_module stores the module name pointer in the RTS hash table
+ -- until exitHpc, so pass a malloced C string.
+ modlNameLiteral <- newCStringFromSBS modlName
+ -- Calling 'hs_hpc_module' multiple times is safe, it will add the module only once.
+ hpc_register_module modlNameLiteral (fromIntegral ticks) (fromIntegral hash) (castPtr tickBoxRef)
+ -- calling 'hpc_startup' multiple times is safe, it will only be initialised once.
+ hpc_startup
foreign import ccall unsafe "hs_hpc_module"
hpc_register_module :: CString -> Word32 -> Word32 -> Ptr Word64 -> IO ()
=====================================
libraries/ghci/GHCi/Run.hs
=====================================
@@ -37,6 +37,9 @@ import Control.Monad
import Data.ByteString (ByteString)
import qualified Data.ByteString.Short.Internal as BS
import qualified Data.ByteString.Unsafe as B
+#if defined(PROFILING)
+import GHC.Data.ShortByteString
+#endif
import GHC.Exts
import qualified GHC.Exts.Heap as Heap
import GHC.Stack
@@ -447,13 +450,6 @@ mkCostCentres mod ccs = do
c_srcspan <- newCStringFromSBS srcspan
toRemotePtr <$> c_mkCostCentre c_name c_module c_srcspan
- newCStringFromSBS sbs = do
- let len = BS.length sbs
- buf <- mallocBytes $ len + 1
- BS.copyToPtr sbs 0 buf (fromIntegral len)
- pokeByteOff buf len (0 :: Word8)
- pure buf
-
foreign import ccall unsafe "mkCostCentre"
c_mkCostCentre :: Ptr CChar -> Ptr CChar -> Ptr CChar -> IO (Ptr CostCentre)
#else
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8ab506ff3219560b20e1d9040e79337…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8ab506ff3219560b20e1d9040e79337…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][master] Trim the continuation in mkDupableContWithDmds
by Marge Bot (@marge-bot) 28 May '26
by Marge Bot (@marge-bot) 28 May '26
28 May '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
4a645683 by Simon Peyton Jones at 2026-05-27T21:41:59-04:00
Trim the continuation in mkDupableContWithDmds
When there are no remaining argument demands, it means the application
is bottoming. In this case, we can trim the continuation to avoid the
panic that was observed in #27261.
See Note [Trimming the continuation for bottoming functions] in
GHC.Core.Opt.Simplify.Iteration.
- - - - -
6 changed files:
- + changelog.d/T27261
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- + testsuite/tests/simplCore/should_compile/T27261.hs
- + testsuite/tests/simplCore/should_compile/T27261_aux.hs
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
changelog.d/T27261
=====================================
@@ -0,0 +1,10 @@
+section: compiler
+issues: #27261
+mrs: !16084
+synopsis:
+ Avoid a crash in ``mkDupableContWithDmds`` when given empty demands
+description:
+ The case of an empty list of remaining argument demands is now explicitly
+ handled by trimming the simplifier continuation, to avoid a compiler crash
+ of the form ``Non-exhaustive patterns in dmd : cont_dmds`` or ``expectNonEmpty``
+ in ``mkDupableContWithDmds``.
=====================================
compiler/GHC/Core/Opt/Simplify/Iteration.hs
=====================================
@@ -62,6 +62,7 @@ import GHC.Types.Var ( isTyCoVar )
import GHC.Builtin.Types.Prim( realWorldStatePrimTy )
import GHC.Builtin.Names( runRWKey, seqHashKey )
+import qualified GHC.Data.List.Infinite as Inf
import GHC.Data.Maybe ( isNothing, orElse, mapMaybe )
import GHC.Data.FastString
import GHC.Unit.Module ( moduleName )
@@ -2444,24 +2445,9 @@ rebuildCall env arg_info _cont
---------- Bottoming applications --------------
rebuildCall env (ArgInfo { ai_fun = fun, ai_args = rev_args, ai_dmds = [] }) cont
- -- When we run out of strictness args, it means
- -- that the call is definitely bottom; see GHC.Core.Opt.Simplify.Utils.mkArgInfo
- -- Then we want to discard the entire strict continuation. E.g.
- -- * case (error "hello") of { ... }
- -- * (error "Hello") arg
- -- * f (error "Hello") where f is strict
- -- etc
- -- Then, especially in the first of these cases, we'd like to discard
- -- the continuation, leaving just the bottoming expression. But the
- -- type might not be right, so we may have to add a coerce.
- | not (contIsTrivial cont) -- Only do this if there is a non-trivial
- -- continuation to discard, else we do it
- -- again and again!
- = seqType cont_ty `seq` -- See Note [Avoiding space leaks in OutType]
- return (emptyFloats env, castBottomExpr res cont_ty)
- where
- res = argInfoExpr fun rev_args
- cont_ty = contResultType cont
+ -- When we run out of demands, it means that the call is definitely bottom.
+ -- See (TC2) in Note [Trimming the continuation for bottoming functions]
+ = rebuild env (argInfoExpr fun rev_args) (mkBottomCont cont)
---------- Simplify type applications --------------
rebuildCall env info (ApplyToTy { sc_arg_ty = arg_ty, sc_hole_ty = hole_ty, sc_cont = cont })
@@ -4045,6 +4031,41 @@ When we have
then we can just duplicate those alts because the A and C cases
will disappear immediately. This is more direct than creating
join points and inlining them away. See #4930.
+
+Note [Trimming the continuation for bottoming functions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Suppose
+ f :: Int -> Int -> Int
+ f x = error "urk"
+
+ foo = f 3 4
+
+f's demand signature say "after one arg I return bottom". We can drop
+the remaining arguments, thus
+
+ foo = case f 3 of {}
+
+This trimming can also be done with other continuations:
+ * case (error "hello") of { ... }
+ * f (error "Hello") where f is strict
+ etc
+
+We implement the trimming in three parts:
+
+(TC1) In `mkArgInfo`, for a bottoming function, we make a list of `RemainingArgDmds`
+ with a finite list of elements (in the example above, just one).
+
+ For comparison, note that, for non-bottoming functions, the `RemainingArgDmds`
+ always finishes with an infinite list of `topDmd`.
+
+(TC2) In `rebuildCall`, when we run out of `RemainingArgDmds` we discard the
+ remaining continuation.
+
+ After discarding the continuation, the types might not match, in which case
+ we leave behind a (case <hole> of {}) wrapper. See the call to `mkBottomCont`.
+
+(TC3) In `mkDupableContWithDmds`, we similarly discard the continuation when
+ we run out of `RemainingArgDmds`.
-}
--------------------
@@ -4079,10 +4100,10 @@ mkDupableCont env cont
= mkDupableContWithDmds (zapSubstEnv env) (repeat topDmd) cont
mkDupableContWithDmds
- :: SimplEnvIS -> [Demand] -- Demands on arguments; always infinite
+ :: SimplEnvIS -> RemainingArgDmds
-> SimplCont -> SimplM ( SimplFloats, SimplCont)
-mkDupableContWithDmds env _ cont
+mkDupableContWithDmds env remaining_dmds cont
-- Check the invariant
| assertPpr (checkSimplEnvIS env) (pprBadSimplEnvIS env) False
= pprPanic "mkDupableContWithDmds" empty
@@ -4090,6 +4111,13 @@ mkDupableContWithDmds env _ cont
| contIsDupable cont
= return (emptyFloats env, cont)
+ -- No more demands => function is definitely bottom
+ -- => simply trim the continuation
+ -- c.f. the null-demands case in `rebuildCall`
+ -- See (TC3) in Note [Trimming the continuation for bottoming functions]
+ | null remaining_dmds
+ = return (emptyFloats env, mkBottomCont cont)
+
mkDupableContWithDmds _ _ (Stop {}) = panic "mkDupableCont" -- Handled by previous eqn
mkDupableContWithDmds env dmds (CastIt { sc_co = co, sc_opt = opt, sc_cont = cont })
@@ -4134,7 +4162,8 @@ mkDupableContWithDmds env _
, thumbsUpPlanA cont
= -- Use Plan A of Note [Duplicating StrictArg]
-- pprTrace "Using plan A" (ppr (ai_fun fun) $$ text "args" <+> ppr (ai_args fun) $$ text "cont" <+> ppr cont) $
- do { let _ :| dmds = expectNonEmpty $ ai_dmds fun
+ do { let _ :| dmds = expectNonEmpty (ai_dmds fun) -- See Invariant of StrictArg;
+ -- ai_dmds is never empty
; (floats1, cont') <- mkDupableContWithDmds env dmds cont
-- Use the demands from the function to add the right
-- demand info on any bindings we make for further args
@@ -4180,7 +4209,10 @@ mkDupableContWithDmds env dmds
-- let a = ...arg...
-- in [...hole...] a
-- NB: sc_dup /= OkToDup; that is caught earlier by contIsDupable
- do { let dmd:|cont_dmds = expectNonEmpty dmds
+ do { let dmd:|cont_dmds =
+ -- We took care to handle an empty demand list at the start,
+ -- ensuring this call to 'expectNonEmpty' does not panic (#27261).
+ expectNonEmpty dmds
; (floats1, cont') <- mkDupableContWithDmds env cont_dmds cont
; let env' = env `setInScopeFromF` floats1
; arg' <- simplArg env' Nothing hole_ty se arg arg_mco
@@ -4251,7 +4283,7 @@ mkDupableStrictBind env arg_bndr join_rhs res_ty
; let arg_info = ArgInfo { ai_fun = join_bndr
, ai_rules = [], ai_args = []
, ai_encl = False, ai_dmds = repeat topDmd
- , ai_discs = repeat 0 }
+ , ai_discs = Inf.repeat 0 }
; return ( addJoinFloats (emptyFloats env) $
unitJoinFloat $
NonRec join_bndr $
=====================================
compiler/GHC/Core/Opt/Simplify/Utils.hs
=====================================
@@ -25,13 +25,13 @@ module GHC.Core.Opt.Simplify.Utils (
StaticEnv(..),
isSimplified, contIsStop,
contIsDupable, contResultType, contHoleType, contHoleScaling,
- contIsTrivial, contArgs, contIsRhs,
+ contIsTrivial, contArgs, contIsRhs, mkBottomCont,
hasArgs, countArgs, contOutArgs, dropContArgs,
mkBoringStop, mkRhsStop, mkLazyArgStop,
interestingCallContext,
-- ArgInfo
- ArgInfo(..), ArgSpec(..), mkArgInfo,
+ ArgInfo(..), ArgSpec(..), RemainingArgDmds, mkArgInfo,
addValArgTo, addTyArgTo,
argInfoExpr, argSpecArg,
pushOutArgs, pushArgSpecs,
@@ -54,8 +54,10 @@ import GHC.Core.Opt.Stats ( Tick(..) )
import qualified GHC.Core.Subst
import GHC.Core.Ppr
import GHC.Core.TyCo.Ppr ( pprParendType )
+import GHC.Core.TyCo.Compare ( eqTypeIgnoringMultiplicity )
import GHC.Core.FVs
import GHC.Core.Utils
+import GHC.Core.Make( mkWildValBinder )
import GHC.Core.Opt.Arity
import GHC.Core.Unfold
import GHC.Core.Unfold.Make
@@ -75,6 +77,8 @@ import GHC.Types.Var.Set
import GHC.Types.Basic
import GHC.Types.Name.Env
+import GHC.Data.List.Infinite ( Infinite(..) )
+import qualified GHC.Data.List.Infinite as Inf
import GHC.Data.OrdList ( isNilOL )
import GHC.Data.FastString ( fsLit )
@@ -205,10 +209,10 @@ data SimplCont
| StrictArg -- (StrictArg (f e1 ..en) K)[e] = K[ f e1 .. en e ]
{ sc_dup :: DupFlag
- , sc_fun :: ArgInfo -- Specifies f, e1..en, Whether f has rules, etc
+ , sc_fun :: ArgInfo -- Specifies f, e1..en, whether f has rules, etc
-- plus demands and discount flags for *this* arg
-- and further args
- -- So ai_dmds and ai_discs are never empty
+ -- Invariant: ai_dmds and ai_discs are never empty
, sc_fun_ty :: OutType -- Type of the function (f e1 .. en),
-- presumably (arg_ty -> res_ty)
-- where res_ty is expected by sc_cont
@@ -348,32 +352,41 @@ doesn't matter because we'll never compute them all.
data ArgInfo
= ArgInfo {
- ai_fun :: OutId, -- The function
- ai_args :: [ArgSpec], -- ...applied to these args (which are in *reverse* order)
+ ai_fun :: OutId, -- ^ The function
+ ai_args :: [ArgSpec], -- ^ ...applied to these args (which are in *reverse* order)
-- NB: all these argumennts are already simplified
- ai_rules :: [CoreRule], -- Rules for this function
- ai_encl :: Bool, -- Flag saying whether this function
- -- or an enclosing one has rules (recursively)
- -- True => be keener to inline in all args
+ ai_rules :: [CoreRule], -- ^ Rules for this function
+ ai_encl :: Bool,
+ -- ^ Flag saying whether this function or an enclosing one has rules
+ -- (recursively)
+ --
+ -- @True@ means: be keener to inline in all args
- ai_dmds :: [Demand], -- Demands on remaining value arguments (beyond ai_args)
- -- Usually infinite, but if it is finite it guarantees
- -- that the function diverges after being given
- -- that number of args
+ ai_dmds :: RemainingArgDmds,
+ -- ^ Demands on remaining value arguments (beyond 'ai_args')
- ai_discs :: [Int] -- Discounts for remaining value arguments (beyond ai_args)
- -- non-zero => be keener to inline
- -- Always infinite
+ ai_discs :: Infinite Int
+ -- ^ Discounts for remaining value arguments (beyond 'ai_args')
+ --
+ -- A non-zero value means: be keener to inline
}
-data ArgSpec
- = ValArg { as_dmd :: Demand -- Demand placed on this argument
- , as_arg :: OutExpr -- Apply to this (coercion or value); c.f. ApplyToVal
- , as_hole_ty :: OutType } -- Type of the function (presumably t1 -> t2)
+-- | 'RemainingArgDmds' gives the demands on any remaining value arguments.
+--
+-- It is usually infinite (with 'topDmd's in the tail), but if it is finite it
+-- guarantees that the function diverges after being applied to that number
+-- of arguments.
+type RemainingArgDmds = [Demand]
- | TyArg { as_arg_ty :: OutType -- Apply to this type; c.f. ApplyToTy
- , as_hole_ty :: OutType } -- Type of the function (presumably forall a. blah)
+data ArgSpec
+ -- | A value argument
+ = ValArg { as_dmd :: Demand -- ^ Demand placed on this argument
+ , as_arg :: OutExpr -- ^ Apply to this (coercion or value); c.f. 'ApplyToVal'
+ , as_hole_ty :: OutType } -- ^ Type of the function (presumably @t1 -> t2@ for 'ValArg' or @forall a. blah@ for 'TyArg')
+ -- | A type argument
+ | TyArg { as_arg_ty :: OutType -- ^ Apply to this type; c.f. 'ApplyToTy'
+ , as_hole_ty :: OutType } -- ^ Type of the function (presumably @t1 -> t2@ for 'ValArg' or @forall a. blah@ for 'TyArg')
instance Outputable ArgInfo where
ppr (ArgInfo { ai_fun = fun, ai_args = args, ai_dmds = dmds, ai_rules = rules })
@@ -389,7 +402,7 @@ instance Outputable ArgSpec where
addValArgTo :: ArgInfo -> OutExpr -> OutType -> ArgInfo
addValArgTo ai arg hole_ty
- | ArgInfo { ai_dmds = dmd:dmds, ai_discs = _:discs } <- ai
+ | ArgInfo { ai_dmds = dmd:dmds, ai_discs = Inf _ discs } <- ai
-- Pop the top demand and and discounts off
, let arg_spec = ValArg { as_arg = arg, as_hole_ty = hole_ty, as_dmd = dmd }
= ai { ai_args = arg_spec : ai_args ai
@@ -492,12 +505,23 @@ contIsDupable (TickIt _ k) = contIsDupable k
contIsTrivial :: SimplCont -> Bool
contIsTrivial (Stop {}) = True
contIsTrivial (ApplyToTy { sc_cont = k }) = contIsTrivial k
--- This one doesn't look right. A value application is not trivial
--- contIsTrivial (ApplyToVal { sc_arg = Coercion _, sc_cont = k }) = contIsTrivial k
contIsTrivial (CastIt { sc_cont = k }) = contIsTrivial k
contIsTrivial _ = False
-------------------
+contStop :: SimplCont -> SimplCont
+-- ^ Get the 'Stop' at the tail of the continuation
+--
+-- Always returns a continuation of form @(Stop ...)@.
+contStop stop@(Stop {}) = stop
+contStop (CastIt { sc_cont = k }) = contStop k
+contStop (StrictBind { sc_cont = k }) = contStop k
+contStop (StrictArg { sc_cont = k }) = contStop k
+contStop (Select { sc_cont = k }) = contStop k
+contStop (ApplyToTy { sc_cont = k }) = contStop k
+contStop (ApplyToVal { sc_cont = k }) = contStop k
+contStop (TickIt _ k) = contStop k
+
contResultType :: SimplCont -> OutType
contResultType (Stop ty _ _) = ty
contResultType (CastIt { sc_cont = k }) = contResultType k
@@ -651,6 +675,35 @@ contEvalContext bndrs cont = go cont
-- Perhaps reconstruct the demand on the scrutinee by looking at field
-- and case binder dmds, see addCaseBndrDmd. No priority right now.
+-------------------
+mkBottomCont ::SimplCont -> SimplCont
+-- ^ Given a continuation `cont`, return a `cont` /of the same type/,
+-- looking like @(case \<hole\> of {})@.
+--
+-- This is used when we are going to fill in the @<hole>@ with bottom.
+-- See (TC2,3) in Note [Trimming the continuation for bottoming functions]
+--
+-- Don't bother to trim, making a @case <hole> of {}@, if we have only
+-- an essentially-trivial continuation; e.g. @(<hole> \@ty |> co)@.
+mkBottomCont cont = go cont
+ where
+ go k@(Stop {}) = k
+ go (TickIt t k') = TickIt t (go k')
+ go k@(CastIt { sc_cont = k' }) = k { sc_cont = go k' }
+ go k@(ApplyToTy { sc_cont = k' }) = k { sc_cont = go k' }
+ go k@(Select { sc_alts = [], sc_cont = Stop {} }) = k -- Optimisation only
+ go k | Stop res_ty _ _ <- stop_cont
+ , hole_ty `eqTypeIgnoringMultiplicity` res_ty
+ = stop_cont
+ | otherwise
+ = Select { sc_alts = []
+ , sc_bndr = mkWildValBinder OneTy hole_ty
+ , sc_env = Simplified OkDup
+ , sc_cont = stop_cont }
+ where
+ hole_ty = contHoleType k
+ stop_cont = contStop k
+
-------------------
mkArgInfo :: SimplEnv -> Id -> [CoreRule] -> SimplCont -> ArgInfo
mkArgInfo env fun rules_for_fun cont
@@ -672,16 +725,17 @@ mkArgInfo env fun rules_for_fun cont
fun_has_rules = not (null rules_for_fun)
- vanilla_discounts, arg_discounts :: [Int]
- vanilla_discounts = repeat 0
+ vanilla_discounts, arg_discounts :: Infinite Int
+ vanilla_discounts = Inf.repeat 0
arg_discounts = case idUnfolding fun of
CoreUnfolding {uf_guidance = UnfIfGoodArgs {ug_args = discounts}}
- -> discounts ++ vanilla_discounts
+ -> discounts Inf.++ vanilla_discounts
_ -> vanilla_discounts
- vanilla_dmds, arg_dmds :: [Demand]
+ vanilla_dmds :: RemainingArgDmds
vanilla_dmds = repeat topDmd
+ arg_dmds :: RemainingArgDmds
arg_dmds
| not (seInline env)
= vanilla_dmds -- See Note [Do not expose strictness if sm_inline=False]
@@ -689,26 +743,22 @@ mkArgInfo env fun rules_for_fun cont
= -- add_type_str fun_ty $
case splitDmdSig (idDmdSig fun) of
(demands, result_info)
- | not (demands `lengthExceeds` n_val_args)
- -> -- Enough args, use the strictness given.
- -- For bottoming functions we used to pretend that the arg
- -- is lazy, so that we don't treat the arg as an
- -- interesting context. This avoids substituting
- -- top-level bindings for (say) strings into
- -- calls to error. But now we are more careful about
- -- inlining lone variables, so its ok
- -- (see GHC.Core.Op.Simplify.Utils.analyseCont)
- if isDeadEndDiv result_info then
- demands -- Finite => result is bottom
- else
- demands ++ vanilla_dmds
+ | not (demands `lengthExceeds` n_val_args)
+ -> remaining_dmds -- Enough args, use the strictness given.
| otherwise
-> warnPprTrace True "More demands than arity" (ppr fun <+> ppr (idArity fun)
<+> ppr n_val_args <+> ppr demands) $
vanilla_dmds -- Not enough args, or no strictness
- add_type_strictness :: Type -> [Demand] -> [Demand]
- -- If the function arg types are strict, record that in the 'strictness bits'
+ where
+ remaining_dmds :: RemainingArgDmds
+ -- isDeadEndDiv: if remaining_dmds is finite, result is bottom
+ -- See (TC1) in Note [Trimming the continuation for bottoming functions]
+ remaining_dmds | isDeadEndDiv result_info = demands
+ | otherwise = demands ++ vanilla_dmds
+
+ add_type_strictness :: Type -> RemainingArgDmds -> RemainingArgDmds
+ -- If the function arg /types/ are strict, record that in the RemainingArgDmds
-- No need to instantiate because unboxed types (which dominate the strict
-- types) can't instantiate type variables.
-- add_type_strictness is done repeatedly (for each call);
@@ -915,16 +965,16 @@ the incentive to disappear when we inline `f`!
lazyArgContext :: ArgInfo -> CallCtxt
-- Use this for lazy arguments
lazyArgContext (ArgInfo { ai_encl = encl_rules, ai_discs = discs })
- | encl_rules = RuleArgCtxt
- | disc:_ <- discs, disc > 0 = DiscArgCtxt -- Be keener here
- | otherwise = BoringCtxt -- Nothing interesting
+ | encl_rules = RuleArgCtxt
+ | Inf disc _ <- discs, disc > 0 = DiscArgCtxt -- Be keener here
+ | otherwise = BoringCtxt -- Nothing interesting
strictArgContext :: ArgInfo -> CallCtxt
strictArgContext (ArgInfo { ai_encl = encl_rules, ai_discs = discs })
-- Use this for strict arguments
- | encl_rules = RuleArgCtxt
- | disc:_ <- discs, disc > 0 = DiscArgCtxt -- Be keener here
- | otherwise = RhsCtxt NonRecursive
+ | encl_rules = RuleArgCtxt
+ | Inf disc _ <- discs, disc > 0 = DiscArgCtxt -- Be keener here
+ | otherwise = RhsCtxt NonRecursive
-- Why RhsCtxt? if we see f (g x), and f is strict, we
-- want to be a bit more eager to inline g, because it may
-- expose an eval (on x perhaps) that can be eliminated or
=====================================
testsuite/tests/simplCore/should_compile/T27261.hs
=====================================
@@ -0,0 +1,17 @@
+{-# OPTIONS_GHC -fno-full-laziness #-}
+
+module T27261 (foo) where
+
+import T27261_aux (myError)
+
+foo :: [String] -> (() -> Int) -> Int
+foo cs =
+ \ k -> ( case bar of
+ Just str -> let cs2 = case cs of { [] -> cs; _ -> "stack entry" : cs }
+ in myError cs2 str
+ Nothing -> \ c -> c () )
+ ( \ _ -> k () )
+
+bar :: Maybe String
+bar = Nothing
+{-# NOINLINE bar #-}
=====================================
testsuite/tests/simplCore/should_compile/T27261_aux.hs
=====================================
@@ -0,0 +1,7 @@
+{-# LANGUAGE BangPatterns #-}
+
+module T27261_aux (myError) where
+
+myError :: [String] -> String -> a
+myError !_ _ = undefined
+{-# NOINLINE myError #-}
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -601,3 +601,4 @@ test('T25718a', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress
test('T25718b', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
test('T25718c', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
test('T19166', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
+test('T27261', [extra_files(['T27261_aux.hs'])], multimod_compile, ['T27261', '-v0 -O'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4a645683ee0bd4421a88cd6ec49b40c…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4a645683ee0bd4421a88cd6ec49b40c…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/az/ghc-10.1-exactprint-update-wip] Added an intro section
by Simon Peyton Jones (@simonpj) 27 May '26
by Simon Peyton Jones (@simonpj) 27 May '26
27 May '26
Simon Peyton Jones pushed to branch wip/az/ghc-10.1-exactprint-update-wip at Glasgow Haskell Compiler / GHC
Commits:
2d4151e9 by Simon Peyton Jones at 2026-05-28T00:10:26+01:00
Added an intro section
- - - - -
1 changed file:
- ExactPrint.md
Changes:
=====================================
ExactPrint.md
=====================================
@@ -13,6 +13,67 @@ information directly into every AST node to allow the tree to be reprinted _exac
original source, byte-for-byte (modulo tab expansion). When a tool modifies the AST it adjusts
only the annotations it needs to change; all surrounding nodes reprint themselves unchanged.
+## Background: the syntax tree
+
+The AST of the source program is represented using the data types defined in `Language.Haskell.Syntax.*`.
+This data type uses the "Trees That Grow (TTG)" plan;
+see [Implementing trees that grow](https://gitlab.haskell.org/ghc/ghc/-/wikis/implementing-trees-that-gr…
+
+For example, in (GHC-independent) `Language.Haskell.Syntax.Expr`:
+```
+data HsExpr p
+ = ... many constructors including ...
+ | HsLet (XLet p)
+ (HsLocalBinds p)
+ (LHsExpr p)
+
+type family XLet p
+type LHsExpr p = XRec p (HsExpr p)
+
+```
+Note that
+* The `(XLet p)` field is the *extension field* of the `HsLet` data constructor,
+ where `XLet` is a type family.
+* Almost every node is wrapped in an `XRec`, another type family. That makes it easy
+ for clients to attach arbitrary information to each node.
+
+GHC specialises this data a type in `GHC.Hs.*`, as follows:
+```
+data Pass = Parsed | Renamed | Typechecked
+
+data GhcPass (c :: Pass) where
+ GhcPs :: GhcPass 'Parsed
+ GhcRn :: GhcPass 'Renamed
+ GhcTc :: GhcPass 'Typechecked
+
+type family XRec p a = r | r -> a
+type instance XRec (GhcPass p) t = XRecGhc t
+
+-- (XRecGhc tree) wraps `tree` in a GHC-specific,
+-- but pass-independent, source location
+type XRecGhc t = GenLocated (Anno t) t
+
+data GenLocated l e = L l e
+type family Anno t
+```
+So, via `XRec`, every node `e :: t` in the GHC-specific version of HsSyn is wrapped in
+a `L ann e`, where `ann :: Anno t` is the annotation on the node.
+
+Notice that there are two places we can hang information:
+* (EXT) **Constructor-specific punctuation**: the extension field of each data constructor
+ can contain information that is specific to that constructor. Example: the location
+ of the keywords `let` and `in` for the `HsLet` construct.
+
+* (XREC) **Entire-node information**: the `Anno t` field that wraps almost every node in the
+ syntax tree can contain information that is needed for *every* node. Classic example:
+ the `SrcSpan` of the node.
+
+**NOTE**: currently there is information in (XREC) that more properly belongs in (EXT).
+A refactoring project is under way to put this right.
+
+
+## File layout
+
The subsystem lives primarily in `utils/check-exact/` and is exposed through three main layers:
| Layer | Key operation | Purpose |
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/2d4151e92b1cce8fcb7140619d008ac…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/2d4151e92b1cce8fcb7140619d008ac…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/sjakobi/multi-caret] Add TcRnDuplicateDecls
by Simon Jakobi (@sjakobi2) 27 May '26
by Simon Jakobi (@sjakobi2) 27 May '26
27 May '26
Simon Jakobi pushed to branch wip/sjakobi/multi-caret at Glasgow Haskell Compiler / GHC
Commits:
1f7ffaaa by Simon Jakobi at 2026-05-27T22:54:22+02:00
Add TcRnDuplicateDecls
- - - - -
3 changed files:
- compiler/GHC/Tc/Errors/Ppr.hs
- testsuite/tests/rename/should_fail/T7164.stderr
- testsuite/tests/rename/should_fail/all.T
Changes:
=====================================
compiler/GHC/Tc/Errors/Ppr.hs
=====================================
@@ -3464,6 +3464,8 @@ instance Diagnostic TcRnMessage where
-> diagnosticRelatedLocations msg'
TcRnBindingNameConflict _ locs
-> NE.tail locs
+ TcRnDuplicateDecls _ names
+ -> map nameSrcSpan (NE.init names)
_ ->
[]
=====================================
testsuite/tests/rename/should_fail/T7164.stderr
=====================================
@@ -1,5 +1,11 @@
-
-T7164.hs:8:1: [GHC-29916]
+T7164.hs:8:1: error: [GHC-29916]
Multiple declarations of ‘derp’
Declared at: T7164.hs:5:5
T7164.hs:8:1
+ |
+5 | derp :: m a
+ | ^^^^^^^^^^^
+ |
+8 | derp = 123
+ | ^^^^
+
=====================================
testsuite/tests/rename/should_fail/all.T
=====================================
@@ -91,7 +91,7 @@ test('T6148a', normal, compile_fail, [''])
test('T6148b', normal, compile_fail, [''])
test('T6148c', normal, compile_fail, [''])
test('T6148d', normal, compile_fail, [''])
-test('T7164', normal, compile_fail, [''])
+test('T7164', normal, compile_fail, ['-fdiagnostics-show-caret'])
test('T7338', normal, compile_fail, [''])
test('T7338a', normal, compile_fail, [''])
test('T7454', normal, compile, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/1f7ffaaadaa800daf07c937c690140b…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/1f7ffaaadaa800daf07c937c690140b…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/mangoiv/ghc-9.12-bp] 3 commits: packaging: regenerate llvm-targets
by Magnus (@MangoIV) 27 May '26
by Magnus (@MangoIV) 27 May '26
27 May '26
Magnus pushed to branch wip/mangoiv/ghc-9.12-bp at Glasgow Haskell Compiler / GHC
Commits:
6b497eee by mangoiv at 2026-05-27T21:25:30+02:00
packaging: regenerate llvm-targets
regenerate llvm-targets using utils/llvm-targets/gen-data-layout.sh and
clang version 19.1.7
Target: x86_64-unknown-linux-gnu
- - - - -
e246c44d by Cheng Shao at 2026-05-27T21:25:30+02:00
ghc-internal: update to unicode 17.0.0
This commit updates the generated code in ghc-internal to match
unicode 17.0.0.
(cherry picked from commit 7077c9f76ebadedefd763078e7f7c42201b8a4b4)
- - - - -
007b39e6 by Cheng Shao at 2026-05-27T21:25:30+02:00
wasm: ensure post-linker output is synchronous ESM
This patch fixes wasm backend's post-linker output script to ensure
it's synchronous ESM and doesn't use top-level await, which doesn't
work in ServiceWorkers. Fixes #27257.
(cherry picked from commit cccf45da01988801b0c97f7e7ed0160191980226)
- - - - -
13 changed files:
- + changelog.d/wasm-fix-serviceworker
- libraries/base/tests/unicode002.stdout
- libraries/base/tests/unicode003.stdout
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/DerivedCoreProperties.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/UnicodeData/GeneralCategory.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/UnicodeData/SimpleLowerCaseMapping.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/UnicodeData/SimpleTitleCaseMapping.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/UnicodeData/SimpleUpperCaseMapping.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Version.hs
- libraries/ghc-internal/tools/ucd2haskell/ucd.sh
- libraries/ghc-internal/tools/ucd2haskell/unicode_version
- llvm-targets
- utils/jsffi/prelude.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/f2e2876064cd043bc850fec297b1ca…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/f2e2876064cd043bc850fec297b1ca…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/davide/hadrian-aclocal_path] Hadrian: Autoreconf builder on windows converts env variable ACLOCAL_PATH to unix paths
by David Eichmann (@DavidEichmann) 27 May '26
by David Eichmann (@DavidEichmann) 27 May '26
27 May '26
David Eichmann pushed to branch wip/davide/hadrian-aclocal_path at Glasgow Haskell Compiler / GHC
Commits:
2b6f845a by David Eichmann at 2026-05-27T18:09:03+01:00
Hadrian: Autoreconf builder on windows converts env variable ACLOCAL_PATH to unix paths
This is needed to fix hadrian bindist builds on windows in the mysy2
clang64 environment
- - - - -
3 changed files:
- boot
- hadrian/src/Rules/BinaryDist.hs
- hadrian/src/Utilities.hs
Changes:
=====================================
boot
=====================================
@@ -54,7 +54,9 @@ def autoreconf():
if os.name == 'nt':
# Get the normalized ACLOCAL_PATH for Windows
# This is necessary since on Windows this will be a Windows
- # path, which autoreconf doesn't know doesn't know how to handle.
+ # path, which autoreconf doesn't know how to handle.
+ #
+ # This logic is duplicated in Hadrian. Specifically in hadrian/src/Rules/BinaryDist.hs
ac_local = os.getenv('ACLOCAL_PATH', '')
ac_local_arg = re.sub(r';', r':', ac_local)
ac_local_arg = re.sub(r'\\', r'/', ac_local_arg)
=====================================
hadrian/src/Rules/BinaryDist.hs
=====================================
@@ -331,7 +331,22 @@ bindistRules = do
ghcRoot <- topDirectory
copyFile (ghcRoot -/- "aclocal.m4") (ghcRoot -/- "distrib" -/- "aclocal.m4")
copyDirectory (ghcRoot -/- "m4") (ghcRoot -/- "distrib")
- buildWithCmdOptions [] $
+
+ -- Get the normalized ACLOCAL_PATH for Windows
+ -- This is necessary since on Windows this will be a Windows
+ -- path, which autoreconf doesn't know how to handle.
+ --
+ -- This logic is duplicated in the `boot` python script
+ win_host <- isWinHost
+ env <- if not win_host
+ then pure []
+ else do
+ aclocalPathMay <- getEnv "ACLOCAL_PATH"
+ pure [ AddEnv "ACLOCAL_PATH" (msys2WindowsToUnixPath aclocalPath)
+ | Just aclocalPath <- [aclocalPathMay]
+ ]
+
+ buildWithCmdOptions env $
target (vanillaContext Stage1 ghc) (Autoreconf $ ghcRoot -/- "distrib") [] []
-- We clean after ourselves, moving the configure script we generated in
-- our bindist dir
=====================================
hadrian/src/Utilities.hs
=====================================
@@ -3,7 +3,8 @@ module Utilities (
askWithResources,
runBuilder, runBuilderWith,
contextDependencies, stage1Dependencies,
- topsortPackages, cabalDependencies
+ topsortPackages, cabalDependencies,
+ msys2WindowsToUnixPath
) where
import qualified Hadrian.Builder as H
@@ -69,3 +70,17 @@ topsortPackages pkgs = do
let annotated = map (annotateInDeg es) es
inDegZero = map snd $ filter ((== 0). fst) annotated
in inDegZero ++ topSort (es \\ inDegZero)
+
+-- | Converts a windows style path to a unix style path using msys2 conventions.
+-- >>> msys2WindowsToUnixPath "C:\\foo\\bar;C:\\msys2\\bin"
+-- "/C/foo/bar:/c/msys2/bin"
+msys2WindowsToUnixPath :: String -> String
+msys2WindowsToUnixPath =
+ replaceDrivePrefix
+ . replace "\\" "/"
+ . replace ";" ":"
+ where
+ replaceDrivePrefix p = case p of
+ drive : ':' : '/' : rest -> '/' : drive : '/' : replaceDrivePrefix rest
+ c : cs -> c : replaceDrivePrefix cs
+ [] -> []
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/2b6f845ab0a42877a0c0e9a11f5ac56…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/2b6f845ab0a42877a0c0e9a11f5ac56…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc] Pushed new branch wip/davide/hadrian-aclocal_path
by David Eichmann (@DavidEichmann) 27 May '26
by David Eichmann (@DavidEichmann) 27 May '26
27 May '26
David Eichmann pushed new branch wip/davide/hadrian-aclocal_path at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/davide/hadrian-aclocal_path
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/davide/windows_ci_env] fixup! TMP: CI: do only x86_64-windows-validate
by David Eichmann (@DavidEichmann) 27 May '26
by David Eichmann (@DavidEichmann) 27 May '26
27 May '26
David Eichmann pushed to branch wip/davide/windows_ci_env at Glasgow Haskell Compiler / GHC
Commits:
18d7b979 by David Eichmann at 2026-05-27T16:28:18+01:00
fixup! TMP: CI: do only x86_64-windows-validate
- - - - -
2 changed files:
- .gitlab-ci.yml
- .gitlab/jobs.yaml
Changes:
=====================================
.gitlab-ci.yml
=====================================
@@ -60,1304 +60,7 @@ default:
interruptible: true
stages:
- - not-interruptible
- - tool-lint # Source linting of the tools
- - quick-build # A very quick smoke-test to weed out broken commits
- - full-build # Build all the things
- - packaging # Source distribution, etc.
- - testing # head.hackage correctness and compiler performance testing
- - deploy # push documentation
-
-# Note [The CI Story]
-# ~~~~~~~~~~~~~~~~~~~
-#
-# There are a few different types of pipelines. Among them:
-#
-# 1. marge-bot merges to `master`. Here we perform an exhaustive validation
-# across all of the platforms which we support. In addition, we push
-# performance metric notes upstream, providing a persistent record of the
-# performance characteristics of the compiler.
-#
-# 2. merge requests. Here we perform a slightly less exhaustive battery of
-# testing. Namely we omit some configurations (e.g. the unregisterised job).
-# These use the merge request's base commit for performance metric
-# comparisons.
-#
-# These and other pipelines are defined implicitly by the rules of individual
-# jobs.
-#
-# At the top level, however, we can declare that pipelines (of whatever type)
-# only run when:
-#
-# 1. Processing a merge request (as mentioned above)
-#
-# 2. Processing a tag
-#
-# 3. Pushing to master on the root ghc/ghc repo (as mentioned above)
-#
-# 4. Pushing to a release branch on the root ghc/ghc repo
-#
-# 5. Somebody manually triggers a pipeline from the GitLab UI
-#
-# In particular, note that pipelines don't automatically run just when changes
-# are pushed to a feature branch.
-workflow:
- rules:
- - if: $CI_MERGE_REQUEST_ID
- - if: $CI_COMMIT_TAG
- # N.B.: If we weren't explicit about CI_PROJECT_ID, the following rule would
- # cause a duplicate pipeline for merge requests coming from the master
- # branch of a fork.
- - if: $CI_PROJECT_ID == "1" && $CI_COMMIT_BRANCH == "master"
- - if: $CI_PROJECT_ID == "1" && $CI_COMMIT_BRANCH =~ /ghc-[0-9]+\.[0-9]+/
- - if: '$CI_PIPELINE_SOURCE == "web"'
-
-# which versions of GHC to allow bootstrap with
-.bootstrap_matrix : &bootstrap_matrix
- matrix:
- # If you update this version, be sure to also update 'MinBootGhcVersion' in configure.ac
- - GHC_VERSION: 9.10.3
- DOCKER_IMAGE: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13-ghc9_10:$DOCKE…"
- - GHC_VERSION: 9.12.2
- DOCKER_IMAGE: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13-ghc9_12:$DOCKE…"
- - GHC_VERSION: 9.14.1
- DOCKER_IMAGE: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13-ghc9_14:$DOCKE…"
-
-# Allow linters to fail on draft MRs.
-# This must be explicitly transcluded in lint jobs which
-# override `rules:`
-.drafts-can-fail-lint: &drafts-can-fail-lint
- if: "$CI_MERGE_REQUEST_TITLE =~ /^\\s*(Draft|wip|WIP):/"
- allow_failure: true
-
-.lint:
- stage: tool-lint
- tags:
- - lint
- rules:
- - *drafts-can-fail-lint
- - when: always
-
-.nightly: &nightly
- variables:
- XZ_OPT: "-9"
- rules:
- - if: $NIGHTLY
- artifacts:
- when: always
- expire_in: 8 weeks
-
-.release: &release
- variables:
- BUILD_FLAVOUR: "release"
- XZ_OPT: "-9"
- IGNORE_PERF_FAILURES: "all"
- HADDOCK_HYPERLINKED_SOURCES: "YES"
- artifacts:
- when: always
- expire_in: 1 year
- rules:
- - if: '$RELEASE_JOB == "yes"'
-
-.full-ci: &full-ci
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/'
- - if: '$CI_COMMIT_BRANCH == "master"'
- - if: '$CI_COMMIT_BRANCH =~ /ghc-[0-9]+\.[0-9]+/'
-
-############################################################
-# Runner Tags
-############################################################
-#
-# * x86_64-linux: Any Docker-capable x86_64 Linux machine
-# * aarch64-linux: Any Docker-capable AArch64 Linux machine
-# * x86_64-windows: A x86_64 Windows machine
-# * lint: Any Docker-capable x86_64 Linux machine; distinct from
-# x86_64-linux to ensure low-latency availability.
-#
-
-####
-# HACK
-###
-#
-# Since 58cfcc65 the default for jobs has been "interruptible", this means
-# that when new commits are pushed to a branch which already has a running
-# pipeline then the old pipelines for this branch are cancelled.
-#
-# This includes the master branch, and in particular, new commits merged
-# to the master branch will cancel the nightly job.
-#
-# The semantics of pipeline cancelling are actually a bit more complicated
-# though. The interruptible flag is *per job*, but once a pipeline has run
-# *any* non-interruptible job, then the whole pipeline is considered
-# non-interruptible (ref
-# https://gitlab.com/gitlab-org/gitlab/-/issues/32837) This leads to the
-# hack in this MR where by default all jobs are `interruptible: True`, but
-# for pipelines we definitely want to run, there is a dummy job which
-# happens first, which is `interreuptible: False`. This has the effect of
-# dirtying the whole pipeline and
-#
-# For now, this patch solves the immediate problem of making sure nightly
-# jobs are not cancelled.
-# In the future, we may want to enable this job also for the master
-# branch, making that change might mean we need more CI capacity than
-# currently available.
-
-
-not-interruptible:
- stage: not-interruptible
- script: "true"
- interruptible: false
- image: "debian:13"
- variables:
- GIT_STRATEGY: none
- tags:
- - lint
- rules:
-# - if: '$CI_COMMIT_BRANCH == "master"'
-# when: always
- - if: $NIGHTLY
- when: always
-
-
-############################################################
-# Validate jobs
-############################################################
+ - test
# These jobs are generated by running the ./.gitlab/generate_jobs script
include: '.gitlab/jobs.yaml'
-
-############################################################
-# tool linting
-############################################################
-
-ghc-linters:
- stage: tool-lint
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint-params
- variables:
- BUILD_FLAVOUR: default
- script:
- - .gitlab/ci.sh configure
- - timeout 10m .gitlab/ci.sh run_hadrian test --test-root-dirs="testsuite/tests/linters"
- dependencies: []
- rules:
- - if: $CI_MERGE_REQUEST_ID
- - *drafts-can-fail-lint
-
-# Check that MRs include a changelog entry in changelog.d/.
-# Skipped if the MR has the ~"no-changelog" label.
-lint-changelog:
- stage: tool-lint
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint-params
- variables:
- BUILD_FLAVOUR: default
- CHANGELOG_EXPECT_MR: "$CI_MERGE_REQUEST_IID"
- script:
- # Check that the MR adds at least one changelog entry
- - git fetch "$CI_MERGE_REQUEST_PROJECT_URL" "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
- - base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
- - added=$(git diff --name-only --diff-filter=A "$base..$CI_COMMIT_SHA" -- 'changelog.d/' | grep -v '^changelog.d/config$' || true)
- - |
- if [ -z "$added" ]; then
- echo "ERROR: No changelog entry found in changelog.d/"
- echo "Please add a changelog entry file describing your user-facing changes."
- echo "If this MR does not need a changelog entry, apply the 'no-changelog' label."
- exit 1
- fi
- - echo "Found changelog entries:" $added
- # Build changelog-d and validate all entries (checks required fields, section names, MR number)
- - .gitlab/ci.sh configure
- - .gitlab/ci.sh run_hadrian test --test-root-dirs="testsuite/tests/linters" --only=changelog-d
- dependencies: []
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/'
- when: never
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*no-changelog.*/'
- when: never
- - if: $CI_MERGE_REQUEST_ID
- - *drafts-can-fail-lint
-
-# Run mypy Python typechecker on linter scripts.
-lint-linters:
- image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
- extends: .lint
- script:
- - mypy testsuite/tests/linters/regex-linters/*.py
- dependencies: []
-
-# Check that .T files all parse by listing broken tests.
-lint-testsuite:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
- script:
- - make -Ctestsuite list_broken TEST_HC=$GHC
- dependencies: []
-
-# Run mypy Python typechecker on testsuite driver
-typecheck-testsuite:
- image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
- extends: .lint
- script:
- - mypy testsuite/driver/runtests.py
- dependencies: []
-
-# We allow the submodule checker to fail when run on merge requests (to
-# accommodate, e.g., haddock changes not yet upstream) but not on `master` or
-# Marge jobs.
-.lint-submods:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint-params
- variables:
- BUILD_FLAVOUR: default
- script:
- - .gitlab/ci.sh configure
- - .gitlab/ci.sh run_hadrian stage0:exe:lint-submodule-refs
- - git fetch "$CI_MERGE_REQUEST_PROJECT_URL" $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- - base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
- - "echo Linting submodule changes between $base..$CI_COMMIT_SHA"
- - git submodule foreach git remote update
- - _build/stageBoot/bin/lint-submodule-refs . $(git rev-list $base..$CI_COMMIT_SHA)
- dependencies: []
-
-# We allow the submodule checker to fail when run on merge requests (to
-# accommodate, e.g., haddock changes not yet upstream) but not on `master` or
-# Marge jobs.
-lint-author:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint-params
- variables:
- BUILD_FLAVOUR: default
- script:
- - git fetch "$CI_MERGE_REQUEST_PROJECT_URL" $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- - base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
- - "echo Linting authors between $base..$CI_COMMIT_SHA"
- - .gitlab/ci.sh lint_author $base $CI_COMMIT_SHA
- dependencies: []
- rules:
- - if: $CI_MERGE_REQUEST_ID
- - *drafts-can-fail-lint
-
-lint-ci-config:
- image: nixos/nix:2.25.2
- extends: .lint
- # We don't need history/submodules in this job
- variables:
- GIT_DEPTH: 1
- GIT_SUBMODULE_STRATEGY: none
- before_script:
- - echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf
- # Note [Nix-in-Docker]
- # ~~~~~~~~~~~~~~~~~~~~
- # The nixos/nix default config is max-jobs=1 and cores=$(logical
- # cores num) which doesn't play nice with our $CPUS convention. We
- # fix it before invoking any nix build to avoid oversubscribing
- # while allowing a reasonable degree of parallelism.
- # FIXME: Disabling build-users-group=nixbld is a workaround for a Nix-in-Docker issue. See
- # https://gitlab.haskell.org/ghc/head.hackage/-/issues/38#note_560487 for
- # discussion.
- - echo "cores = $CPUS" >> /etc/nix/nix.conf
- - echo "max-jobs = $CPUS" >> /etc/nix/nix.conf
- - nix run nixpkgs#gnused -- -i -e 's/ nixbld//' /etc/nix/nix.conf
- script:
- - nix run .gitlab/generate-ci#generate-jobs
- # 1 if .gitlab/generate_jobs changed the output of the generated config
- - nix shell nixpkgs#git -c git diff --exit-code
- # And run this to generate the .gitlab/jobs-metadata.json
- - nix run .gitlab/generate-ci#generate-job-metadata
- artifacts:
- when: always
- paths:
- - .gitlab/jobs-metadata.json
- - .gitlab/jobs.yaml
- dependencies: []
-
-lint-submods:
- extends: .lint-submods
- # Allow failure on merge requests since any necessary submodule patches may
- # not be upstreamed yet.
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/'
- allow_failure: false
- # Don't run on nightly because the program needs a base commit to check.
- - if: $NIGHTLY
- when: never
- - allow_failure: true
-
-lint-submods-branch:
- extends: .lint-submods
- variables:
- BUILD_FLAVOUR: default
- script:
- - .gitlab/ci.sh configure
- - .gitlab/ci.sh run_hadrian stage0:exe:lint-submodule-refs
- - "echo Linting submodule changes between $CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA"
- - git submodule foreach git remote update
- - _build/stageBoot/bin/lint-submodule-refs . $(git rev-list $CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA)
- rules:
- - if: '$CI_COMMIT_BRANCH == "master"'
- - if: '$CI_COMMIT_BRANCH =~ /ghc-[0.9]+\.[0-9]+/'
- - *drafts-can-fail-lint
-
-############################################################
-# GHC source code linting
-############################################################
-
-.lint-params:
- needs: []
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
- before_script:
- - export PATH="/opt/toolchain/bin:$PATH"
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
- - .gitlab/ci.sh setup
- after_script:
- - .gitlab/ci.sh save_cache
- - cat ci_timings.txt
- variables:
- GHC_FLAGS: -Werror
- cache:
- key: lint-$CACHE_REV
- paths:
- - cabal-cache
-
-############################################################
-# GHC-in-GHCi (Hadrian)
-############################################################
-
-hadrian-ghc-in-ghci:
- stage: quick-build
- needs:
- - job: lint-linters
- - job: lint-submods
- optional: true
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
- variables:
- GHC_FLAGS: -Werror -Wwarn=unused-imports
- tags:
- - x86_64-linux
- script:
- - git clean -xdf && git submodule foreach git clean -xdf
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- # Enable -Werror when building hadrian
- - "echo 'package hadrian' > hadrian/cabal.project.local"
- - "echo ' ghc-options: -Werror' >> hadrian/cabal.project.local"
- # Load ghc-in-ghci then immediately exit and check the modules loaded
- - export CORES="$(mk/detect-cpu-count.sh)"
- - echo ":q" | HADRIAN_ARGS=-j$CORES hadrian/ghci-multi -j$CORES | tail -n2 | grep "Ok,"
- after_script:
- - .gitlab/ci.sh save_cache
- - cat ci_timings.txt
- cache:
- key: hadrian-ghci-$CACHE_REV
- paths:
- - cabal-cache
-
-############################################################
-# Hadrian Multi-Repl
-############################################################
-
-hadrian-multi:
- stage: testing
- needs:
- - job: x86_64-linux-deb13-validate
- optional: true
- - job: nightly-x86_64-linux-deb13-validate
- optional: true
- - job: release-x86_64-linux-deb13-release
- optional: true
- dependencies: null
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
- variables:
- GHC_FLAGS: "-Werror=-Wno-error=incomplete-record-selectors -Wwarn=deprecations -Wwarn=unused-imports"
- # -Wno-error=incomplete-record-selectors is present because -Wall now
- # includes -Wincomplete-record-selectors, and hadrian-multi has many, many
- # warnings about incomplete record selectors. A better fix would be to
- # remove the use of incomplete record selectors, since each of them represents
- # a potential crash.
- CONFIGURE_ARGS: --enable-bootstrap-with-devel-snapshot
- tags:
- - x86_64-linux
- script:
- - export BOOT_HC=$GHC
- - root=$(pwd)/ghc
- - ls
- - |
- mkdir tmp
- tar -xf ghc-x86_64-linux-deb13-validate.tar.xz -C tmp \
- || tar -xf ghc-x86_64-linux-deb13-release.tar.xz -C tmp
- pushd tmp/ghc-*/
- ./configure --prefix=$root
- make install
- popd
- rm -Rf tmp
- - export HC=$root/bin/ghc
- # This GHC means, use this GHC to configure with
- - export GHC=$root/bin/ghc
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- # Now GHC means, use this GHC for hadrian
- - export GHC=$BOOT_HC
- - export CORES="$(mk/detect-cpu-count.sh)"
- # Load hadrian-multi then immediately exit and check the modules loaded
- - echo ":q" | HADRIAN_ARGS=-j$CORES hadrian/ghci-multi -j$CORES | tail -n2 | grep "Ok,"
- after_script:
- - .gitlab/ci.sh save_cache
- cache:
- key: hadrian-ghci-$CACHE_REV
- paths:
- - cabal-cache
- rules:
- - *full-ci
-
-############################################################
-# stack-hadrian-build
-############################################################
-
-# Verify that Hadrian builds with stack. Note that we don't actually perform a
-# build of GHC itself; we merely test that the Hadrian executable builds and
-# works (by invoking `hadrian --version`).
-stack-hadrian-build:
- extends: hadrian-ghc-in-ghci
- stage: quick-build
- script:
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- - hadrian/build-stack --version
-
-####################################
-# Testing reinstallable ghc codepath
-####################################
-
-test-cabal-reinstall-x86_64-linux-deb13:
- extends: nightly-x86_64-linux-deb13-validate
- stage: full-build
- variables:
- REINSTALL_GHC: "yes"
- BUILD_FLAVOUR: validate
- TEST_ENV: "x86_64-linux-deb13-cabal-install"
- rules:
- - if: $NIGHTLY
- allow_failure: true
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-reinstall.*/'
-
-########################################
-# Testing ABI is invariant across builds
-########################################
-
-abi-test-nightly:
- stage: full-build
- needs:
- - job: nightly-x86_64-linux-fedora43-release-hackage
- - job: nightly-x86_64-linux-fedora43-release
- tags:
- - x86_64-linux
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-fedora43:$DOCKER_REV"
- dependencies: null
- before_script:
- - mkdir -p normal
- - mkdir -p hackage
- - tar -xf ghc-x86_64-linux-fedora43-release.tar.xz -C normal/
- - tar -xf ghc-x86_64-linux-fedora43-release-hackage_docs.tar.xz -C hackage/
- script:
- - .gitlab/ci.sh compare_interfaces_of "normal/ghc-*" "hackage/ghc-*"
- artifacts:
- paths:
- - out
- rules:
- # This job is broken. Disabling it until some kind soul can finish its
- # implementation. #23269
- - when: never
- - if: $NIGHTLY
-
-############################################################
-# Packaging
-############################################################
-
-doc-tarball:
- stage: packaging
- needs:
- - job: x86_64-linux-deb13-numa-slow-validate
- optional: true
- - job: nightly-x86_64-linux-deb13-validate
- optional: true
- - job: release-x86_64-linux-deb13-release
- optional: true
-
- - job: x86_64-windows-validate
- optional: true
- - job: nightly-x86_64-windows-validate
- optional: true
- - job: release-x86_64-windows-release
- optional: true
-
- tags:
- - x86_64-linux
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- dependencies: null
- variables:
- LINUX_BINDIST: "ghc-x86_64-linux-deb13.tar.xz"
- WINDOWS_BINDIST: "ghc-x86_64-windows.tar.xz"
- artifacts:
- expose_as: "Documentation Preview"
- paths:
- - haddock.html.tar.xz
- - docs/haddock/
- - libraries.html.tar.xz
- - docs/libraries/
- - users_guide.html.tar.xz
- - docs/users_guide/
- - docs/index.html
- - Haddock.pdf
- - users_guide.pdf
- script:
- - |
- mv "ghc-x86_64-linux-deb13-numa-slow-validate.tar.xz" "$LINUX_BINDIST" \
- || mv "ghc-x86_64-linux-deb13-validate.tar.xz" "$LINUX_BINDIST" \
- || mv "ghc-x86_64-linux-deb13-release.tar.xz" "$LINUX_BINDIST" \
- || true
- mv "ghc-x86_64-windows-validate.tar.xz" "$WINDOWS_BINDIST" \
- || mv "ghc-x86_64-windows-release.tar.xz" "$WINDOWS_BINDIST" \
- || true
- if [ ! -f "$LINUX_BINDIST" ]; then
- echo "Error: $LINUX_BINDIST does not exist. Did the Debian job fail?"
- exit 1
- fi
- if [ ! -f "$WINDOWS_BINDIST" ]; then
- echo "Error: $WINDOWS_BINDIST does not exist. Did the 64-bit Windows job fail?"
- exit 1
- fi
- - rm -Rf docs
- - bash -ex distrib/mkDocs/mkDocs $LINUX_BINDIST $WINDOWS_BINDIST
- - mv docs/*.tar.xz docs/*.pdf .
- - ls -lh
-
-hackage-doc-tarball:
- stage: packaging
- needs:
- - job: nightly-x86_64-linux-fedora43-release-hackage
- optional: true
- - job: release-x86_64-linux-fedora43-release-hackage
- optional: true
- - job: source-tarball
- tags:
- - x86_64-linux
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- dependencies: null
- variables:
- # Don't clone the git repo..
- GIT_STRATEGY: none
- # Don't attempt to boot a source tarball
- NO_BOOT: "1"
- artifacts:
- paths:
- - hackage_docs
- before_script:
- - tar -xf ghc-*[0-9]-src.tar.xz
- - tar -xf ghc-x86_64-linux-fedora43-release.tar.xz -C ghc*/
- script:
- - cd ghc*/
- - mv .gitlab/rel_eng/upload_ghc_libs.py .
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- - ./upload_ghc_libs.py prepare --bindist ghc*linux/
- - mv .upload-libs/docs ../hackage_docs
- rules:
- - if: $NIGHTLY
- - if: '$RELEASE_JOB == "yes"'
-
-source-tarball:
- stage: full-build
- needs:
- - hadrian-ghc-in-ghci
- tags:
- - x86_64-linux
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- dependencies: []
- artifacts:
- paths:
- - ghc-*.tar.xz
- script:
- - sudo chown ghc:ghc -R .
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- - ./hadrian/build source-dist
- - mv _build/source-dist/*.xz .
- rules:
- - if: $NIGHTLY
- - if: '$RELEASE_JOB == "yes"'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-bootstrap.*/'
- - *full-ci
-
-generate-hadrian-bootstrap-sources:
- stage: full-build
- needs:
- - hadrian-ghc-in-ghci
- tags:
- - x86_64-linux
- image: "$DOCKER_IMAGE"
- dependencies: []
- parallel: *bootstrap_matrix
- artifacts:
- paths:
- - hadrian-bootstrap-sources-*.tar.gz
- script:
- - bash -c "[ $($GHC --numeric-version) = $GHC_VERSION ] || { echo $GHC_VERSION is not the same as the version of $GHC && exit 1; }"
- - python3 ./hadrian/bootstrap/bootstrap.py -w $GHC fetch -o hadrian-bootstrap-sources-$GHC_VERSION
- rules:
- - if: $NIGHTLY
- - if: '$RELEASE_JOB == "yes"'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-bootstrap.*/'
- - *full-ci
-
-
-package-hadrian-bootstrap-sources:
- stage: full-build
- tags:
- - x86_64-linux
- needs: ["generate-hadrian-bootstrap-sources"]
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- artifacts:
- paths:
- - hadrian-bootstrap-sources-all.tar.gz
- script:
- - tar -czvf hadrian-bootstrap-sources-all.tar.gz hadrian-bootstrap-sources-*.tar.gz
- rules:
- - if: $NIGHTLY
- - if: '$RELEASE_JOB == "yes"'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-bootstrap.*/'
- - *full-ci
-
-test-bootstrap:
- stage: full-build
- needs: [generate-hadrian-bootstrap-sources, source-tarball]
- tags:
- - x86_64-linux
- image: "$DOCKER_IMAGE"
- parallel: *bootstrap_matrix
- dependencies: null
- script:
- - sudo chown ghc:ghc -R .
- - mkdir test-bootstrap
- - tar -xf ghc-*[0-9]-src.tar.xz -C test-bootstrap
- - tar -xf ghc-*-testsuite.tar.xz -C test-bootstrap
- - cp hadrian-bootstrap-sources-$GHC_VERSION.tar.gz test-bootstrap/ghc-*
- - pushd test-bootstrap/ghc-*
- - python3 ./hadrian/bootstrap/bootstrap.py -w $GHC --bootstrap-sources hadrian-bootstrap-sources-$GHC_VERSION.tar.gz
- - export HADRIAN_PATH="$PWD/_build/bin/hadrian"
- - .gitlab/ci.sh setup
- # Bootstrapping should not depend on HAPPY or ALEX so set them to false
- # so the build fails if they are invoked.
- - unset HAPPY; unset ALEX
- # Check the commands are not available, parens are crucial to start a subshell
- - (! command -v alex --version)
- - (! command -v happy --version)
- - .gitlab/ci.sh configure
- - .gitlab/ci.sh build_hadrian
- - .gitlab/ci.sh test_hadrian
- - popd
- - rm -Rf test-bootstrap
- variables:
- # Don't record performance benchmarks
- TEST_ENV: ""
- BIN_DIST_NAME: "ghc-x86_64-deb13-linux"
- BUILD_FLAVOUR: "validate"
- NO_BOOT: "1"
- rules:
- - if: $NIGHTLY
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-bootstrap.*/'
- - *full-ci
- - if: '$RELEASE_JOB == "yes"'
- when: always
- variables:
- BUILD_FLAVOUR: "release"
-
-
-############################################################
-# Testing via head.hackage
-############################################################
-
-# Triggering jobs in the ghc/head.hackage project requires that we have a job
-# token for that repository. Furthermore the head.hackage CI job must have
-# access to an unprivileged access token with the ability to query the ghc/ghc
-# project such that it can find the job ID of the fedora43 job for the current
-# pipeline.
-#
-# hackage-lint: Can be triggered on any MR, normal validate pipeline or nightly build.
-# Runs head.hackage with -dlint and a slow-validate bindist
-#
-# hackage-label-lint: Trigged on MRs with "user-facing" label, runs the slow-validate
-# head.hackage build with -dlint.
-#
-# nightly-hackage-lint: Runs automatically on nightly pipelines with slow-validate + dlint config.
-#
-# nightly-hackage-perf: Runs automaticaly on nightly pipelines with release build and eventlogging enabled.
-#
-# release-hackage-lint: Runs automatically on release pipelines with -dlint on a release bindist.
-
-.hackage:
- stage: testing
- variables:
- UPSTREAM_PROJECT_PATH: "$CI_PROJECT_PATH"
- UPSTREAM_PROJECT_ID: "$CI_PROJECT_ID"
- UPSTREAM_PIPELINE_ID: "$CI_PIPELINE_ID"
- RELEASE_JOB: "$RELEASE_JOB"
- trigger:
- project: "ghc/head.hackage"
- branch: "upstream-testing"
- strategy: "depend"
-
-hackage-lint:
- needs:
- - job: x86_64-linux-deb13-numa-slow-validate
- optional: true
- artifacts: false
- - job: nightly-x86_64-linux-deb13-numa-slow-validate
- optional: true
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- - job: aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- extends: .hackage
- variables:
- SLOW_VALIDATE: 1
- EXTRA_HC_OPTS: "-dlint"
- # No for release jobs because there isn't a slow-valdate bindist. There is an
- # automatic pipeline for release bindists (see release-hackage-lint)
- rules:
- - if: '$RELEASE_JOB != "yes"'
- when: manual
-
-hackage-label-lint:
- needs:
- - job: x86_64-linux-deb13-numa-slow-validate
- optional: true
- artifacts: false
- - job: aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- extends: .hackage
- variables:
- SLOW_VALIDATE: 1
- EXTRA_HC_OPTS: "-dlint"
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*user-facing.*/'
-
-# The head.hackage job is split into two jobs because enabling `-dlint`
-# affects the total allocation numbers for the simplifier portion significantly.
-nightly-hackage-lint:
- needs:
- - job: nightly-x86_64-linux-deb13-numa-slow-validate
- optional: true
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- rules:
- - if: $NIGHTLY
- variables:
- NIGHTLY: "$NIGHTLY"
- extends: .hackage
- variables:
- SLOW_VALIDATE: 1
- EXTRA_HC_OPTS: "-dlint"
-
-nightly-hackage-perf:
- needs:
- - job: nightly-x86_64-linux-fedora43-release
- optional: true
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- rules:
- - if: $NIGHTLY
- variables:
- NIGHTLY: "$NIGHTLY"
- extends: .hackage
- variables:
- # Generate logs for nightly builds which include timing information.
- EXTRA_HC_OPTS: "-ddump-timings"
- # Ask head.hackage to generate eventlogs
- EVENTLOGGING: 1
-
-release-hackage-lint:
- needs:
- - job: release-x86_64-linux-fedora43-release
- optional: true
- artifacts: false
- - job: release-aarch64-linux-deb13-release+no_split_sections
- optional: true
- artifacts: false
- rules:
- - if: '$RELEASE_JOB == "yes"'
- extends: .hackage
- # The ghcup metadata pipeline requires all prior jobs to
- # pass. The hackage job can easily fail due to API changes
- # or similar - so we allow it to fail.
- allow_failure: true
- variables:
- # No slow-validate bindist on release pipeline
- EXTRA_HC_OPTS: "-dlint"
-
-############################################################
-# Testing via test-primops
-############################################################
-
-# Triggering jobs in the ghc/test-primops project
-
-.test-primops:
- stage: testing
- variables:
- UPSTREAM_PROJECT_PATH: "$CI_PROJECT_PATH"
- UPSTREAM_PROJECT_ID: "$CI_PROJECT_ID"
- UPSTREAM_PIPELINE_ID: "$CI_PIPELINE_ID"
- trigger:
- project: "ghc/test-primops"
- branch: "upstream-testing"
- strategy: "depend"
-
-.test-primops-validate-template:
- needs:
- - job: x86_64-linux-deb13-validate
- artifacts: false
- - job: aarch64-linux-deb13-validate
- artifacts: false
- - job: aarch64-darwin-validate
- artifacts: false
- - job: x86_64-darwin-validate
- artifacts: false
- extends: .test-primops
-
-test-primops-label:
- extends: .test-primops-validate-template
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-primops.*/'
- # We do not use *.full-ci here since that would imply running in nightly
- # where we do not have the normal validate jobs. We have the -nightly job
- # below to handle this case.
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/'
-
-test-primops-nightly:
- extends: .test-primops
- needs:
- - job: nightly-x86_64-linux-deb13-validate
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- artifacts: false
- - job: nightly-aarch64-darwin-validate
- artifacts: false
- - job: nightly-x86_64-darwin-validate
- artifacts: false
- rules:
- - if: $NIGHTLY
-
-test-primops-release:
- extends: .test-primops
- rules:
- - if: '$RELEASE_JOB == "yes"'
-
-############################################################
-# Nofib testing
-# (Disabled: See #21859)
-############################################################
-
-perf-nofib:
- # Dependencies used by perf-nofib can't be built when some compiler changes
- # aren't (yet) supported by head.hackage.
- # Hence we allow this job to fail.
- allow_failure: true
- stage: testing
- needs:
- - job: x86_64-linux-fedora43-release
- optional: true
- - job: nightly-x86_64-linux-fedora43-release
- optional: true
- - job: release-x86_64-linux-fedora43-release
- optional: true
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-fedora43:$DOCKER_REV"
- rules:
- - when: never
- - *full-ci
- tags:
- - x86_64-linux
- before_script:
- - cd nofib
- - "cabal update --index=$HACKAGE_INDEX_STATE --project-file=cabal.project.head-hackage"
- script:
- - root=$(pwd)/ghc
- - |
- mkdir tmp
- tar -xf ../ghc-x86_64-linux-fedora43-release.tar.xz -C tmp
- pushd tmp/ghc-*/
- ./configure --prefix=$root
- make install
- popd
- rm -Rf tmp
- - export PATH=$root/bin:$PATH
- - cabal install -w "$root/bin/ghc" --lib regex-compat unboxed-ref parallel random-1.2.1 --allow-newer --package-env local.env --project-file=cabal.project.head-hackage
- - export GHC_ENVIRONMENT="$(pwd)/local.env"
- - "make HC=$root/bin/ghc BOOT_HC=$root/bin/ghc boot mode=fast -j$CPUS"
- - "make HC=$root/bin/ghc BOOT_HC=$root/bin/ghc EXTRA_RUNTEST_OPTS='-cachegrind +RTS -V0 -RTS' NoFibRuns=1 mode=fast -j$CPUS 2>&1 | tee nofib.log"
- artifacts:
- expire_in: 12 week
- when: always
- paths:
- - nofib/nofib.log
-
-############################################################
-# Ad-hoc performance testing
-############################################################
-
-perf:
- stage: testing
- needs:
- - job: x86_64-linux-deb13-validate
- optional: true
- - job: nightly-x86_64-linux-deb13-validate
- optional: true
- - job: release-x86_64-linux-deb13-release
- optional: true
- dependencies: null
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- tags:
- - x86_64-linux-perf
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
- script:
- - root=$(pwd)/ghc
- - |
- mkdir tmp
- tar -xf ghc-x86_64-linux-deb13-validate.tar.xz -C tmp \
- || tar -xf ghc-x86_64-linux-deb13-release.tar.xz -C tmp
- pushd tmp/ghc-*/
- ./configure --prefix=$root
- make install
- popd
- rm -Rf tmp
- - export BOOT_HC=$(which ghc)
- - export HC=$root/bin/ghc
- - .gitlab/ci.sh perf_test
- artifacts:
- expire_in: 2 year
- when: always
- paths:
- - out
- rules:
- - *full-ci
-
-############################################################
-# ABI testing
-############################################################
-
-abi-test:
- stage: testing
- needs:
- - job: x86_64-linux-deb13-validate
- optional: true
- - job: nightly-x86_64-linux-deb13-validate
- optional: true
- - job: release-x86_64-linux-deb13-release
- optional: true
- dependencies: null
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- tags:
- - x86_64-linux
- script:
- - root=$(pwd)/ghc
- - |
- mkdir tmp
- tar -xf ghc-x86_64-linux-deb13-validate.tar.xz -C tmp \
- || tar -xf ghc-x86_64-linux-deb13-release.tar.xz -C tmp
- pushd tmp/ghc-*/
- ./configure --prefix=$root
- make install
- popd
- rm -Rf tmp
- - export BOOT_HC=$(which ghc)
- - export HC=$root/bin/ghc
- - .gitlab/ci.sh abi_test
- artifacts:
- paths:
- - out
- rules:
- - *full-ci
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-abi.*/'
-
-############################################################
-# ghc-wasm-meta integration testing
-############################################################
-
-.ghc-wasm-meta:
- stage: testing
- variables:
- UPSTREAM_GHC_PIPELINE_ID: $CI_PIPELINE_ID
- UPSTREAM_GHC_PROJECT_ID: $CI_PROJECT_ID
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-wasm.*/'
- trigger:
- project: haskell-wasm/ghc-wasm-meta
- branch: master
- strategy: depend
-
-ghc-wasm-meta-gmp:
- extends: .ghc-wasm-meta
- needs:
- - job: x86_64-linux-alpine3_23-wasm-cross_wasm32-wasi-release+host_fully_static+text_simdutf
- artifacts: false
- variables:
- UPSTREAM_GHC_FLAVOUR: gmp
- UPSTREAM_GHC_JOB_NAME: x86_64-linux-alpine3_23-wasm-cross_wasm32-wasi-release+host_fully_static+text_simdutf
-
-ghc-wasm-meta-native:
- extends: .ghc-wasm-meta
- needs:
- - job: x86_64-linux-alpine3_23-wasm-int_native-cross_wasm32-wasi-release+host_fully_static+text_simdutf
- artifacts: false
- variables:
- UPSTREAM_GHC_FLAVOUR: native
- UPSTREAM_GHC_JOB_NAME: x86_64-linux-alpine3_23-wasm-int_native-cross_wasm32-wasi-release+host_fully_static+text_simdutf
-
-ghc-wasm-meta-unreg:
- extends: .ghc-wasm-meta
- needs:
- - job: x86_64-linux-alpine3_23-wasm-unreg-cross_wasm32-wasi-release+host_fully_static+text_simdutf
- artifacts: false
- variables:
- UPSTREAM_GHC_FLAVOUR: unreg
- UPSTREAM_GHC_JOB_NAME: x86_64-linux-alpine3_23-wasm-unreg-cross_wasm32-wasi-release+host_fully_static+text_simdutf
-
-############################################################
-# Documentation deployment via GitLab Pages
-############################################################
-
-pages:
- stage: deploy
- needs: [doc-tarball]
- dependencies: null
- image: "debian:13"
- # See #18973
- allow_failure: true
- tags:
- - x86_64-linux
- script:
- - mkdir -p public/doc
- # haddock docs are not in the hadrian produce doc tarballs at the moment
- # - tar -xf haddock.html.tar.xz -C public/doc
- - tar -xf libraries.html.tar.xz -C public/doc
- - tar -xf users_guide.html.tar.xz -C public/doc
- - |
- cat >public/index.html <<EOF
- <!DOCTYPE HTML>
- <meta charset="UTF-8">
- <meta http-equiv="refresh" content="1; url=doc/">
- EOF
- - cp -f docs/index.html public/doc
- rules:
- # N.B. only run this on ghc/ghc since the deployed pages are quite large
- # and we only serve GitLab Pages for ghc/ghc.
- - if: '$CI_COMMIT_BRANCH == "master" && $CI_PROJECT_NAMESPACE == "ghc"'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*publish-docs.*/'
-
- artifacts:
- paths:
- - public
-
-#############################################################
-# Generation of GHCUp metadata
-#############################################################
-
-
-project-version:
- stage: packaging
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- tags:
- - x86_64-linux
- variables:
- BUILD_FLAVOUR: default
- script:
- # Calculate the project version
- - sudo chown ghc:ghc -R .
- - .gitlab/ci.sh setup
- - .gitlab/ci.sh configure
- - echo "ProjectVersion=$(cat VERSION)" > version.sh
-
- needs: []
- dependencies: []
- artifacts:
- paths:
- - version.sh
-
-.ghcup-metadata:
- stage: deploy
- image: nixos/nix:2.25.2
- dependencies: null
- tags:
- # N.B. we use the OpenCape runners here since this job involves a significant
- # amount of artifact fetching. This is much more efficient on these runners
- # as they are near the GitLab box.
- - opencape
- - x86_64-linux
- variables:
- BUILD_FLAVOUR: default
- GIT_SUBMODULE_STRATEGY: "none"
- before_script:
- - echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf
- # FIXME: See Note [Nix-in-Docker]
- - echo "cores = $CPUS" >> /etc/nix/nix.conf
- - echo "max-jobs = $CPUS" >> /etc/nix/nix.conf
- - nix run nixpkgs#gnused -- -i -e 's/ nixbld//' /etc/nix/nix.conf
- - nix-channel --update
- - cat version.sh
- # Calculate the project version
- - . ./version.sh
-
- # Download existing ghcup metadata for the correct year
- - PipelineYear="$(date -d $CI_PIPELINE_CREATED_AT +%Y)"
- - nix shell nixpkgs#wget -c wget "https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-$PipelineYear…" -O ghcup-0.0.7.yaml
-
- - nix run .gitlab/generate-ci#generate-job-metadata
-
- artifacts:
- paths:
- - metadata_test.yaml
- - version.sh
-
-ghcup-metadata-nightly:
- extends: .ghcup-metadata
- # Explicit needs for validate pipeline because we only need certain bindists
- needs:
- - job: nightly-x86_64-linux-fedora43-release
- artifacts: false
- - job: nightly-x86_64-linux-ubuntu24_04-validate
- artifacts: false
- - job: nightly-x86_64-linux-ubuntu22_04-validate
- artifacts: false
- - job: nightly-x86_64-linux-rocky8-validate
- artifacts: false
- - job: nightly-x86_64-darwin-validate
- artifacts: false
- - job: nightly-aarch64-darwin-validate
- artifacts: false
- - job: nightly-x86_64-windows-validate
- artifacts: false
- - job: nightly-x86_64-linux-alpine3_23-validate
- artifacts: false
- - job: nightly-i386-linux-deb11-validate
- artifacts: false
- - job: nightly-i386-linux-deb13-validate
- artifacts: false
- - job: nightly-i386-linux-alpine3_23-validate
- artifacts: false
- - job: nightly-aarch64-linux-deb11-validate
- artifacts: false
- - job: nightly-x86_64-linux-deb11-validate
- artifacts: false
- - job: nightly-x86_64-linux-deb13-validate
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- artifacts: false
- - job: nightly-x86_64-linux-deb12-validate
- artifacts: false
- - job: nightly-aarch64-linux-alpine3_23-validate
- artifacts: false
- - job: source-tarball
- artifacts: false
- - job: project-version
- script:
- - nix shell -f .gitlab/rel_eng -c ghcup-metadata --metadata ghcup-0.0.7.yaml --date="$(date -d $CI_PIPELINE_CREATED_AT +%Y-%m-%d)" --pipeline-id="$CI_PIPELINE_ID" --version="$ProjectVersion" > "metadata_test.yaml"
- rules:
- - if: $NIGHTLY
-
-# Update the ghcup metadata with information about this nightly pipeline
-ghcup-metadata-nightly-push:
- stage: deploy
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-fedora43:$DOCKER_REV"
- dependencies: null
- tags:
- - x86_64-linux
- variables:
- BUILD_FLAVOUR: default
- GIT_SUBMODULE_STRATEGY: "none"
- needs:
- - job: ghcup-metadata-nightly
- artifacts: true
- script:
- - git clone https://gitlab.haskell.org/ghc/ghcup-metadata.git
- - PipelineYear="$(date -d $CI_PIPELINE_CREATED_AT +%Y)"
- - cp metadata_test.yaml "ghcup-metadata/ghcup-nightlies-$PipelineYear-0.0.7.yaml"
- - cp metadata_test.yaml "ghcup-metadata/ghcup-nightlies-0.0.7.yaml"
- - cd ghcup-metadata
- - git config user.email "ghc-ci(a)gitlab-haskell.org"
- - git config user.name "GHC GitLab CI"
- - git remote add gitlab_origin https://oauth2:$PROJECT_PUSH_TOKEN@gitlab.haskell.org/ghc/ghcup-metadata.git
- - git add .
- - git commit -m "Update metadata"
- - git push gitlab_origin HEAD:updates
- rules:
- # Only run the update on scheduled nightly pipelines, ie once a day
- - if: $NIGHTLY && $CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_BRANCH == "master"
-
-
-ghcup-metadata-release:
- # No explicit needs for release pipeline as we assume we need everything and everything will pass.
- extends: .ghcup-metadata
- script:
- - nix shell -f .gitlab/rel_eng -c ghcup-metadata --release-mode --metadata ghcup-0.0.7.yaml --date="$(date -d $CI_PIPELINE_CREATED_AT +%Y-%m-%d)" --pipeline-id="$CI_PIPELINE_ID" --version="$ProjectVersion" --fragment
- - nix shell -f .gitlab/rel_eng -c ghcup-metadata --release-mode --metadata ghcup-0.0.7.yaml --date="$(date -d $CI_PIPELINE_CREATED_AT +%Y-%m-%d)" --pipeline-id="$CI_PIPELINE_ID" --version="$ProjectVersion" > "metadata_test.yaml"
- rules:
- - if: '$RELEASE_JOB == "yes"'
-
-.ghcup-metadata-testing:
- stage: deploy
- variables:
- UPSTREAM_PROJECT_PATH: "$CI_PROJECT_PATH"
- UPSTREAM_PROJECT_ID: "$CI_PROJECT_ID"
- UPSTREAM_PIPELINE_ID: "$CI_PIPELINE_ID"
- RELEASE_JOB: "$RELEASE_JOB"
- # Do not inherit global variables (such as CONFIGURE_ARGS) as these take
- # precedence over the variables defined in the downstream job.
- inherit:
- variables: false
- trigger:
- project: "ghc/ghcup-ci"
- branch: "upstream-testing"
- strategy: "depend"
- forward:
- yaml_variables: true
- pipeline_variables: false
-
-ghcup-metadata-testing-nightly:
- needs:
- - job: ghcup-metadata-nightly
- artifacts: false
- extends: .ghcup-metadata-testing
- variables:
- NIGHTLY: "$NIGHTLY"
- UPSTREAM_JOB_NAME: "ghcup-metadata-nightly"
- rules:
- - if: '$NIGHTLY == "1"'
-
-ghcup-metadata-testing-release:
- needs:
- - job: ghcup-metadata-release
- artifacts: false
- extends: .ghcup-metadata-testing
- variables:
- UPSTREAM_JOB_NAME: "ghcup-metadata-release"
- rules:
- - if: '$RELEASE_JOB == "yes"'
- when: manual
=====================================
.gitlab/jobs.yaml
=====================================
@@ -26,7 +26,11 @@
"dependencies": [],
"image": null,
"needs": [],
- "rules": [],
+ "rules": [
+ {
+ "when": "always"
+ }
+ ],
"script": [
"echo \"PATH=$PATH\"",
"echo \"MSYSTEM=$MSYSTEM\"",
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/18d7b979857a0c8fa4760a90595ed89…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/18d7b979857a0c8fa4760a90595ed89…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/davide/windows_ci_env] fixup! TMP: CI: do only x86_64-windows-validate
by David Eichmann (@DavidEichmann) 27 May '26
by David Eichmann (@DavidEichmann) 27 May '26
27 May '26
David Eichmann pushed to branch wip/davide/windows_ci_env at Glasgow Haskell Compiler / GHC
Commits:
74684457 by David Eichmann at 2026-05-27T16:27:35+01:00
fixup! TMP: CI: do only x86_64-windows-validate
- - - - -
2 changed files:
- .gitlab-ci.yml
- .gitlab/jobs.yaml
Changes:
=====================================
.gitlab-ci.yml
=====================================
@@ -60,1304 +60,7 @@ default:
interruptible: true
stages:
- - not-interruptible
- - tool-lint # Source linting of the tools
- - quick-build # A very quick smoke-test to weed out broken commits
- - full-build # Build all the things
- - packaging # Source distribution, etc.
- - testing # head.hackage correctness and compiler performance testing
- - deploy # push documentation
-
-# Note [The CI Story]
-# ~~~~~~~~~~~~~~~~~~~
-#
-# There are a few different types of pipelines. Among them:
-#
-# 1. marge-bot merges to `master`. Here we perform an exhaustive validation
-# across all of the platforms which we support. In addition, we push
-# performance metric notes upstream, providing a persistent record of the
-# performance characteristics of the compiler.
-#
-# 2. merge requests. Here we perform a slightly less exhaustive battery of
-# testing. Namely we omit some configurations (e.g. the unregisterised job).
-# These use the merge request's base commit for performance metric
-# comparisons.
-#
-# These and other pipelines are defined implicitly by the rules of individual
-# jobs.
-#
-# At the top level, however, we can declare that pipelines (of whatever type)
-# only run when:
-#
-# 1. Processing a merge request (as mentioned above)
-#
-# 2. Processing a tag
-#
-# 3. Pushing to master on the root ghc/ghc repo (as mentioned above)
-#
-# 4. Pushing to a release branch on the root ghc/ghc repo
-#
-# 5. Somebody manually triggers a pipeline from the GitLab UI
-#
-# In particular, note that pipelines don't automatically run just when changes
-# are pushed to a feature branch.
-workflow:
- rules:
- - if: $CI_MERGE_REQUEST_ID
- - if: $CI_COMMIT_TAG
- # N.B.: If we weren't explicit about CI_PROJECT_ID, the following rule would
- # cause a duplicate pipeline for merge requests coming from the master
- # branch of a fork.
- - if: $CI_PROJECT_ID == "1" && $CI_COMMIT_BRANCH == "master"
- - if: $CI_PROJECT_ID == "1" && $CI_COMMIT_BRANCH =~ /ghc-[0-9]+\.[0-9]+/
- - if: '$CI_PIPELINE_SOURCE == "web"'
-
-# which versions of GHC to allow bootstrap with
-.bootstrap_matrix : &bootstrap_matrix
- matrix:
- # If you update this version, be sure to also update 'MinBootGhcVersion' in configure.ac
- - GHC_VERSION: 9.10.3
- DOCKER_IMAGE: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13-ghc9_10:$DOCKE…"
- - GHC_VERSION: 9.12.2
- DOCKER_IMAGE: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13-ghc9_12:$DOCKE…"
- - GHC_VERSION: 9.14.1
- DOCKER_IMAGE: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13-ghc9_14:$DOCKE…"
-
-# Allow linters to fail on draft MRs.
-# This must be explicitly transcluded in lint jobs which
-# override `rules:`
-.drafts-can-fail-lint: &drafts-can-fail-lint
- if: "$CI_MERGE_REQUEST_TITLE =~ /^\\s*(Draft|wip|WIP):/"
- allow_failure: true
-
-.lint:
- stage: tool-lint
- tags:
- - lint
- rules:
- - *drafts-can-fail-lint
- - when: always
-
-.nightly: &nightly
- variables:
- XZ_OPT: "-9"
- rules:
- - if: $NIGHTLY
- artifacts:
- when: always
- expire_in: 8 weeks
-
-.release: &release
- variables:
- BUILD_FLAVOUR: "release"
- XZ_OPT: "-9"
- IGNORE_PERF_FAILURES: "all"
- HADDOCK_HYPERLINKED_SOURCES: "YES"
- artifacts:
- when: always
- expire_in: 1 year
- rules:
- - if: '$RELEASE_JOB == "yes"'
-
-.full-ci: &full-ci
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/'
- - if: '$CI_COMMIT_BRANCH == "master"'
- - if: '$CI_COMMIT_BRANCH =~ /ghc-[0-9]+\.[0-9]+/'
-
-############################################################
-# Runner Tags
-############################################################
-#
-# * x86_64-linux: Any Docker-capable x86_64 Linux machine
-# * aarch64-linux: Any Docker-capable AArch64 Linux machine
-# * x86_64-windows: A x86_64 Windows machine
-# * lint: Any Docker-capable x86_64 Linux machine; distinct from
-# x86_64-linux to ensure low-latency availability.
-#
-
-####
-# HACK
-###
-#
-# Since 58cfcc65 the default for jobs has been "interruptible", this means
-# that when new commits are pushed to a branch which already has a running
-# pipeline then the old pipelines for this branch are cancelled.
-#
-# This includes the master branch, and in particular, new commits merged
-# to the master branch will cancel the nightly job.
-#
-# The semantics of pipeline cancelling are actually a bit more complicated
-# though. The interruptible flag is *per job*, but once a pipeline has run
-# *any* non-interruptible job, then the whole pipeline is considered
-# non-interruptible (ref
-# https://gitlab.com/gitlab-org/gitlab/-/issues/32837) This leads to the
-# hack in this MR where by default all jobs are `interruptible: True`, but
-# for pipelines we definitely want to run, there is a dummy job which
-# happens first, which is `interreuptible: False`. This has the effect of
-# dirtying the whole pipeline and
-#
-# For now, this patch solves the immediate problem of making sure nightly
-# jobs are not cancelled.
-# In the future, we may want to enable this job also for the master
-# branch, making that change might mean we need more CI capacity than
-# currently available.
-
-
-not-interruptible:
- stage: not-interruptible
- script: "true"
- interruptible: false
- image: "debian:13"
- variables:
- GIT_STRATEGY: none
- tags:
- - lint
- rules:
-# - if: '$CI_COMMIT_BRANCH == "master"'
-# when: always
- - if: $NIGHTLY
- when: always
-
-
-############################################################
-# Validate jobs
-############################################################
+ - build
# These jobs are generated by running the ./.gitlab/generate_jobs script
include: '.gitlab/jobs.yaml'
-
-############################################################
-# tool linting
-############################################################
-
-ghc-linters:
- stage: tool-lint
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint-params
- variables:
- BUILD_FLAVOUR: default
- script:
- - .gitlab/ci.sh configure
- - timeout 10m .gitlab/ci.sh run_hadrian test --test-root-dirs="testsuite/tests/linters"
- dependencies: []
- rules:
- - if: $CI_MERGE_REQUEST_ID
- - *drafts-can-fail-lint
-
-# Check that MRs include a changelog entry in changelog.d/.
-# Skipped if the MR has the ~"no-changelog" label.
-lint-changelog:
- stage: tool-lint
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint-params
- variables:
- BUILD_FLAVOUR: default
- CHANGELOG_EXPECT_MR: "$CI_MERGE_REQUEST_IID"
- script:
- # Check that the MR adds at least one changelog entry
- - git fetch "$CI_MERGE_REQUEST_PROJECT_URL" "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
- - base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
- - added=$(git diff --name-only --diff-filter=A "$base..$CI_COMMIT_SHA" -- 'changelog.d/' | grep -v '^changelog.d/config$' || true)
- - |
- if [ -z "$added" ]; then
- echo "ERROR: No changelog entry found in changelog.d/"
- echo "Please add a changelog entry file describing your user-facing changes."
- echo "If this MR does not need a changelog entry, apply the 'no-changelog' label."
- exit 1
- fi
- - echo "Found changelog entries:" $added
- # Build changelog-d and validate all entries (checks required fields, section names, MR number)
- - .gitlab/ci.sh configure
- - .gitlab/ci.sh run_hadrian test --test-root-dirs="testsuite/tests/linters" --only=changelog-d
- dependencies: []
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/'
- when: never
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*no-changelog.*/'
- when: never
- - if: $CI_MERGE_REQUEST_ID
- - *drafts-can-fail-lint
-
-# Run mypy Python typechecker on linter scripts.
-lint-linters:
- image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
- extends: .lint
- script:
- - mypy testsuite/tests/linters/regex-linters/*.py
- dependencies: []
-
-# Check that .T files all parse by listing broken tests.
-lint-testsuite:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
- script:
- - make -Ctestsuite list_broken TEST_HC=$GHC
- dependencies: []
-
-# Run mypy Python typechecker on testsuite driver
-typecheck-testsuite:
- image: "registry.gitlab.haskell.org/ghc/ci-images/linters:$DOCKER_REV"
- extends: .lint
- script:
- - mypy testsuite/driver/runtests.py
- dependencies: []
-
-# We allow the submodule checker to fail when run on merge requests (to
-# accommodate, e.g., haddock changes not yet upstream) but not on `master` or
-# Marge jobs.
-.lint-submods:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint-params
- variables:
- BUILD_FLAVOUR: default
- script:
- - .gitlab/ci.sh configure
- - .gitlab/ci.sh run_hadrian stage0:exe:lint-submodule-refs
- - git fetch "$CI_MERGE_REQUEST_PROJECT_URL" $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- - base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
- - "echo Linting submodule changes between $base..$CI_COMMIT_SHA"
- - git submodule foreach git remote update
- - _build/stageBoot/bin/lint-submodule-refs . $(git rev-list $base..$CI_COMMIT_SHA)
- dependencies: []
-
-# We allow the submodule checker to fail when run on merge requests (to
-# accommodate, e.g., haddock changes not yet upstream) but not on `master` or
-# Marge jobs.
-lint-author:
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint-params
- variables:
- BUILD_FLAVOUR: default
- script:
- - git fetch "$CI_MERGE_REQUEST_PROJECT_URL" $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
- - base="$(git merge-base FETCH_HEAD $CI_COMMIT_SHA)"
- - "echo Linting authors between $base..$CI_COMMIT_SHA"
- - .gitlab/ci.sh lint_author $base $CI_COMMIT_SHA
- dependencies: []
- rules:
- - if: $CI_MERGE_REQUEST_ID
- - *drafts-can-fail-lint
-
-lint-ci-config:
- image: nixos/nix:2.25.2
- extends: .lint
- # We don't need history/submodules in this job
- variables:
- GIT_DEPTH: 1
- GIT_SUBMODULE_STRATEGY: none
- before_script:
- - echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf
- # Note [Nix-in-Docker]
- # ~~~~~~~~~~~~~~~~~~~~
- # The nixos/nix default config is max-jobs=1 and cores=$(logical
- # cores num) which doesn't play nice with our $CPUS convention. We
- # fix it before invoking any nix build to avoid oversubscribing
- # while allowing a reasonable degree of parallelism.
- # FIXME: Disabling build-users-group=nixbld is a workaround for a Nix-in-Docker issue. See
- # https://gitlab.haskell.org/ghc/head.hackage/-/issues/38#note_560487 for
- # discussion.
- - echo "cores = $CPUS" >> /etc/nix/nix.conf
- - echo "max-jobs = $CPUS" >> /etc/nix/nix.conf
- - nix run nixpkgs#gnused -- -i -e 's/ nixbld//' /etc/nix/nix.conf
- script:
- - nix run .gitlab/generate-ci#generate-jobs
- # 1 if .gitlab/generate_jobs changed the output of the generated config
- - nix shell nixpkgs#git -c git diff --exit-code
- # And run this to generate the .gitlab/jobs-metadata.json
- - nix run .gitlab/generate-ci#generate-job-metadata
- artifacts:
- when: always
- paths:
- - .gitlab/jobs-metadata.json
- - .gitlab/jobs.yaml
- dependencies: []
-
-lint-submods:
- extends: .lint-submods
- # Allow failure on merge requests since any necessary submodule patches may
- # not be upstreamed yet.
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/'
- allow_failure: false
- # Don't run on nightly because the program needs a base commit to check.
- - if: $NIGHTLY
- when: never
- - allow_failure: true
-
-lint-submods-branch:
- extends: .lint-submods
- variables:
- BUILD_FLAVOUR: default
- script:
- - .gitlab/ci.sh configure
- - .gitlab/ci.sh run_hadrian stage0:exe:lint-submodule-refs
- - "echo Linting submodule changes between $CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA"
- - git submodule foreach git remote update
- - _build/stageBoot/bin/lint-submodule-refs . $(git rev-list $CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA)
- rules:
- - if: '$CI_COMMIT_BRANCH == "master"'
- - if: '$CI_COMMIT_BRANCH =~ /ghc-[0.9]+\.[0-9]+/'
- - *drafts-can-fail-lint
-
-############################################################
-# GHC source code linting
-############################################################
-
-.lint-params:
- needs: []
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- extends: .lint
- before_script:
- - export PATH="/opt/toolchain/bin:$PATH"
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
- - .gitlab/ci.sh setup
- after_script:
- - .gitlab/ci.sh save_cache
- - cat ci_timings.txt
- variables:
- GHC_FLAGS: -Werror
- cache:
- key: lint-$CACHE_REV
- paths:
- - cabal-cache
-
-############################################################
-# GHC-in-GHCi (Hadrian)
-############################################################
-
-hadrian-ghc-in-ghci:
- stage: quick-build
- needs:
- - job: lint-linters
- - job: lint-submods
- optional: true
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
- variables:
- GHC_FLAGS: -Werror -Wwarn=unused-imports
- tags:
- - x86_64-linux
- script:
- - git clean -xdf && git submodule foreach git clean -xdf
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- # Enable -Werror when building hadrian
- - "echo 'package hadrian' > hadrian/cabal.project.local"
- - "echo ' ghc-options: -Werror' >> hadrian/cabal.project.local"
- # Load ghc-in-ghci then immediately exit and check the modules loaded
- - export CORES="$(mk/detect-cpu-count.sh)"
- - echo ":q" | HADRIAN_ARGS=-j$CORES hadrian/ghci-multi -j$CORES | tail -n2 | grep "Ok,"
- after_script:
- - .gitlab/ci.sh save_cache
- - cat ci_timings.txt
- cache:
- key: hadrian-ghci-$CACHE_REV
- paths:
- - cabal-cache
-
-############################################################
-# Hadrian Multi-Repl
-############################################################
-
-hadrian-multi:
- stage: testing
- needs:
- - job: x86_64-linux-deb13-validate
- optional: true
- - job: nightly-x86_64-linux-deb13-validate
- optional: true
- - job: release-x86_64-linux-deb13-release
- optional: true
- dependencies: null
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
- variables:
- GHC_FLAGS: "-Werror=-Wno-error=incomplete-record-selectors -Wwarn=deprecations -Wwarn=unused-imports"
- # -Wno-error=incomplete-record-selectors is present because -Wall now
- # includes -Wincomplete-record-selectors, and hadrian-multi has many, many
- # warnings about incomplete record selectors. A better fix would be to
- # remove the use of incomplete record selectors, since each of them represents
- # a potential crash.
- CONFIGURE_ARGS: --enable-bootstrap-with-devel-snapshot
- tags:
- - x86_64-linux
- script:
- - export BOOT_HC=$GHC
- - root=$(pwd)/ghc
- - ls
- - |
- mkdir tmp
- tar -xf ghc-x86_64-linux-deb13-validate.tar.xz -C tmp \
- || tar -xf ghc-x86_64-linux-deb13-release.tar.xz -C tmp
- pushd tmp/ghc-*/
- ./configure --prefix=$root
- make install
- popd
- rm -Rf tmp
- - export HC=$root/bin/ghc
- # This GHC means, use this GHC to configure with
- - export GHC=$root/bin/ghc
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- # Now GHC means, use this GHC for hadrian
- - export GHC=$BOOT_HC
- - export CORES="$(mk/detect-cpu-count.sh)"
- # Load hadrian-multi then immediately exit and check the modules loaded
- - echo ":q" | HADRIAN_ARGS=-j$CORES hadrian/ghci-multi -j$CORES | tail -n2 | grep "Ok,"
- after_script:
- - .gitlab/ci.sh save_cache
- cache:
- key: hadrian-ghci-$CACHE_REV
- paths:
- - cabal-cache
- rules:
- - *full-ci
-
-############################################################
-# stack-hadrian-build
-############################################################
-
-# Verify that Hadrian builds with stack. Note that we don't actually perform a
-# build of GHC itself; we merely test that the Hadrian executable builds and
-# works (by invoking `hadrian --version`).
-stack-hadrian-build:
- extends: hadrian-ghc-in-ghci
- stage: quick-build
- script:
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- - hadrian/build-stack --version
-
-####################################
-# Testing reinstallable ghc codepath
-####################################
-
-test-cabal-reinstall-x86_64-linux-deb13:
- extends: nightly-x86_64-linux-deb13-validate
- stage: full-build
- variables:
- REINSTALL_GHC: "yes"
- BUILD_FLAVOUR: validate
- TEST_ENV: "x86_64-linux-deb13-cabal-install"
- rules:
- - if: $NIGHTLY
- allow_failure: true
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-reinstall.*/'
-
-########################################
-# Testing ABI is invariant across builds
-########################################
-
-abi-test-nightly:
- stage: full-build
- needs:
- - job: nightly-x86_64-linux-fedora43-release-hackage
- - job: nightly-x86_64-linux-fedora43-release
- tags:
- - x86_64-linux
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-fedora43:$DOCKER_REV"
- dependencies: null
- before_script:
- - mkdir -p normal
- - mkdir -p hackage
- - tar -xf ghc-x86_64-linux-fedora43-release.tar.xz -C normal/
- - tar -xf ghc-x86_64-linux-fedora43-release-hackage_docs.tar.xz -C hackage/
- script:
- - .gitlab/ci.sh compare_interfaces_of "normal/ghc-*" "hackage/ghc-*"
- artifacts:
- paths:
- - out
- rules:
- # This job is broken. Disabling it until some kind soul can finish its
- # implementation. #23269
- - when: never
- - if: $NIGHTLY
-
-############################################################
-# Packaging
-############################################################
-
-doc-tarball:
- stage: packaging
- needs:
- - job: x86_64-linux-deb13-numa-slow-validate
- optional: true
- - job: nightly-x86_64-linux-deb13-validate
- optional: true
- - job: release-x86_64-linux-deb13-release
- optional: true
-
- - job: x86_64-windows-validate
- optional: true
- - job: nightly-x86_64-windows-validate
- optional: true
- - job: release-x86_64-windows-release
- optional: true
-
- tags:
- - x86_64-linux
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- dependencies: null
- variables:
- LINUX_BINDIST: "ghc-x86_64-linux-deb13.tar.xz"
- WINDOWS_BINDIST: "ghc-x86_64-windows.tar.xz"
- artifacts:
- expose_as: "Documentation Preview"
- paths:
- - haddock.html.tar.xz
- - docs/haddock/
- - libraries.html.tar.xz
- - docs/libraries/
- - users_guide.html.tar.xz
- - docs/users_guide/
- - docs/index.html
- - Haddock.pdf
- - users_guide.pdf
- script:
- - |
- mv "ghc-x86_64-linux-deb13-numa-slow-validate.tar.xz" "$LINUX_BINDIST" \
- || mv "ghc-x86_64-linux-deb13-validate.tar.xz" "$LINUX_BINDIST" \
- || mv "ghc-x86_64-linux-deb13-release.tar.xz" "$LINUX_BINDIST" \
- || true
- mv "ghc-x86_64-windows-validate.tar.xz" "$WINDOWS_BINDIST" \
- || mv "ghc-x86_64-windows-release.tar.xz" "$WINDOWS_BINDIST" \
- || true
- if [ ! -f "$LINUX_BINDIST" ]; then
- echo "Error: $LINUX_BINDIST does not exist. Did the Debian job fail?"
- exit 1
- fi
- if [ ! -f "$WINDOWS_BINDIST" ]; then
- echo "Error: $WINDOWS_BINDIST does not exist. Did the 64-bit Windows job fail?"
- exit 1
- fi
- - rm -Rf docs
- - bash -ex distrib/mkDocs/mkDocs $LINUX_BINDIST $WINDOWS_BINDIST
- - mv docs/*.tar.xz docs/*.pdf .
- - ls -lh
-
-hackage-doc-tarball:
- stage: packaging
- needs:
- - job: nightly-x86_64-linux-fedora43-release-hackage
- optional: true
- - job: release-x86_64-linux-fedora43-release-hackage
- optional: true
- - job: source-tarball
- tags:
- - x86_64-linux
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- dependencies: null
- variables:
- # Don't clone the git repo..
- GIT_STRATEGY: none
- # Don't attempt to boot a source tarball
- NO_BOOT: "1"
- artifacts:
- paths:
- - hackage_docs
- before_script:
- - tar -xf ghc-*[0-9]-src.tar.xz
- - tar -xf ghc-x86_64-linux-fedora43-release.tar.xz -C ghc*/
- script:
- - cd ghc*/
- - mv .gitlab/rel_eng/upload_ghc_libs.py .
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- - ./upload_ghc_libs.py prepare --bindist ghc*linux/
- - mv .upload-libs/docs ../hackage_docs
- rules:
- - if: $NIGHTLY
- - if: '$RELEASE_JOB == "yes"'
-
-source-tarball:
- stage: full-build
- needs:
- - hadrian-ghc-in-ghci
- tags:
- - x86_64-linux
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- dependencies: []
- artifacts:
- paths:
- - ghc-*.tar.xz
- script:
- - sudo chown ghc:ghc -R .
- - . .gitlab/ci.sh setup
- - . .gitlab/ci.sh configure
- - ./hadrian/build source-dist
- - mv _build/source-dist/*.xz .
- rules:
- - if: $NIGHTLY
- - if: '$RELEASE_JOB == "yes"'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-bootstrap.*/'
- - *full-ci
-
-generate-hadrian-bootstrap-sources:
- stage: full-build
- needs:
- - hadrian-ghc-in-ghci
- tags:
- - x86_64-linux
- image: "$DOCKER_IMAGE"
- dependencies: []
- parallel: *bootstrap_matrix
- artifacts:
- paths:
- - hadrian-bootstrap-sources-*.tar.gz
- script:
- - bash -c "[ $($GHC --numeric-version) = $GHC_VERSION ] || { echo $GHC_VERSION is not the same as the version of $GHC && exit 1; }"
- - python3 ./hadrian/bootstrap/bootstrap.py -w $GHC fetch -o hadrian-bootstrap-sources-$GHC_VERSION
- rules:
- - if: $NIGHTLY
- - if: '$RELEASE_JOB == "yes"'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-bootstrap.*/'
- - *full-ci
-
-
-package-hadrian-bootstrap-sources:
- stage: full-build
- tags:
- - x86_64-linux
- needs: ["generate-hadrian-bootstrap-sources"]
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- artifacts:
- paths:
- - hadrian-bootstrap-sources-all.tar.gz
- script:
- - tar -czvf hadrian-bootstrap-sources-all.tar.gz hadrian-bootstrap-sources-*.tar.gz
- rules:
- - if: $NIGHTLY
- - if: '$RELEASE_JOB == "yes"'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-bootstrap.*/'
- - *full-ci
-
-test-bootstrap:
- stage: full-build
- needs: [generate-hadrian-bootstrap-sources, source-tarball]
- tags:
- - x86_64-linux
- image: "$DOCKER_IMAGE"
- parallel: *bootstrap_matrix
- dependencies: null
- script:
- - sudo chown ghc:ghc -R .
- - mkdir test-bootstrap
- - tar -xf ghc-*[0-9]-src.tar.xz -C test-bootstrap
- - tar -xf ghc-*-testsuite.tar.xz -C test-bootstrap
- - cp hadrian-bootstrap-sources-$GHC_VERSION.tar.gz test-bootstrap/ghc-*
- - pushd test-bootstrap/ghc-*
- - python3 ./hadrian/bootstrap/bootstrap.py -w $GHC --bootstrap-sources hadrian-bootstrap-sources-$GHC_VERSION.tar.gz
- - export HADRIAN_PATH="$PWD/_build/bin/hadrian"
- - .gitlab/ci.sh setup
- # Bootstrapping should not depend on HAPPY or ALEX so set them to false
- # so the build fails if they are invoked.
- - unset HAPPY; unset ALEX
- # Check the commands are not available, parens are crucial to start a subshell
- - (! command -v alex --version)
- - (! command -v happy --version)
- - .gitlab/ci.sh configure
- - .gitlab/ci.sh build_hadrian
- - .gitlab/ci.sh test_hadrian
- - popd
- - rm -Rf test-bootstrap
- variables:
- # Don't record performance benchmarks
- TEST_ENV: ""
- BIN_DIST_NAME: "ghc-x86_64-deb13-linux"
- BUILD_FLAVOUR: "validate"
- NO_BOOT: "1"
- rules:
- - if: $NIGHTLY
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-bootstrap.*/'
- - *full-ci
- - if: '$RELEASE_JOB == "yes"'
- when: always
- variables:
- BUILD_FLAVOUR: "release"
-
-
-############################################################
-# Testing via head.hackage
-############################################################
-
-# Triggering jobs in the ghc/head.hackage project requires that we have a job
-# token for that repository. Furthermore the head.hackage CI job must have
-# access to an unprivileged access token with the ability to query the ghc/ghc
-# project such that it can find the job ID of the fedora43 job for the current
-# pipeline.
-#
-# hackage-lint: Can be triggered on any MR, normal validate pipeline or nightly build.
-# Runs head.hackage with -dlint and a slow-validate bindist
-#
-# hackage-label-lint: Trigged on MRs with "user-facing" label, runs the slow-validate
-# head.hackage build with -dlint.
-#
-# nightly-hackage-lint: Runs automatically on nightly pipelines with slow-validate + dlint config.
-#
-# nightly-hackage-perf: Runs automaticaly on nightly pipelines with release build and eventlogging enabled.
-#
-# release-hackage-lint: Runs automatically on release pipelines with -dlint on a release bindist.
-
-.hackage:
- stage: testing
- variables:
- UPSTREAM_PROJECT_PATH: "$CI_PROJECT_PATH"
- UPSTREAM_PROJECT_ID: "$CI_PROJECT_ID"
- UPSTREAM_PIPELINE_ID: "$CI_PIPELINE_ID"
- RELEASE_JOB: "$RELEASE_JOB"
- trigger:
- project: "ghc/head.hackage"
- branch: "upstream-testing"
- strategy: "depend"
-
-hackage-lint:
- needs:
- - job: x86_64-linux-deb13-numa-slow-validate
- optional: true
- artifacts: false
- - job: nightly-x86_64-linux-deb13-numa-slow-validate
- optional: true
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- - job: aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- extends: .hackage
- variables:
- SLOW_VALIDATE: 1
- EXTRA_HC_OPTS: "-dlint"
- # No for release jobs because there isn't a slow-valdate bindist. There is an
- # automatic pipeline for release bindists (see release-hackage-lint)
- rules:
- - if: '$RELEASE_JOB != "yes"'
- when: manual
-
-hackage-label-lint:
- needs:
- - job: x86_64-linux-deb13-numa-slow-validate
- optional: true
- artifacts: false
- - job: aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- extends: .hackage
- variables:
- SLOW_VALIDATE: 1
- EXTRA_HC_OPTS: "-dlint"
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*user-facing.*/'
-
-# The head.hackage job is split into two jobs because enabling `-dlint`
-# affects the total allocation numbers for the simplifier portion significantly.
-nightly-hackage-lint:
- needs:
- - job: nightly-x86_64-linux-deb13-numa-slow-validate
- optional: true
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- rules:
- - if: $NIGHTLY
- variables:
- NIGHTLY: "$NIGHTLY"
- extends: .hackage
- variables:
- SLOW_VALIDATE: 1
- EXTRA_HC_OPTS: "-dlint"
-
-nightly-hackage-perf:
- needs:
- - job: nightly-x86_64-linux-fedora43-release
- optional: true
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- optional: true
- artifacts: false
- rules:
- - if: $NIGHTLY
- variables:
- NIGHTLY: "$NIGHTLY"
- extends: .hackage
- variables:
- # Generate logs for nightly builds which include timing information.
- EXTRA_HC_OPTS: "-ddump-timings"
- # Ask head.hackage to generate eventlogs
- EVENTLOGGING: 1
-
-release-hackage-lint:
- needs:
- - job: release-x86_64-linux-fedora43-release
- optional: true
- artifacts: false
- - job: release-aarch64-linux-deb13-release+no_split_sections
- optional: true
- artifacts: false
- rules:
- - if: '$RELEASE_JOB == "yes"'
- extends: .hackage
- # The ghcup metadata pipeline requires all prior jobs to
- # pass. The hackage job can easily fail due to API changes
- # or similar - so we allow it to fail.
- allow_failure: true
- variables:
- # No slow-validate bindist on release pipeline
- EXTRA_HC_OPTS: "-dlint"
-
-############################################################
-# Testing via test-primops
-############################################################
-
-# Triggering jobs in the ghc/test-primops project
-
-.test-primops:
- stage: testing
- variables:
- UPSTREAM_PROJECT_PATH: "$CI_PROJECT_PATH"
- UPSTREAM_PROJECT_ID: "$CI_PROJECT_ID"
- UPSTREAM_PIPELINE_ID: "$CI_PIPELINE_ID"
- trigger:
- project: "ghc/test-primops"
- branch: "upstream-testing"
- strategy: "depend"
-
-.test-primops-validate-template:
- needs:
- - job: x86_64-linux-deb13-validate
- artifacts: false
- - job: aarch64-linux-deb13-validate
- artifacts: false
- - job: aarch64-darwin-validate
- artifacts: false
- - job: x86_64-darwin-validate
- artifacts: false
- extends: .test-primops
-
-test-primops-label:
- extends: .test-primops-validate-template
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-primops.*/'
- # We do not use *.full-ci here since that would imply running in nightly
- # where we do not have the normal validate jobs. We have the -nightly job
- # below to handle this case.
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/'
-
-test-primops-nightly:
- extends: .test-primops
- needs:
- - job: nightly-x86_64-linux-deb13-validate
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- artifacts: false
- - job: nightly-aarch64-darwin-validate
- artifacts: false
- - job: nightly-x86_64-darwin-validate
- artifacts: false
- rules:
- - if: $NIGHTLY
-
-test-primops-release:
- extends: .test-primops
- rules:
- - if: '$RELEASE_JOB == "yes"'
-
-############################################################
-# Nofib testing
-# (Disabled: See #21859)
-############################################################
-
-perf-nofib:
- # Dependencies used by perf-nofib can't be built when some compiler changes
- # aren't (yet) supported by head.hackage.
- # Hence we allow this job to fail.
- allow_failure: true
- stage: testing
- needs:
- - job: x86_64-linux-fedora43-release
- optional: true
- - job: nightly-x86_64-linux-fedora43-release
- optional: true
- - job: release-x86_64-linux-fedora43-release
- optional: true
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-fedora43:$DOCKER_REV"
- rules:
- - when: never
- - *full-ci
- tags:
- - x86_64-linux
- before_script:
- - cd nofib
- - "cabal update --index=$HACKAGE_INDEX_STATE --project-file=cabal.project.head-hackage"
- script:
- - root=$(pwd)/ghc
- - |
- mkdir tmp
- tar -xf ../ghc-x86_64-linux-fedora43-release.tar.xz -C tmp
- pushd tmp/ghc-*/
- ./configure --prefix=$root
- make install
- popd
- rm -Rf tmp
- - export PATH=$root/bin:$PATH
- - cabal install -w "$root/bin/ghc" --lib regex-compat unboxed-ref parallel random-1.2.1 --allow-newer --package-env local.env --project-file=cabal.project.head-hackage
- - export GHC_ENVIRONMENT="$(pwd)/local.env"
- - "make HC=$root/bin/ghc BOOT_HC=$root/bin/ghc boot mode=fast -j$CPUS"
- - "make HC=$root/bin/ghc BOOT_HC=$root/bin/ghc EXTRA_RUNTEST_OPTS='-cachegrind +RTS -V0 -RTS' NoFibRuns=1 mode=fast -j$CPUS 2>&1 | tee nofib.log"
- artifacts:
- expire_in: 12 week
- when: always
- paths:
- - nofib/nofib.log
-
-############################################################
-# Ad-hoc performance testing
-############################################################
-
-perf:
- stage: testing
- needs:
- - job: x86_64-linux-deb13-validate
- optional: true
- - job: nightly-x86_64-linux-deb13-validate
- optional: true
- - job: release-x86_64-linux-deb13-release
- optional: true
- dependencies: null
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- tags:
- - x86_64-linux-perf
- before_script:
- # workaround for docker permissions
- - sudo chown ghc:ghc -R .
- script:
- - root=$(pwd)/ghc
- - |
- mkdir tmp
- tar -xf ghc-x86_64-linux-deb13-validate.tar.xz -C tmp \
- || tar -xf ghc-x86_64-linux-deb13-release.tar.xz -C tmp
- pushd tmp/ghc-*/
- ./configure --prefix=$root
- make install
- popd
- rm -Rf tmp
- - export BOOT_HC=$(which ghc)
- - export HC=$root/bin/ghc
- - .gitlab/ci.sh perf_test
- artifacts:
- expire_in: 2 year
- when: always
- paths:
- - out
- rules:
- - *full-ci
-
-############################################################
-# ABI testing
-############################################################
-
-abi-test:
- stage: testing
- needs:
- - job: x86_64-linux-deb13-validate
- optional: true
- - job: nightly-x86_64-linux-deb13-validate
- optional: true
- - job: release-x86_64-linux-deb13-release
- optional: true
- dependencies: null
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- tags:
- - x86_64-linux
- script:
- - root=$(pwd)/ghc
- - |
- mkdir tmp
- tar -xf ghc-x86_64-linux-deb13-validate.tar.xz -C tmp \
- || tar -xf ghc-x86_64-linux-deb13-release.tar.xz -C tmp
- pushd tmp/ghc-*/
- ./configure --prefix=$root
- make install
- popd
- rm -Rf tmp
- - export BOOT_HC=$(which ghc)
- - export HC=$root/bin/ghc
- - .gitlab/ci.sh abi_test
- artifacts:
- paths:
- - out
- rules:
- - *full-ci
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-abi.*/'
-
-############################################################
-# ghc-wasm-meta integration testing
-############################################################
-
-.ghc-wasm-meta:
- stage: testing
- variables:
- UPSTREAM_GHC_PIPELINE_ID: $CI_PIPELINE_ID
- UPSTREAM_GHC_PROJECT_ID: $CI_PROJECT_ID
- rules:
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*test-wasm.*/'
- trigger:
- project: haskell-wasm/ghc-wasm-meta
- branch: master
- strategy: depend
-
-ghc-wasm-meta-gmp:
- extends: .ghc-wasm-meta
- needs:
- - job: x86_64-linux-alpine3_23-wasm-cross_wasm32-wasi-release+host_fully_static+text_simdutf
- artifacts: false
- variables:
- UPSTREAM_GHC_FLAVOUR: gmp
- UPSTREAM_GHC_JOB_NAME: x86_64-linux-alpine3_23-wasm-cross_wasm32-wasi-release+host_fully_static+text_simdutf
-
-ghc-wasm-meta-native:
- extends: .ghc-wasm-meta
- needs:
- - job: x86_64-linux-alpine3_23-wasm-int_native-cross_wasm32-wasi-release+host_fully_static+text_simdutf
- artifacts: false
- variables:
- UPSTREAM_GHC_FLAVOUR: native
- UPSTREAM_GHC_JOB_NAME: x86_64-linux-alpine3_23-wasm-int_native-cross_wasm32-wasi-release+host_fully_static+text_simdutf
-
-ghc-wasm-meta-unreg:
- extends: .ghc-wasm-meta
- needs:
- - job: x86_64-linux-alpine3_23-wasm-unreg-cross_wasm32-wasi-release+host_fully_static+text_simdutf
- artifacts: false
- variables:
- UPSTREAM_GHC_FLAVOUR: unreg
- UPSTREAM_GHC_JOB_NAME: x86_64-linux-alpine3_23-wasm-unreg-cross_wasm32-wasi-release+host_fully_static+text_simdutf
-
-############################################################
-# Documentation deployment via GitLab Pages
-############################################################
-
-pages:
- stage: deploy
- needs: [doc-tarball]
- dependencies: null
- image: "debian:13"
- # See #18973
- allow_failure: true
- tags:
- - x86_64-linux
- script:
- - mkdir -p public/doc
- # haddock docs are not in the hadrian produce doc tarballs at the moment
- # - tar -xf haddock.html.tar.xz -C public/doc
- - tar -xf libraries.html.tar.xz -C public/doc
- - tar -xf users_guide.html.tar.xz -C public/doc
- - |
- cat >public/index.html <<EOF
- <!DOCTYPE HTML>
- <meta charset="UTF-8">
- <meta http-equiv="refresh" content="1; url=doc/">
- EOF
- - cp -f docs/index.html public/doc
- rules:
- # N.B. only run this on ghc/ghc since the deployed pages are quite large
- # and we only serve GitLab Pages for ghc/ghc.
- - if: '$CI_COMMIT_BRANCH == "master" && $CI_PROJECT_NAMESPACE == "ghc"'
- - if: '$CI_MERGE_REQUEST_LABELS =~ /.*publish-docs.*/'
-
- artifacts:
- paths:
- - public
-
-#############################################################
-# Generation of GHCUp metadata
-#############################################################
-
-
-project-version:
- stage: packaging
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb13:$DOCKER_REV"
- tags:
- - x86_64-linux
- variables:
- BUILD_FLAVOUR: default
- script:
- # Calculate the project version
- - sudo chown ghc:ghc -R .
- - .gitlab/ci.sh setup
- - .gitlab/ci.sh configure
- - echo "ProjectVersion=$(cat VERSION)" > version.sh
-
- needs: []
- dependencies: []
- artifacts:
- paths:
- - version.sh
-
-.ghcup-metadata:
- stage: deploy
- image: nixos/nix:2.25.2
- dependencies: null
- tags:
- # N.B. we use the OpenCape runners here since this job involves a significant
- # amount of artifact fetching. This is much more efficient on these runners
- # as they are near the GitLab box.
- - opencape
- - x86_64-linux
- variables:
- BUILD_FLAVOUR: default
- GIT_SUBMODULE_STRATEGY: "none"
- before_script:
- - echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf
- # FIXME: See Note [Nix-in-Docker]
- - echo "cores = $CPUS" >> /etc/nix/nix.conf
- - echo "max-jobs = $CPUS" >> /etc/nix/nix.conf
- - nix run nixpkgs#gnused -- -i -e 's/ nixbld//' /etc/nix/nix.conf
- - nix-channel --update
- - cat version.sh
- # Calculate the project version
- - . ./version.sh
-
- # Download existing ghcup metadata for the correct year
- - PipelineYear="$(date -d $CI_PIPELINE_CREATED_AT +%Y)"
- - nix shell nixpkgs#wget -c wget "https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-$PipelineYear…" -O ghcup-0.0.7.yaml
-
- - nix run .gitlab/generate-ci#generate-job-metadata
-
- artifacts:
- paths:
- - metadata_test.yaml
- - version.sh
-
-ghcup-metadata-nightly:
- extends: .ghcup-metadata
- # Explicit needs for validate pipeline because we only need certain bindists
- needs:
- - job: nightly-x86_64-linux-fedora43-release
- artifacts: false
- - job: nightly-x86_64-linux-ubuntu24_04-validate
- artifacts: false
- - job: nightly-x86_64-linux-ubuntu22_04-validate
- artifacts: false
- - job: nightly-x86_64-linux-rocky8-validate
- artifacts: false
- - job: nightly-x86_64-darwin-validate
- artifacts: false
- - job: nightly-aarch64-darwin-validate
- artifacts: false
- - job: nightly-x86_64-windows-validate
- artifacts: false
- - job: nightly-x86_64-linux-alpine3_23-validate
- artifacts: false
- - job: nightly-i386-linux-deb11-validate
- artifacts: false
- - job: nightly-i386-linux-deb13-validate
- artifacts: false
- - job: nightly-i386-linux-alpine3_23-validate
- artifacts: false
- - job: nightly-aarch64-linux-deb11-validate
- artifacts: false
- - job: nightly-x86_64-linux-deb11-validate
- artifacts: false
- - job: nightly-x86_64-linux-deb13-validate
- artifacts: false
- - job: nightly-aarch64-linux-deb13-validate
- artifacts: false
- - job: nightly-x86_64-linux-deb12-validate
- artifacts: false
- - job: nightly-aarch64-linux-alpine3_23-validate
- artifacts: false
- - job: source-tarball
- artifacts: false
- - job: project-version
- script:
- - nix shell -f .gitlab/rel_eng -c ghcup-metadata --metadata ghcup-0.0.7.yaml --date="$(date -d $CI_PIPELINE_CREATED_AT +%Y-%m-%d)" --pipeline-id="$CI_PIPELINE_ID" --version="$ProjectVersion" > "metadata_test.yaml"
- rules:
- - if: $NIGHTLY
-
-# Update the ghcup metadata with information about this nightly pipeline
-ghcup-metadata-nightly-push:
- stage: deploy
- image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-fedora43:$DOCKER_REV"
- dependencies: null
- tags:
- - x86_64-linux
- variables:
- BUILD_FLAVOUR: default
- GIT_SUBMODULE_STRATEGY: "none"
- needs:
- - job: ghcup-metadata-nightly
- artifacts: true
- script:
- - git clone https://gitlab.haskell.org/ghc/ghcup-metadata.git
- - PipelineYear="$(date -d $CI_PIPELINE_CREATED_AT +%Y)"
- - cp metadata_test.yaml "ghcup-metadata/ghcup-nightlies-$PipelineYear-0.0.7.yaml"
- - cp metadata_test.yaml "ghcup-metadata/ghcup-nightlies-0.0.7.yaml"
- - cd ghcup-metadata
- - git config user.email "ghc-ci(a)gitlab-haskell.org"
- - git config user.name "GHC GitLab CI"
- - git remote add gitlab_origin https://oauth2:$PROJECT_PUSH_TOKEN@gitlab.haskell.org/ghc/ghcup-metadata.git
- - git add .
- - git commit -m "Update metadata"
- - git push gitlab_origin HEAD:updates
- rules:
- # Only run the update on scheduled nightly pipelines, ie once a day
- - if: $NIGHTLY && $CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_BRANCH == "master"
-
-
-ghcup-metadata-release:
- # No explicit needs for release pipeline as we assume we need everything and everything will pass.
- extends: .ghcup-metadata
- script:
- - nix shell -f .gitlab/rel_eng -c ghcup-metadata --release-mode --metadata ghcup-0.0.7.yaml --date="$(date -d $CI_PIPELINE_CREATED_AT +%Y-%m-%d)" --pipeline-id="$CI_PIPELINE_ID" --version="$ProjectVersion" --fragment
- - nix shell -f .gitlab/rel_eng -c ghcup-metadata --release-mode --metadata ghcup-0.0.7.yaml --date="$(date -d $CI_PIPELINE_CREATED_AT +%Y-%m-%d)" --pipeline-id="$CI_PIPELINE_ID" --version="$ProjectVersion" > "metadata_test.yaml"
- rules:
- - if: '$RELEASE_JOB == "yes"'
-
-.ghcup-metadata-testing:
- stage: deploy
- variables:
- UPSTREAM_PROJECT_PATH: "$CI_PROJECT_PATH"
- UPSTREAM_PROJECT_ID: "$CI_PROJECT_ID"
- UPSTREAM_PIPELINE_ID: "$CI_PIPELINE_ID"
- RELEASE_JOB: "$RELEASE_JOB"
- # Do not inherit global variables (such as CONFIGURE_ARGS) as these take
- # precedence over the variables defined in the downstream job.
- inherit:
- variables: false
- trigger:
- project: "ghc/ghcup-ci"
- branch: "upstream-testing"
- strategy: "depend"
- forward:
- yaml_variables: true
- pipeline_variables: false
-
-ghcup-metadata-testing-nightly:
- needs:
- - job: ghcup-metadata-nightly
- artifacts: false
- extends: .ghcup-metadata-testing
- variables:
- NIGHTLY: "$NIGHTLY"
- UPSTREAM_JOB_NAME: "ghcup-metadata-nightly"
- rules:
- - if: '$NIGHTLY == "1"'
-
-ghcup-metadata-testing-release:
- needs:
- - job: ghcup-metadata-release
- artifacts: false
- extends: .ghcup-metadata-testing
- variables:
- UPSTREAM_JOB_NAME: "ghcup-metadata-release"
- rules:
- - if: '$RELEASE_JOB == "yes"'
- when: manual
=====================================
.gitlab/jobs.yaml
=====================================
@@ -26,7 +26,11 @@
"dependencies": [],
"image": null,
"needs": [],
- "rules": [],
+ "rules": [
+ {
+ "when": "always"
+ }
+ ],
"script": [
"echo \"PATH=$PATH\"",
"echo \"MSYSTEM=$MSYSTEM\"",
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/74684457b29db6a598c6cd1d2256fba…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/74684457b29db6a598c6cd1d2256fba…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/jeltsch/module-graph-reuse-in-downsweep] Allow `downsweep` to use nodes of an existing module graph
by Wolfgang Jeltsch (@jeltsch) 27 May '26
by Wolfgang Jeltsch (@jeltsch) 27 May '26
27 May '26
Wolfgang Jeltsch pushed to branch wip/jeltsch/module-graph-reuse-in-downsweep at Glasgow Haskell Compiler / GHC
Commits:
b859a2f0 by Wolfgang Jeltsch at 2026-05-27T18:23:23+03:00
Allow `downsweep` to use nodes of an existing module graph
To this end, `downsweep` has not been able to use the nodes of a module
graph obtained from a previous downsweeping round. In some GHC API
applications, downsweeping is performed somewhat incrementally and
therefore could profit from reusing such existing results. This
contribution makes this possible.
Resolves #27054.
Co-authored-by: Matthew Pickering <matthewtpickering(a)gmail.com>
- - - - -
16 changed files:
- + changelog.d/module-graph-reuse-in-downsweep
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/Make.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/A.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/B.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/C.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/D.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/X.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/Y.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/Z.hs
- + testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.stdout
- testsuite/tests/ghc-api/downsweep/OldModLocation.hs
- testsuite/tests/ghc-api/downsweep/PartialDownsweep.hs
- testsuite/tests/ghc-api/downsweep/all.T
- testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.hs
Changes:
=====================================
changelog.d/module-graph-reuse-in-downsweep
=====================================
@@ -0,0 +1,9 @@
+section: compiler
+synopsis: Allow `downsweep` to use nodes of an existing module graph
+issues: #27054
+mrs: !16028
+description: {
+ This contribution enables `downsweep` to use the nodes of a module
+ graph obtained from a previous downsweeping round, which allows GHC
+ API applications to build module graphs somewhat incrementally.
+}
=====================================
compiler/GHC/Driver/Downsweep.hs
=====================================
@@ -146,6 +146,10 @@ The result is having a uniform graph available for the whole compilation pipelin
-- an import of this module mean.
type DownsweepCache = M.Map (UnitId, PkgQual, ModuleNameWithIsBoot) [Either DriverMessages ModuleNodeInfo]
+moduleGraphNodeMap :: ModuleGraph -> M.Map NodeKey ModuleGraphNode
+moduleGraphNodeMap graph
+ = M.fromList [(mkNodeKey node, node) | node <- mgModSummaries' graph]
+
-----------------------------------------------------------------------------
--
-- | Downsweep (dependency analysis) for --make mode
@@ -158,6 +162,13 @@ type DownsweepCache = M.Map (UnitId, PkgQual, ModuleNameWithIsBoot) [Either Driv
-- cache to avoid recalculating a module summary if the source is
-- unchanged.
--
+-- Downsweeping can start from scratch for from a given module graph. In the
+-- latter case, the given graph is fully included in the resulting graph, even
+-- if parts of it are not reachable from any of the given roots. When an import
+-- is processed, the source of the imported module is not consulted if this
+-- module is already mentioned in the given graph. The sources of the root
+-- modules are always consulted, though.
+--
-- The returned ModuleGraph has one node for each home-package
-- module, plus one for any hs-boot files. The imports of these nodes
-- are all there, including the imports of non-home-package modules.
@@ -172,6 +183,8 @@ downsweep :: HscEnv
-> Maybe Messager
-> [ModSummary]
-- ^ Old summaries
+ -> Maybe ModuleGraph
+ -- ^ Optionally a module graph to extend
-> [ModuleName] -- Ignore dependencies on these; treat
-- them as if they were package modules
-> Bool -- True <=> allow multiple targets to have
@@ -181,7 +194,7 @@ downsweep :: HscEnv
-- The non-error elements of the returned list all have distinct
-- (Modules, IsBoot) identifiers, unless the Bool is true in
-- which case there can be repeats
-downsweep hsc_env diag_wrapper msg old_summaries excl_mods allow_dup_roots = do
+downsweep hsc_env diag_wrapper msg old_summaries maybe_base_graph excl_mods allow_dup_roots = do
n_jobs <- mkWorkerLimit (hsc_dflags hsc_env)
(root_errs, root_summaries) <- rootSummariesParallel n_jobs hsc_env diag_wrapper msg summary
let closure_errs = checkHomeUnitsClosed unit_env
@@ -191,7 +204,7 @@ downsweep hsc_env diag_wrapper msg old_summaries excl_mods allow_dup_roots = do
case all_errs of
[] -> do
- (downsweep_errs, downsweep_nodes) <- downsweepFromRootNodes hsc_env old_summary_map excl_mods allow_dup_roots DownsweepUseCompile (map ModuleNodeCompile root_summaries) []
+ (downsweep_errs, downsweep_nodes) <- downsweepFromRootNodes hsc_env old_summary_map maybe_base_graph excl_mods allow_dup_roots DownsweepUseCompile (map ModuleNodeCompile root_summaries) []
let (other_errs, unit_nodes) = partitionEithers $ HUG.unitEnv_foldWithKey (\nodes uid hue -> nodes ++ unitModuleNodes downsweep_nodes uid hue) [] (hsc_HUG hsc_env)
@@ -232,7 +245,7 @@ downsweep hsc_env diag_wrapper msg old_summaries excl_mods allow_dup_roots = do
downsweepThunk :: HscEnv -> ModSummary -> IO ModuleGraph
downsweepThunk hsc_env mod_summary = unsafeInterleaveIO $ do
debugTraceMsg (hsc_logger hsc_env) 3 $ text "Computing Module Graph thunk..."
- ~(errs, mg) <- downsweepFromRootNodes hsc_env mempty [] True DownsweepUseFixed [ModuleNodeCompile mod_summary] []
+ ~(errs, mg) <- downsweepFromRootNodes hsc_env mempty Nothing [] True DownsweepUseFixed [ModuleNodeCompile mod_summary] []
let dflags = hsc_dflags hsc_env
liftIO $ printOrThrowDiagnostics (hsc_logger hsc_env)
(initPrintConfig dflags)
@@ -360,7 +373,7 @@ downsweepInstalledModules hsc_env mods = do
_ -> throwGhcException $ ProgramError $ showSDoc (hsc_dflags hsc_env) $ text "downsweepInstalledModules: Could not find installed module" <+> ppr i
nodes <- mapM process installed_mods
- (errs, mg) <- downsweepFromRootNodes hsc_env mempty [] True DownsweepUseFixed nodes external_uids
+ (errs, mg) <- downsweepFromRootNodes hsc_env mempty Nothing [] True DownsweepUseFixed nodes external_uids
-- Similarly here, we should really not get any errors, but print them out if we do.
let dflags = hsc_dflags hsc_env
@@ -385,19 +398,21 @@ data DownsweepMode = DownsweepUseCompile | DownsweepUseFixed
-- all the dependencies, all the way to the leaf units.
downsweepFromRootNodes :: HscEnv
-> M.Map (UnitId, OsPath) ModSummary
+ -> Maybe ModuleGraph
-> [ModuleName]
-> Bool
-> DownsweepMode -- ^ Whether to create fixed or compile nodes for dependencies
-> [ModuleNodeInfo] -- ^ The starting ModuleNodeInfo
-> [UnitId] -- ^ The starting units
-> IO ([DriverMessages], [ModuleGraphNode])
-downsweepFromRootNodes hsc_env old_summaries excl_mods allow_dup_roots mode root_nodes root_uids
+downsweepFromRootNodes hsc_env old_summaries maybe_base_graph excl_mods allow_dup_roots mode root_nodes root_uids
= do
let root_map = mkRootMap root_nodes
checkDuplicates root_map
let env = DownsweepEnv hsc_env mode old_summaries excl_mods
(deps', map0) <- runDownsweepM env $ do
- (module_deps, map0) <- loopModuleNodeInfos root_nodes (M.empty, root_map)
+ let base_nodes = maybe M.empty moduleGraphNodeMap maybe_base_graph
+ (module_deps, map0) <- loopModuleNodeInfos root_nodes (base_nodes, root_map)
let all_deps = loopUnit hsc_env module_deps root_uids
let all_instantiations = getHomeUnitInstantiations hsc_env
deps' <- loopInstantiations all_instantiations all_deps
=====================================
compiler/GHC/Driver/Make.hs
=====================================
@@ -232,7 +232,7 @@ depanalPartial diag_wrapper msg excluded_mods allow_dup_roots = do
liftIO $ flushFinderCaches (hsc_FC hsc_env) (hsc_unit_env hsc_env)
(errs, mod_graph) <- liftIO $ downsweep
- hsc_env diag_wrapper msg (mgModSummaries old_graph)
+ hsc_env diag_wrapper msg (mgModSummaries old_graph) Nothing
excluded_mods allow_dup_roots
return (unionManyMessages errs, mod_graph)
=====================================
testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.hs
=====================================
@@ -0,0 +1,105 @@
+{-# LANGUAGE Haskell2010 #-}
+
+{-# OPTIONS_GHC -Wall -Werror #-}
+
+import Control.Monad (unless)
+import Control.Monad.IO.Class (liftIO)
+import Control.Arrow ((>>>))
+import Data.List (sort)
+import System.Environment (getArgs)
+import System.Exit (exitFailure)
+import System.IO (stderr)
+import System.Directory (removeFile)
+import Language.Haskell.Syntax.Module.Name (moduleNameString)
+import GHC.Utils.Ppr (Mode (PageMode))
+import GHC.Utils.Outputable (vcat, defaultSDocContext, printSDocLn, ppr)
+import GHC.Utils.Logger (getLogger)
+import GHC.Types.SrcLoc (noLoc)
+import GHC.Types.Error (mkUnknownDiagnostic)
+import GHC.Unit.Types (moduleName)
+import GHC.Unit.Module.ModSummary (ms_mod)
+import GHC.Unit.Module.Graph (ModuleGraph, mgModSummaries)
+import GHC.Driver.DynFlags (defaultFatalMessager, defaultFlushOut)
+import GHC.Driver.Monad (Ghc, getSession, getSessionDynFlags)
+import GHC.Driver.Make (downsweep)
+import GHC.Driver.Errors.Types (DriverMessages)
+import GHC
+ (
+ defaultErrorHandler,
+ guessTarget,
+ setTargets,
+ parseDynamicFlags,
+ setSessionDynFlags,
+ runGhc
+ )
+
+sourceDirectory :: String
+sourceDirectory = "IncrementalDownsweep.modules"
+
+withSimpleErrorHandler :: Ghc a -> Ghc a
+withSimpleErrorHandler = defaultErrorHandler defaultFatalMessager
+ defaultFlushOut
+
+handleDriverMessages :: [DriverMessages] -> IO ()
+handleDriverMessages driverMsgs
+ = unless (null driverMsgs) $
+ do
+ printSDocLn defaultSDocContext
+ (PageMode True)
+ stderr
+ (vcat (map ppr driverMsgs))
+ exitFailure
+
+performDownsweepTurn :: Maybe ModuleGraph -> String -> Ghc ModuleGraph
+performDownsweepTurn maybeGivenModuleGraph rootModuleName = do
+ target <- guessTarget rootModuleName Nothing Nothing
+ setTargets [target]
+ session <- getSession
+ (driverMsgs, resultingModuleGraph)
+ <- liftIO $ downsweep session
+ mkUnknownDiagnostic
+ Nothing
+ []
+ maybeGivenModuleGraph
+ []
+ False
+ liftIO $ handleDriverMessages driverMsgs
+ return resultingModuleGraph
+
+outputModuleNamesInGraph :: ModuleGraph -> IO ()
+outputModuleNamesInGraph = mgModSummaries >>>
+ map (ms_mod >>> moduleName >>> moduleNameString) >>>
+ sort >>>
+ print
+
+main :: IO ()
+main = do
+ libDir : otherArgs <- getArgs
+ runGhc (Just libDir) $ withSimpleErrorHandler $ do
+
+ -- Setup
+ logger <- getLogger
+ originalDynFlags <- getSessionDynFlags
+ (finalDynFlags, _, _)
+ <- parseDynamicFlags logger originalDynFlags $
+ map noLoc (["-i", "-i" ++ sourceDirectory] ++ otherArgs)
+ _ <- setSessionDynFlags finalDynFlags
+
+ -- Turn 1: From scratch, using 'A' as root
+ moduleGraph1 <- performDownsweepTurn Nothing "A"
+ liftIO $ outputModuleNamesInGraph moduleGraph1
+
+ -- Turn 2: From scratch, using 'X' as root
+ -- NOTE: 'A' is not included, because it is not reachable.
+ moduleGraph2 <- performDownsweepTurn Nothing "X"
+ liftIO $ outputModuleNamesInGraph moduleGraph2
+
+ -- Deletion of the source files used in turn 1
+ _ <- liftIO $
+ mapM_ (((sourceDirectory ++ "/") ++) >>> (++ ".hs") >>> removeFile)
+ ["A", "B", "C", "D"]
+
+ -- Turn 3: Based on the result of turn 1, using 'X' as root
+ -- NOTE: 'A' is included, because the result of turn 1 contains it.
+ moduleGraph3 <- performDownsweepTurn (Just moduleGraph1) "X"
+ liftIO $ outputModuleNamesInGraph moduleGraph3
=====================================
testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/A.hs
=====================================
@@ -0,0 +1,4 @@
+module A where
+
+import B
+import C
=====================================
testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/B.hs
=====================================
@@ -0,0 +1,3 @@
+module B where
+
+import D
=====================================
testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/C.hs
=====================================
@@ -0,0 +1,3 @@
+module C where
+
+import D
=====================================
testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/D.hs
=====================================
@@ -0,0 +1 @@
+module D where
=====================================
testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/X.hs
=====================================
@@ -0,0 +1,4 @@
+module X where
+
+import Y
+import Z
=====================================
testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/Y.hs
=====================================
@@ -0,0 +1,3 @@
+module Y where
+
+import B
=====================================
testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.modules/Z.hs
=====================================
@@ -0,0 +1,3 @@
+module Z where
+
+import C
=====================================
testsuite/tests/ghc-api/downsweep/IncrementalDownsweep.stdout
=====================================
@@ -0,0 +1,3 @@
+["A","B","C","D"]
+["B","C","D","X","Y","Z"]
+["A","B","C","D","X","Y","Z"]
=====================================
testsuite/tests/ghc-api/downsweep/OldModLocation.hs
=====================================
@@ -48,13 +48,13 @@ main = do
liftIO $ do
- _emss <- downsweep hsc_env mkUnknownDiagnostic Nothing [] [] False
+ _emss <- downsweep hsc_env mkUnknownDiagnostic Nothing [] Nothing [] False
flushFinderCaches (hsc_FC hsc_env) (hsc_unit_env hsc_env)
createDirectoryIfMissing False "mydir"
renameFile "B.hs" "mydir/B.hs"
- (_, nodes) <- downsweep hsc_env mkUnknownDiagnostic Nothing [] [] False
+ (_, nodes) <- downsweep hsc_env mkUnknownDiagnostic Nothing [] Nothing [] False
-- If 'checkSummaryTimestamp' were to call 'addHomeModuleToFinder' with
-- (ms_location old_summary) like summariseFile used to instead of
=====================================
testsuite/tests/ghc-api/downsweep/PartialDownsweep.hs
=====================================
@@ -169,7 +169,7 @@ go label mods cnd =
setTargets [tgt]
hsc_env <- getSession
- (_, nodes) <- liftIO $ downsweep hsc_env mkUnknownDiagnostic Nothing [] [] False
+ (_, nodes) <- liftIO $ downsweep hsc_env mkUnknownDiagnostic Nothing [] Nothing [] False
it label $ cnd (mgModSummaries nodes)
=====================================
testsuite/tests/ghc-api/downsweep/all.T
=====================================
@@ -14,3 +14,10 @@ test('OldModLocation',
],
compile_and_run,
['-package ghc'])
+
+test('IncrementalDownsweep',
+ [ extra_files(['IncrementalDownsweep.modules/'])
+ , extra_run_opts('"' + config.libdir + '"')
+ ],
+ compile_and_run,
+ ['-package ghc'])
=====================================
testsuite/tests/ghc-api/fixed-nodes/InterfaceModuleGraph.hs
=====================================
@@ -67,7 +67,7 @@ main = do
keyC = msKey msC
let mkGraph s = do
- ([], nodes) <- downsweepFromRootNodes hsc_env mempty [] True DownsweepUseFixed s []
+ ([], nodes) <- downsweepFromRootNodes hsc_env mempty Nothing [] True DownsweepUseFixed s []
return $ mkModuleGraph nodes
graph <- liftIO $ mkGraph [ModuleNodeCompile msC]
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/b859a2f0dd8b9b924cabab566c0f4e1…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/b859a2f0dd8b9b924cabab566c0f4e1…
You're receiving this email because of your account on gitlab.haskell.org.
1
0