Skip to content

coerce error when role is nominal could be more explicit

Motivation

If a type Foo a have a type parameter a with role nominal, it's not possible to coerce it to Foo b, even if a and b are Coercible. That's the definition of the role system.

However, the error message associated with it are not helpful.

For example, consider the following example:

{-# LANGUAGE RoleAnnotations #-}
import Data.Monoid (Sum(..))
import Data.Coerce (coerce)

type role Foo nominal
data Foo a = Foo a
  deriving (Ord, Eq)

foo :: Foo Int
foo = coerce (Foo (10 :: Sum Int))

With ghc 9.6, it fails with:

GHCi, version 9.6.2: https://www.haskell.org/ghc/  :? for help
[1 of 2] Compiling Main             ( V.hs, interpreted )

V.hs:20:8: error: [GHC-18872]
    • Couldn't match type ‘Sum Int’ with ‘Int’
        arising from a use of ‘coerce’
    • In the expression: coerce (Foo (10 :: Sum Int))
      In an equation for ‘foo'’: foo' = coerce (Foo (10 :: Sum Int))
   |
20 | foo' = coerce (Foo (10 :: Sum Int))

Removes the type role annotations, and that's fine. Note how the error message does not reference the role system, or representational or nominal at all. It does not reference Foo at all, even if the problem is actually not with matching the type Sum Int and Int. Even the wording match is confusing.

Here is a second example, which is actually the real life example which annoyed me recently. In vector latest version, Data.Vector.Storable role annotation changed to nominal, hence it is not possible anymore to coerce between two Vector.

{-# LANGUAGE RoleAnnotations #-}
import Data.Monoid (Sum(..))
import Data.Coerce (coerce)
import Data.Vector.Storable

foo :: Vector (Sum Int)
foo = coerce (empty :: Vector Int)

However, the error message:

GHCi, version 9.6.2: https://www.haskell.org/ghc/  :? for help
[1 of 2] Compiling Main             ( V.hs, interpreted )

V.hs:7:7: error: [GHC-18872]
    • Couldn't match type ‘Int’ with ‘Sum Int’
        arising from a use of ‘coerce’
    • In the expression: coerce (empty :: Vector Int)
      In an equation for ‘foo’: foo = coerce (empty :: Vector Int)
  |
7 | foo = coerce (empty :: Vector Int)

Does not give any clue about the root cause for the problem. See, here, no notion of role or Vector. This was particularly vicious for me because when bumping from GHC 9.6.1 to 9.6.2, I got the vector version bump at the same time and got this error message on multiples places in my codebase.

Note that GHC is correct with the error, just that the wording can be improved with more context.

Proposal

I suggest to improve the wording to at least include a reference to coerce, the role annotation, nominal, and pointing at the Vector type. For example, I'll be happy with:

GHCi, version 9.6.2: https://www.haskell.org/ghc/  :? for help
[1 of 2] Compiling Main             ( V.hs, interpreted )

V.hs:7:7: error: [GHC-18872]
    • Couldn't coerce type `Vector Int` with `Vector (Sum Int)`
        arising from a use of ‘coerce’ because of role annotation `type role Vector nominal`.
    • In the expression: coerce (empty :: Vector Int)
      In an equation for ‘foo’: foo = coerce (empty :: Vector Int)
  |
7 | foo = coerce (empty :: Vector Int)
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information