[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 5 commits: Various Hadrian bootstrapping fixes
Marge Bot (@marge-bot)
gitlab at gitlab.haskell.org
Wed Aug 31 01:13:06 UTC 2022
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
0154bc80 by sheaf at 2022-08-30T06:05:41-04:00
Various Hadrian bootstrapping fixes
- Don't always produce a distribution archive (#21629)
- Use correct executable names for ghc-pkg and hsc2hs on windows
(we were missing the .exe file extension)
- Fix a bug where we weren't using the right archive format on Windows
when unpacking the bootstrap sources.
Fixes #21629
- - - - -
451b1d90 by Matthew Pickering at 2022-08-30T06:06:16-04:00
ci: Attempt using normal submodule cloning strategy
We do not use any recursively cloned submodules, and this protects us
from flaky upstream remotes.
Fixes #22121
- - - - -
9d5ad7c4 by Pi Delport at 2022-08-30T22:40:46+00:00
Fix typo in Any docs: stray "--"
- - - - -
3a002632 by Pi Delport at 2022-08-30T22:40:46+00:00
Fix typo in Any docs: syntatic -> syntactic
- - - - -
5a944e82 by Simon Peyton Jones at 2022-08-30T21:12:49-04:00
Add a missing trimArityType
This buglet was exposed by #22114, a consequence of my earlier
refactoring of arity for join points.
- - - - -
8 changed files:
- .gitlab-ci.yml
- .gitlab/ci.sh
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- hadrian/bootstrap/bootstrap.py
- libraries/ghc-prim/GHC/Types.hs
- + testsuite/tests/simplCore/should_compile/T22114.hs
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
.gitlab-ci.yml
=====================================
@@ -17,7 +17,7 @@ variables:
# Overridden by individual jobs
CONFIGURE_ARGS: ""
- GIT_SUBMODULE_STRATEGY: "recursive"
+ GIT_SUBMODULE_STRATEGY: "normal"
# Makes ci.sh isolate CABAL_DIR
HERMETIC: "YES"
=====================================
.gitlab/ci.sh
=====================================
@@ -377,8 +377,8 @@ function cleanup_submodules() {
# On Windows submodules can inexplicably get into funky states where git
# believes that the submodule is initialized yet its associated repository
# is not valid. Avoid failing in this case with the following insanity.
- git submodule sync --recursive || git submodule deinit --force --all
- git submodule update --init --recursive
+ git submodule sync || git submodule deinit --force --all
+ git submodule update --init
git submodule foreach git clean -xdf
else
info "Not cleaning submodules, not in a git repo"
=====================================
compiler/GHC/Core/Opt/Arity.hs
=====================================
@@ -873,24 +873,49 @@ exprEtaExpandArity opts e
* *
********************************************************************* -}
-findRhsArity :: ArityOpts -> RecFlag -> Id -> CoreExpr -> Arity -> SafeArityType
+findRhsArity :: ArityOpts -> RecFlag -> Id -> CoreExpr
+ -> (Bool, SafeArityType)
-- This implements the fixpoint loop for arity analysis
-- See Note [Arity analysis]
--- If findRhsArity e = (n, is_bot) then
--- (a) any application of e to <n arguments will not do much work,
--- so it is safe to expand e ==> (\x1..xn. e x1 .. xn)
--- (b) if is_bot=True, then e applied to n args is guaranteed bottom
--
--- Returns an ArityType that is guaranteed trimmed to typeArity of 'bndr'
+-- The Bool is True if the returned arity is greater than (exprArity rhs)
+-- so the caller should do eta-expansion
+-- That Bool is never True for join points, which are never eta-expanded
+--
+-- Returns an SafeArityType that is guaranteed trimmed to typeArity of 'bndr'
-- See Note [Arity trimming]
-findRhsArity opts is_rec bndr rhs old_arity
- = case is_rec of
- Recursive -> go 0 botArityType
- NonRecursive -> step init_env
+
+findRhsArity opts is_rec bndr rhs
+ | isJoinId bndr
+ = (False, join_arity_type)
+ -- False: see Note [Do not eta-expand join points]
+ -- But do return the correct arity and bottom-ness, because
+ -- these are used to set the bndr's IdInfo (#15517)
+ -- Note [Invariants on join points] invariant 2b, in GHC.Core
+
+ | otherwise
+ = (arity_increased, non_join_arity_type)
+ -- arity_increased: eta-expand if we'll get more lambdas
+ -- to the top of the RHS
where
+ old_arity = exprArity rhs
+
init_env :: ArityEnv
init_env = findRhsArityEnv opts (isJoinId bndr)
+ -- Non-join-points only
+ non_join_arity_type = case is_rec of
+ Recursive -> go 0 botArityType
+ NonRecursive -> step init_env
+ arity_increased = arityTypeArity non_join_arity_type > old_arity
+
+ -- Join-points only
+ -- See Note [Arity for non-recursive join bindings]
+ -- and Note [Arity for recursive join bindings]
+ join_arity_type = case is_rec of
+ Recursive -> go 0 botArityType
+ NonRecursive -> trimArityType ty_arity (cheapArityType rhs)
+
ty_arity = typeArity (idType bndr)
id_one_shots = idDemandOneShots bndr
@@ -1076,6 +1101,117 @@ But /only/ for called-once demands. Suppose we had
Now we don't want to eta-expand f1 to have 3 args; only two.
Nor, in the case of f2, do we want to push that error call under
a lambda. Hence the takeWhile in combineWithDemandDoneShots.
+
+Note [Do not eta-expand join points]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Similarly to CPR (see Note [Don't w/w join points for CPR] in
+GHC.Core.Opt.WorkWrap), a join point stands well to gain from its outer binding's
+eta-expansion, and eta-expanding a join point is fraught with issues like how to
+deal with a cast:
+
+ let join $j1 :: IO ()
+ $j1 = ...
+ $j2 :: Int -> IO ()
+ $j2 n = if n > 0 then $j1
+ else ...
+
+ =>
+
+ let join $j1 :: IO ()
+ $j1 = (\eta -> ...)
+ `cast` N:IO :: State# RealWorld -> (# State# RealWorld, ())
+ ~ IO ()
+ $j2 :: Int -> IO ()
+ $j2 n = (\eta -> if n > 0 then $j1
+ else ...)
+ `cast` N:IO :: State# RealWorld -> (# State# RealWorld, ())
+ ~ IO ()
+
+The cast here can't be pushed inside the lambda (since it's not casting to a
+function type), so the lambda has to stay, but it can't because it contains a
+reference to a join point. In fact, $j2 can't be eta-expanded at all. Rather
+than try and detect this situation (and whatever other situations crop up!), we
+don't bother; again, any surrounding eta-expansion will improve these join
+points anyway, since an outer cast can *always* be pushed inside. By the time
+CorePrep comes around, the code is very likely to look more like this:
+
+ let join $j1 :: State# RealWorld -> (# State# RealWorld, ())
+ $j1 = (...) eta
+ $j2 :: Int -> State# RealWorld -> (# State# RealWorld, ())
+ $j2 = if n > 0 then $j1
+ else (...) eta
+
+Note [Arity for recursive join bindings]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+ f x = joinrec j 0 = \ a b c -> (a,x,b)
+ j n = j (n-1)
+ in j 20
+
+Obviously `f` should get arity 4. But it's a bit tricky:
+
+1. Remember, we don't eta-expand join points; see
+ Note [Do not eta-expand join points].
+
+2. But even though we aren't going to eta-expand it, we still want `j` to get
+ idArity=4, via the findRhsArity fixpoint. Then when we are doing findRhsArity
+ for `f`, we'll call arityType on f's RHS:
+ - At the letrec-binding for `j` we'll whiz up an arity-4 ArityType
+ for `j` (See Note [arityType for non-recursive let-bindings]
+ in GHC.Core.Opt.Arity)b
+ - At the occurrence (j 20) that arity-4 ArityType will leave an arity-3
+ result.
+
+3. All this, even though j's /join-arity/ (stored in the JoinId) is 1.
+ This is is the Main Reason that we want the idArity to sometimes be
+ larger than the join-arity c.f. Note [Invariants on join points] item 2b
+ in GHC.Core.
+
+4. Be very careful of things like this (#21755):
+ g x = let j 0 = \y -> (x,y)
+ j n = expensive n `seq` j (n-1)
+ in j x
+ Here we do /not/ want eta-expand `g`, lest we duplicate all those
+ (expensive n) calls.
+
+ But it's fine: the findRhsArity fixpoint calculation will compute arity-1
+ for `j` (not arity 2); and that's just what we want. But we do need that
+ fixpoint.
+
+ Historical note: an earlier version of GHC did a hack in which we gave
+ join points an ArityType of ABot, but that did not work with this #21755
+ case.
+
+5. arityType does not usually expect to encounter free join points;
+ see GHC.Core.Opt.Arity Note [No free join points in arityType].
+ But consider
+ f x = join j1 y = .... in
+ joinrec j2 z = ...j1 y... in
+ j2 v
+
+ When doing findRhsArity on `j2` we'll encounter the free `j1`.
+ But that is fine, because we aren't going to eta-expand `j2`;
+ we just want to know its arity. So we have a flag am_no_eta,
+ switched on when doing findRhsArity on a join point RHS. If
+ the flag is on, we allow free join points, but not otherwise.
+
+
+Note [Arity for non-recursive join bindings]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Note [Arity for recursive join bindings] deals with recursive join
+bindings. But what about /non-recursive/ones? If we just call
+findRhsArity, it will call arityType. And that can be expensive when
+we have deeply nested join points:
+ join j1 x1 = join j2 x2 = join j3 x3 = blah3
+ in blah2
+ in blah1
+(e.g. test T18698b).
+
+So we call cheapArityType instead. It's good enough for practical
+purposes.
+
+(Side note: maybe we should use cheapArity for the RHS of let bindings
+in the main arityType function.)
-}
=====================================
compiler/GHC/Core/Opt/Simplify/Utils.hs
=====================================
@@ -102,6 +102,14 @@ bindContextLevel :: BindContext -> TopLevelFlag
bindContextLevel (BC_Let top_lvl _) = top_lvl
bindContextLevel (BC_Join {}) = NotTopLevel
+bindContextRec :: BindContext -> RecFlag
+bindContextRec (BC_Let _ rec_flag) = rec_flag
+bindContextRec (BC_Join rec_flag _) = rec_flag
+
+isJoinBC :: BindContext -> Bool
+isJoinBC (BC_Let {}) = False
+isJoinBC (BC_Join {}) = True
+
{- *********************************************************************
* *
@@ -1776,39 +1784,26 @@ Wrinkles
tryEtaExpandRhs :: SimplEnv -> BindContext -> OutId -> OutExpr
-> SimplM (ArityType, OutExpr)
-- See Note [Eta-expanding at let bindings]
--- If tryEtaExpandRhs rhs = (n, is_bot, rhs') then
--- (a) rhs' has manifest arity n
--- (b) if is_bot is True then rhs' applied to n args is guaranteed bottom
-tryEtaExpandRhs env (BC_Join is_rec _) bndr rhs
- = assertPpr (isJoinId bndr) (ppr bndr) $
- return (arity_type, rhs)
- -- Note [Do not eta-expand join points]
- -- But do return the correct arity and bottom-ness, because
- -- these are used to set the bndr's IdInfo (#15517)
- -- Note [Invariants on join points] invariant 2b, in GHC.Core
- where
- -- See Note [Arity for non-recursive join bindings]
- -- and Note [Arity for recursive join bindings]
- arity_type = case is_rec of
- NonRecursive -> cheapArityType rhs
- Recursive -> findRhsArity (seArityOpts env) Recursive
- bndr rhs (exprArity rhs)
-
-tryEtaExpandRhs env (BC_Let _ is_rec) bndr rhs
- | seEtaExpand env -- Provided eta-expansion is on
- , new_arity > old_arity -- And the current manifest arity isn't enough
+tryEtaExpandRhs env bind_cxt bndr rhs
+ | do_eta_expand -- If the current manifest arity isn't enough
+ -- (never true for join points)
+ , seEtaExpand env -- and eta-expansion is on
, wantEtaExpansion rhs
- = do { tick (EtaExpansion bndr)
+ = -- Do eta-expansion.
+ assertPpr( not (isJoinBC bind_cxt) ) (ppr bndr) $
+ -- assert: this never happens for join points; see GHC.Core.Opt.Arity
+ -- Note [Do not eta-expand join points]
+ do { tick (EtaExpansion bndr)
; return (arity_type, etaExpandAT in_scope arity_type rhs) }
| otherwise
= return (arity_type, rhs)
+
where
in_scope = getInScope env
- old_arity = exprArity rhs
arity_opts = seArityOpts env
- arity_type = findRhsArity arity_opts is_rec bndr rhs old_arity
- new_arity = arityTypeArity arity_type
+ is_rec = bindContextRec bind_cxt
+ (do_eta_expand, arity_type) = findRhsArity arity_opts is_rec bndr rhs
wantEtaExpansion :: CoreExpr -> Bool
-- Mostly True; but False of PAPs which will immediately eta-reduce again
@@ -1894,117 +1889,6 @@ But note that this won't eta-expand, say
Does it matter not eta-expanding such functions? I'm not sure. Perhaps
strictness analysis will have less to bite on?
-Note [Do not eta-expand join points]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Similarly to CPR (see Note [Don't w/w join points for CPR] in
-GHC.Core.Opt.WorkWrap), a join point stands well to gain from its outer binding's
-eta-expansion, and eta-expanding a join point is fraught with issues like how to
-deal with a cast:
-
- let join $j1 :: IO ()
- $j1 = ...
- $j2 :: Int -> IO ()
- $j2 n = if n > 0 then $j1
- else ...
-
- =>
-
- let join $j1 :: IO ()
- $j1 = (\eta -> ...)
- `cast` N:IO :: State# RealWorld -> (# State# RealWorld, ())
- ~ IO ()
- $j2 :: Int -> IO ()
- $j2 n = (\eta -> if n > 0 then $j1
- else ...)
- `cast` N:IO :: State# RealWorld -> (# State# RealWorld, ())
- ~ IO ()
-
-The cast here can't be pushed inside the lambda (since it's not casting to a
-function type), so the lambda has to stay, but it can't because it contains a
-reference to a join point. In fact, $j2 can't be eta-expanded at all. Rather
-than try and detect this situation (and whatever other situations crop up!), we
-don't bother; again, any surrounding eta-expansion will improve these join
-points anyway, since an outer cast can *always* be pushed inside. By the time
-CorePrep comes around, the code is very likely to look more like this:
-
- let join $j1 :: State# RealWorld -> (# State# RealWorld, ())
- $j1 = (...) eta
- $j2 :: Int -> State# RealWorld -> (# State# RealWorld, ())
- $j2 = if n > 0 then $j1
- else (...) eta
-
-Note [Arity for recursive join bindings]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Consider
- f x = joinrec j 0 = \ a b c -> (a,x,b)
- j n = j (n-1)
- in j 20
-
-Obviously `f` should get arity 4. But it's a bit tricky:
-
-1. Remember, we don't eta-expand join points; see
- Note [Do not eta-expand join points].
-
-2. But even though we aren't going to eta-expand it, we still want `j` to get
- idArity=4, via the findRhsArity fixpoint. Then when we are doing findRhsArity
- for `f`, we'll call arityType on f's RHS:
- - At the letrec-binding for `j` we'll whiz up an arity-4 ArityType
- for `j` (See Note [arityType for non-recursive let-bindings]
- in GHC.Core.Opt.Arity)b
- - At the occurrence (j 20) that arity-4 ArityType will leave an arity-3
- result.
-
-3. All this, even though j's /join-arity/ (stored in the JoinId) is 1.
- This is is the Main Reason that we want the idArity to sometimes be
- larger than the join-arity c.f. Note [Invariants on join points] item 2b
- in GHC.Core.
-
-4. Be very careful of things like this (#21755):
- g x = let j 0 = \y -> (x,y)
- j n = expensive n `seq` j (n-1)
- in j x
- Here we do /not/ want eta-expand `g`, lest we duplicate all those
- (expensive n) calls.
-
- But it's fine: the findRhsArity fixpoint calculation will compute arity-1
- for `j` (not arity 2); and that's just what we want. But we do need that
- fixpoint.
-
- Historical note: an earlier version of GHC did a hack in which we gave
- join points an ArityType of ABot, but that did not work with this #21755
- case.
-
-5. arityType does not usually expect to encounter free join points;
- see GHC.Core.Opt.Arity Note [No free join points in arityType].
- But consider
- f x = join j1 y = .... in
- joinrec j2 z = ...j1 y... in
- j2 v
-
- When doing findRhsArity on `j2` we'll encounter the free `j1`.
- But that is fine, because we aren't going to eta-expand `j2`;
- we just want to know its arity. So we have a flag am_no_eta,
- switched on when doing findRhsArity on a join point RHS. If
- the flag is on, we allow free join points, but not otherwise.
-
-
-Note [Arity for non-recursive join bindings]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Note [Arity for recursive join bindings] deals with recursive join
-bindings. But what about /non-recursive/ones? If we just call
-findRhsArity, it will call arityType. And that can be expensive when
-we have deeply nested join points:
- join j1 x1 = join j2 x2 = join j3 x3 = blah3
- in blah2
- in blah1
-(e.g. test T18698b).
-
-So we call cheapArityType instead. It's good enough for practical
-purposes.
-
-(Side note: maybe we should use cheapArity for the RHS of let bindings
-in the main arityType function.)
-
************************************************************************
* *
=====================================
hadrian/bootstrap/bootstrap.py
=====================================
@@ -86,14 +86,17 @@ class Compiler:
self.ghc_path = ghc_path.resolve()
+ exe = ''
+ if platform.system() == 'Windows': exe = '.exe'
+
info = self._get_ghc_info()
self.version = info['Project version']
#self.lib_dir = Path(info['LibDir'])
#self.ghc_pkg_path = (self.lib_dir / 'bin' / 'ghc-pkg').resolve()
- self.ghc_pkg_path = (self.ghc_path.parent / 'ghc-pkg').resolve()
+ self.ghc_pkg_path = (self.ghc_path.parent / ('ghc-pkg' + exe)).resolve()
if not self.ghc_pkg_path.is_file():
raise TypeError(f'ghc-pkg {self.ghc_pkg_path} is not a file')
- self.hsc2hs_path = (self.ghc_path.parent / 'hsc2hs').resolve()
+ self.hsc2hs_path = (self.ghc_path.parent / ('hsc2hs' + exe)).resolve()
if not self.hsc2hs_path.is_file():
raise TypeError(f'hsc2hs {self.hsc2hs_path} is not a file')
@@ -367,6 +370,11 @@ def main() -> None:
help='path to GHC')
parser.add_argument('-s', '--bootstrap-sources', type=Path,
help='Path to prefetched bootstrap sources tarball')
+ parser.add_argument('--archive', dest='want_archive', action='store_true',
+ help='produce a Hadrian distribution archive (default)')
+ parser.add_argument('--no-archive', dest='want_archive', action='store_false',
+ help='do not produce a Hadrian distribution archive')
+ parser.set_defaults(want_archive=True)
subparsers = parser.add_subparsers(dest="command")
@@ -381,6 +389,9 @@ def main() -> None:
ghc = None
+ sources_fmt = 'gztar' # The archive format for the bootstrap sources archive.
+ if platform.system() == 'Windows': sources_fmt = 'zip'
+
if args.deps is None:
if args.bootstrap_sources is None:
# find appropriate plan in the same directory as the script
@@ -390,7 +401,7 @@ def main() -> None:
# We have a tarball with all the required information, unpack it and use for further
elif args.bootstrap_sources is not None and args.command != 'list-sources':
print(f'Unpacking {args.bootstrap_sources} to {TARBALLS}')
- shutil.unpack_archive(args.bootstrap_sources.resolve(), TARBALLS, 'gztar')
+ shutil.unpack_archive(args.bootstrap_sources.resolve(), TARBALLS, sources_fmt)
args.deps = TARBALLS / 'plan-bootstrap.json'
print(f"using plan-bootstrap.json ({args.deps}) from {args.bootstrap_sources}")
else:
@@ -428,10 +439,7 @@ def main() -> None:
shutil.copyfile(args.deps, rootdir / 'plan-bootstrap.json')
- fmt = 'gztar'
- if platform.system() == 'Windows': fmt = 'zip'
-
- archivename = shutil.make_archive(args.output, fmt, root_dir=rootdir)
+ archivename = shutil.make_archive(args.output, sources_fmt, root_dir=rootdir)
print(f"""
Bootstrap sources saved to {archivename}
@@ -475,21 +483,21 @@ Alternatively, you could use `bootstrap.py -w {ghc.ghc_path} -d {args.deps} fetc
bootstrap(info, ghc)
hadrian_path = (BINDIR / 'hadrian').resolve()
- archive = make_archive(hadrian_path)
-
print(dedent(f'''
Bootstrapping finished!
The resulting hadrian executable can be found at
{hadrian_path}
+ '''))
- It has been archived for distribution in
-
- {archive}
+ if args.want_archive:
+ dist_archive = make_archive(hadrian_path)
+ print(dedent(f'''
+ The Hadrian executable has been archived for distribution in
- You can use this executable to build GHC.
- '''))
+ {dist_archive}
+ '''))
else:
print(f"No such command: {args.command}")
=====================================
libraries/ghc-prim/GHC/Types.hs
=====================================
@@ -143,7 +143,7 @@ data Symbol
-- | The type constructor 'Any' is type to which you can unsafely coerce any
-- lifted type, and back. More concretely, for a lifted type @t@ and
--- value @x :: t@, -- @unsafeCoerce (unsafeCoerce x :: Any) :: t@ is equivalent
+-- value @x :: t@, @unsafeCoerce (unsafeCoerce x :: Any) :: t@ is equivalent
-- to @x at .
--
type family Any :: k where { }
@@ -165,7 +165,7 @@ type family Any :: k where { }
-- ==== __Examples__
--
-- Unless the OverloadedLists extension is enabled, list literals are
--- syntatic sugar for repeated applications of @:@ and @[]@.
+-- syntactic sugar for repeated applications of @:@ and @[]@.
--
-- >>> 1:2:3:4:[] == [1,2,3,4]
-- True
=====================================
testsuite/tests/simplCore/should_compile/T22114.hs
=====================================
@@ -0,0 +1,17 @@
+{-# LANGUAGE Haskell2010 #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module T22114 where
+
+import Data.Kind (Type)
+
+value :: [Int] -> () -> Maybe Bool
+value = valu
+ where valu [0] = valuN
+ valu _ = \_ -> Nothing
+
+type family T :: Type where
+ T = () -> Maybe Bool
+
+valuN :: T
+valuN = valuN
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -428,3 +428,4 @@ test('T21948', [grep_errmsg(r'^ Arity=5') ], compile, ['-O -ddump-simpl'])
test('T21763', only_ways(['optasm']), compile, ['-O2 -ddump-rules'])
test('T21763a', only_ways(['optasm']), compile, ['-O2 -ddump-rules'])
test('T22028', normal, compile, ['-O -ddump-rule-firings'])
+test('T22114', normal, compile, ['-O'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/6aada809cd75dc229a3b7a62e79aa4a1624358e2...5a944e820a429c4208317f1171c6dfde29ad82b7
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/6aada809cd75dc229a3b7a62e79aa4a1624358e2...5a944e820a429c4208317f1171c6dfde29ad82b7
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/20220830/5b48c846/attachment-0001.html>
More information about the ghc-commits
mailing list