Skip to content

-ddump-deriv doesn't display promoted data constructors correctly

This is a very minor bug that only affects the pretty-printed output of -ddump-deriv. Here is one way to tickle the bug:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# OPTIONS_GHC -ddump-deriv #-}
module Bug where

data T (a :: ()) = MkT
class C a where
  m :: a
instance C (T a) where
  m = MkT

newtype T2 = MkT2 (T '()) deriving C
$ /opt/ghc/8.10.1/bin/ghc Bug.hs
[1 of 1] Compiling Bug              ( Bug.hs, Bug.o )

==================== Derived instances ====================
Derived class instances:
  instance Bug.C Bug.T2 where
    Bug.m
      = GHC.Prim.coerce @(Bug.T ()) @Bug.T2 (Bug.m @(Bug.T ())) :: Bug.T2
  

Derived type family instances:

Notice that in the original source, MkT2's field has type T '(), but in the -ddump-deriv output, it displays T (), which does not add a leading tick in front of the promoted unary tuple data constructor.

The culprit is the use of nlHsTyVar in GHC.Hs.Utils.typeToLHsType, which harcodes NotPromoted:

nlHsTyVar x   = noLoc (HsTyVar noExtField NotPromoted (noLoc x))

This assumption works for most use cases, but not in typeToLHsType, which has to deal with promoted data constructors. Rather than use nlHsTyVar, I think we should do something closer to what Haddock does:

      -- Most TyCons:
      | otherwise
      = mk_app_tys (HsTyVar noExtField prom $ noLoc (getName tc))
                   vis_tys
      where
        prom = if isPromotedDataCon tc then IsPromoted else NotPromoted

Patch incoming.

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