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.
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
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:
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.
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.
It looks like linear-base hasn’t had its bounds bumped for 9.10. I had to use --allow-newer. Is that expected?
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
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).
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).
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?
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.
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