[Git][ghc/ghc][wip/with2-primop] 9 commits: XXX: Tracing
Ben Gamari
gitlab at gitlab.haskell.org
Sat Apr 18 18:56:22 UTC 2020
Ben Gamari pushed to branch wip/with2-primop at Glasgow Haskell Compiler / GHC
Commits:
12decb2a by Ben Gamari at 2020-04-17T20:17:18+00:00
XXX: Tracing
- - - - -
9710994c by Ben Gamari at 2020-04-18T02:02:09+00:00
Fix CoreLint
- - - - -
3c0f3eaf by Ben Gamari at 2020-04-18T02:02:28+00:00
XXX: Eta expand
This shouldn't be necessary
- - - - -
f0c45959 by Ben Gamari at 2020-04-18T03:27:47+00:00
lintJoinLams look through casts
- - - - -
1758b5eb by Ben Gamari at 2020-04-18T03:29:25+00:00
XXX: CoreLint: Relax tail call restriction on join points
- - - - -
c8f5b207 by Ben Gamari at 2020-04-18T17:10:25+00:00
Remove state token from keepAlive#
- - - - -
dc538a69 by Ben Gamari at 2020-04-18T17:10:42+00:00
Desugar: Eta expand runRW# continuation
- - - - -
98621772 by Ben Gamari at 2020-04-18T17:11:05+00:00
XXX: Don't apply Note [dodgy unsafeCoerce 1]
- - - - -
ae6dae6a by Ben Gamari at 2020-04-18T17:22:32+00:00
CorePrep: Catch unexpected runRW# applications
- - - - -
15 changed files:
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Op/Simplify.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/HsToCore/Utils.hs
- compiler/GHC/StgToCmm/Bind.hs
- compiler/GHC/StgToCmm/Closure.hs
- compiler/GHC/StgToCmm/Env.hs
- compiler/GHC/StgToCmm/Expr.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/prelude/primops.txt.pp
- libraries/base/Foreign/Marshal/Alloc.hs
- libraries/base/GHC/ForeignPtr.hs
- libraries/base/GHC/IO/Unsafe.hs
- libraries/base/GHC/ST.hs
- libraries/ghc-compact/GHC/Compact/Serialized.hs
Changes:
=====================================
compiler/GHC/Core/Lint.hs
=====================================
@@ -708,8 +708,13 @@ lintJoinLams :: JoinArity -> Maybe Id -> CoreExpr -> LintM LintedType
lintJoinLams join_arity enforce rhs
= go join_arity rhs
where
- go 0 rhs = lintCoreExpr rhs
- go n (Lam var expr) = lintLambda var $ go (n-1) expr
+ go 0 rhs = lintCoreExpr rhs
+ go n (Lam var expr) = lintLambda var $ go (n-1) expr
+ go n (Cast expr co) = do { _ <- go n expr
+ ; lintCastExpr expr co
+ }
+ -- N.B. join points can be cast. e.g. we consider ((\x -> ...) `cast` ...)
+ -- to be a join point at join arity 1.
go n _other | Just bndr <- enforce -- Join point with too few RHS lambdas
= failWithL $ mkBadJoinArityMsg bndr join_arity n rhs
| otherwise -- Future join point, not yet eta-expanded
@@ -770,6 +775,19 @@ type LintedCoercion = Coercion
type LintedTyCoVar = TyCoVar
type LintedId = Id
+-- | Lint an expression cast through the given coercion, returning the type
+-- resulting from the cast.
+lintCastExpr :: CoreExpr -> Coercion -> LintM LintedType
+lintCastExpr expr co
+ = do { expr_ty <- markAllJoinsBad $ lintCoreExpr expr
+ ; co' <- lintCoercion co
+ ; let (Pair from_ty to_ty, role) = coercionKindRole co'
+ ; checkValueType to_ty $
+ text "target of cast" <+> quotes (ppr co')
+ ; lintRole co' Representational role
+ ; ensureEqTys from_ty expr_ty (mkCastErr expr co' from_ty expr_ty)
+ ; return to_ty }
+
lintCoreExpr :: CoreExpr -> LintM LintedType
-- The returned type has the substitution from the monad
-- already applied to it:
@@ -787,14 +805,7 @@ lintCoreExpr (Lit lit)
= return (literalType lit)
lintCoreExpr (Cast expr co)
- = do { expr_ty <- markAllJoinsBad $ lintCoreExpr expr
- ; co' <- lintCoercion co
- ; let (Pair from_ty to_ty, role) = coercionKindRole co'
- ; checkValueType to_ty $
- text "target of cast" <+> quotes (ppr co')
- ; lintRole co' Representational role
- ; ensureEqTys from_ty expr_ty (mkCastErr expr co' from_ty expr_ty)
- ; return to_ty }
+ = markAllJoinsBad $ lintCastExpr expr co
lintCoreExpr (Tick tickish expr)
= do case tickish of
@@ -863,14 +874,23 @@ lintCoreExpr e@(App _ _)
; arg3_ty <- lintJoinLams 1 (Just fun) arg3
; lintValApp arg3 fun_ty2 arg3_ty }
+ | Var fun <- fun
+ , fun `hasKey` runRWKey
+ = failWithL (text "Invalid runRW# application")
+
| Var fun <- fun
, fun `hasKey` keepAliveIdKey
- , [arg_ty1, arg_ty2, arg_ty3, arg_ty4, arg5, arg6, arg7] <- args
- = do { fun_ty5 <- lintCoreArgs (idType fun) [ arg_ty1, arg_ty2, arg_ty3, arg_ty4 ]
- ; arg6_ty <- lintJoinLams 1 (Just fun) arg6 -- f :: State# RW -> (# State# RW, o #)
- ; lintCoreArgs fun_ty5 [arg5, arg6, arg7]
+ , [arg_ty1, arg_ty2, arg_ty3, arg_ty4, arg5, arg6] <- args
+ = do { fun_ty6 <- lintCoreArgs (idType fun)
+ [ arg_ty1, arg_ty2, arg_ty3, arg_ty4, arg5 ]
+ ; arg6_ty <- lintJoinLams 0 (Just fun) arg6 -- f :: State# RW -> (# State# RW, o #)
+ ; lintValApp arg6 fun_ty6 arg6_ty
}
+ | Var fun <- fun
+ , fun `hasKey` keepAliveIdKey
+ = failWithL (text "Invalid keepAlive# application")
+
| otherwise
= do { fun_ty <- lintCoreFun fun (length args)
; lintCoreArgs fun_ty args }
@@ -1172,9 +1192,7 @@ lintCaseExpr scrut var alt_ty alts =
do { let e = Case scrut var alt_ty alts -- Just for error messages
-- Check the scrutinee
- ; scrut_ty <- markAllJoinsBad $ lintCoreExpr scrut
- -- See Note [Join points are less general than the paper]
- -- in GHC.Core
+ ; scrut_ty <- lintCoreExpr scrut
; alt_ty <- addLoc (CaseTy scrut) $
lintValueType alt_ty
=====================================
compiler/GHC/Core/Op/Simplify.hs
=====================================
@@ -1897,27 +1897,29 @@ rebuildCall env info@(ArgInfo { ai_fun = fun, ai_args = rev_args
-- keepAlive# @arg_rep @arg_ty @out_rep @out_ty x (\s -> K[rhs]) s0
rebuildCall env (ArgInfo { ai_fun = fun, ai_args = rev_args }) cont
| fun `hasKey` keepAliveIdKey
- , [ ValArg s0
- , ValArg (Lam f_arg f_body)
+ , [ ValArg y
, ValArg x
, TyArg {} -- res_ty
, TyArg {} -- res_rep
, TyArg {as_arg_ty=arg_ty}
, TyArg {as_arg_ty=arg_rep}
] <- rev_args
- -- Extract type of second component of (# State# RealWorld, a #)
- , Just (_, [_, _, _, ty']) <- splitTyConApp_maybe (contResultType cont)
- = do { (env', f_arg) <- simplLamBndr (zapSubstEnv env) f_arg
- ; f_body' <- simplExprC env' f_body cont
- ; let f' = Lam f_arg f_body'
+ = do { let ty' = contResultType cont
+ ; j <- newJoinId [] ty'
+ ; let env' = zapSubstEnv env
+ ; y' <- simplExprC env' y cont
+ ; let bind = NonRec j y'
+ ; x' <- simplExpr env' x
+ ; arg_rep' <- simplType env' arg_rep
+ ; arg_ty' <- simplType env' arg_ty
; let call' = mkApps (Var fun)
- [ mkTyArg arg_rep, mkTyArg arg_ty
+ [ mkTyArg arg_rep', mkTyArg arg_ty'
, mkTyArg (getRuntimeRep ty'), mkTyArg ty'
- , x
- , f'
- , s0
+ , x'
+ , Var j
]
- ; return (emptyFloats env, call') }
+ ; --pprTrace "rebuild keepAlive" (ppr fun $$ ppr rev_args $$ ppr cont) $
+ return (emptyFloats env `extendFloats` bind, call') }
---------- Simplify applications and casts --------------
rebuildCall env info (CastIt co cont)
=====================================
compiler/GHC/CoreToStg/Prep.hs
=====================================
@@ -45,7 +45,7 @@ import GHC.Types.Var.Env
import GHC.Types.Id
import GHC.Types.Id.Info
import TysWiredIn
-import TysPrim ( realWorldStatePrimTy, primRepToRuntimeRep )
+import TysPrim ( realWorldStatePrimTy )
import GHC.Core.DataCon
import GHC.Types.Basic
import GHC.Types.Module
@@ -856,42 +856,26 @@ cpeApp top_env expr
Lam s body -> cpe_app (extendCorePrepEnv env s realWorldPrimId) body [] 0
_ -> cpe_app env arg [CpeApp (Var realWorldPrimId)] 1
+ cpe_app env (Var f) args n
+ | f `hasKey` runRWKey
+ = pprPanic "cpe_app(runRW#)" (ppr args $$ ppr n)
+
-- See Note [CorePrep handling of keepAlive#]
cpe_app env (Var f) [CpeApp (Type arg_rep), CpeApp (Type arg_ty),
- CpeApp (Type result_rep), CpeApp (Type result_ty),
- CpeApp x, CpeApp k, CpeApp s0] 3
+ CpeApp (Type _result_rep), CpeApp (Type result_ty),
+ CpeApp x, CpeApp y] 2
| f `hasKey` keepAliveIdKey
- = do { let voidRepTy = primRepToRuntimeRep VoidRep
- -- out_ty ~ (# State# RealWorld, a #)
- out_ty = mkTyConApp (tupleTyCon Unboxed 2)
- [voidRepTy, result_rep, realWorldStatePrimTy, result_ty]
- ; b0 <- newVar out_ty
- ; y <- newVar result_ty
- ; s1 <- newVar realWorldStatePrimTy
+ = do { y' <- newVar result_ty
; s2 <- newVar realWorldStatePrimTy
- -- Beta reduce
- ; (floats0, k') <- case k of
- Lam s body -> cpe_app (extendCorePrepEnvExpr env s s0) body [] 0
- _ -> cpe_app env k [CpeApp s0] 1
; let touchId = mkPrimOpId TouchOp
-
- -- @stateResultAlt s y expr@ is a case alternative of the form,
- -- (# s, y #) -> expr
- stateResultAlt :: Var -> Var -> CoreExpr -> CoreAlt
- stateResultAlt stateVar resultVar rhs =
- (DataAlt (tupleDataCon Unboxed 2), [stateVar, resultVar], rhs)
-
- expr = Case k' b0 out_ty [stateResultAlt s1 y rhs1]
- rhs1 = let scrut = mkApps (Var touchId) [Type arg_rep, Type arg_ty, x, Var s1]
- in Case scrut s2 out_ty [(DEFAULT, [], rhs2)]
- rhs2 = mkApps (Var $ dataConWrapId $ tupleDataCon Unboxed 2)
- [mkTyArg voidRepTy, mkTyArg result_rep, mkTyArg realWorldStatePrimTy, mkTyArg result_ty, Var s2, Var y]
- ; (floats1, body) <- pprTrace "cpe_app" (ppr expr) $ cpeBody env expr
- ; return (floats0 `appendFloats` floats1, body)
+ expr = Case y y' result_ty [(DEFAULT, [], rhs1)]
+ rhs1 = let scrut = mkApps (Var touchId) [Type arg_rep, Type arg_ty, x, Var realWorldPrimId]
+ in Case scrut s2 result_ty [(DEFAULT, [], Var y')]
+ ; pprTrace "cpe_app" (ppr expr) $ cpeBody env expr
}
- cpe_app _env (Var f) args _
+ cpe_app _env (Var f) args n
| f `hasKey` keepAliveIdKey
- = pprPanic "cpe_app(keepAlive#)" (ppr args)
+ = pprPanic "cpe_app(keepAlive#)" (ppr args $$ ppr n)
cpe_app env (Var v) args depth
= do { v1 <- fiddleCCall v
=====================================
compiler/GHC/HsToCore/Utils.hs
=====================================
@@ -56,6 +56,7 @@ import GHC.Core
import GHC.HsToCore.Monad
import GHC.Core.Utils
+import GHC.Core.Arity ( etaExpand )
import GHC.Core.Make
import GHC.Types.Id.Make
import GHC.Types.Id
@@ -489,6 +490,9 @@ mkCoreAppDs _ (Var f `App` Type _r `App` Type ty1 `App` Type ty2 `App` arg1) arg
Var v1 | isInternalName (idName v1)
-> v1 -- Note [Desugaring seq], points (2) and (3)
_ -> mkWildValBinder ty1
+mkCoreAppDs _ e@(Var f `App` Type r `App` Type ty1) arg
+ | f `hasKey` runRWKey
+ = e `App` etaExpand 1 arg
mkCoreAppDs s fun arg = mkCoreApp s fun arg -- The rest is done in GHC.Core.Make
=====================================
compiler/GHC/StgToCmm/Bind.hs
=====================================
@@ -500,7 +500,8 @@ closureCodeBody top_lvl bndr cl_info cc args arity body fv_details
(CmmMachOp (mo_wordSub platform)
[ CmmReg (CmmLocal node) -- See [NodeReg clobbered with loopification]
, mkIntExpr platform (funTag dflags cl_info) ])
- ; fv_bindings <- mapM bind_fv fv_details
+ ; fv_bindings <- pprTrace "closureBodyBody" (ppr bndr $$ ppr body)
+ $ mapM bind_fv fv_details
-- Load free vars out of closure *after*
-- heap check, to reduce live vars over check
; when node_points $ load_fvs node lf_info fv_bindings
@@ -523,7 +524,7 @@ closureCodeBody top_lvl bndr cl_info cc args arity body fv_details
-- A function closure pointer may be tagged, so we
-- must take it into account when accessing the free variables.
-bind_fv :: (NonVoid Id, ByteOff) -> FCode (LocalReg, ByteOff)
+bind_fv :: HasCallStack => (NonVoid Id, ByteOff) -> FCode (LocalReg, ByteOff)
bind_fv (id, off) = do { reg <- rebindToReg id; return (reg, off) }
load_fvs :: LocalReg -> LambdaFormInfo -> [(LocalReg, ByteOff)] -> FCode ()
=====================================
compiler/GHC/StgToCmm/Closure.hs
=====================================
@@ -232,6 +232,13 @@ data LambdaFormInfo
| LFLetNoEscape -- See LetNoEscape module for precise description
+instance Outputable LambdaFormInfo where
+ ppr LFReEntrant{} = text "re-entrant"
+ ppr LFThunk{} = text "thunk"
+ ppr LFCon{} = text "data-con"
+ ppr LFUnknown{} = text "unknown"
+ ppr LFUnlifted = text "unlifted"
+ ppr LFLetNoEscape = text "let-no-escape"
-------------------------
-- StandardFormInfo tells whether this thunk has one of
@@ -626,7 +633,7 @@ getCallMethod _ _name _ LFLetNoEscape _n_args _v_args (LneLoc blk_id lne_regs)
_self_loop_info
= JumpToIt blk_id lne_regs
-getCallMethod _ name _ _lf_info _ _ _ _ = pprPanic "Unknown call method" (ppr name)
+getCallMethod _ name _ _lf_info _ _ _loc _ = pprPanic "Unknown call method" (ppr name $$ ppr _lf_info $$ ppr _loc)
-----------------------------------------------------------------------------
-- Data types for closure information
=====================================
compiler/GHC/StgToCmm/Env.hs
=====================================
@@ -60,7 +60,7 @@ mkCgIdInfo id lf expr
litIdInfo :: DynFlags -> Id -> LambdaFormInfo -> CmmLit -> CgIdInfo
litIdInfo dflags id lf lit
- = CgIdInfo { cg_id = id, cg_lf = lf
+ = pprTrace "litIdInfo" (ppr id) $ CgIdInfo { cg_id = id, cg_lf = lf
, cg_loc = CmmLoc (addDynTag platform (CmmLit lit) tag) }
where
tag = lfDynTag dflags lf
@@ -77,7 +77,8 @@ lneIdInfo platform id regs
rhsIdInfo :: Id -> LambdaFormInfo -> FCode (CgIdInfo, LocalReg)
rhsIdInfo id lf_info
- = do platform <- getPlatform
+ = pprTrace "rhsIdInfo" (ppr id) $
+ do platform <- getPlatform
reg <- newTemp (gcWord platform)
return (mkCgIdInfo id lf_info (CmmReg (CmmLocal reg)), reg)
@@ -177,25 +178,26 @@ getNonVoidArgAmodes (arg:args)
-- Interface functions for binding and re-binding names
------------------------------------------------------------------------
-bindToReg :: NonVoid Id -> LambdaFormInfo -> FCode LocalReg
+bindToReg :: HasCallStack => NonVoid Id -> LambdaFormInfo -> FCode LocalReg
-- Bind an Id to a fresh LocalReg
bindToReg nvid@(NonVoid id) lf_info
= do platform <- getPlatform
let reg = idToReg platform nvid
- addBindC (mkCgIdInfo id lf_info (CmmReg (CmmLocal reg)))
+ pprTrace "bindToReg" (ppr id $$ ppr lf_info $$ callStackDoc)
+ $ addBindC (mkCgIdInfo id lf_info (CmmReg (CmmLocal reg)))
return reg
-rebindToReg :: NonVoid Id -> FCode LocalReg
+rebindToReg :: HasCallStack => NonVoid Id -> FCode LocalReg
-- Like bindToReg, but the Id is already in scope, so
-- get its LF info from the envt
rebindToReg nvid@(NonVoid id)
= do { info <- getCgIdInfo id
; bindToReg nvid (cg_lf info) }
-bindArgToReg :: NonVoid Id -> FCode LocalReg
+bindArgToReg :: HasCallStack => NonVoid Id -> FCode LocalReg
bindArgToReg nvid@(NonVoid id) = bindToReg nvid (mkLFArgument id)
-bindArgsToRegs :: [NonVoid Id] -> FCode [LocalReg]
+bindArgsToRegs :: HasCallStack => [NonVoid Id] -> FCode [LocalReg]
bindArgsToRegs args = mapM bindArgToReg args
idToReg :: Platform -> NonVoid Id -> LocalReg
=====================================
compiler/GHC/StgToCmm/Expr.hs
=====================================
@@ -364,6 +364,7 @@ assignment.
-}
cgCase (StgApp v []) bndr alt_type@(PrimAlt _) alts
| isUnliftedType (idType v) -- Note [Dodgy unsafeCoerce 1]
+ , not $ isJoinId v -- TODO: necessary as idInfoToAmode panics on LneLoc
= -- assignment suffices for unlifted types
do { platform <- getPlatform
; unless (reps_compatible platform) $
=====================================
compiler/GHC/Types/Id/Make.hs
=====================================
@@ -1392,20 +1392,14 @@ keepAliveId
-- keepAlive#
-- :: forall (rep_a :: RuntimeRep) (a :: TYPE rep_a)
-- (rep_r :: RuntimeRep) (r :: TYPE rep_r).
- -- a
- -- -> (State# RealWorld -> (# State# RealWorld, r #))
- -- -> State# RealWorld
- -- -> (# State# RealWorld, r #)
+ -- a -> r -> r
--
rep_a = runtimeRep1TyVar
a = openAlphaTyVar
rep_r = runtimeRep2TyVar
r = openBetaTyVar
ty = mkInvForAllTys [rep_a, a, rep_r, r]
- $ mkVisFunTys [mkTyVarTy a, cont_ty, realWorldStatePrimTy] result_ty
- cont_ty = realWorldStatePrimTy `mkVisFunTy` result_ty
- -- (# State# RealWorld, r #)
- result_ty = mkTupleTy Unboxed [realWorldStatePrimTy, mkTyVarTy r]
+ $ mkVisFunTys [mkTyVarTy a, mkTyVarTy r] (mkTyVarTy r)
id_info = noCafIdInfo
`setStrictnessInfo` mkClosedStrictSig [topDmd, strictApply1Dmd, topDmd] topDiv
`setArityInfo` 3
=====================================
compiler/prelude/primops.txt.pp
=====================================
@@ -3240,7 +3240,7 @@ primop SeqOp "seq#" GenPrimOp
-- See Note [seq# magic] in GHC.Core.Op.ConstantFold
pseudoop "keepAlive#"
- o -> (State# RealWorld -> (# State# RealWorld, p #)) -> State# RealWorld -> (# State# RealWorld, p #)
+ o -> p -> p
{ TODO. }
primop GetSparkOp "getSpark#" GenPrimOp
=====================================
libraries/base/Foreign/Marshal/Alloc.hs
=====================================
@@ -131,7 +131,7 @@ allocaBytes (I# size) action = IO $ \ s0 ->
case unsafeFreezeByteArray# mbarr# s1 of { (# s2, barr# #) ->
let addr = Ptr (byteArrayContents# barr#) in
case action addr of { IO action' ->
- keepAlive# barr# action' s2
+ keepAlive# barr# (action' s2)
}}}
allocaBytesAligned :: Int -> Int -> (Ptr a -> IO b) -> IO b
@@ -140,7 +140,7 @@ allocaBytesAligned (I# size) (I# align) action = IO $ \ s0 ->
case unsafeFreezeByteArray# mbarr# s1 of { (# s2, barr# #) ->
let addr = Ptr (byteArrayContents# barr#) in
case action addr of { IO action' ->
- keepAlive# barr# action' s2
+ keepAlive# barr# (action' s2)
}}}
-- |Resize a memory area that was allocated with 'malloc' or 'mallocBytes'
=====================================
libraries/base/GHC/ForeignPtr.hs
=====================================
@@ -412,7 +412,7 @@ withForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b
-- 'Storable' class.
withForeignPtr fo@(ForeignPtr _ r) f = IO $ \s ->
case f (unsafeForeignPtrToPtr fo) of
- IO action# -> keepAlive# r action# s
+ IO action# -> keepAlive# r (action# s)
touchForeignPtr :: ForeignPtr a -> IO ()
=====================================
libraries/base/GHC/IO/Unsafe.hs
=====================================
@@ -102,7 +102,7 @@ like 'Control.Exception.bracket' cannot be used safely within
@since 4.4.0.0
-}
unsafeDupablePerformIO :: IO a -> a
-unsafeDupablePerformIO (IO m) = case runRW# m of (# _, a #) -> a
+unsafeDupablePerformIO (IO m) = case runRW# (\s -> m s) of (# _, a #) -> a
{-|
'unsafeInterleaveIO' allows an 'IO' computation to be deferred lazily.
=====================================
libraries/base/GHC/ST.hs
=====================================
@@ -135,5 +135,5 @@ instance Show (ST s a) where
-- The @forall@ ensures that the internal state used by the 'ST'
-- computation is inaccessible to the rest of the program.
runST :: (forall s. ST s a) -> a
-runST (ST st_rep) = case runRW# st_rep of (# _, a #) -> a
+runST (ST st_rep) = case runRW# (\s -> st_rep s) of (# _, a #) -> a
-- See Note [Definition of runRW#] in GHC.Magic
=====================================
libraries/ghc-compact/GHC/Compact/Serialized.hs
=====================================
@@ -90,7 +90,7 @@ withSerializedCompact (Compact buffer root lock) func = withMVar lock $ \_ -> do
(# s', rootAddr #) -> (# s', Ptr rootAddr #) )
blockList <- mkBlockList buffer
let serialized = SerializedCompact blockList rootPtr
- IO (\s1 -> case func serialized of IO action' -> keepAlive# buffer action' s1)
+ IO (\s1 -> case func serialized of IO action' -> keepAlive# buffer (action' s1))
fixupPointers :: Addr# -> Addr# -> State# RealWorld ->
(# State# RealWorld, Maybe (Compact a) #)
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/0040f7ccaeb8a0f6945662c805eaa6c4bcc2023c...ae6dae6a6c4d668c2639764bee1e0bbf42c646d1
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/0040f7ccaeb8a0f6945662c805eaa6c4bcc2023c...ae6dae6a6c4d668c2639764bee1e0bbf42c646d1
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/20200418/3f1052a0/attachment-0001.html>
More information about the ghc-commits
mailing list