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

10 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

3 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