%
% (c) The University of Glasgow 2006
%
\begin{code}
module Kind (
Kind, typeKind,
anyKind, liftedTypeKind, unliftedTypeKind, openTypeKind,
argTypeKind, ubxTupleKind, constraintKind,
mkArrowKind, mkArrowKinds,
anyKindTyCon, liftedTypeKindTyCon, openTypeKindTyCon,
unliftedTypeKindTyCon, argTypeKindTyCon, ubxTupleKindTyCon,
constraintKindTyCon,
tySuperKind, tySuperKindTyCon,
pprKind, pprParendKind,
kindFunResult, kindAppResult, synTyConResKind,
splitKindFunTys, splitKindFunTysN, splitKindFunTy_maybe,
isLiftedTypeKind, isUnliftedTypeKind, isOpenTypeKind,
isUbxTupleKind, isArgTypeKind, isConstraintKind,
isConstraintOrLiftedKind, isKind,
isSuperKind, noHashInKind,
isLiftedTypeKindCon, isConstraintKindCon,
isAnyKind, isAnyKindCon,
isSubArgTypeKind, tcIsSubArgTypeKind,
isSubOpenTypeKind, tcIsSubOpenTypeKind,
isSubKind, tcIsSubKind, defaultKind,
isSubKindCon, tcIsSubKindCon, isSubOpenTypeKindCon,
isKiVar, splitKiTyVars, partitionKiTyVars,
kiVarsOfKind, kiVarsOfKinds,
promoteType, isPromotableType, isPromotableKind,
) where
#include "HsVersions.h"
import Type ( typeKind, substKiWith, eqKind )
import TypeRep
import TysPrim
import TyCon
import Var
import VarSet
import PrelNames
import Outputable
import Data.List ( partition )
\end{code}
%************************************************************************
%* *
Predicates over Kinds
%* *
%************************************************************************
\begin{code}
isLiftedTypeKindCon :: TyCon -> Bool
isLiftedTypeKindCon tc = tc `hasKey` liftedTypeKindTyConKey
noHashInKind :: Kind -> Bool
noHashInKind (TyVarTy {}) = True
noHashInKind (FunTy k1 k2) = noHashInKind k1 && noHashInKind k2
noHashInKind (ForAllTy _ ki) = noHashInKind ki
noHashInKind (TyConApp kc kis)
= not (kc `hasKey` unliftedTypeKindTyConKey)
&& not (kc `hasKey` ubxTupleKindTyConKey)
&& all noHashInKind kis
noHashInKind _ = panic "noHashInKind"
\end{code}
%************************************************************************
%* *
Functions over Kinds
%* *
%************************************************************************
\begin{code}
kindFunResult :: Kind -> KindOrType -> Kind
kindFunResult (FunTy _ res) _ = res
kindFunResult (ForAllTy kv res) arg = substKiWith [kv] [arg] res
kindFunResult k _ = pprPanic "kindFunResult" (ppr k)
kindAppResult :: Kind -> [Type] -> Kind
kindAppResult k [] = k
kindAppResult k (a:as) = kindAppResult (kindFunResult k a) as
splitKindFunTys :: Kind -> ([Kind],Kind)
splitKindFunTys (FunTy a r) = case splitKindFunTys r of
(as, k) -> (a:as, k)
splitKindFunTys k = ([], k)
splitKindFunTy_maybe :: Kind -> Maybe (Kind,Kind)
splitKindFunTy_maybe (FunTy a r) = Just (a,r)
splitKindFunTy_maybe _ = Nothing
splitKindFunTysN :: Int -> Kind -> ([Kind],Kind)
splitKindFunTysN 0 k = ([], k)
splitKindFunTysN n (FunTy a r) = case splitKindFunTysN (n1) r of
(as, k) -> (a:as, k)
splitKindFunTysN n k = pprPanic "splitKindFunTysN" (ppr n <+> ppr k)
synTyConResKind :: TyCon -> Kind
synTyConResKind tycon = kindAppResult (tyConKind tycon) (map mkTyVarTy (tyConTyVars tycon))
isUbxTupleKind, isOpenTypeKind, isArgTypeKind, isUnliftedTypeKind,
isConstraintKind, isAnyKind, isConstraintOrLiftedKind :: Kind -> Bool
isOpenTypeKindCon, isUbxTupleKindCon, isArgTypeKindCon,
isUnliftedTypeKindCon, isSubArgTypeKindCon, tcIsSubArgTypeKindCon,
isSubOpenTypeKindCon, tcIsSubOpenTypeKindCon, isConstraintKindCon,
isAnyKindCon :: TyCon -> Bool
isAnyKindCon tc = tyConUnique tc == anyKindTyConKey
isAnyKind (TyConApp tc _) = isAnyKindCon tc
isAnyKind _ = False
isOpenTypeKindCon tc = tyConUnique tc == openTypeKindTyConKey
isOpenTypeKind (TyConApp tc _) = isOpenTypeKindCon tc
isOpenTypeKind _ = False
isUbxTupleKindCon tc = tyConUnique tc == ubxTupleKindTyConKey
isUbxTupleKind (TyConApp tc _) = isUbxTupleKindCon tc
isUbxTupleKind _ = False
isArgTypeKindCon tc = tyConUnique tc == argTypeKindTyConKey
isArgTypeKind (TyConApp tc _) = isArgTypeKindCon tc
isArgTypeKind _ = False
isUnliftedTypeKindCon tc = tyConUnique tc == unliftedTypeKindTyConKey
isUnliftedTypeKind (TyConApp tc _) = isUnliftedTypeKindCon tc
isUnliftedTypeKind _ = False
isConstraintKindCon tc = tyConUnique tc == constraintKindTyConKey
isConstraintKind (TyConApp tc _) = isConstraintKindCon tc
isConstraintKind _ = False
isConstraintOrLiftedKind (TyConApp tc _)
= isConstraintKindCon tc || isLiftedTypeKindCon tc
isConstraintOrLiftedKind _ = False
isSubOpenTypeKind, tcIsSubOpenTypeKind :: Kind -> Bool
isSubOpenTypeKind (TyConApp kc []) = isSubOpenTypeKindCon kc
isSubOpenTypeKind _ = False
tcIsSubOpenTypeKind (TyConApp kc []) = tcIsSubOpenTypeKindCon kc
tcIsSubOpenTypeKind _ = False
isSubOpenTypeKindCon kc
| isSubArgTypeKindCon kc = True
| isUbxTupleKindCon kc = True
| isOpenTypeKindCon kc = True
| otherwise = False
tcIsSubOpenTypeKindCon kc
| tcIsSubArgTypeKindCon kc = True
| isUbxTupleKindCon kc = True
| isOpenTypeKindCon kc = True
| otherwise = False
isSubArgTypeKindCon kc
| isUnliftedTypeKindCon kc = True
| isLiftedTypeKindCon kc = True
| isArgTypeKindCon kc = True
| isConstraintKindCon kc = True
| otherwise = False
tcIsSubArgTypeKindCon kc
| isConstraintKindCon kc = False
| otherwise = isSubArgTypeKindCon kc
isSubArgTypeKind, tcIsSubArgTypeKind :: Kind -> Bool
isSubArgTypeKind (TyConApp kc []) = isSubArgTypeKindCon kc
isSubArgTypeKind _ = False
tcIsSubArgTypeKind (TyConApp kc []) = tcIsSubArgTypeKindCon kc
tcIsSubArgTypeKind _ = False
isSuperKind :: Type -> Bool
isSuperKind (TyConApp (skc) []) = isSuperKindTyCon skc
isSuperKind _ = False
isKind :: Kind -> Bool
isKind k = isSuperKind (typeKind k)
isSubKind, tcIsSubKind :: Kind -> Kind -> Bool
isSubKind = isSubKind' False
tcIsSubKind = isSubKind' True
isSubKind' :: Bool -> Kind -> Kind -> Bool
isSubKind' duringTc (FunTy a1 r1) (FunTy a2 r2)
= (isSubKind' duringTc a2 a1) && (isSubKind' duringTc r1 r2)
isSubKind' duringTc k1@(TyConApp kc1 k1s) k2@(TyConApp kc2 k2s)
| isPromotedTypeTyCon kc1 || isPromotedTypeTyCon kc2
= eqKind k1 k2
| isSuperKindTyCon kc1 || isSuperKindTyCon kc2
= ASSERT2( isSuperKindTyCon kc2 && null k1s && null k2s, ppr kc1 <+> ppr kc2 )
True
| otherwise =
ASSERT2( null k1s && null k2s, ppr k1 <+> ppr k2 )
if duringTc then kc1 `tcIsSubKindCon` kc2
else kc1 `isSubKindCon` kc2
isSubKind' _duringTc k1 k2 = eqKind k1 k2
isSubKindCon :: TyCon -> TyCon -> Bool
isSubKindCon kc1 kc2
| kc1 == kc2 = True
| isSubArgTypeKindCon kc1 && isArgTypeKindCon kc2 = True
| isSubOpenTypeKindCon kc1 && isOpenTypeKindCon kc2 = True
| otherwise = False
tcIsSubKindCon :: TyCon -> TyCon -> Bool
tcIsSubKindCon kc1 kc2
| kc1 == kc2 = True
| isConstraintKindCon kc1 || isConstraintKindCon kc2 = False
| otherwise = isSubKindCon kc1 kc2
defaultKind :: Kind -> Kind
defaultKind k
| tcIsSubOpenTypeKind k = liftedTypeKind
| otherwise = k
splitKiTyVars :: [TyVar] -> ([KindVar], [TyVar])
splitKiTyVars = span (isSuperKind . tyVarKind)
partitionKiTyVars :: [TyVar] -> ([KindVar], [TyVar])
partitionKiTyVars = partition (isSuperKind . tyVarKind)
isKiVar :: TyVar -> Bool
isKiVar v = isSuperKind (varType v)
kiVarsOfKind :: Kind -> VarSet
kiVarsOfKind = tyVarsOfType
kiVarsOfKinds :: [Kind] -> VarSet
kiVarsOfKinds = tyVarsOfTypes
isPromotableType :: Type -> Bool
isPromotableType = go emptyVarSet
where
go vars (TyConApp tc tys) = ASSERT( not (isPromotedDataTyCon tc) ) all (go vars) tys
go vars (FunTy arg res) = all (go vars) [arg,res]
go vars (TyVarTy tvar) = tvar `elemVarSet` vars
go vars (ForAllTy tvar ty) = isPromotableTyVar tvar && go (vars `extendVarSet` tvar) ty
go _ _ = panic "isPromotableType"
isPromotableTyVar :: TyVar -> Bool
isPromotableTyVar = isLiftedTypeKind . varType
promoteType :: Type -> Kind
promoteType (TyConApp tc tys) = mkTyConApp (mkPromotedTypeTyCon tc)
(map promoteType tys)
promoteType (FunTy arg res) = mkArrowKind (promoteType arg) (promoteType res)
promoteType (TyVarTy tvar) = mkTyVarTy (promoteTyVar tvar)
promoteType (ForAllTy tvar ty) = ForAllTy (promoteTyVar tvar) (promoteType ty)
promoteType _ = panic "promoteType"
promoteTyVar :: TyVar -> KindVar
promoteTyVar tvar = mkKindVar (tyVarName tvar) tySuperKind
isPromotableKind :: Kind -> Maybe Int
isPromotableKind kind =
let (args, res) = splitKindFunTys kind in
if all isLiftedTypeKind (res:args)
then Just $ length args
else Nothing
\end{code}