Please contribute to the GHC 9.10 breakage inventory

I’m collecting a list of all breaking changes between GHC 9.8 and 9.10, that is, anything that you have to change (except just bounds) to get code that previously compiled with 9.8 to compile with 9.10. My hope is that it will feed into a processes of making breaking changes less severe in the future. If you have come across any breaking changes please let me know here or in an issue or PR on the repo.

See also: Please contribute to the GHC 9.8 breakage inventory

11 Likes

Ah, I see you were faster than me to report text-short, thanks!
Edit: I can confirm, most of my projects are blocked on short-text.

1 Like

Is there a migration guide for changes to the GHC api itself? I’m the author of tasty-autocollect, which writes a compiler plugin. Every GHC release, I have to dive into the Haddocks and compare/contrast types and functions with the previous version.

I don’t mind this too much, and understand that’s just the burden I need to carry, but it’d be cool to share a few overarching themes I’ve had to do, if others are in a similar boat. For GHC 9.10, for example, there’s a lot of SrcAnn → EpAnn changes, and moving HsToken args into the XRec argument

4 Likes

There isn’t a systematically maintained migration guide for the GHC API, because the API is large, poorly-defined and changes regularly, so it’s hard to know which changes are going to affect clients. (There is interest in producing a better API, but not a lot of progress so far unfortunately.)

But contributions to the GHC migration guide (including for the GHC API) are very welcome:

1 Like

(There is interest in producing a better API, but not a lot of progress so far unfortunately.)

Is there a repository or database available to look at, like most of the other in-progress projects listed here?

There are some TH API changes, that cause breakage: libraries/template-haskell/changelog.md · master · Glasgow Haskell Compiler / GHC · GitLab

The kind of Code was changed from forall r. (Type -> Type) -> TYPE r -> Type to (Type -> Type) -> forall r. TYPE r -> Type

This breaks code in th-compat library that relays on the order of forall’s (1)

The InfixD constructor of the Dec data type now stores a NamespaceSpecifier

This breaks haskell-src-meta, lens, th-desugar, true-name (2).

I found that user’s guide doesn’t mention breaking change introduced in Remove arity inference in type declarations (#23514) (e89aa072) · Commits · Glasgow Haskell Compiler / GHC · GitLab, so I created an issue #24830: Document arity inference removance in the release notes · Issues · Glasgow Haskell Compiler / GHC · GitLab

This patch breaks singletons package family (1). Fixed by Ryan in singletons-th: Adapt to GHC 9.10's lack of arity inference · goldfirere/singletons@f355fd5 · GitHub

Links to the head.hackage patches

  1. !303: adapt head.hackage to remove arity inference patch · Merge requests · Glasgow Haskell Compiler / head.hackage · GitLab
  2. !352: Fixes for namespacing of fixity signatures · Merge requests · Glasgow Haskell Compiler / head.hackage · GitLab
4 Likes

Here’s an interesting one. With the recent improvements done to the desugaring and typechecking of do-expressions, the following no longer type checks with 9.10 whereas it did with 9.8 (needs dependency on linear-base). This is a good thing!

{-# LANGUAGE UnicodeSyntax, NoImplicitPrelude, QualifiedDo, LinearTypes #-}
module X where

import Prelude (Bool(..), error)
import System.IO.Linear as Linear
import Control.Functor.Linear as Linear

f :: a ⊸ (a, Bool)
f x = (x, True)

instance MonadFail Linear.IO where
  fail = error

g :: a ⊸ Linear.IO a
g x = Linear.do
  (y, True) <- pure (f x)
  return y

Previously, if the result of f had False, the pattern would fail and we’d abruptly exit the program without handling y (which is linear, and would never have been consumed). Now, the linearity forces y to be handled in the False case.

Good!

3 Likes

Thanks! I have a few questions:

  1. Do you know any breakage this has caused in practice? My breakage inventory is only for breakage that has occurred in practice, not just APIs that have changed.

  2. It looks like linear-base hasn’t had its bounds bumped for 9.10. I had to use --allow-newer. Is that expected?

  3. I don’t really get the “improvement” anyway. It seems like I can still do the following. So what’s the benefit of the new rule?

{-# LANGUAGE UnicodeSyntax, NoImplicitPrelude, QualifiedDo, LinearTypes #-}
module X where

import Prelude (Bool(..), error)
import System.IO.Linear as Linear
import Control.Functor.Linear as Linear

f :: a ⊸ (a, Bool)
f x = (x, True)

instance MonadFail Linear.IO where
  fail = error

g :: a ⊸ Linear.IO a
g x = Linear.do
  y_b <- pure (f x)
  y <- case y_b of
    (y, True) -> pure y
    (y, False) -> error "foo" y
  pure y
1 Like

In practice, this came up when compiling my ghengin package with a newer GHC. I thought of reporting it since it was quite confusing at first why things that were linear before were no longer accepted. Not sure how many programs using linear types exist in the wild though.

The good thing is you now have to explicitly use y linearly (which you do by calling error on it). If y is something which must definitely be freed before the program terminates, it’s great we are forced to handle it explicitly — instead of y being completely lost/dropped if the match fails.

An artificial example: say y is a seat “token” in some remote cluster, and you need to explicitly free the seat up for someone else to use the cluster. If your program matched False, it would call fail “e.g. Pattern match failed in do notation” and the token seat lost as the program abruptly ends. In your reply, you are forced to match on (y, False) and ignore y (the token) using error. (Note how fail :: String -> m (), no mention of the y type at all)

My guess is that this wasn’t an intended change, but rather a consequence of desugaring do notation in a more correct way (@ani’s work).

2 Likes

OT: I see there’s no inventory for 9.6. I’m nowhere near 9.10. And 9.6 has some pretty severe breakages (e.g. removed Alternative instance in transformers).

1 Like

Thanks, do you have a particular commit fixing this issue that I can link to when adding an entry for the breakage inventory?

I think you’re referring to the orphan instance in the deprecated module Control.Monad.Trans.Error. It was removed in transformers-6 (changelog). This was mentioned in the 9.6 migration guide.

I upgraded all my packages to GHC 9.10:

I only ran into one thing that needed to be changed, and it was just a warning:

2 Likes

Thanks all. I have added the reported examples to the inventory.

1 Like

Hello folks, coming late to the party, I wanted to report that upgrading monocle from ghc-9.6 to 9.10 (in preparation for 9.12) went smoothly, unfortunately one of the last packages failed to build with a few GHC API errors. I guess we are not tracking these breakages here?

For what it’s worth, here are the errors I couldn’t fix so far: Support GHC 9.10 by TristanCacqueray · Pull Request #262 · awakesecurity/proto3-suite · GitHub . This survival guide is somewhat helpful Exact Print Annotation GHC Changes for GHC 9.10 · GitHub , but not nearly enough to address all the errors in the PR.

Thanks. There’s so much breakage with the GHC API that I’m not making a particular effort to track it, but if you wanted to submit a PR detailing what you found then that would be welcome.

1 Like

Alright, I’ll do that when we get a clean build. For now I found that comparing the failing code using https://hackage.haskell.org/package/ghc-9.6.6 and https://hackage.haskell.org/package/ghc-9.10.1 is good enough to fix most errors. I am down to the following issue which seems a bit more complicated:

src/Proto3/Suite/DotProto/Generate/Syntax.hs:669:39: error: [GHC-83865]
    • Couldn't match type: GhcPass Parsed
                     with: GenLocated SrcSpanAnnN GHC.Types.Name.Reader.RdrName
      Expected: HsMatchContext (LIdP (NoGhcTc (GhcPass Parsed)))
        Actual: HsMatchContext GhcPs
    • In the first argument of ‘mkSimpleMatch’, namely ‘ctxt’

src/Proto3/Suite/DotProto/Generate/Syntax.hs:673:18: error: [GHC-83865]
    • Couldn't match type: GenLocated
                             SrcSpanAnnN GHC.Types.Name.Reader.RdrName
                     with: GhcPass Parsed
      Expected: GhcPs
        Actual: HsName
    • In the ‘mc_fun’ field of a record

On the upside, dealing with these failures is a great way to learn more about GHC :slight_smile:

Are the nixpkgs Haskell’s maintained lists good references?

Oh yes, that’s what we are using, see: Bump GHC from 9.6 to 9.10 by TristanCacqueray · Pull Request #1142 · change-metrics/monocle · GitHub

1 Like

GhcPass Parsed should be RdrName, so you should just need to make it located: RdrName → Located RdrName. e.g. L noAnn name

You can look at my skeletest project on Hackage; I do a lot of these shims between ghc versions