Skip to content

ghc-8.10 regression: function against record with many fields makes time to compile (noticed on protocol-buffers-descriptor-2.4.13)

Here is the self-contained example extracted from protocol-buffers-descriptor-2.4.13:

{-# OPTIONS_GHC -O1 -Wall #-}


{-

   $ time ghc-8.8 -c A.hs
   0.2s
   $ time ghc-8.10.2 -c A.hs
   <too long to wait>
   $ time ghc-8.10.3 -c A.hs
   <too long to wait>
-}

module FileOptions (FileOptions(..)) where

import Prelude (Bool(..), Maybe(..))

class Mergeable a where
  mergeAppend :: a -> a -> a
  mergeAppend _a b = b

instance Mergeable a => Mergeable (Maybe a) where
    mergeAppend = mayMerge

mayMerge :: (Mergeable b) => Maybe b -> Maybe b -> Maybe b
mayMerge Nothing  y        = y
mayMerge x        Nothing  = x
mayMerge (Just x) (Just y) = Just (mergeAppend x y)

instance Mergeable Bool

data FileOptions = FileOptions
   { f1 :: !(Maybe Bool)
   , f2 :: !(Maybe Bool)
   , f3 :: !(Maybe Bool)
   , f4 :: !(Maybe Bool)
   , f5 :: !(Maybe Bool)
   , f6 :: !(Maybe Bool)
   , f7 :: !(Maybe Bool)
   , f8 :: !(Maybe Bool)
   , f9 :: !(Maybe Bool)
   -- adding more of these makes ghc slower and slower to compile example
   , fA :: !(Maybe Bool)
}

instance Mergeable FileOptions where
  mergeAppend (FileOptions x1 x2 x3 x4 x5 x6 x7 x8 x9 xA)
              (FileOptions y1 y2 y3 y4 y5 y6 y7 y8 y9 yA)
   = FileOptions
      (mergeAppend x1 y1)
      (mergeAppend x2 y2)
      (mergeAppend x3 y3)
      (mergeAppend x4 y4)
      (mergeAppend x5 y5)
      (mergeAppend x6 y6)
      (mergeAppend x7 y7)
      (mergeAppend x8 y8)
      (mergeAppend x9 y9)
      (mergeAppend xA yA)

Running:

$ time ghc-8.8 -c A.hs
0.2s
$ time ghc-8.10.2 -c A.hs
<too long to wait>

Environment

  • GHC version used: ghc-8.8.4

Optional:

  • Operating System: Linux
  • System Architecture: amd64
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information