
GHC 9.0.x Migration Guide

Compiler changes
 Simplified subsumption
 Whitespacesensitive !, ~, @, and $
 The order of TH splices is more important
 Overloaded Quotation Brackets
 Typed TH quotes and splices have different types
 Type variable order in toplevel field selectors
 More validity checking in quantified constraints
 Eager instantiation
 GHC is pickier about nested foralls and contexts in GADT constructors
 GHC is pickier about nested foralls and contexts in instance and deriving declarations
 Improved PatternMatch Coverage checker
 I/O manager (WinIO) related changes
 Library changes

Compiler changes
GHC 9.0.x Migration Guide
This guide summarises the changes you may need to make to your code to migrate from GHC 8.10 to GHC 9.0. This guide complements the GHC 9.0.x release notes which should be consulted as well.
Compiler changes
Simplified subsumption
GHC now implements simplified subsumption, as described in GHC Proposal #287. This change simplifies the type system, and prevents the possiblity of GHC silently changing the semantics of user programs, but it does mean that some libraries may need etaexpansion to typecheck. Here are some examples of specific programs that will no longer work under simplified subsumption and how they can be repaired in a backwardscompatible manner:
Deep skolemisation
Given these definitions:
f :: forall a b. a > b > b
g :: (forall p. p > forall q. q > q) > Int
Previous versions of GHC would typecheck the following:
h :: Int
h = g f
This relies on deep skolemisation, which no longer exists under simplified subsumption. As a result, GHC 9.0 will reject h
:
error:
• Couldn't match type: b0 > b0
with: forall q. q > q
Expected: p > forall q. q > q
Actual: p > b0 > b0
• In the first argument of ‘g’, namely ‘f’
In the expression: g f
In an equation for ‘h’: h = g f

 h = g f
 ^
To make h
work under simplified subsumption, eta expand the argument to g
:
h :: Int
h = g (\x > f x)
The above example uses higherrank forall
s, but a similar scenario exists with higherrank contexts as well. Given these definitions:
f' :: (Eq a, Eq b) => a > b > b
g' :: (Eq p => p > Eq q => q > q) > Int
Previous versions of GHC would typecheck the following:
h' :: Int
h' = g' f'
Again, this relies on deep skolemisation. As a result, GHC 9.0 will reject h'
:
error:
• Couldn't match kind ‘Constraint’ with ‘*’
When matching types
q0 > q0 :: *
Eq q0 :: Constraint
Expected: p0 > Eq q0 => q0 > q0
Actual: p0 > (q0 > q0) > q0 > q0
• In the first argument of ‘g'’, namely ‘f'’
In the expression: g' f'
In an equation for ‘h'’: h' = g' f'

 h' = g' f'
 ^^
h'
can also be repaired with manual eta expansion:
h' :: Int
h' = g' (\x > f' x)
Given that the situation with higherrank contexts mirrors that of higherrank forall
s so closely, we will only provide examples involving higherrank forall
s from here on out.
Deep instantiation
Given this definition:
f :: Int > forall a. a > a
f _ x = x
Previous versions of GHC would typecheck the following:
g :: b > Int > a > a
g x = f
This requires deeply instantiating the type of f
. Simplified subsumption gets rid of deep instantiation, however, so g
will not typecheck on GHC 9.0:
error:
• Couldn't match type: forall a1. a1 > a1
with: a > a
Expected: Int > a > a
Actual: Int > forall a. a > a
• In the expression: f
In an equation for ‘g’: g x = f
• Relevant bindings include
g :: b > Int > a > a (bound at Bug.hs:8:1)

 g x = f
 ^
There are two possible ways to migrate this code:

Change the type of
g
to have a nestedforall
:g :: b > Int > forall a. a > a g x = f

Eta expand
g
:g :: b > Int > a > a g x y = f y
Contravariance/covariance of function arrows
Given these definitions:
f :: (Bool > Bool) > Char
g :: ((forall a. a > a) > Char) > Int
Previous versions of GHC would typecheck the following:
h :: Int
h = g f
This is because GHC's subtyping rules supported contravariance in function arrows, which is something that simplified subsumption removes. As a result, h
will not typecheck on GHC 9.0:
error:
• Couldn't match type: Bool > Bool
with: forall a. a > a
Expected: (forall a. a > a) > Char
Actual: (Bool > Bool) > Char
• In the first argument of ‘g’, namely ‘f’
In the expression: g f
In an equation for ‘h’: h = g f

 h = g f
 ^
h
can be repaired with manual eta expansion:
h :: Int
h = g (\x > f x)
Just as simplified subsumption removes contravariance in function arrows, it also removes covariance in function arrows. In concrete terms, h'
below will no longer typecheck:
f' :: Char > forall a. a > a
g' :: (Char > Bool > Bool) > Int
h' :: Int
h' = g' f'
error:
• Couldn't match type: forall a. a > a
with: Bool > Bool
Expected: Char > Bool > Bool
Actual: Char > forall a. a > a
• In the first argument of ‘g'’, namely ‘f'’
In the expression: g' f'
In an equation for ‘h'’: h' = g' f'

 h' = g' f'
 ^^
Once again, h'
can be repaired with manual eta expansion:
h' :: Int
h' = g' (\x > f' x)
!
, ~
, @
, and $
Whitespacesensitive GHC 9.0 implements Proposal 229, which means that the !
, ~
, and @
characters are more sensitive to preceding and trailing whitespace than they were before. As a result, some things which used to parse one way will now parse differently (or throw a parse error). Here are some particular scenarios that you may encounter:

f ~ x = x
 Before: function named
f
with a lazy (irrefutable) pattern on its argumentx
 After: After: infix function named
(~)
To restore the old behavior, remove the trailing whitespace after
~
, like so:f ~x = x
 Before: function named

f @ x = y
 Before: value binding that binds both
f
andx
toy
using an aspattern  After: infix function named
(@)
To restore the old behavior, remove the leading and trailing whitespace around
@
, like so:f@x = x
 Before: value binding that binds both

f ! x = x
 Before: function named
f
with a bang pattern on its argumentx
 After: infix function named
(!)
To restore the old behavior, remove the trailing whitespace after
!
, like so:f !x = x
 Before: function named

f = g @ True
 Before: visible type application
 After: application of the infix function
(@)
tog
andTrue
To restore the old behavior, remove the trailing whitespace after
@
, like so:f = g @True

f = ($x)
 Before: operator section that applies the infix function
($)
to the argumentx
 After: Template Haskell splice that splices in
x :: Q Exp
To restore the old behavior, add a space between
$
andx
, like so:f = ($ x)
 Before: operator section that applies the infix function

f = (!x)

Before: operator section that applies the infix function
(!)
to the argumentx

After: parse error:
error: Bang pattern in expression context: !x Did you mean to add a space after the '!'?
As the parse error suggests, the old behavior can be restored by instead writing:
f = (! x)


data T = MkT ! Int

Before: data constructor
MkT
with a strictInt
field 
After: parse error:
error: Not a data constructor: ‘!’
To restore the old behavior, remove the trailing whitespace after
!
, like so:data T = MkT !Int

The order of TH splices is more important
GHC's constraint solver now solves constraints in each toplevel group sooner. This has practical consequences for Template Haskell, as TH splices necessarily separate toplevel groups. For example, the following program would compile in previous versions of GHC, but not in GHC 9.0:
data T = MkT
tStr :: String
tStr = show MkT
$(return [])
instance Show T where
show MkT = "MkT"
This is because each toplevel group's constraints are solved before moving on to the next, and since the toplevel group for tStr
appears before the toplevel group that defines a Show T
instance, GHC 9.0 will throw an error about a missing Show T
instance in the expression show MkT
. The issue can be fixed by rearranging the order of declarations. For instance, the following will compile:
data T = MkT
instance Show T where
show MkT = "MkT"
$(return [])
tStr :: String
tStr = show MkT
Overloaded Quotation Brackets
GHC 9.0 implements Proposal 246, which means that the type of expression quotation brackets is now generalised from Q Exp
to Quote m => m Exp
. All other forms of quotation are similarly generalised. There are two main breaking changes as a result:

Toplevel unannotated quotations now fail to typecheck due to the monomorphism restriction:
x = [ 5 ]
Fix: Provide a type signature for
x
or enableNoMonomorphismRestriction
. 
Methods of the
Lift
typeclass are restricted fromQ
to only using methods fromQuote
. The definition ofLift
is now:class Lift (t :: TYPE r) where lift :: Quote m => t > m Exp liftTyped :: Quote m => t > m (TExp t)
If you have manually defined instances for
Lift
then it might be necessary to rewrite some type signatures in terms of the more restrictedQuote
interface. In our testing so far we've not found anyLift
instances relying on any special methods ofQ
.Another solution is to use the
DeriveLift
extension rather than manually defining the instance.
You may consider using the thcompat
library if you wish to write backwardscompatible code that uses the Quote
type class.
Typed TH quotes and splices have different types
GHC 9.0 implements Proposal 195, which means that typed Template Haskell now uses a Code
newtype:
newtype Code m a = Code { examineCode :: m (TExp a) }
In particular, Code
is now used in the following places:
 In a typed TH quote, such as
[ ... ]
, if the...
expression has typea
, then the quotation has typeQuote m => Code m a
. (Previously, it would have had typeQ (TExp a)
.)  In a typed TH splice, such as
$$(...)
, the...
expression must have typeCode Q a
for somea
. (Previously, it must have had typeQ (TExp a)
.)
You may consider using the thcompat
library if you wish to write backwardscompatible typed TH code involving Code
.
Type variable order in toplevel field selectors
Previous versions of GHC did not specify the order or specificity of type variables in the types of toplevel field selectors. GHC 9.0 does specify this, which can impact users of TypeApplications
. For example, given the following definitions:
{# LANGUAGE PolyKinds #}
newtype P a = MkP { unP :: Proxy a }
newtype N :: Type > Type > Type where
MkN :: forall b a. { unN :: Either a b } > N a b
Previous versions of GHC would give the following types to unP
and unN
:
unP :: forall k (a :: k). P a > Proxy a
unN :: forall a b. N a b > Either a b
GHC will now give them the following types instead: ::
unP :: forall {k} (a :: k). P a > Proxy a
unN :: forall b a. N a b > Either a b
More validity checking in quantified constraints
GHC now performs more validity checks on quantified constraints, meaning that some code will require enabling language extensions that were not previously required. As one example, this code will compile on previous versions of GHC:
{# LANGUAGE QuantifiedConstraints #}
{# LANGUAGE TypeFamilies #}
data family F a
f :: (forall a. Show (F a)) => Int
f = 42
However, it will be rejected with GHC 9.0:
error:
• Non typevariable argument in the constraint: Show (F a)
(Use FlexibleContexts to permit this)
• In the quantified constraint ‘forall a. Show (F a)’
In the type signature: f :: (forall a. Show (F a)) => Int

7  f :: (forall a. Show (F a)) => Int
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Eager instantiation
GHC now consistently does eager instantiation during type inference. As a consequence, visible type application (VTA) now only works when the head of the application is:
 A variable
 An expression with a type signature
For example (let x = blah in id) @Bool True
no longer typechecks. You should write let x = blah in id @Bool True
instead.
forall
s and contexts in GADT constructors
GHC is pickier about nested GHC has a rule that GADT constructors cannot contain nested forall
s or contexts in GADT constructors. This was always true in previous released, but GHC 9.0 enforces this rule more strictly. In particular, nested forall
s or contexts that occur underneath parentheses are now rejected. This means the following examples will no longer compile on GHC 9.0:
data S a where
MkS :: (forall a. S a)
data U a where
MkU :: (Show a => U a)
forall
s and contexts in instance and deriving
declarations
GHC is pickier about nested Much like GHC does not permit nested forall
s or contexts in GADT constructors, it also does not permit them in the types at the tops of instance declarations. GHC also enforces this more strictly in 9.0, so the following examples will no longer compile:
instance (forall a. C a) where ...
instance (Show a => C a) where ...
A similar nonestedforall
s rule applies to types involved in deriving
clauses and via
types (for instances derived with DerivingVia
). The following examples will also be rejected with GHC 9.0:
data T = MkT deriving (C1, (forall x. C2 x))
deriving via (forall x. V x) instance C (S x)
Improved PatternMatch Coverage checker
The coverage checker will now detect more redundant cases, in particular wrt. long distance information.
If for some reason (like bitrot prevention of a debugonly case branch) a redundant or inaccessible righthand side is not to be flagged, a guard like  GHC.Magic.lazy False
should prevent the checker from flagging it as such.
I/O manager (WinIO) related changes
If internal GHC I/O primitives were used you may need to manually add support for WINIO. GHC now emits new preprocessor macros
__IO_MANAGER_WINIO__
which can be used to determine whether you are compiling with a compiler that is winio
aware.
The compiler also exposes a helper function (<!>)
which can be used to select between the WINIO and Posix implementation of a function. An example usage:
#if defined(__IO_MANAGER_WINIO__)
import GHC.IO.Handle.Windows (handleToHANDLE)
import GHC.IO.SubSystem ((<!>))
#endif
to import the required changes. These can be used as
withHandleToHANDLE :: Handle > (HANDLE > IO a) > IO a
withHandleToHANDLE haskell_handle action =
#if defined(__IO_MANAGER_WINIO__)
withHandleToHANDLE = withHandleToHANDLEPosix <!> withHandleToHANDLENative
#else
withHandleToHANDLE = withHandleToHANDLEPosix
#endif
The Win32
package exposes helpers that can be used to aid in supporting WINIO porting.
Library changes
base4.15.*
The unsafeCoerce#
function has been moved from GHC.Prim
to Unsafe.Coerce
. As a result, attempting to import unsafeCoerce#
from GHC.Prim
(or GHC.Base
, which previously reexported unsafeCoerce#
) will result in an error with GHC 9.0. A backwardscompatible way to fix the error is to import unsafeCoerce#
from GHC.Exts
instead.
ghc9.0.*
The meaning of the hs_fixds
field of HsGroup
has changed slightly. It now only contains fixity signatures defined for toplevel declarations and class methods defined outside of the class itself. Previously, hs_fixds
would also contain fixity signatures for class methods defined inside the class, such as the fixity signature for m
in the following example: ::
class C a where
infixl 4 `m`
m :: a > a > a
If you wish to attain the previous behavior of hs_fixds
, use the new hsGroupTopLevelFixitySigs
function, which collects all toplevel fixity signatures, including those for class methods defined inside classes.
ghcprim0.7.*
The Unit
data type from GHC.Tuple
has been renamed to Solo
, per #14673/#18099 (closed).
integergmp1.1
/ integersimple
/ ghcbignum1.0
integersimple
package has been removed, use ghcbignum
built with native
backend instead.
integergmp1.1
package is provided for backward compatibility but now it is based on ghcbignum
. As a consequence packages depending on integergmp
:
 to use
Integer
's constructors (S#
,Jn#
,Jp#
): should continue to work as before, whatever backend is used byghcbignum
(i.e. even if it's notgmp
).  to use functions from
GHC.Integer
: don't need to depend on it anymore asGHC.Integer
is now inbase
.  to use GMP specific functions (prime test, secure powmod, etc.): should use another package providing these functions (e.g. hgmp).
ghcbignum
only exposes functions provided by all of its backends.
templatehaskell2.17.*
GHC now exports explicit specificity in type variable binders, which means that one can now define type variables that are not eligible for visible type application (also known as inferred type variables). Example:
id1 :: forall a. a > a  Here, the `a` is specified
id1 x = x
ex1 = id1 @Int 42  Typechecks. The `a` in `forall a`
 is eligible for visible type application.
id2 :: forall {a}. a > a  Here, the `a` is inferred
id2 x = x
ex1 = id2 @Int 42  Does not typecheck. The `a` in `forall {a}`
 is not eligible for visible type application.
As a result, the TyVarBndr
data type in templatehaskell
is now parameterized by a flag
type parameter:
data TyVarBndr flag = PlainTV Name flag  ^ @a@
 KindedTV Name flag Kind  ^ @(a :: k)@
There are two primary ways of instantiating flag
:

With
Specificity
:data Specificity = SpecifiedSpec  ^ @a@. Eligible for visible type application.  InferredSpec  ^ @{a}@. Not eligible for visible type application.
This corresponds to type variable binders that can be marked as specified or inferred, such as in invisible
forall
s:data Type = ForallT [TyVarBndr Specificity] Cxt Type  ...
Note that
templatehaskell
defines theTyVarBndrSpec
type synonym as a convenient alias forTyVarBndr Specificity
. 
With
()
. This corresponds to type variable binders where the notion of specified versus inferred is not meaningful. For example, this is used in type synonyms:data TySynEqn = TySynEqn (Maybe [TyVarBndr ()]) Type Type
Note that
templatehaskell
defines theTyVarBndrUnit
type synonym as a convenient alias forTyVarBndr ()
. Also note that theplainTV
andkindedTV
functions fromLanguage.Haskell.TH.Lib
now returnTyVarBndr ()
.
If you wish to write backwardscompatible code involving TyVarBndr
s, you may consider using the Language.Haskell.TH.Datatype.TyVarBndr
module from the thabstraction
library.