{-
Note [Promoting a Type to a Kind]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Suppsoe we have a data constructor D
     D :: forall (a:*). Maybe a -> T a
We promote this to be a type constructor 'D:
     'D :: forall (k:BOX). 'Maybe k -> 'T k

The transformation from type to kind is done by promoteType

  * Convert forall (a:*) to forall (k:BOX), and substitute

  * Ensure all foralls are at the top (no higher rank stuff)

  * Ensure that all type constructors mentioned (Maybe and T
    in the example) are promotable; that is, they have kind
          * -> ... -> * -> *
-}

-- | Promotes a type to a kind.
-- Assumes the argument satisfies 'isPromotableType'
promoteType :: Type -> Kind
promoteType ty
  = mkForAllTys kvs (go rho)
  where
    (tvs, rho) = splitForAllTys ty
    kvs = [ mkKindVar (tyVarName tv) superKind | tv <- tvs ]
    env = zipVarEnv tvs kvs

    go (TyConApp tc tys) | Just prom_tc <- promotableTyCon_maybe tc
                         = mkTyConApp prom_tc (map go tys)
    go (FunTy arg res)   = mkArrowKind (go arg) (go res)
    go (TyVarTy tv)      | Just kv <- lookupVarEnv env tv
                         = TyVarTy kv
    go _ = panic "promoteType"  -- Argument did not satisfy isPromotableType
promoteType :: Type -> Kind
promoteType ty
  = mkForAllTys kvs (go rho)
  where
    (tvs, rho) = splitForAllTys ty
    kvs = [ mkKindVar (tyVarName tv) superKind | tv <- tvs ]
    env = zipVarEnv tvs kvs

    go (TyConApp tc tys) | Just prom_tc <- promotableTyCon_maybe tc
                         = mkTyConApp prom_tc (map go tys)
    go (FunTy arg res)   = mkArrowKind (go arg) (go res)
    go (TyVarTy tv)      | Just kv <- lookupVarEnv env tv
                         = TyVarTy kv
    go _ = panic "promoteType"  -- Argument did not satisfy isPromotableType
promoteType ty
  = mkForAllTys kvs (go rho)
  where
    (tvs, rho) = splitForAllTys ty
    kvs = [ mkKindVar (tyVarName tv) superKind | tv <- tvs ]
    env = zipVarEnv tvs kvs

    go (TyConApp tc tys) | Just prom_tc <- promotableTyCon_maybe tc
                         = mkTyConApp prom_tc (map go tys)
    go (FunTy arg res)   = mkArrowKind (go arg) (go res)
    go (TyVarTy tv)      | Just kv <- lookupVarEnv env tv
                         = TyVarTy kv
    go _ = panic "promoteType"  -- Argument did not satisfy isPromotableType