Data Constructor promotion in GHC-7.6

I had this code:

class SymbolSet tpe where
  data Symbol tpe :: *

data SSet tpe where
  Identity :: tpe -> SSet tpe
  And :: SSet tpe -> Symbol tpe -> SSet tpe

class HasElem a b where

instance (SymbolSet tpe) => HasElem (And (Identity tpe) s) s
instance (HasElem sset s) => HasElem (And sset s) s

which was compiling in GHC-7.4. However on moving to GHC-7.6 it started giving compilation errors:

'And' of tpe `forall tpe. tpe -> Symbol * tpe -> SSet tpe' is not promotable

on digging through the docs, I found a new clause added to "Datatype Promotion" pages in GHC-7.6 vs GHC-7.4

We do not promote datatypes whose constructors are kind polymorphic, involve constraints, or use existential quantification.

My question is:

  1. What is the rationale behind not promoting such constructors?
  2. What would be the correct way of doing it?

You didn't say which version of GHC 7.6 you were using or include which extensions you have on, so I'm guessing a bit.

This ticket seems to answer your question 1, although I don't totally understand the problem myself. In your particular example, I think SSet isn't promotable because one of its arguments (Symbol tpe) is an associated type which brings with it the SymbolSet constraint.

If I move Symbol out of the class we get the type promoted, however now we get kind mismatch errors:

{-# LANGUAGE DataKinds , TypeFamilies , GADTs , MultiParamTypeClasses #-}
class SymbolSet tpe where
  -- data Symbol tpe :: *
data Symbol tpe :: *
-- ...

I can get the whole shebang to compile by adding kind signatures to HasElem:

{-# LANGUAGE DataKinds , TypeFamilies , GADTs , MultiParamTypeClasses, FlexibleInstances  #-}
class SymbolSet tpe where
-- MOVED OUT OF CLASS:
data Symbol tpe :: *

data SSet tpe where
  Identity :: tpe -> SSet tpe
  And :: SSet tpe -> Symbol tpe -> SSet tpe

-- ADDED KIND SIGNATURES:
class HasElem (a :: SSet *) (b :: Symbol *) where

instance (SymbolSet tpe) => HasElem (And (Identity tpe) s) s
instance (HasElem sset s) => HasElem (And sset s) s

I don't really understand your code so that may not work for you.