[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 4 commits: JavaScript codegen: Use GHC's tag inference where JS backend-specific...
Marge Bot (@marge-bot)
gitlab at gitlab.haskell.org
Fri Feb 9 05:43:36 UTC 2024
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
045a0888 by Josh Meredith at 2024-02-09T00:43:07-05:00
JavaScript codegen: Use GHC's tag inference where JS backend-specific evaluation inference was previously used (#24309)
- - - - -
2b379950 by Zubin Duggal at 2024-02-09T00:43:08-05:00
ci: Allow release-hackage-lint to fail
Otherwise it blocks the ghcup metadata pipeline from running.
- - - - -
1b048b32 by Jade at 2024-02-09T00:43:10-05:00
Adjust error message for trailing whitespace in as-pattern.
Fixes #22524
- - - - -
d6fe8aa9 by doyougnu at 2024-02-09T00:43:14-05:00
gitlab: js: add codeowners
Fixes:
- #24409
Follow on from:
- #21078 and MR !9133
- When we added the JS backend this was forgotten. This patch adds the
rightful codeowners.
- - - - -
15 changed files:
- .gitlab-ci.yml
- CODEOWNERS
- compiler/GHC/JS/JStg/Syntax.hs
- compiler/GHC/Parser/Errors/Ppr.hs
- compiler/GHC/Parser/Lexer.x
- compiler/GHC/Stg/InferTags/Rewrite.hs
- compiler/GHC/StgToJS/Apply.hs
- compiler/GHC/StgToJS/Expr.hs
- compiler/GHC/StgToJS/ExprCtx.hs
- compiler/GHC/StgToJS/Types.hs
- compiler/GHC/StgToJS/Utils.hs
- testsuite/tests/diagnostic-codes/codes.stdout
- + testsuite/tests/parser/should_fail/SuffixAtFail.hs
- + testsuite/tests/parser/should_fail/SuffixAtFail.stderr
- testsuite/tests/parser/should_fail/all.T
Changes:
=====================================
.gitlab-ci.yml
=====================================
@@ -841,6 +841,10 @@ release-hackage-lint:
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"
=====================================
CODEOWNERS
=====================================
@@ -52,6 +52,8 @@
/compiler/GHC/Core/Opt/ @simonpj @sgraf
/compiler/GHC/ThToHs.hs @rae
/compiler/GHC/Wasm/ @nrnrnr
+/compiler/GHC/JS/ @luite @doyougnu @hsyl20 @JoshMeredith
+/compiler/GHC/StgToJS/ @luite @doyougnu @hsyl20 @JoshMeredith
[Core libraries]
/libraries/base/ @hvr
=====================================
compiler/GHC/JS/JStg/Syntax.hs
=====================================
@@ -70,6 +70,7 @@ module GHC.JS.JStg.Syntax
) where
import GHC.Prelude
+import GHC.Utils.Outputable
import GHC.JS.Ident
@@ -148,6 +149,16 @@ data JStgExpr
| ApplExpr JStgExpr [JStgExpr] -- ^ Application
deriving (Eq, Typeable, Generic)
+instance Outputable JStgExpr where
+ ppr x = case x of
+ ValExpr _ -> text ("ValExpr" :: String)
+ SelExpr x' _ -> text ("SelExpr" :: String) <+> ppr x'
+ IdxExpr x' y' -> text ("IdxExpr" :: String) <+> ppr (x', y')
+ InfixExpr _ x' y' -> text ("InfixExpr" :: String) <+> ppr (x', y')
+ UOpExpr _ x' -> text ("UOpExpr" :: String) <+> ppr x'
+ IfExpr p t e -> text ("IfExpr" :: String) <+> ppr (p, t, e)
+ ApplExpr x' xs -> text ("ApplExpr" :: String) <+> ppr (x', xs)
+
-- * Useful pattern synonyms to ease programming with the deeply embedded JS
-- AST. Each pattern wraps @UOp@ and @Op@ into a @JStgExpr at s to save typing and
-- for convienience. In addition we include a string wrapper for JS string
=====================================
compiler/GHC/Parser/Errors/Ppr.hs
=====================================
@@ -386,7 +386,8 @@ instance Diagnostic PsMessage where
-> mkSimpleDecorated $ text "primitive string literal must contain only characters <= \'\\xFF\'"
PsErrSuffixAT
-> mkSimpleDecorated $
- text "Suffix occurrence of @. For an as-pattern, remove the leading whitespace."
+ text "The symbol '@' occurs as a suffix." $$
+ text "For an as-pattern, there must not be any whitespace surrounding '@'."
PsErrPrecedenceOutOfRange i
-> mkSimpleDecorated $ text "Precedence out of range: " <> int i
PsErrSemiColonsInCondExpr c st t se e
=====================================
compiler/GHC/Parser/Lexer.x
=====================================
@@ -1784,6 +1784,21 @@ qvarsym, qconsym :: StringBuffer -> Int -> Token
qvarsym buf len = ITqvarsym $! splitQualName buf len False
qconsym buf len = ITqconsym $! splitQualName buf len False
+
+errSuffixAt :: PsSpan -> P a
+errSuffixAt span = do
+ input <- getInput
+ failLocMsgP start (go input start) (\srcSpan -> mkPlainErrorMsgEnvelope srcSpan $ PsErrSuffixAT)
+ where
+ start = psRealLoc (psSpanStart span)
+ go inp loc
+ | Just (c, i) <- alexGetChar inp
+ , let next = advanceSrcLoc loc c =
+ if c == ' '
+ then go i next
+ else next
+ | otherwise = loc
+
-- See Note [Whitespace-sensitive operator parsing]
varsym :: OpWs -> Action
varsym opws at OpWsPrefix = sym $ \span exts s ->
@@ -1817,7 +1832,7 @@ varsym opws at OpWsPrefix = sym $ \span exts s ->
do { warnOperatorWhitespace opws span s
; return (ITvarsym s) }
varsym opws at OpWsSuffix = sym $ \span _ s ->
- if | s == fsLit "@" -> failMsgP (\srcLoc -> mkPlainErrorMsgEnvelope srcLoc $ PsErrSuffixAT)
+ if | s == fsLit "@" -> errSuffixAt span
| s == fsLit "." -> return ITdot
| otherwise ->
do { warnOperatorWhitespace opws span s
=====================================
compiler/GHC/Stg/InferTags/Rewrite.hs
=====================================
@@ -7,7 +7,7 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
-module GHC.Stg.InferTags.Rewrite (rewriteTopBinds)
+module GHC.Stg.InferTags.Rewrite (rewriteTopBinds, rewriteOpApp)
where
import GHC.Prelude
@@ -388,15 +388,15 @@ rewriteId v = do
if is_tagged then return $! setIdTagSig v (TagSig TagProper)
else return v
-rewriteExpr :: InferStgExpr -> RM TgStgExpr
-rewriteExpr (e at StgCase {}) = rewriteCase e
-rewriteExpr (e at StgLet {}) = rewriteLet e
-rewriteExpr (e at StgLetNoEscape {}) = rewriteLetNoEscape e
-rewriteExpr (StgTick t e) = StgTick t <$!> rewriteExpr e
-rewriteExpr e@(StgConApp {}) = rewriteConApp e
-rewriteExpr e@(StgOpApp {}) = rewriteOpApp e
-rewriteExpr e@(StgApp {}) = rewriteApp e
-rewriteExpr (StgLit lit) = return $! (StgLit lit)
+rewriteExpr :: GenStgExpr 'InferTaggedBinders -> RM (GenStgExpr 'CodeGen)
+rewriteExpr (e at StgCase {}) = rewriteCase e
+rewriteExpr (e at StgLet {}) = rewriteLet e
+rewriteExpr (e at StgLetNoEscape {}) = rewriteLetNoEscape e
+rewriteExpr (StgTick t e) = StgTick t <$!> rewriteExpr e
+rewriteExpr e@(StgConApp {}) = rewriteConApp e
+rewriteExpr e@(StgApp {}) = rewriteApp e
+rewriteExpr (StgLit lit) = return $! (StgLit lit)
+rewriteExpr (StgOpApp op args res_ty) = (StgOpApp op) <$!> rewriteArgs args <*> pure res_ty
rewriteCase :: InferStgExpr -> RM TgStgExpr
@@ -404,7 +404,7 @@ rewriteCase (StgCase scrut bndr alt_type alts) =
withBinder NotTopLevel bndr $
pure StgCase <*>
rewriteExpr scrut <*>
- pure (fst bndr) <*>
+ rewriteId (fst bndr) <*>
pure alt_type <*>
mapM rewriteAlt alts
=====================================
compiler/GHC/StgToJS/Apply.hs
=====================================
@@ -157,7 +157,7 @@ genApp ctx i args
| [] <- args
, [vt] <- idJSRep i
, isUnboxable vt
- , ctxIsEvaluated ctx i
+ , ctxIsEvaluated i
= do
let c = head (concatMap typex_expr $ ctxTarget ctx)
is <- varsForId i
@@ -171,7 +171,7 @@ genApp ctx i args
-- case of Id without args and known to be already evaluated: return fields
-- individually
| [] <- args
- , ctxIsEvaluated ctx i || isStrictType (idType i)
+ , ctxIsEvaluated i || isStrictType (idType i)
= do
a <- storeIdFields i (ctxTarget ctx)
-- optional runtime assert for detecting unexpected thunks (unevaluated)
@@ -199,7 +199,7 @@ genApp ctx i args
a' = case args of
[StgVarArg a'] -> a'
_ -> panic "genApp: unexpected arg"
- if isStrictId a' || ctxIsEvaluated ctx a'
+ if isStrictId a' || ctxIsEvaluated a'
then return (t |= ai, ExprInline Nothing)
else return (returnS (app "h$e" [ai]), ExprCont)
_ -> panic "genApp: invalid size"
=====================================
compiler/GHC/StgToJS/Expr.hs
=====================================
@@ -137,12 +137,12 @@ genBind ctx bndr =
j <- assign b r >>= \case
Just ja -> return ja
Nothing -> allocCls Nothing [(b,r)]
- return (j, addEvalRhs ctx [(b,r)])
+ return (j, ctx)
StgRec bs -> do
jas <- mapM (uncurry assign) bs -- fixme these might depend on parts initialized by allocCls
let m = if null jas then Nothing else Just (mconcat $ catMaybes jas)
j <- allocCls m . map snd . filter (isNothing . fst) $ zip jas bs
- return (j, addEvalRhs ctx bs)
+ return (j, ctx)
where
ctx' = ctxClearLneFrame ctx
@@ -168,7 +168,7 @@ genBind ctx bndr =
(tgt ||= ApplExpr (var ("h$c_sel_" <> mkFastString sel_tag)) [the_fvj])
_ -> panic "genBind.assign: invalid size"
assign b (StgRhsClosure _ext _ccs _upd [] expr _typ)
- | snd (isInlineExpr (ctxEvaluatedIds ctx) expr) = do
+ | isInlineExpr expr = do
d <- declVarsForId b
tgt <- varsForId b
let ctx' = ctx { ctxTarget = assocIdExprs b tgt }
@@ -177,12 +177,6 @@ genBind ctx bndr =
assign _b StgRhsCon{} = return Nothing
assign b r = genEntry ctx' b r >> return Nothing
- addEvalRhs c [] = c
- addEvalRhs c ((b,r):xs)
- | StgRhsCon{} <- r = addEvalRhs (ctxAssertEvaluated b c) xs
- | (StgRhsClosure _ _ ReEntrant _ _ _) <- r = addEvalRhs (ctxAssertEvaluated b c) xs
- | otherwise = addEvalRhs c xs
-
genBindLne :: HasDebugCallStack
=> ExprCtx
-> CgStgBinding
@@ -559,7 +553,7 @@ genCase :: HasDebugCallStack
-> LiveVars
-> G (JStgStat, ExprResult)
genCase ctx bnd e at alts l
- | snd (isInlineExpr (ctxEvaluatedIds ctx) e) = do
+ | isInlineExpr e = do
bndi <- identsForId bnd
let ctx' = ctxSetTop bnd
$ ctxSetTarget (assocIdExprs bnd (map toJExpr bndi))
@@ -570,7 +564,7 @@ genCase ctx bnd e at alts l
ExprCont -> pprPanic "genCase: expression was not inline"
(pprStgExpr panicStgPprOpts e)
- (aj, ar) <- genAlts (ctxAssertEvaluated bnd ctx) bnd at d alts
+ (aj, ar) <- genAlts ctx bnd at d alts
(saveCCS,restoreCCS) <- ifProfilingM $ do
ccsVar <- freshIdent
pure ( ccsVar ||= toJExpr jCurrentCCS
@@ -586,7 +580,7 @@ genCase ctx bnd e at alts l
, ar
)
| otherwise = do
- rj <- genRet (ctxAssertEvaluated bnd ctx) bnd at alts l
+ rj <- genRet ctx bnd at alts l
let ctx' = ctxSetTop bnd
$ ctxSetTarget (assocIdExprs bnd (map toJExpr [R1 ..]))
$ ctx
=====================================
compiler/GHC/StgToJS/ExprCtx.hs
=====================================
@@ -18,14 +18,12 @@
module GHC.StgToJS.ExprCtx
( ExprCtx
, initExprCtx
- , ctxAssertEvaluated
, ctxIsEvaluated
, ctxSetSrcSpan
, ctxSrcSpan
, ctxSetTop
, ctxTarget
, ctxSetTarget
- , ctxEvaluatedIds
-- * Let-no-escape
, ctxClearLneFrame
, ctxUpdateLneFrame
@@ -43,9 +41,12 @@ import GHC.Prelude
import GHC.StgToJS.Types
import GHC.Types.Unique.FM
-import GHC.Types.Unique.Set
import GHC.Types.Var
import GHC.Types.SrcLoc
+import GHC.Types.Id
+import GHC.Types.Id.Info
+
+import GHC.Stg.InferTags.TagSig
import GHC.Utils.Outputable
import GHC.Utils.Panic
@@ -61,10 +62,6 @@ data ExprCtx = ExprCtx
, ctxTarget :: [TypedExpr]
-- ^ Target variables for the evaluated expression
- , ctxEvaluatedIds :: UniqSet Id
- -- ^ Ids that we know to be evaluated (e.g. case binders when the expression
- -- to evaluate is in an alternative)
-
, ctxSrcSpan :: Maybe RealSrcSpan
-- ^ Source location
@@ -95,7 +92,6 @@ initExprCtx :: Id -> ExprCtx
initExprCtx i = ExprCtx
{ ctxTop = i
, ctxTarget = []
- , ctxEvaluatedIds = emptyUniqSet
, ctxLneFrameBs = emptyUFM
, ctxLneFrameVars = []
, ctxLneFrameSize = 0
@@ -110,10 +106,6 @@ ctxSetTarget t ctx = ctx { ctxTarget = t }
ctxSetTop :: Id -> ExprCtx -> ExprCtx
ctxSetTop i ctx = ctx { ctxTop = i }
--- | Add an Id to the known-evaluated set
-ctxAssertEvaluated :: Id -> ExprCtx -> ExprCtx
-ctxAssertEvaluated i ctx = ctx { ctxEvaluatedIds = addOneToUniqSet (ctxEvaluatedIds ctx) i }
-
-- | Set source location
ctxSetSrcSpan :: RealSrcSpan -> ExprCtx -> ExprCtx
ctxSetSrcSpan span ctx = ctx { ctxSrcSpan = Just span }
@@ -139,8 +131,39 @@ ctxClearLneFrame ctx =
}
-- | Predicate: do we know for sure that the given Id is evaluated?
-ctxIsEvaluated :: ExprCtx -> Id -> Bool
-ctxIsEvaluated ctx i = i `elementOfUniqSet` ctxEvaluatedIds ctx
+ctxIsEvaluated :: Id -> Bool
+ctxIsEvaluated i =
+ maybe False isTaggedSig (idTagSig_maybe i)
+ && go (idDetails i)
+ where
+ go JoinId{} = False
+ go _ = True
+
+
+ -- DFunId new_type -> not new_type
+ -- -- DFuns terminate, unless the dict is implemented
+ -- -- with a newtype in which case they may not
+
+ -- DataConWorkId {} -> True
+
+ -- ClassOpId {} -> False
+ -- -- suppose an argument, and we don't have one
+
+ -- PrimOpId op _ -> primop_ok op
+ -- -- probably already handled by StgOpApp
+
+ -- JoinId {} -> False
+ -- -- Don't speculate join points
+
+ -- TickBoxOpId {} -> False
+ -- -- Don't speculate box ticking
+
+ -- -- Tagged (evaluated) ids
+ -- _ | Just sig <- idTagSig_maybe i
+ -- , isTaggedSig sig
+ -- -> True
+
+ -- _ -> False
-- | Does the given Id correspond to a LNE binding
ctxIsLneBinding :: ExprCtx -> Id -> Bool
=====================================
compiler/GHC/StgToJS/Types.hs
=====================================
@@ -342,6 +342,9 @@ data TypedExpr = TypedExpr
, typex_expr :: [JStgExpr]
}
+instance Outputable TypedExpr where
+ ppr (TypedExpr typ x) = ppr (typ, x)
+
-- | A Primop result is either an inlining of some JS payload, or a primitive
-- call to a JS function defined in Shim files in base.
data PrimRes
=====================================
compiler/GHC/StgToJS/Utils.hs
=====================================
@@ -69,7 +69,6 @@ import GHC.Types.Var.Set
import GHC.Types.Id
import GHC.Types.Id.Info
import GHC.Types.Unique.FM
-import GHC.Types.Unique.Set
import GHC.Types.ForeignCall
import GHC.Types.TyThing
import GHC.Types.Name
@@ -108,11 +107,16 @@ assignToExprCtx ctx es = assignToTypedExprs (ctxTarget ctx) es
assignCoerce1 :: [TypedExpr] -> [TypedExpr] -> JStgStat
assignCoerce1 [x] [y] = assignCoerce x y
assignCoerce1 [] [] = mempty
-assignCoerce1 _x _y = pprPanic "assignCoerce1"
+-- We silently ignore the case of an empty list on the first argument. It denotes
+-- "assign nothing to n empty slots on the right". Usually this case shouldn't come
+-- up, but rare cases where the earlier code can't correctly guess the size of type
+-- classes causes slots to be allocated when they aren't needed.
+assignCoerce1 [] _ = mempty
+assignCoerce1 x y = pprPanic "assignCoerce1"
(vcat [ text "lengths do not match"
-- FIXME: Outputable instance removed until JStg replaces JStat
- -- , ppr x
- -- , ppr y
+ , ppr x
+ , ppr y
])
-- | Assign p2 to p1 with optional coercion
@@ -417,61 +421,48 @@ stgLneLiveExpr rhs = dVarSetElems (liveVars $ stgRhsLive rhs)
-- stgLneLiveExpr StgRhsCon {} = []
-- | returns True if the expression is definitely inline
-isInlineExpr :: UniqSet Id -> CgStgExpr -> (UniqSet Id, Bool)
-isInlineExpr v = \case
+isInlineExpr :: CgStgExpr -> Bool
+isInlineExpr = \case
StgApp i args
- -> (emptyUniqSet, isInlineApp v i args)
+ -> isInlineApp i args
StgLit{}
- -> (emptyUniqSet, True)
+ -> True
StgConApp{}
- -> (emptyUniqSet, True)
+ -> True
StgOpApp (StgFCallOp f _) _ _
- -> (emptyUniqSet, isInlineForeignCall f)
+ -> isInlineForeignCall f
StgOpApp (StgPrimOp SeqOp) [StgVarArg e] t
- -> (emptyUniqSet, e `elementOfUniqSet` v || isStrictType t)
+ -> ctxIsEvaluated e || isStrictType t
StgOpApp (StgPrimOp op) _ _
- -> (emptyUniqSet, primOpIsReallyInline op)
+ -> primOpIsReallyInline op
StgOpApp (StgPrimCallOp _c) _ _
- -> (emptyUniqSet, True)
- StgCase e b _ alts
- ->let (_ve, ie) = isInlineExpr v e
- v' = addOneToUniqSet v b
- (vas, ias) = unzip $ map (isInlineExpr v') (fmap alt_rhs alts)
- vr = L.foldl1' intersectUniqSets vas
- in (vr, (ie || b `elementOfUniqSet` v) && and ias)
- StgLet _ b e
- -> isInlineExpr (inspectInlineBinding v b) e
- StgLetNoEscape _ _b e
- -> isInlineExpr v e
- StgTick _ e
- -> isInlineExpr v e
-
-inspectInlineBinding :: UniqSet Id -> CgStgBinding -> UniqSet Id
-inspectInlineBinding v = \case
- StgNonRec i r -> inspectInlineRhs v i r
- StgRec bs -> foldl' (\v' (i,r) -> inspectInlineRhs v' i r) v bs
-
-inspectInlineRhs :: UniqSet Id -> Id -> CgStgRhs -> UniqSet Id
-inspectInlineRhs v i = \case
- StgRhsCon{} -> addOneToUniqSet v i
- StgRhsClosure _ _ ReEntrant _ _ _ -> addOneToUniqSet v i
- _ -> v
+ -> True
+ StgCase e _ _ alts
+ ->let ie = isInlineExpr e
+ ias = map isInlineExpr (fmap alt_rhs alts)
+ in ie && and ias
+ StgLet _ _ e
+ -> isInlineExpr e
+ StgLetNoEscape _ _ e
+ -> isInlineExpr e
+ StgTick _ e
+ -> isInlineExpr e
isInlineForeignCall :: ForeignCall -> Bool
isInlineForeignCall (CCall (CCallSpec _ cconv safety)) =
not (playInterruptible safety) &&
not (cconv /= JavaScriptCallConv && playSafe safety)
-isInlineApp :: UniqSet Id -> Id -> [StgArg] -> Bool
-isInlineApp v i = \case
+isInlineApp :: Id -> [StgArg] -> Bool
+isInlineApp i = \case
_ | isJoinId i -> False
[] -> isUnboxedTupleType (idType i) ||
isStrictType (idType i) ||
- i `elementOfUniqSet` v
+ ctxIsEvaluated i
[StgVarArg a]
| DataConWrapId dc <- idDetails i
, isNewTyCon (dataConTyCon dc)
- , isStrictType (idType a) || a `elementOfUniqSet` v || isStrictId a
+ , isStrictType (idType a) || ctxIsEvaluated a || isStrictId a
-> True
_ -> False
=====================================
testsuite/tests/diagnostic-codes/codes.stdout
=====================================
@@ -34,7 +34,6 @@
[GHC-90355] is untested (constructor = PsErrLetInFunAppExpr)
[GHC-01239] is untested (constructor = PsErrIfInFunAppExpr)
[GHC-04807] is untested (constructor = PsErrProcInFunAppExpr)
-[GHC-33856] is untested (constructor = PsErrSuffixAT)
[GHC-25078] is untested (constructor = PsErrPrecedenceOutOfRange)
[GHC-18910] is untested (constructor = PsErrSemiColonsInCondCmd)
[GHC-66418] is untested (constructor = PsErrParseErrorOnInput)
=====================================
testsuite/tests/parser/should_fail/SuffixAtFail.hs
=====================================
@@ -0,0 +1,3 @@
+module Main where
+
+foo x@ () = ()
=====================================
testsuite/tests/parser/should_fail/SuffixAtFail.stderr
=====================================
@@ -0,0 +1,7 @@
+
+SuffixAtFail.hs:3:6: error: [GHC-33856]
+ The symbol '@' occurs as a suffix.
+ For an as-pattern, there must not be any whitespace surrounding '@'.
+ |
+3 | foo x@ () = ()
+ | ^^^^^
=====================================
testsuite/tests/parser/should_fail/all.T
=====================================
@@ -219,4 +219,5 @@ test('T20609', normal, compile_fail, [''])
test('T20609a', normal, compile_fail, [''])
test('T20609b', normal, compile_fail, [''])
test('T20609c', normal, compile_fail, [''])
-test('T20609d', normal, compile_fail, [''])
\ No newline at end of file
+test('T20609d', normal, compile_fail, [''])
+test('SuffixAtFail', normal, compile_fail, ['-fdiagnostics-show-caret'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/d1e7fa2e32d77115dab04cc9e7f5a985a40e0dfd...d6fe8aa9f60c1df0373eae9f0e389a6954d2e17e
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/d1e7fa2e32d77115dab04cc9e7f5a985a40e0dfd...d6fe8aa9f60c1df0373eae9f0e389a6954d2e17e
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20240209/3ccda299/attachment-0001.html>
More information about the ghc-commits
mailing list