packages feed

ddc-core-0.4.3.1: DDC/Core/Check/Context/Elem.hs

module DDC.Core.Check.Context.Elem
        ( -- * Positions in the context.
          Pos    (..)

          -- * Roles of type variables.
        , Role   (..)

          -- * Existentials.
        , Exists (..)
        , typeOfExists
        , takeExists
        , slurpExists

          -- * Context elements.
        , Elem   (..)
        , takeExistsOfElem)
where
import DDC.Type.Exp.Simple
import DDC.Data.Pretty
import qualified DDC.Type.Sum   as Sum


-- Positions --------------------------------------------------------------------------------------
-- | A position in the type checker context.
--   A position is used to record a particular position in the context stack,
--   so that we can pop elements higher than it.
data Pos
        = Pos !Int
        deriving (Show, Eq)

instance Pretty Pos where
 ppr (Pos p)
        = text "*" <> int p


-- Role -------------------------------------------------------------------------------------------
-- | The role of some type variable.
data Role
        -- | Concrete type variables are region variables that have been introduced
        --   in an enclosing lexical scope. All the capabilities for these will 
        --   also be in the context.
        = RoleConcrete
        
        -- | Abstract type variables are the ones that are bound by type abstraction
        --   Inside the body of a type abstraction we can assume a region supports
        --   any given capability. We only need to worry about if it really does
        --   when we actually run the enclosed computation.
        | RoleAbstract
        deriving (Show, Eq)


instance Pretty Role where
 ppr role
  = case role of
        RoleConcrete    -> text "Concrete"
        RoleAbstract    -> text "Abstract"


-- Exists -----------------------------------------------------------------------------------------
-- | An existential variable.
data Exists n
        = Exists !Int !(Kind n)
        deriving (Show)

instance Eq (Exists n) where
 (==)   (Exists i1 _) (Exists i2 _)     = i1 == i2
 (/=)   (Exists i1 _) (Exists i2 _)     = i1 /= i2


instance Ord (Exists n) where
 compare (Exists i1 _) (Exists i2 _)
        = compare i1 i2


instance Pretty (Exists n) where
 ppr (Exists i _) = text "?" <> ppr i


-- | Wrap an existential variable into a type.
typeOfExists :: Exists n -> Type n
typeOfExists (Exists n k)
        = TCon (TyConExists n k)


-- | Take an Exists from a type.
takeExists :: Type n -> Maybe (Exists n)
takeExists tt
 = case tt of
        TCon (TyConExists n k)  -> Just (Exists n k)
        _                       -> Nothing


-- | Slurp all the existential variables from this type.
slurpExists :: Type n -> [Exists n]
slurpExists tt
 = case tt of
        TCon (TyConExists n k)  -> [Exists n k]
        TCon _                  -> []
        TVar {}                 -> []
        TAbs b xBody            -> slurpExists (typeOfBind b) ++ slurpExists xBody
        TApp t1 t2              -> slurpExists t1 ++ slurpExists t2
        TForall b xBody         -> slurpExists (typeOfBind b) ++ slurpExists xBody
        TSum ts                 -> concatMap slurpExists $ Sum.toList ts



-- Elem -------------------------------------------------------------------------------------------
-- | An element in the type checker context.
data Elem n
        -- | A context position marker.
        = ElemPos        !Pos

        -- | Kind of some variable.
        | ElemKind       !(Bind n) !Role

        -- | Type of some variable.
        | ElemType       !(Bind n)

        -- | Existential variable declaration
        | ElemExistsDecl !(Exists n)

        -- | Existential variable solved to some monotype.
        | ElemExistsEq   !(Exists n) !(Type n)
        deriving (Show, Eq)


instance (Pretty n, Eq n) => Pretty (Elem n) where
 ppr ll
  = case ll of
        ElemPos p
         -> ppr p

        ElemKind b role  
         -> (padL 4 $ ppr (binderOfBind b))
                <+> text ":" 
                <+> (ppr $ typeOfBind b)
                <+> text "@" <> ppr role

        ElemType b
         -> (padL 4 $ ppr (binderOfBind b))
                <+> text ":"
                <+> (ppr $ typeOfBind b)

        ElemExistsDecl (Exists i k)
         -> padL 4 (text "?" <> ppr i) <+> text ":" <+> ppr k

        ElemExistsEq (Exists i k) t 
         -> padL 4 (text "?" <> ppr i) <+> text ":" <+> ppr k <+> text "=" <+> ppr t


-- | Take the existential from this context element, if there is one.
takeExistsOfElem :: Elem n -> Maybe (Exists n)
takeExistsOfElem ee
 = case ee of
        ElemExistsDecl i        -> Just i
        ElemExistsEq   i _      -> Just i
        _                       -> Nothing