DerivingVia fails to roundtrip through TH
The following programs works on GHC HEAD, as expected:
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
module Bug where
newtype List a = MkList [a]
deriving via forall a. [a] instance Eq a => Eq (List a)
However, if you declare the standalone-derived instance using Template Haskell quotes:
$([d| deriving via forall a. [a] instance Eq a => Eq (List a) |])
Then it fails to typecheck:
[1 of 1] Compiling Bug ( Bug.hs, interpreted )
Bug.hs:8:2: error:
• Couldn't match representation of type ‘a’ with that of ‘a1’
arising from a use of ‘GHC.Prim.coerce’
‘a’ is a rigid type variable bound by
the instance declaration
at Bug.hs:8:2-65
‘a1’ is a rigid type variable bound by
the instance declaration
at Bug.hs:8:2-65
• In the expression:
GHC.Prim.coerce
@([] a_a3ek -> [] a_a3ek -> Bool) @(List a -> List a -> Bool)
((==) @([] a_a3ek))
In an equation for ‘==’:
(==)
= GHC.Prim.coerce
@([] a_a3ek -> [] a_a3ek -> Bool) @(List a -> List a -> Bool)
((==) @([] a_a3ek))
When typechecking the code for ‘==’
in a derived instance for ‘Eq (List a)’:
To see the code I am typechecking, use -ddump-deriv
In the instance declaration for ‘Eq (List a)’
• Relevant bindings include
(==) :: List a -> List a -> Bool (bound at Bug.hs:8:2)
|
8 | $([d| deriving via forall a. [a] instance Eq a => Eq (List a) |])
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Bug.hs:8:2: error:
• Couldn't match representation of type ‘a’ with that of ‘a1’
arising from a use of ‘GHC.Prim.coerce’
‘a’ is a rigid type variable bound by
the instance declaration
at Bug.hs:8:2-65
‘a1’ is a rigid type variable bound by
the instance declaration
at Bug.hs:8:2-65
• In the expression:
GHC.Prim.coerce
@([] a_a3ek -> [] a_a3ek -> Bool) @(List a -> List a -> Bool)
((/=) @([] a_a3ek))
In an equation for ‘/=’:
(/=)
= GHC.Prim.coerce
@([] a_a3ek -> [] a_a3ek -> Bool) @(List a -> List a -> Bool)
((/=) @([] a_a3ek))
When typechecking the code for ‘/=’
in a derived instance for ‘Eq (List a)’:
To see the code I am typechecking, use -ddump-deriv
In the instance declaration for ‘Eq (List a)’
• Relevant bindings include
(/=) :: List a -> List a -> Bool (bound at Bug.hs:8:2)
|
8 | $([d| deriving via forall a. [a] instance Eq a => Eq (List a) |])
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Eek. What went wrong? -ddump-splices
reveals the answer:
[1 of 1] Compiling Bug ( Bug.hs, interpreted )
Bug.hs:8:2-65: Splicing declarations
[d| deriving via forall a_a3g8. [a_a3g8] instance Eq a_a3g8 =>
Eq (List a_a3g8) |]
======>
deriving via forall a_a3gW. [a_a3gW] instance Eq a_a3g8 =>
Eq (List a_a3g8)
By the time the declaration has been spliced in, the a
in the [a]
part is no longer the same a
as in the Eq a => Eq (List a)
part. Crucially, these must be the same in order for this instance to work.