This is the thirty-first edition of our Haskell ecosystem activities report, which describes the work Well-Typed are doing on GHC, Cabal, HLS and other parts of the core Haskell toolchain. The current edition covers roughly the months of March 2026 to May 2026.

You can find the previous editions collected under the haskell-ecosystem-report tag.

Sponsorship

We offer Haskell Ecosystem Support Packages to provide commercial users with support from Well-Typed’s experts while investing in the Haskell community and its technical ecosystem including through the work described in this report. To find out more, read our announcement of these packages in partnership with the Haskell Foundation. We need funding to continue this essential maintenance work!

Many thanks to our Haskell Ecosystem Supporters: Standard Chartered, Channable and QBayLogic, as well as to our other clients who also contribute to making this work possible: Anduril, Juspay and Mercury; and to the HLS Open Collective for supporting HLS release management.

Highlights

Reinstallable base

Rodrigo and Wolfgang have continued working to disentangle base from GHC, with the ultimate goal of being able to use different versions of base with a single GHC version. This is all part of a long-term project to make GHC upgrades easier, documented in the reinstallable-base repo, and recently described in an excellent haskell.org blog article by Simon Peyton Jones. Simon, Rodrigo and Wolfgang are working together to rethink GHC’s treatment of “known-key names” so base will be much less tightly coupled to ghc-internal (!15899).

One big milestone was making the current base buildable both with GHC 9.14 (!16070) and with the upcoming GHC 10.0 (!16035).

Various other pieces of technical groundwork were required:

  • moving most of the System.IO implementation into base (!15694),
  • similarly moving Text.Read (!15693, !15777),
  • making various SafeHaskell-related changes (CLC #408, !16034).

Wolfgang also opened several CLC proposals identifying key areas that require further work:

  • the deprecation of unstable base modules (CLC #392), and
  • working towards making bytestring and text not depend on internal I/O machinery (CLC #410).

Semaphores and -jsem

The implementation of semaphores used by cabal-install and GHC to coordinate concurrency suffered from a serious issue when GHC and cabal-install were linked against different libc implementations (#25087).

Zubin remedied this issue with a new semaphore implementation on top of Unix domain sockets (!8), described in GHC proposal #673. GHC (!15729) and cabal-install (#11628) were then switched to this new protocol version.

As part of this work, Zubin also identified some deficiencies in the semantics of interruptible FFI (#27110).

Cabal modernisation

Sam worked to modernise the architecture of cabal-install by making it directly call the Cabal library to build packages (#11703). This unlocked the performance optimisations described in a recent blog post (#11767, #11768), achieving speed-ups of around 10-15% in certain situations.

In the long term, we would like to move towards Cabal having a fine-grained build graph across the whole project, rather than using a component-level build graph and relying on GHC to orchestrate the compilation of all the modules in a component/package. This will unlock more parallelism and other developer experience improvements.

Sam also implemented many improvements to build-type: Hooks, the modern replacement for build-type: Custom:

  • an improved API for SetupHooks authors (#11772),
  • better documentation (#11771),
  • improved recompilation checking for pre-build rules (#11731),
  • support for generating non-Haskell files in pre-build rules (#11573).

Tobias chimed in by adding support for recursive globs in file monitoring, which is useful for SetupHooks (#11658).

Windows DLL support

Duncan, with the help of David, embarked on the project of adding proper dynamic linking support to GHC on Windows. While this is still work-in-progress, several important steps have already been taken:

  • extending Cmm syntax to support symbols from external DSOs/DLLs (!15135),
  • solving the recursive DLL dependency between the RTS and ghc-internal (!15907),
  • making GHC use __attribute__((dllimport)) for external symbol declarations (!15914),
  • updating Hadrian to create individual .def files per ghc-internal DLL (!16082).

Critical process issue on macOS

Magnus diagnosed a critical issue with process on macOS (#27144, #356), implementing a fix in #363. As part of this work, he discovered an issue with several uploaded versions of process (#365) which was resolved by coordinating with the process maintainers.

GHC

Releases

Keeping all of GHC’s active release branches in good shape is a demanding, largely behind-the-scenes effort. Each release requires triaging and backporting a steady stream of bugfixes, with patches that often don’t cleanly apply and require careful reworking. Information about upcoming releases is available on the GHC release status page.

GHC currently has four (!) active branches. Zubin worked towards the 10.0 release as well as on 9.14.2; Magnus prepared 9.12.5, and Andreas took on 9.10.4.

Frontend

  • Rodrigo bumped the default language edition to GHC2024 (#26039, !14420). Starting from GHC 10.0, code without an explicit language edition will default to GHC2024. Compared to GHC2021, this adds the extensions DataKinds, DerivingStrategies, DisambiguateRecordFields, ExplicitNamespaces, GADTs, MonoLocalBinds, LambdaCase and RoleAnnotations.

  • Magnus fixed the documentation of getSizeofMutableByteArray# (!16065).

  • Sam fixed a loop with -XDeepSubsumption on GHC 9.14 (#26823, !15604).

  • Wolfgang made several performance improvements to the driver, allowing downsweep to use existing module graph nodes (!16028), introducing a cache for hole modules (!15888), and storing home unit dependencies as sets (!15849).

  • Hannes made several performance improvements to ghc-pkg, speeding up its closure computation (!16062) and migrating it to use OsPath (!15584).

  • Andreas modularised the GHC.Driver.Main module (!15940), as that single module had become quite unwieldy.

  • Following on from previous work allowing typechecker plugins to run in the pattern match checker (!14797), Sam made sure that plugins are only initialised once per module (!15485), fixing the regression reported in #26839.

  • Rodrigo provided a standalone reproducer for the simplifier slowness reported in #26989, which allowed Simon Peyton Jones to diagnose and fix this quadratic behaviour (!15725).

  • Sam investigated the type family performance regressions reported in #26426, identifying two key patches that had accidentally fixed the regression and recording these findings in Notes (!16113).

  • Andreas identified that a patch to use Generics within GHC significantly regressed compile times (#27191). The offending patch was reverted for the time being, and the coding style Wiki page was updated to document this unfortunate limitation.

Backend

  • Sam finished up work by Matthew Craven to improve the representation of floating point literals in GHC, fixing several issues with the treatment of negative zero and NaN values (!15528). This brings GHC much closer to proper IEEE 754 floating point compliance.

  • Andreas discovered a bug with AArch64 profiled dynamic builds of GHC and concluded that it was a bug in gcc/binutils (#26994).

  • Sam fixed a crash in Core Prep caused by invalid profiling tick occurrences (#27182, !16003).

  • Sam investigated a crash in mkDupableContWithDmds, and worked with Simon Peyton Jones to land a fix (#27261, !16084).

  • Sam fixed several bugs in the implementation of the hsExprType function (#26910, !15772).

  • Zubin fixed the typing of void pointer chains in capi FFI calls to avoid -Wincompatible-pointer-type errors by the C compiler (#26852, !15547).

  • Sam helped first-time contributor Avery Parker land his AmeriHac contribution to add constant folding for SIMD vector operations (!15512).

  • Sam reviewed several patches to the AArch64 native code generator by Ian Duncan, in the process uncovering a cluster of latent correctness bugs:

    • !15620 fixed a bug in “shift right” using a logical shift instead of an arithmetic shift (#26979). A separate register clobbering bug was identified and fixed.
    • !15619 fixed sign extension at 32-bit width (#26978). A separate bug with the overflow bit was identified and fixed (#27047). Another register clobbering bug was found and fixed separately (#27046, !16031).
  • Sam fixed a recalcitrant “failed to detect OverLit” crash in coreExprToPmLit (!15895, #27124, #25926).

  • Magnus and Sam investigated the GHC panic reported in #27227, which was narrowed down to Cabal bug #7684, and subsequently fixed (#11791).

ghci & bytecode

Work continued on making the bytecode interpreter, which underpins GHCi as well as the debugger, more capable and memory efficient.

  • Hannes introduced the -fimport-loaded-target ghci flag to fix a regression with the :add command relating to support for multiple home units (!15533, #26866).

  • Hannes fixed a regression in the behaviour of :load (#27202, !15980).

  • Hannes added support for hpc in the bytecode interpreter (#27036, !15843).

  • Rodrigo added support for static constructors in the bytecode interpreter, also fixing its treatment of unlifted values (#25636, !15221).

  • Hannes improved the memory usage of the bytecode interpreter by recording only a LinkableUsage instead of Linkable in LoaderState (#26500, #27018, !15689).

RTS

  • Duncan consolidated the ticker implementations to a single one on POSIX (!15781), removing signal-based ticker implementations (!15757, !16014) which presented a number of disadvantages (described in #27073).

  • David resurrected an old MR improving the documentation of the allocator (!3812).

  • Andreas added missing profiling headers for origin_thunk frames (!15665).

  • Duncan identified some incorrect STOP_THREAD status codes in ghc-events (#130).

Build system

  • David made several improvements to GHC’s build system and Hadrian, in relation to his work on Windows DLL support:

    • a fix for Unix paths in ACLOCAL_PATH (!16112),
    • proper LLVM program versioning logic (!16025),
    • work on response files to avoid MAX_PATH issues on Windows (!15891, !16120).
  • Andreas fixed an issue with --target in the configure script (!15649).

  • Zubin stopped Hadrian from including package hashes in Haddock directory names, as this was causing many broken links when browsing Haddocks (#26635, !15475).

GHC contribution experience

  • Magnus overhauled the MR template to be more helpful for new contributors (!15943, #27165).

  • Many team members provided reviews and helped land contributions from others, as described elsewhere in this report.

CI and tests

  • Magnus has been doing significant work on the gitlab.haskell.org instance and CI infrastructure to improve robustness of CI, deal with spam and manage the server load imposed by AI crawlers.

  • Magnus changed the Darwin CI to clone rather than copy when creating the Cabal cache (!15683).

  • Sam added a vendored mini-QuickCheck component for use in GHC’s testsuite, fixing some bugs in the previous implementation used in the foundation primops testsuite (!15893, #25969, #25990).

Haskell Language Server

  • Zubin prepared release 2.14.0 of the Haskell Language Server (#4897).

  • Hannes reviewed many HLS PRs from contributors:

    • #4958 adding a code action to delete unused bindings,
    • #4913 improving the handling of hs-boot files,
    • #4915 updating the splice plugin,
    • #4917 preserving qualified field names when expanding record inlay hints,
    • #4902 excluding internal superclass names in class placeholders,
    • #4886 cancelling outstanding threads when closing the SQLite connection,
    • #4867 improving HLS’s response for prepareRename,
    • #4865 migrating the Stackage build to use GitHub actions,
    • #4854 fixing a redundant hash in the ghcide cache path.
  • Hannes released version 0.19.0 of hie-bios (#506).

  • Sam fixed a hie-bios regression in which the local build directory would get overwritten, leading to cache trashing (#501, #503).

Haskell syntax highlighting

Sam fixed a large number of bugs in the language-haskell VS Code syntax highlighting extension.

Haskell Debugger

Rodrigo continued to lead development of the Haskell Debugger (hdb), an interactive step-through debugger for Haskell, with contributions from Andrea and Hannes. Built on top of the bytecode interpreter, it implements the Debug Adapter Protocol, allowing debugging of Haskell programs directly in the editor. We:

  • added a new RTS message to GHC allowing a thread’s flags (TSO flags) to be set or unset (!15831, #27131), which is needed to safely implement features like pausing, or toggling step-out/step-in per thread;

  • arranged for hdb to run the debuggee directly in the terminal when using the external interpreter (#260);

  • added support for custom external interpreter commands to GHC (!15676), making use of them rather than parsing heap terms (#222);

  • fixed a bug where forcing a thunk would invalidate stack frames on all threads rather than just the right one (#292), and fixed breakpoints being overwritten by looking for active breaks in the correct ModBreaks (#298);

  • refactored the home-unit session initialisation (#279).

Andrea made various quality-of-life improvements to the debugger:

  • allowing imports at the REPL (#229);
  • bringing interactive imports back into scope after resuming execution (#275);
  • inheriting the entry file’s language extensions (#230);
  • adding LogMessage support to implement log points (#223);
  • sharing a single HDB+GHC session for use with HLS (#308).

Runtime observability

ghc-debug

Hannes performed various maintenance tasks on ghc-debug, a key tool for out-of-process heap analysis of Haskell programs:

  • released version 0.8.0.0 (!88),
  • bumped version bounds (!91),
  • fixed FreeBSD support (!89),
  • landed an old MR by Teo Camarasu, adding support for the non-moving GC (!10).

eventlog-live, eventlog-socket

Wen continued to develop eventlog-live, which allows GHC’s eventlog to be monitored live as a program runs. Highlights of the changes to eventlog-live:

  • support for receiving eventlog input over TCP (#154, #155),

  • improved profiling support with cost-centre profiles (#134) and ghc-stack-profiler profiles (#131),

  • integration with the RTS control server (#139, #122, #126),

  • a new demo showing eventlog-live monitoring GHC itself (#138, #148),

  • support for GHC 9.12 (#136).

This also included a litany of improvements to the underlying eventlog-socket library:

  • lifecycle hooks (#63),
  • command registration (#45),
  • support for startProfTimer and stopProfTimer (#65),
  • allow building with hsc2hs in cross-compilation mode (#64).

Finally, Wen also landed several supporting changes in GHC itself:

  • fixed a race condition in the RTS between flushEventLog and starting/stopping event logging (!15750),
  • added a new -lI eventlog flag to emit IPE events (!16004),
  • added support for dynamically changing trace flags (!15936).

ghc-stack-profiler

Hannes continued maintaining ghc-stack-profiler, a profiler that relies on stack annotations rather than heavier profiling mechanisms:

  • released version 0.2.0.0 (#24);

  • made the profiler more robust, ensuring it never crashes on decoding errors (#12) and backporting a fix for stack-decoding segmentation faults from GHC HEAD (#20);

  • integrated the profiler with eventlog-socket, adding support for its lifecycle hooks (#19) and an eventlog-socket test suite (#25);

  • improved thread management by using async (#10) and exposing stopStackProfilerThread (#11).

IHaskell

Sam added Windows support to IHaskell, a library that provides Haskell integration for Jupyter notebooks (#1595).

stm library

Magnus performed some important maintenance tasks on the stm library, adding missing compiler versions to CI (#98) and fixing a slow test (#97).