Skip to content

GHC 9.4 regression: derived instance for GADT no longer infers necessary constraints

The syntactic-3.8.4 Hackage library fails to compile with GHC 9.4, whereas it compiled without issue using previous versions of GHC:

[ 1 of 20] Compiling Language.Syntactic.Syntax ( src/Language/Syntactic/Syntax.hs, /home/ryanglscott/Documents/Hacking/Haskell/syntactic-3.8.4/dist-newstyle/build/x86_64-linux/ghc-9.4.2/syntactic-3.8.4/build/Language/Syntactic/Syntax.o, /home/ryanglscott/Documents/Hacking/Haskell/syntactic-3.8.4/dist-newstyle/build/x86_64-linux/ghc-9.4.2/syntactic-3.8.4/build/Language/Syntactic/Syntax.dyn_o )

src/Language/Syntactic/Syntax.hs:207:13: error:
    • No instance for (Functor sym1) arising from a use of ‘fmap’
      Possible fix:
        add (Functor sym1) to the context of
          the type signature for:
            fmap :: forall a b.
                    (a -> b) -> (:+:) sym1 sym2 a -> (:+:) sym1 sym2 b
          or the instance declaration
    • In the first argument of ‘InjL’, namely ‘(fmap f a1)’
      In the expression: InjL (fmap f a1)
      In an equation for ‘fmap’: fmap f (InjL a1) = InjL (fmap f a1)
      When typechecking the code for ‘fmap’
        in a derived instance for ‘Functor (sym1 :+: sym2)’:
        To see the code I am typechecking, use -ddump-deriv
    |
207 |   deriving (Functor, Foldable, Traversable)
    |             ^^^^^^^

src/Language/Syntactic/Syntax.hs:207:13: error:
    • No instance for (Functor sym1) arising from a use of ‘<$’
      Possible fix:
        add (Functor sym1) to the context of
          the type signature for:
            (<$) :: forall a b. a -> (:+:) sym1 sym2 b -> (:+:) sym1 sym2 a
          or the instance declaration
    • In the first argument of ‘InjL’, namely ‘((<$) z a1)’
      In the expression: InjL ((<$) z a1)
      In an equation for ‘<$’: (<$) z (InjL a1) = InjL ((<$) z a1)
      When typechecking the code for ‘<$’
        in a derived instance for ‘Functor (sym1 :+: sym2)’:
        To see the code I am typechecking, use -ddump-deriv
    |
207 |   deriving (Functor, Foldable, Traversable)
    |             ^^^^^^^

src/Language/Syntactic/Syntax.hs:207:22: error:
    • Could not deduce (Foldable sym1) arising from a use of ‘foldMap’
      from the context: Monoid m
        bound by the type signature for:
                   foldMap :: forall m a.
                              Monoid m =>
                              (a -> m) -> (:+:) sym1 sym2 a -> m
        at src/Language/Syntactic/Syntax.hs:207:22-29
      Possible fix:
        add (Foldable sym1) to the context of
          the type signature for:
            foldMap :: forall m a.
                       Monoid m =>
                       (a -> m) -> (:+:) sym1 sym2 a -> m
          or the instance declaration
    • In the expression: foldMap f a1
      In an equation for ‘foldMap’: foldMap f (InjL a1) = foldMap f a1
      When typechecking the code for ‘foldMap’
        in a derived instance for ‘Foldable (sym1 :+: sym2)’:
        To see the code I am typechecking, use -ddump-deriv
      In the instance declaration for ‘Foldable (sym1 :+: sym2)’
    |
207 |   deriving (Functor, Foldable, Traversable)
    |                      ^^^^^^^^

src/Language/Syntactic/Syntax.hs:207:22: error:
    • No instance for (Foldable sym1) arising from a use of ‘foldr’
      Possible fix:
        add (Foldable sym1) to the context of
          the type signature for:
            foldr :: forall a b. (a -> b -> b) -> b -> (:+:) sym1 sym2 a -> b
          or the instance declaration
    • In the expression: foldr f b2 b1
      In the expression: \ b1 b2 -> foldr f b2 b1
      In the expression: (\ b1 b2 -> foldr f b2 b1) a1 z
      When typechecking the code for ‘foldr’
        in a derived instance for ‘Foldable (sym1 :+: sym2)’:
        To see the code I am typechecking, use -ddump-deriv
    |
207 |   deriving (Functor, Foldable, Traversable)
    |                      ^^^^^^^^

src/Language/Syntactic/Syntax.hs:207:22: error:
    • No instance for (Foldable sym1) arising from a use of ‘null’
      Possible fix:
        add (Foldable sym1) to the context of
          the type signature for:
            null :: forall a. (:+:) sym1 sym2 a -> Bool
          or the instance declaration
    • In the expression: null a1
      In an equation for ‘null’: null (InjL a1) = null a1
      When typechecking the code for ‘null’
        in a derived instance for ‘Foldable (sym1 :+: sym2)’:
        To see the code I am typechecking, use -ddump-deriv
      In the instance declaration for ‘Foldable (sym1 :+: sym2)’
    |
207 |   deriving (Functor, Foldable, Traversable)
    |                      ^^^^^^^^

src/Language/Syntactic/Syntax.hs:207:32: error:
    • Could not deduce (Traversable sym1)
        arising from a use of ‘traverse’
      from the context: Applicative f
        bound by the type signature for:
                   traverse :: forall (f :: * -> *) a b.
                               Applicative f =>
                               (a -> f b) -> (:+:) sym1 sym2 a -> f ((:+:) sym1 sym2 b)
        at src/Language/Syntactic/Syntax.hs:207:32-42
      Possible fix:
        add (Traversable sym1) to the context of
          the type signature for:
            traverse :: forall (f :: * -> *) a b.
                        Applicative f =>
                        (a -> f b) -> (:+:) sym1 sym2 a -> f ((:+:) sym1 sym2 b)
          or the instance declaration
    • In the second argument of ‘fmap’, namely ‘(traverse f a1)’
      In the expression: fmap (\ b1 -> InjL b1) (traverse f a1)
      In an equation for ‘traverse’:
          traverse f (InjL a1) = fmap (\ b1 -> InjL b1) (traverse f a1)
      When typechecking the code for ‘traverse’
        in a derived instance for ‘Traversable (sym1 :+: sym2)’:
        To see the code I am typechecking, use -ddump-deriv
    |
207 |   deriving (Functor, Foldable, Traversable)
    |                                ^^^^^^^^^^^

Here is a minimized example of the issue:

{-# LANGUAGE DeriveFunctor #-}
module Bug where

data T1 f a = MkT1 (f a)
  deriving Functor

data T2 f a where
  MkT2 :: f a -> T2 f a
  deriving Functor

With GHC 9.2.4, this typechecks:

$ ghc-9.2.4 Bug.hs -fforce-recomp
[1 of 1] Compiling Bug              ( Bug.hs, Bug.o )

With GHC 9.4.2, the derived instance for T1 typechecks, but the instance for T2 does not:

$ ghc-9.4.2 Bug.hs -fforce-recomp -ddump-deriv
[1 of 1] Compiling Bug              ( Bug.hs, Bug.o )

==================== Derived instances ====================
Derived class instances:
  instance GHC.Base.Functor (Bug.T2 f) where
    GHC.Base.fmap f_aCj (Bug.MkT2 a1_aCk)
      = Bug.MkT2 (GHC.Base.fmap f_aCj a1_aCk)
    (GHC.Base.<$) z_aCl (Bug.MkT2 a1_aCm)
      = Bug.MkT2 ((GHC.Base.<$) z_aCl a1_aCm)
  
  instance GHC.Base.Functor f => GHC.Base.Functor (Bug.T1 f) where
    GHC.Base.fmap f_aCn (Bug.MkT1 a1_aCo)
      = Bug.MkT1 (GHC.Base.fmap f_aCn a1_aCo)
    (GHC.Base.<$) z_aCp (Bug.MkT1 a1_aCq)
      = Bug.MkT1 ((GHC.Base.<$) z_aCp a1_aCq)
  

Derived type family instances:



Bug.hs:9:12: error:
    • No instance for (Functor f) arising from a use of ‘fmap’
      Possible fix:
        add (Functor f) to the context of
          the type signature for:
            fmap :: forall a b. (a -> b) -> T2 f a -> T2 f b
          or the instance declaration
    • In the first argument of ‘MkT2’, namely ‘(fmap f a1)’
      In the expression: MkT2 (fmap f a1)
      In an equation for ‘fmap’: fmap f (MkT2 a1) = MkT2 (fmap f a1)
      When typechecking the code for ‘fmap’
        in a derived instance for ‘Functor (T2 f)’:
        To see the code I am typechecking, use -ddump-deriv
  |
9 |   deriving Functor
  |            ^^^^^^^

Bug.hs:9:12: error:
    • No instance for (Functor f) arising from a use of ‘<$’
      Possible fix:
        add (Functor f) to the context of
          the type signature for:
            (<$) :: forall a b. a -> T2 f b -> T2 f a
          or the instance declaration
    • In the first argument of ‘MkT2’, namely ‘((<$) z a1)’
      In the expression: MkT2 ((<$) z a1)
      In an equation for ‘<$’: (<$) z (MkT2 a1) = MkT2 ((<$) z a1)
      When typechecking the code for ‘<$’
        in a derived instance for ‘Functor (T2 f)’:
        To see the code I am typechecking, use -ddump-deriv
  |
9 |   deriving Functor
  |            ^^^^^^^

As shown in the -ddump-deriv output, the T2 instance is missing a Functor f constraint that is necessary to typecheck. For whatever reason, the T1 instance has this constraint but the T2 instance does not.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information