GHC 9.4.1-rc1 is now available!

The GHC developers are happy to announce the availability of the first
(and likely last) release candidate of GHC 9.4.1. Binary distributions, source
distributions, and documentation are available at

This major release will include:

  • A new profiling mode, -fprof-late, which adds automatic cost-center
    annotations to all top-level functions after Core optimisation has
    run. This provides informative profiles while interfering
    significantly less with GHC’s aggressive optimisations, making it
    easier to understand the performance of programs which depend upon

  • A variety of plugin improvements including the introduction of a new
    plugin type, defaulting plugins, and the ability for typechecking
    plugins to rewrite type-families.

  • An improved constructed product result analysis, allowing unboxing of
    nested structures, and a new boxity analysis, leading to less reboxing.

  • Introduction of a tag-check elision optimisation, bringing
    significant performance improvements in strict programs.

  • Generalisation of a variety of primitive types to be levity
    polymorphic. Consequently, the ArrayArray# type can at long last be
    retired, replaced by standard Array#.

  • Introduction of the \cases syntax from GHC proposal 0302

  • A complete overhaul of GHC’s Windows support. This includes a
    migration to a fully Clang-based C toolchain, a deep refactoring of
    the linker, and many fixes in WinIO.

  • Support for multiple home packages, significantly improving support
    in IDEs and other tools for multi-package projects.

  • A refactoring of GHC’s error message infrastructure, allowing GHC to
    provide diagnostic information to downstream consumers as structured
    data, greatly easing IDE support.

  • Significant compile-time improvements to runtime and memory consumption.

  • On overhaul of our packaging infrastructure, allowing full
    traceability of release artifacts and more reliable binary

  • Reintroduction of deep subsumption (which was previously dropped with the
    simplified subsumption change) as a language extension.

  • … and much more. See the release notes for a full accounting.

Note that, as 9.4.1 is the first release for which the released artifacts will
all be generated by our Hadrian build system, it is possible that there will be
packaging issues. If you enounter trouble while using a binary distribution,
please open a ticket. Likewise, if you are a downstream packager, do consider
migrating to Hadrian to run your build; the Hadrian build system can be built
using cabal-install, stack, or the in-tree bootstrap script. We will be
publishing a blog post describing the migration process to Hadrian in the
coming weeks.

We would like to thank Microsoft Azure, GitHub, IOG, the Zw3rk
stake pool, Tweag I/O, Serokell, Equinix, SimSpace, the Haskell
Foundation, and other anonymous contributors whose on-going financial
and in-kind support has facilitated GHC maintenance and release
management over the years. Finally, this release would not have been
possible without the hundreds of open-source contributors whose work
comprise this release.

As always, do give this release a try and open a ticket if you see
anything amiss.

Happy testing,

  • Ben

Congrats to the team!

It would be nice if there was a “breaking changes” section in the release notes.

Also it seems that the change of

data Word64 = W64# Word#

changing to

data Word64 = W64# Word64#

(and similar change to other sized Words and Ints) seems to be missing from the release notes.

1 Like

That change was already in 9.2:

1 Like

There are also some interesting bug fixes to the unix package: · 703690614518f38306a81985fb587ee77cf40c48 · Glasgow Haskell Compiler / Packages / unix · GitLab

Oh interesting, that’s a mistake. The change didn’t actually ship on ghc 9.2 (see

Strangly, GHC.Int does have that change in 9.2:

I see that there is some CPP so both versions are in 9.2:


data {-# CTYPE "HsWord64" #-} Word64 = W64# Word64#
-- ^ 64-bit unsigned integer type



-- Word64 is represented in the same way as Word.
-- Operations may assume and must ensure that it holds only values
-- from its logical range.

data {-# CTYPE "HsWord64" #-} Word64 = W64# Word#
-- ^ 64-bit unsigned integer type

If machine words are 64 bits then data Word64 = W64# Word# is fine, but that’s probably annoying to use as an interface…

May I suggest that package candidates for the boot libraries be uploaded to Hackage together with their documentation?

This would give us easy access to the changelogs, and also allow us to check for some of the haddock issues that have plagued recent GHC releases, such as Haddocks for base- on Hackage contain broken source links to ghc-prim (#20698) · Issues · Glasgow Haskell Compiler / GHC · GitLab.


It seems that the reintroduction of deep subsumption is missing from the release notes. Should I open a ticket for this?

May I suggest that package candidates for the boot libraries be uploaded to Hackage together with their documentation?

We do so; the boot libraries for this release have been uploaded as Hackage candidates (e.g. base and ghc-prim).

Sadly the one exception is template-haskell, which could not be uploaded as the .cabal file is rejected by Hackage (see GHC #21912).

1 Like

That was fast. Thank you.

Just a side comment, I have not updated to ghc 9.2.3 yet due to HLS is not yet released with the support. Since perhaps more people are getting dependent on HLS being around them, perhaps either HLS needs to support future versions such as x.y.* or risking rollout of new GHC versions being soft blocked by it…


I see that there is some CPP so both versions are in 9.2: …

Correct, prior to GHC 9.4 the representation of Word64 would depend upon the target word size: Word64# would be used on 32-bit platforms and Word# would be used on 64-bit platforms. This was changed in 9.4. See GHC #11953. However, looking more closely, it appears that this was never added to the changelog. I will fix this.


Great catch, I have added an entry in !8698.

Thank you! For people who have not come across it yet, the complete overhaul of GHC’s Windows support is vital because a recent change in MSYS2 means that if a user updates MSYS2 package mingw-w64-x86_64-crt-git (as a dependency of ffmpeg or gtk4, for example) all versions of GHC before GHC 9.4.1 are then broken on Windows. See [windows] GHC fails to link due to msys2 crt update (#21111) · Issues · Glasgow Haskell Compiler / GHC · GitLab.

1 Like

Is there a source for GHC boot library versions suitable for machines?

Stack uses the user’s guide as a source for this (

For the 9.4 GHC alpha/RC releases this process doesn’t work, I’m comparing

and noting a couple of small changes to the URL that are easily fixed.

Where I got stuck is that the $ver-notes.html page used to contain the boot library versions. Will this be added for the final 9.4.1 release or has this been (re)moved?

Of course, we would ideally not scrape HTML for this information, is there a better source for this that we can use?

There is ghc-pkg list if you have installed the bindist. Otherwise you can refer to library-versions/pkg_versions.txt · master · Ben Gamari / ghc-utils · GitLab which we do try to keep up-to-date.

1 Like

GHCup could maintain such a list. We already do bindist inspection for HLS, see

Adding this for GHC wouldn’t be too hard: unpack src dist, get the cabal files in the libraries subdir and parse the versions via Cabal library.

Then the resulting yaml file is committed to the repo.

1 Like

Much better, thanks!

This will clean up the stackage-content script by a lot. Is this file updated manually? Would it be reasonable to add GHC alphas/RCs here as well? My original goal is to start producing stackage snapshots when a GHC alpha is released. Everything that can remove special cases here would help.

Oh, hmm, I’m also seeing that Win32 is missing for a lot of recent releases in library-versions/pkg_versions.txt · master · Ben Gamari / ghc-utils · GitLab

Indeed it is manually maintained although I do think we should do a better job updating it. Indeed Win32 is quite annoying to keep up-to-date since we need to manually extract a Windows bindist in a Windows environment (or manually extract the version from the bindist). I have started working on a more convenient (albeit hacky) extraction script although the make bindists don’t make this very easy. Perhaps leveraging ghcs.nix for this would be worthwhile.