Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
GHC
GHC
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,264
    • Issues 4,264
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
    • Iterations
  • Merge Requests 419
    • Merge Requests 419
  • Requirements
    • Requirements
    • List
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
  • Security & Compliance
    • Security & Compliance
    • Dependency List
    • License Compliance
  • Operations
    • Operations
    • Incidents
    • Environments
  • Analytics
    • Analytics
    • CI / CD
    • Code Review
    • Insights
    • Issue
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • Glasgow Haskell Compiler
  • GHCGHC
  • Wiki
    • Migration
  • 8.10

Last edited by Ryan Scott Jan 05, 2021
Page history New page

8.10

  • GHC 8.10.x Migration Guide
    • Compiler changes
      • Implicit kind variable changes
      • GHC infers fewer dependent kinds
      • GHC is pickier about impredicative uses of constraints
      • GHC is pickier about inferred type signatures
      • GHC is pickier about requiring language extensions to match on GADT constructors
      • TypeFamilyDependencies may require UndecidableInstances
      • New RecordWildCards warnings
      • Improvements to pattern match checking with user-defined COMPLETE sets
    • Library changes
      • ghc-8.10
        • New hierarchical module structure
      • template-haskell-2.16.0.0
        • Lift changes
        • TupE/UnboxedTupE changes
        • Unary tuple changes

GHC 8.10.x Migration Guide

This guide summarises the changes you may need to make to your code to migrate from GHC 8.8 to GHC 8.10. This guide complements the GHC 8.10.x release notes which should be consulted as well.


Compiler changes

Implicit kind variable changes

GHC 8.10 implements proposal 103, which means that GHC is much less likely to implicitly quantify kind variables than it used to be. Here are some examples of code which will no longer work with GHC 8.10:

  • Kind variables are no longer implicitly quantified when an explicit forall is used at the beginning of a function's type signature. For instance, the following will no longer work:

    {-# LANGUAGE PolyKinds #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    
    f :: forall (a :: k). Proxy a
    f = Proxy
    error: Not in scope: type variable ‘k’
      |
    6 | f :: forall (a :: k). Proxy a
      |                   ^

    This is because k is implicitly quantified in the kind of a. Here are two potential ways to migrate this code:

    1. If you are using GHC 8.0 or later, you can simply quantify k explicitly:

      f :: forall k (a :: k). Proxy a
      f = Proxy

      Note that GHC 8.0, 8.2, and 8.4 require enabling the TypeInType extension in order to do this. On GHC 8.6 or later, however, explicitly quantifying kind variables simply requires the PolyKinds extension.

    2. If you need to support versions of GHC older than 8.0, you may find the following piece of CPP useful:

      #if __GLASGOW_HASKELL__ >= 800
      # define KVS(kvs) kvs
      #else
      # define KVS(kvs)
      #endif
      
      f :: forall KVS(k) (a :: k). Proxy a
      f = Proxy
  • Kind variables are no longer implicitly quantified in data constructor declarations:

    data T a        = T1 (S (a :: k)) | forall (b::k). T2 (S b)  -- no longer accepted
    data T (a :: k) = T1 (S (a :: k)) | forall (b::k). T2 (S b)  -- still accepted

    As the above examples show, code that breaks because of this change can generally be fixed by adding explicit kind signatures to the type variable binders of the data type itself.

  • Implicitly quantified kind variables are no longer put in front of other variables:

    f :: Proxy (a :: k) -> Proxy (b :: j)
    ghci> :t +v f   -- old order:
    f :: forall k j (a :: k) (b :: j). Proxy a -> Proxy b
    
    ghci> :t +v f   -- new order:
    f :: forall k (a :: k) j (b :: j). Proxy a -> Proxy b

    This is a breaking change for users of TypeApplications. If you wish to restore the old order, then explicitly quantify the type variables of f.

  • In type synonyms and type family equations, free variables on the right-hand side are no longer implicitly quantified unless used in an outermost kind annotation:

    type T = Just (Nothing :: Maybe a)         -- no longer accepted
    type T = Just Nothing :: Maybe (Maybe a)   -- still accepted

GHC infers fewer dependent kinds

GHC 8.10 features improvements to its kind inference engine. One downside to this is that it is slightly more conservative about inferring dependent kinds than it used to be. For example, the following example will kind-check on old versions of GHC, but not with GHC 8.10:

{-# LANGUAGE DataKinds, GADTs, PolyKinds, ScopedTypeVariables #-}
module Foo where

import Data.Kind

data T a where
  MkT1 :: T Int
  MkT2 :: T Bool

data ST a :: T a -> Type where
  SMkT1 :: ST Int  MkT1
  SMkT2 :: ST Bool MkT2
Foo.hs:11:20: error:
    • Expected kind ‘T a’, but ‘MkT1’ has kind ‘T Int’
    • In the second argument of ‘ST’, namely ‘MkT1’
      In the type ‘ST Int MkT1’
      In the definition of data constructor ‘SMkT1’
   |
11 |   SMkT1 :: ST Int  MkT1
   |                    ^^^^

To fix this issue in a backwards-compatible way, one can give ST a complete, user-specified kind signature (consult the relevant users' guide section for a more detailed description on what this means). In other words, apply the following change:

-data ST a :: T a -> Type where
+data ST (a :: Type) :: T a -> Type where

GHC is pickier about impredicative uses of constraints

Now that issue #11514 (closed) has been fixed, GHC is more stringent about impredicative uses of constraints. For example, the following program would be accepted on older versions of GHC, but not with GHC 8.10 or later:

foo :: forall a. (Show a => a -> a) -> ()
foo = undefined

foo is impredicative since it attempts to instantiate undefined at type (Show a => a -> a) -> (). This can be fixed by simply adding the necessary wildcard patterns, like so:

foo :: forall a. (Show a => a -> a) -> ()
foo _ = undefined

GHC is pickier about inferred type signatures

GHC now performs more validity checks on inferred type signatures. One consequence of this change is that some programs that used to be accepted will no longer compile without enabling the required language extensions. For example, in these two modules:

{-# LANGUAGE RankNTypes #-}
module A where

foo :: (forall a. a -> a) -> b -> b
foo f x = f x
module B where

import A

bar = foo

Notice that A enables RankNTypes, but B does not. Previous versions of GHC would allow bar to typecheck, even though its inferred type is higher-rank. GHC 8.10 will now reject this, as one must now enable RankNTypes in B to accept the inferred type signature.

GHC is pickier about requiring language extensions to match on GADT constructors

Given this module:

{-# LANGUAGE GADTs #-}
module A where

data T a where
  MkT1 :: (Int ~ a) => T a
  MkT2 :: T Bool

Previous versions of GHC would typecheck this code:

module B where

import A

f :: T Int -> ()
f MkT1 = ()

But not this code:

module C where

import A

f :: T Bool -> ()
f MkT2 = ()
C.hs:6:3: error:
    • A pattern match on a GADT requires the GADTs or TypeFamilies language extension
    • In the pattern: MkT2
      In an equation for ‘f’: f MkT2 = ()
  |
6 | f MkT2 = ()
  |   ^^^^

Note that both MkT1 and MkT2 are GADT constructors, however. GHC 8.10 fixes this inconsistency and now requires enabling GADTs or TypeFamilies on both the B and C examples above.

TypeFamilyDependencies may require UndecidableInstances

Type family dependencies (also known as injective type families) sometimes now need UndecidableInstances in order to be accepted. Here is an example:

type family F1 a = r | r -> a
type family F2 a = r | r -> a
type instance F2 [a] = Maybe (F1 a)

Because GHC needs to look under a type family to see that a is determined by the right-hand side of F2's equation, this now needs UndecidableInstances. The problem is very much akin to its need to detect some functional dependencies.

New RecordWildCards warnings

GHC 8.10 introduces two new flags, -Wunused-record-wildcards and -Wredundant-record-wildcards, which are implied by -Wall. This means that certain programs that use RecordWildCards will trigger warnings that did not do so previously. For instance, the following program emits no warnings on old versions of GHC, but will warn with GHC 8.10:

{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_GHC -Wall #-}

data P = P { x :: Int, y :: Int }

f1 :: P -> Int
f1 P{..} = 1 + 3

f2 :: P -> Int
f2 P{x,y,..} = x + y
Foo.hs:8:6: warning: [-Wunused-record-wildcards]
    No variables bound in the record wildcard match are used
      Possible fix: omit the ‘..’
  |
8 | f1 P{..} = 1 + 3
  |      ^^

Foo.hs:11:10: warning: [-Wredundant-record-wildcards]
    Record wildcard does not bind any new variables
      Possible fix: omit the ‘..’
   |
11 | f2 P{x,y,..} = x + y
   |          ^^

To fix the warnings, simply remove the uses of .., as neither use is necessary.

Improvements to pattern match checking with user-defined COMPLETE sets

Previously, the user guide specified a couple of heuristics to define how pattern match warnings with user-defined COMPLETE sets are handled. Now these heuristics (and surprising behavior such as in #13363 (closed)) are gone and it should "just work". This means that potentially more and more accurate warnings are generated, which might lead to compilation errors with -Werror.

An example from the wild is this catch-all match which is now correctly flagged as redundant, because Con', App and Fun form a COMPLETE set.

Deletion of redundant matches should always get rid of the warning without introducing new inexhaustiveness warnings (or, worse, introducing inexhaustiveness crashes at runtime without producing a warning).

Apart from that, redundancy checking around pattern guards improved, all while the performance of the checker increased.


Library changes

ghc-8.10

New hierarchical module structure

TODO: Mention https://gitlab.haskell.org/ghc/ghc/wikis/module-dependencies/hierarchical

template-haskell-2.16.0.0

Lift changes

The Lift class features a new method liftTyped :: t -> Q (TExp t). To facilitate making it easier to define implementations of lift in terms of liftTyped, the default implementation of lift has been changed. Before, the default implementation used the Data type class:

  default lift :: Data t => t -> Q Exp
  lift = liftData

The new default implementation is in terms of liftTyped:

  default lift :: (r ~ 'LiftedRep) => t -> Q Exp
  lift = unTypeQ . liftTyped

This will affect any Lift instance that does not explicitly define lift. There are two ways to adapt to this change:

  1. Derive the Lift instance using the DeriveLift extension, which has been available since GHC 8.0.
  2. Explicitly define liftTyped, guarding it with #if MIN_VERSION_template_haskell(2,16,0) ... #endif if you want to preserve backwards compatibility with older versions of template-haskell.

TupE/UnboxedTupE changes

The types of the TupE and UnboxedTupE constructors have changed:

 data Exp
   = ...
-  | TupE        [Exp]
-  | UnboxedTupE [Exp]
+  | TupE        [Maybe Exp]
+  | UnboxedTypE [Maybe Exp]

This is because TupE and UnboxedTupE are now capable of handling tuple sections. For example, (1,) is represented with TupE [Just (LitE (IntegerL 1)), Nothing] as an Exp.

Unary tuple changes

Using TupleT 1, TupE [exp], or TupP [pat] will now produce unary tuples (i.e., involving the Unit type from GHC.Tuple) instead of silently dropping the parentheses. This brings Template Haskell's treatment of boxed tuples in line with that of unboxed tuples, as UnboxedTupleT, UnboxedTupE, and UnboxedTupP also produce unary unboxed tuples (i.e., Unit#) when applied to only one argument.

Clone repository

GHC Home
GHC User's Guide

Joining In

Newcomers info
Mailing Lists & IRC
The GHC Team

Documentation

GHC Status Info
Working conventions
Building Guide
Debugging
Commentary

Wiki

Title Index
Recent Changes