Add Coercion.lhs
authorManuel M T Chakravarty <chak@cse.unsw.edu.au>
Sun, 6 Aug 2006 21:40:25 +0000 (21:40 +0000)
committerManuel M T Chakravarty <chak@cse.unsw.edu.au>
Sun, 6 Aug 2006 21:40:25 +0000 (21:40 +0000)
- Extra patch as diff doesn't capture add files

compiler/types/Coercion.lhs [new file with mode: 0644]

diff --git a/compiler/types/Coercion.lhs b/compiler/types/Coercion.lhs
new file mode 100644 (file)
index 0000000..747dc8a
--- /dev/null
@@ -0,0 +1,381 @@
+\r
+ Module for type coercions, as in System FC.\r
+\r
+Coercions are represented as types, and their kinds tell what types the \r
+coercion works on. \r
+\r
+The coercion kind constructor is a special TyCon that must always be saturated\r
+\r
+  typeKind (symCoercion type) :: TyConApp CoercionTyCon{...} [type, type]\r
+\r
+\begin{code}\r
+module Coercion (\r
+        Coercion,\r
\r
+        mkCoKind, mkReflCoKind, splitCoercionKind_maybe, splitCoercionKind,\r
+        coercionKind, coercionKinds, coercionKindPredTy,\r
+\r
+       -- Equality predicates\r
+       isEqPred, mkEqPred, getEqPredTys, isEqPredTy,  \r
+\r
+       -- Coercion transformations\r
+        mkSymCoercion, mkTransCoercion,\r
+        mkLeftCoercion, mkRightCoercion, mkInstCoercion, mkAppCoercion,\r
+        mkForAllCoercion, mkFunCoercion, mkInstsCoercion, mkUnsafeCoercion,\r
+        mkNewTypeCoercion, mkAppsCoercion,\r
+\r
+        splitNewTypeRepCo_maybe, decomposeCo,\r
+\r
+        unsafeCoercionTyCon, symCoercionTyCon,\r
+        transCoercionTyCon, leftCoercionTyCon, \r
+        rightCoercionTyCon, instCoercionTyCon -- needed by TysWiredIn\r
+       ) where \r
+\r
+#include "HsVersions.h"\r
+\r
+import TypeRep\r
+import Type      ( Type, Kind, PredType, substTyWith, mkAppTy, mkForAllTy,\r
+                    mkFunTy, splitAppTy_maybe, splitForAllTy_maybe, coreView,\r
+                    kindView, mkTyConApp, isCoercionKind, isEqPred, mkAppTys\r
+                  )\r
+import TyCon      ( TyCon, tyConArity, mkCoercionTyCon, isNewTyCon,\r
+                    newTyConRhs, newTyConCo, \r
+                    isCoercionTyCon, isCoercionTyCon_maybe )\r
+import Var       ( Var, TyVar, isTyVar, tyVarKind )\r
+import Name       ( BuiltInSyntax(..), Name, mkWiredInName, tcName )\r
+import OccName    ( mkOccNameFS )\r
+import PrelNames  ( symCoercionTyConKey, \r
+                    transCoercionTyConKey, leftCoercionTyConKey,\r
+                    rightCoercionTyConKey, instCoercionTyConKey, \r
+                    unsafeCoercionTyConKey, gHC_PRIM\r
+                  )\r
+import Util       ( lengthIs, snocView )\r
+import Unique     ( hasKey )\r
+import BasicTypes ( Arity )\r
+import Outputable\r
+\r
+\r
+\r
+------------------------------\r
+decomposeCo :: Arity -> Coercion -> [Coercion]\r
+-- (decomposeCo 3 c) = [right (left (left c)), right (left c), right c]\r
+decomposeCo n co\r
+  = go n co []\r
+  where\r
+    go 0 co cos = cos\r
+    go n co cos = go (n-1) (mkLeftCoercion co)\r
+                          (mkRightCoercion co : cos)\r
+\r
+------------------------------\r
+\r
+-------------------------------------------------------\r
+-- and some coercion kind stuff\r
+\r
+isEqPredTy (PredTy pred) = isEqPred pred\r
+isEqPredTy other         = False\r
+\r
+mkEqPred :: (Type, Type) -> PredType\r
+mkEqPred (ty1, ty2) = EqPred ty1 ty2\r
+\r
+getEqPredTys :: PredType -> (Type,Type)\r
+getEqPredTys (EqPred ty1 ty2) = (ty1, ty2)\r
+getEqPredTys other           = pprPanic "getEqPredTys" (ppr other)\r
+\r
+mkCoKind :: Type -> Type -> CoercionKind\r
+mkCoKind ty1 ty2 = PredTy (EqPred ty1 ty2)\r
+\r
+mkReflCoKind :: Type -> CoercionKind\r
+mkReflCoKind ty = mkCoKind ty ty\r
+\r
+splitCoercionKind :: CoercionKind -> (Type, Type)\r
+splitCoercionKind co | Just co' <- kindView co = splitCoercionKind co'\r
+splitCoercionKind (PredTy (EqPred ty1 ty2))    = (ty1, ty2)\r
+\r
+splitCoercionKind_maybe :: Kind -> Maybe (Type, Type)\r
+splitCoercionKind_maybe co | Just co' <- kindView co = splitCoercionKind_maybe co'\r
+splitCoercionKind_maybe (PredTy (EqPred ty1 ty2)) = Just (ty1, ty2)\r
+splitCoercionKind_maybe other = Nothing\r
+\r
+isCoVar :: Var -> Bool\r
+isCoVar tv = isTyVar tv && isCoercionKind (tyVarKind tv)\r
+\r
+type Coercion     = Type\r
+type CoercionKind = Kind       -- A CoercionKind is always of form (ty1 :=: ty2)\r
+\r
+coercionKind :: Coercion -> (Type, Type)\r
+--     c :: (t1 :=: t2)\r
+-- Then (coercionKind c) = (t1,t2)\r
+\r
+coercionKind (TyVarTy a) | isCoVar a = splitCoercionKind (tyVarKind a)\r
+                         | otherwise = let t = (TyVarTy a) in (t, t)\r
+coercionKind (AppTy ty1 ty2) \r
+  = let (t1, t2) = coercionKind ty1\r
+        (s1, s2) = coercionKind ty2 in\r
+    (mkAppTy t1 s1, mkAppTy t2 s2)\r
+coercionKind (TyConApp tc args)\r
+  | Just (ar, rule) <- isCoercionTyCon_maybe tc \r
+  = if length args >= ar \r
+    then splitCoercionKind (rule args)\r
+    else pprPanic ("arity/arguments mismatch in coercionKind:") \r
+             (ppr ar $$ ppr tc <+> ppr args)\r
+  | otherwise\r
+  = let (lArgs, rArgs) = coercionKinds args in\r
+    (TyConApp tc lArgs, TyConApp tc rArgs)\r
+coercionKind (FunTy ty1 ty2) \r
+  = let (t1, t2) = coercionKind ty1\r
+        (s1, s2) = coercionKind ty2 in\r
+    (mkFunTy t1 s1, mkFunTy t2 s2)\r
+coercionKind (ForAllTy tv ty) \r
+  = let (ty1, ty2) = coercionKind ty in\r
+    (ForAllTy tv ty1, ForAllTy tv ty2)\r
+coercionKind (NoteTy _ ty) = coercionKind ty\r
+coercionKind (PredTy (EqPred c1 c2)) \r
+  = let k1 = coercionKindPredTy c1\r
+        k2 = coercionKindPredTy c2 in\r
+    (k1,k2)\r
+coercionKind (PredTy (ClassP cl args)) \r
+  = let (lArgs, rArgs) = coercionKinds args in\r
+    (PredTy (ClassP cl lArgs), PredTy (ClassP cl rArgs))\r
+coercionKind (PredTy (IParam name ty))\r
+  = let (ty1, ty2) = coercionKind ty in\r
+    (PredTy (IParam name ty1), PredTy (IParam name ty2))\r
+\r
+coercionKindPredTy :: Coercion -> CoercionKind\r
+coercionKindPredTy c = let (t1, t2) = coercionKind c in mkCoKind t1 t2\r
+\r
+coercionKinds :: [Coercion] -> ([Type], [Type])\r
+coercionKinds tys = unzip $ map coercionKind tys\r
+\r
+-------------------------------------\r
+-- Coercion kind and type mk's\r
+-- (make saturated TyConApp CoercionTyCon{...} args)\r
+\r
+mkCoercion coCon args = ASSERT( tyConArity coCon == length args ) \r
+                        TyConApp coCon args\r
+\r
+mkAppCoercion, mkFunCoercion, mkTransCoercion, mkInstCoercion :: Coercion -> Coercion -> Coercion\r
+mkSymCoercion, mkLeftCoercion, mkRightCoercion :: Coercion -> Coercion\r
+\r
+mkAppCoercion    co1 co2 = mkAppTy co1 co2\r
+mkAppsCoercion   co1 tys = foldl mkAppTy co1 tys\r
+-- note that a TyVar should be used here, not a CoVar (nor a TcTyVar)\r
+mkForAllCoercion tv  co  = ASSERT ( isTyVar tv ) mkForAllTy tv co\r
+mkFunCoercion    co1 co2 = mkFunTy co1 co2\r
+\r
+mkSymCoercion co      \r
+  | Just co2 <- splitSymCoercion_maybe co = co2\r
+  | Just (co1, co2) <- splitAppCoercion_maybe co \r
+    -- should make this case better\r
+  = mkAppCoercion (mkSymCoercion co1) (mkSymCoercion co2)\r
+  | Just (co1, co2) <- splitTransCoercion_maybe co\r
+  = mkTransCoercion (mkSymCoercion co1) (mkSymCoercion co2)\r
+  | Just (co, ty) <- splitInstCoercion_maybe co\r
+  = mkInstCoercion (mkSymCoercion co) ty\r
+  | Just co <- splitLeftCoercion_maybe co\r
+  = mkLeftCoercion (mkSymCoercion co)\r
+  | Just co <- splitRightCoercion_maybe co\r
+  = mkRightCoercion (mkSymCoercion co)\r
+mkSymCoercion (ForAllTy tv ty) = ForAllTy tv (mkSymCoercion ty)\r
+-- for atomic types and constructors, we can just ignore sym since these\r
+-- are reflexive coercions\r
+mkSymCoercion (TyVarTy tv) \r
+  | isCoVar tv = mkCoercion symCoercionTyCon [TyVarTy tv]\r
+  | otherwise  = TyVarTy tv\r
+mkSymCoercion co = mkCoercion symCoercionTyCon [co] \r
+                   -- this should not happen but does\r
+\r
+-- Smart constructors for left and right\r
+mkLeftCoercion co \r
+  | Just (co', _) <- splitAppCoercion_maybe co = co'\r
+  | otherwise                           = mkCoercion leftCoercionTyCon [co]\r
+\r
+mkRightCoercion  co      \r
+  | Just (co1, co2) <- splitAppCoercion_maybe co = co2\r
+  | otherwise = mkCoercion rightCoercionTyCon [co]\r
+\r
+mkTransCoercion co1 co2 = mkCoercion transCoercionTyCon [co1, co2]\r
+\r
+mkInstCoercion  co ty = mkCoercion instCoercionTyCon  [co, ty]\r
+\r
+mkInstsCoercion co tys = foldl mkInstCoercion co tys\r
+\r
+splitSymCoercion_maybe :: Coercion -> Maybe Coercion\r
+splitSymCoercion_maybe (TyConApp tc [co]) = \r
+  if tc `hasKey` symCoercionTyConKey\r
+  then Just co\r
+  else Nothing\r
+splitSymCoercion_maybe co = Nothing\r
+\r
+splitAppCoercion_maybe :: Coercion -> Maybe (Coercion, Coercion)\r
+-- Splits a coercion application, being careful *not* to split (left c), etc\r
+-- which are really sytactic constructs, not applications\r
+splitAppCoercion_maybe co  | Just co' <- coreView co = splitAppCoercion_maybe co'\r
+splitAppCoercion_maybe (FunTy ty1 ty2)   = Just (TyConApp funTyCon [ty1], ty2)\r
+splitAppCoercion_maybe (AppTy ty1 ty2)   = Just (ty1, ty2)\r
+splitAppCoercion_maybe (TyConApp tc tys) \r
+   | not (isCoercionTyCon tc)\r
+   = case snocView tys of\r
+       Just (tys', ty') -> Just (TyConApp tc tys', ty')\r
+       Nothing          -> Nothing\r
+splitAppCoercion_maybe co = Nothing\r
+\r
+splitTransCoercion_maybe :: Coercion -> Maybe (Coercion, Coercion)\r
+splitTransCoercion_maybe (TyConApp tc [ty1, ty2]) \r
+ = if tc `hasKey` transCoercionTyConKey then\r
+       Just (ty1, ty2)\r
+   else\r
+       Nothing\r
+splitTransCoercion_maybe other = Nothing\r
+\r
+splitInstCoercion_maybe :: Coercion -> Maybe (Coercion, Type)\r
+splitInstCoercion_maybe (TyConApp tc [ty1, ty2])\r
+ = if tc `hasKey` instCoercionTyConKey then\r
+       Just (ty1, ty2)\r
+    else\r
+       Nothing\r
+splitInstCoercion_maybe other = Nothing\r
+\r
+splitLeftCoercion_maybe :: Coercion -> Maybe Coercion\r
+splitLeftCoercion_maybe (TyConApp tc [co])\r
+ = if tc `hasKey` leftCoercionTyConKey then\r
+       Just co\r
+   else\r
+       Nothing\r
+splitLeftCoercion_maybe other = Nothing\r
+\r
+splitRightCoercion_maybe :: Coercion -> Maybe Coercion\r
+splitRightCoercion_maybe (TyConApp tc [co])\r
+ = if tc `hasKey` rightCoercionTyConKey then\r
+       Just co\r
+   else\r
+       Nothing\r
+splitRightCoercion_maybe other = Nothing\r
+\r
+-- Unsafe coercion is not safe, it is used when we know we are dealing with\r
+-- bottom, which is the one case in which it is safe\r
+mkUnsafeCoercion :: Type -> Type -> Coercion\r
+mkUnsafeCoercion ty1 ty2 \r
+  = mkCoercion unsafeCoercionTyCon [ty1, ty2]\r
+\r
+\r
+-- make the coercion associated with a newtype\r
+mkNewTypeCoercion :: Name -> TyCon -> [TyVar] -> Type -> TyCon\r
+mkNewTypeCoercion name tycon tvs rhs_ty \r
+  = ASSERT (length tvs == tyConArity tycon)\r
+    mkCoercionTyCon name (tyConArity tycon) rule\r
+  where\r
+    rule args = mkCoKind (substTyWith tvs args rhs_ty) (TyConApp tycon args)\r
+\r
+--------------------------------------\r
+-- Coercion Type Constructors...\r
+\r
+-- Example.  The coercion ((sym c) (sym d) (sym e))\r
+-- will be represented by (TyConApp sym [c, sym d, sym e])\r
+-- If sym c :: p1=q1\r
+--    sym d :: p2=q2\r
+--    sym e :: p3=q3\r
+-- then ((sym c) (sym d) (sym e)) :: (p1 p2 p3)=(q1 q2 q3)\r
+--\r
+-- (mkKindingFun f) is given the args [c, sym d, sym e]\r
+mkKindingFun :: ([Type] -> (Type, Type, [Type])) -> [Type] -> Kind\r
+mkKindingFun f args = \r
+  let (ty1, ty2, rest) = f args in \r
+  let (argtys1, argtys2) = unzip (map coercionKind rest) in\r
+  mkCoKind (mkAppTys ty1 argtys1) (mkAppTys ty2 argtys2)\r
+        \r
+\r
+symCoercionTyCon, transCoercionTyCon, leftCoercionTyCon, rightCoercionTyCon, instCoercionTyCon :: TyCon\r
+-- Each coercion TyCon is built with the special CoercionTyCon record and\r
+-- carries its won kinding rule.  Such CoercionTyCons must be fully applied\r
+-- by any TyConApp in which they are applied, however they may also be over\r
+-- applied (see example above) and the kinding function must deal with this.\r
+symCoercionTyCon = \r
+  mkCoercionTyCon symCoercionTyConName 1 (mkKindingFun flipCoercionKindOf)\r
+  where\r
+    flipCoercionKindOf (co:rest) = (ty2, ty1, rest)\r
+       where\r
+         (ty1, ty2) = coercionKind co\r
+\r
+transCoercionTyCon = \r
+  mkCoercionTyCon transCoercionTyConName 2 (mkKindingFun composeCoercionKindsOf)\r
+  where\r
+    composeCoercionKindsOf (co1:co2:rest) = (a1, r2, rest)\r
+      where\r
+        (a1, r1) = coercionKind co1\r
+        (a2, r2) = coercionKind co2 \r
+\r
+leftCoercionTyCon =\r
+  mkCoercionTyCon leftCoercionTyConName 1 (mkKindingFun leftProjectCoercionKindOf)\r
+  where\r
+    leftProjectCoercionKindOf (co:rest) = (ty1, ty2, rest)\r
+      where\r
+        (ty1,ty2) = fst (splitCoercionKindOf co)\r
+\r
+rightCoercionTyCon =\r
+  mkCoercionTyCon rightCoercionTyConName 1 (mkKindingFun rightProjectCoercionKindOf)\r
+  where\r
+    rightProjectCoercionKindOf (co:rest) = (ty1, ty2, rest)\r
+      where\r
+        (ty1,ty2) = snd (splitCoercionKindOf co)\r
+\r
+splitCoercionKindOf :: Type -> ((Type,Type), (Type,Type))\r
+-- Helper for left and right.  Finds coercion kind of its input and\r
+-- returns the left and right projections of the coercion...\r
+--\r
+-- if c :: t1 s1 :=: t2 s2 then splitCoercionKindOf c = ((t1, t2), (s1, s2))\r
+splitCoercionKindOf co\r
+  | Just (ty1, ty2) <- splitCoercionKind_maybe (coercionKindPredTy co)\r
+  , Just (ty_fun1, ty_arg1) <- splitAppTy_maybe ty1\r
+  , Just (ty_fun2, ty_arg2) <- splitAppTy_maybe ty2\r
+  = ((ty_fun1, ty_fun2),(ty_arg1, ty_arg2))\r
+\r
+instCoercionTyCon \r
+  =  mkCoercionTyCon instCoercionTyConName 2 (mkKindingFun instCoercionKind)\r
+  where\r
+    instantiateCo t s =\r
+      let Just (tv, ty) = splitForAllTy_maybe t in\r
+      substTyWith [tv] [s] ty\r
+\r
+    instCoercionKind (co1:ty:rest) = (instantiateCo t1 ty, instantiateCo t2 ty, rest)\r
+      where (t1, t2) = coercionKind co1\r
+\r
+unsafeCoercionTyCon \r
+  = mkCoercionTyCon unsafeCoercionTyConName 2 (mkKindingFun unsafeCoercionKind)\r
+  where\r
+   unsafeCoercionKind (ty1:ty2:rest) = (ty1,ty2,rest) \r
+        \r
+--------------------------------------\r
+-- ...and their names\r
+\r
+mkCoConName occ key coCon = mkWiredInName gHC_PRIM (mkOccNameFS tcName occ)\r
+                            key Nothing (ATyCon coCon) BuiltInSyntax\r
+\r
+transCoercionTyConName = mkCoConName FSLIT("trans") transCoercionTyConKey transCoercionTyCon\r
+symCoercionTyConName   = mkCoConName FSLIT("sym") symCoercionTyConKey symCoercionTyCon\r
+leftCoercionTyConName  = mkCoConName FSLIT("left") leftCoercionTyConKey leftCoercionTyCon\r
+rightCoercionTyConName = mkCoConName FSLIT("right") rightCoercionTyConKey rightCoercionTyCon\r
+instCoercionTyConName  = mkCoConName FSLIT("inst") instCoercionTyConKey instCoercionTyCon\r
+unsafeCoercionTyConName = mkCoConName FSLIT("CoUnsafe") unsafeCoercionTyConKey unsafeCoercionTyCon\r
+\r
+\r
+\r
+-- this is here to avoid module loops\r
+splitNewTypeRepCo_maybe :: Type -> Maybe (Type, Coercion)  \r
+-- Sometimes we want to look through a recursive newtype, and that's what happens here\r
+-- It only strips *one layer* off, so the caller will usually call itself recursively\r
+-- Only applied to types of kind *, hence the newtype is always saturated\r
+splitNewTypeRepCo_maybe ty \r
+  | Just ty' <- coreView ty = splitNewTypeRepCo_maybe ty'\r
+splitNewTypeRepCo_maybe (TyConApp tc tys)\r
+  | isNewTyCon tc \r
+  = ASSERT( tys `lengthIs` tyConArity tc )     -- splitNewTypeRepCo_maybe only be applied \r
+                                                --     to *types* (of kind *)\r
+        case newTyConRhs tc of\r
+         (tvs, rep_ty) -> \r
+              ASSERT( length tvs == length tys )\r
+             Just (substTyWith tvs tys rep_ty, mkTyConApp co_con tys)\r
+  where\r
+    co_con = maybe (pprPanic "splitNewTypeRepCo_maybe" (ppr tc)) id (newTyConCo tc)\r
+\r
+splitNewTypeRepCo_maybe other = Nothing\r
+\end{code}
\ No newline at end of file