packages feed

disco-0.1.6: src/Disco/AST/Typed.hs

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE PatternSynonyms #-}

-----------------------------------------------------------------------------

-----------------------------------------------------------------------------

-- |
-- Module      :  Disco.AST.Typed
-- Copyright   :  disco team and contributors
-- Maintainer  :  byorgey@gmail.com
--
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Typed abstract syntax trees representing the typechecked surface
-- syntax of the Disco language.  Each tree node is annotated with the
-- type of its subtree.
module Disco.AST.Typed (
  -- * Type-annotated terms
  ATerm,
  pattern ATVar,
  pattern ATPrim,
  pattern ATLet,
  pattern ATUnit,
  pattern ATBool,
  pattern ATNat,
  pattern ATRat,
  pattern ATChar,
  pattern ATString,
  pattern ATAbs,
  pattern ATApp,
  pattern ATTup,
  pattern ATCase,
  pattern ATChain,
  pattern ATTyOp,
  pattern ATContainer,
  pattern ATContainerComp,
  pattern ATList,
  pattern ATListComp,
  pattern ATTest,
  ALink,
  pattern ATLink,
  Container (..),
  ABinding,

  -- * Branches and guards
  ABranch,
  AGuard,
  pattern AGBool,
  pattern AGPat,
  pattern AGLet,
  AQual,
  pattern AQBind,
  pattern AQGuard,
  APattern,
  pattern APVar,
  pattern APWild,
  pattern APUnit,
  pattern APBool,
  pattern APTup,
  pattern APInj,
  pattern APNat,
  pattern APChar,
  pattern APString,
  pattern APCons,
  pattern APList,
  pattern APAdd,
  pattern APMul,
  pattern APSub,
  pattern APNeg,
  pattern APFrac,
  pattern ABinding,

  -- * Utilities
  varsBound,
  getType,
  setType,
  substQT,
  AProperty,
)
where

import Unbound.Generics.LocallyNameless
import Unbound.Generics.LocallyNameless.Unsafe

import Control.Arrow ((***))
import Data.Coerce (coerce)
import Data.Data (Data)
import Data.Void

import Control.Lens.Plated (transform)
import Disco.AST.Generic
import Disco.AST.Surface
import Disco.Names
import Disco.Pretty
import Disco.Syntax.Operators
import Disco.Syntax.Prims
import Disco.Types

-- | The extension descriptor for Typed specific AST types.
data TY
  deriving (Data)

type AProperty = Property_ TY

------------------------------------------------------------

-- TODO: Should probably really do this with a 2-level/open recursion
-- approach, with a cofree comonad or whatever

-- | An @ATerm@ is a typechecked term where every node in the tree has
--   been annotated with the type of the subterm rooted at that node.
type ATerm = Term_ TY

type instance X_Binder TY = [APattern]

type instance X_TVar TY = Void -- Names are now qualified
type instance X_TPrim TY = Type
type instance X_TLet TY = Type
type instance X_TUnit TY = ()
type instance X_TBool TY = Type
type instance X_TNat TY = Type
type instance X_TRat TY = ()
type instance X_TChar TY = ()
type instance X_TString TY = ()
type instance X_TAbs TY = Type
type instance X_TApp TY = Type
type instance X_TCase TY = Type
type instance X_TChain TY = Type
type instance X_TTyOp TY = Type
type instance X_TContainer TY = Type
type instance X_TContainerComp TY = Type
type instance X_TAscr TY = Void -- No more type ascriptions in typechecked terms
type instance X_TTup TY = Type
type instance X_TParens TY = Void -- No more explicit parens

-- A test frame for reporting counterexamples in a test. These don't appear
-- in source programs, but because the deugarer manipulates partly-desugared
-- terms it helps to be able to represent these in 'ATerm'.
type instance X_Term TY = Either ([(String, Type, Name ATerm)], ATerm) (Type, QName ATerm)

pattern ATVar :: Type -> QName ATerm -> ATerm
pattern ATVar ty qname = XTerm_ (Right (ty, qname))

pattern ATPrim :: Type -> Prim -> ATerm
pattern ATPrim ty name = TPrim_ ty name

pattern ATLet :: Type -> Bind (Telescope ABinding) ATerm -> ATerm
pattern ATLet ty bind = TLet_ ty bind

pattern ATUnit :: ATerm
pattern ATUnit = TUnit_ ()

pattern ATBool :: Type -> Bool -> ATerm
pattern ATBool ty bool = TBool_ ty bool

pattern ATNat :: Type -> Integer -> ATerm
pattern ATNat ty int = TNat_ ty int

pattern ATRat :: Rational -> ATerm
pattern ATRat rat = TRat_ () rat

pattern ATChar :: Char -> ATerm
pattern ATChar c = TChar_ () c

pattern ATString :: String -> ATerm
pattern ATString s = TString_ () s

pattern ATAbs :: Quantifier -> Type -> Bind [APattern] ATerm -> ATerm
pattern ATAbs q ty bind = TAbs_ q ty bind

pattern ATApp :: Type -> ATerm -> ATerm -> ATerm
pattern ATApp ty term1 term2 = TApp_ ty term1 term2

pattern ATTup :: Type -> [ATerm] -> ATerm
pattern ATTup ty termlist = TTup_ ty termlist

pattern ATCase :: Type -> [ABranch] -> ATerm
pattern ATCase ty branch = TCase_ ty branch

pattern ATChain :: Type -> ATerm -> [ALink] -> ATerm
pattern ATChain ty term linklist = TChain_ ty term linklist

pattern ATTyOp :: Type -> TyOp -> Type -> ATerm
pattern ATTyOp ty1 tyop ty2 = TTyOp_ ty1 tyop ty2

pattern ATContainer :: Type -> Container -> [(ATerm, Maybe ATerm)] -> Maybe (Ellipsis ATerm) -> ATerm
pattern ATContainer ty c tl mets = TContainer_ ty c tl mets

pattern ATContainerComp :: Type -> Container -> Bind (Telescope AQual) ATerm -> ATerm
pattern ATContainerComp ty c b = TContainerComp_ ty c b

pattern ATTest :: [(String, Type, Name ATerm)] -> ATerm -> ATerm
pattern ATTest ns t = XTerm_ (Left (ns, t))

{-# COMPLETE
  ATVar
  , ATPrim
  , ATLet
  , ATUnit
  , ATBool
  , ATNat
  , ATRat
  , ATChar
  , ATString
  , ATAbs
  , ATApp
  , ATTup
  , ATCase
  , ATChain
  , ATTyOp
  , ATContainer
  , ATContainerComp
  , ATTest
  #-}

pattern ATList :: Type -> [ATerm] -> Maybe (Ellipsis ATerm) -> ATerm
pattern ATList t xs e <- ATContainer t ListContainer (map fst -> xs) e
  where
    ATList t xs e = ATContainer t ListContainer (map (,Nothing) xs) e

pattern ATListComp :: Type -> Bind (Telescope AQual) ATerm -> ATerm
pattern ATListComp t b = ATContainerComp t ListContainer b

type ALink = Link_ TY

type instance X_TLink TY = ()

pattern ATLink :: BOp -> ATerm -> ALink
pattern ATLink bop term = TLink_ () bop term

{-# COMPLETE ATLink #-}

type AQual = Qual_ TY

type instance X_QBind TY = ()
type instance X_QGuard TY = ()

pattern AQBind :: Name ATerm -> Embed ATerm -> AQual
pattern AQBind namet embedt = QBind_ () namet embedt

pattern AQGuard :: Embed ATerm -> AQual
pattern AQGuard embedt = QGuard_ () embedt

{-# COMPLETE AQBind, AQGuard #-}

type ABinding = Binding_ TY

pattern ABinding :: Maybe (Embed PolyType) -> Name ATerm -> Embed ATerm -> ABinding
pattern ABinding m b n = Binding_ m b n

{-# COMPLETE ABinding #-}

type ABranch = Bind (Telescope AGuard) ATerm

type AGuard = Guard_ TY

type instance X_GBool TY = ()
type instance X_GPat TY = ()
type instance X_GLet TY = () -- ??? Type?

pattern AGBool :: Embed ATerm -> AGuard
pattern AGBool embedt = GBool_ () embedt

pattern AGPat :: Embed ATerm -> APattern -> AGuard
pattern AGPat embedt pat = GPat_ () embedt pat

pattern AGLet :: ABinding -> AGuard
pattern AGLet b = GLet_ () b

{-# COMPLETE AGBool, AGPat, AGLet #-}

type APattern = Pattern_ TY

-- We have to use Embed Type because we don't want any type variables
-- inside the types being treated as binders!

type instance X_PVar TY = Embed Type
type instance X_PWild TY = Embed Type
type instance X_PAscr TY = Void -- No more ascriptions in typechecked patterns.
type instance X_PUnit TY = ()
type instance X_PBool TY = ()
type instance X_PChar TY = ()
type instance X_PString TY = ()
type instance X_PTup TY = Embed Type
type instance X_PInj TY = Embed Type
type instance X_PNat TY = Embed Type
type instance X_PCons TY = Embed Type
type instance X_PList TY = Embed Type
type instance X_PAdd TY = Embed Type
type instance X_PMul TY = Embed Type
type instance X_PSub TY = Embed Type
type instance X_PNeg TY = Embed Type
type instance X_PFrac TY = Embed Type

type instance X_Pattern TY = ()

pattern APVar :: Type -> Name ATerm -> APattern
pattern APVar ty name <- PVar_ (unembed -> ty) name
  where
    APVar ty name = PVar_ (embed ty) name

pattern APWild :: Type -> APattern
pattern APWild ty <- PWild_ (unembed -> ty)
  where
    APWild ty = PWild_ (embed ty)

pattern APUnit :: APattern
pattern APUnit = PUnit_ ()

pattern APBool :: Bool -> APattern
pattern APBool b = PBool_ () b

pattern APChar :: Char -> APattern
pattern APChar c = PChar_ () c

pattern APString :: String -> APattern
pattern APString s = PString_ () s

pattern APTup :: Type -> [APattern] -> APattern
pattern APTup ty lp <- PTup_ (unembed -> ty) lp
  where
    APTup ty lp = PTup_ (embed ty) lp

pattern APInj :: Type -> Side -> APattern -> APattern
pattern APInj ty s p <- PInj_ (unembed -> ty) s p
  where
    APInj ty s p = PInj_ (embed ty) s p

pattern APNat :: Type -> Integer -> APattern
pattern APNat ty n <- PNat_ (unembed -> ty) n
  where
    APNat ty n = PNat_ (embed ty) n

pattern APCons :: Type -> APattern -> APattern -> APattern
pattern APCons ty p1 p2 <- PCons_ (unembed -> ty) p1 p2
  where
    APCons ty p1 p2 = PCons_ (embed ty) p1 p2

pattern APList :: Type -> [APattern] -> APattern
pattern APList ty lp <- PList_ (unembed -> ty) lp
  where
    APList ty lp = PList_ (embed ty) lp

pattern APAdd :: Type -> Side -> APattern -> ATerm -> APattern
pattern APAdd ty s p t <- PAdd_ (unembed -> ty) s p t
  where
    APAdd ty s p t = PAdd_ (embed ty) s p t

pattern APMul :: Type -> Side -> APattern -> ATerm -> APattern
pattern APMul ty s p t <- PMul_ (unembed -> ty) s p t
  where
    APMul ty s p t = PMul_ (embed ty) s p t

pattern APSub :: Type -> APattern -> ATerm -> APattern
pattern APSub ty p t <- PSub_ (unembed -> ty) p t
  where
    APSub ty p t = PSub_ (embed ty) p t

pattern APNeg :: Type -> APattern -> APattern
pattern APNeg ty p <- PNeg_ (unembed -> ty) p
  where
    APNeg ty p = PNeg_ (embed ty) p

pattern APFrac :: Type -> APattern -> APattern -> APattern
pattern APFrac ty p1 p2 <- PFrac_ (unembed -> ty) p1 p2
  where
    APFrac ty p1 p2 = PFrac_ (embed ty) p1 p2

{-# COMPLETE
  APVar
  , APWild
  , APUnit
  , APBool
  , APChar
  , APString
  , APTup
  , APInj
  , APNat
  , APCons
  , APList
  , APAdd
  , APMul
  , APSub
  , APNeg
  , APFrac
  #-}

varsBound :: APattern -> [(Name ATerm, Type)]
varsBound (APVar ty n) = [(n, ty)]
varsBound (APWild _) = []
varsBound APUnit = []
varsBound (APBool _) = []
varsBound (APChar _) = []
varsBound (APString _) = []
varsBound (APTup _ ps) = varsBound =<< ps
varsBound (APInj _ _ p) = varsBound p
varsBound (APNat _ _) = []
varsBound (APCons _ p q) = varsBound p ++ varsBound q
varsBound (APList _ ps) = varsBound =<< ps
varsBound (APAdd _ _ p _) = varsBound p
varsBound (APMul _ _ p _) = varsBound p
varsBound (APSub _ p _) = varsBound p
varsBound (APNeg _ p) = varsBound p
varsBound (APFrac _ p q) = varsBound p ++ varsBound q

------------------------------------------------------------
-- getType
------------------------------------------------------------

instance HasType ATerm where
  getType (ATVar ty _) = ty
  getType (ATPrim ty _) = ty
  getType ATUnit = TyUnit
  getType (ATBool ty _) = ty
  getType (ATNat ty _) = ty
  getType (ATRat _) = TyF
  getType (ATChar _) = TyC
  getType (ATString _) = TyList TyC
  getType (ATAbs _ ty _) = ty
  getType (ATApp ty _ _) = ty
  getType (ATTup ty _) = ty
  getType (ATTyOp ty _ _) = ty
  getType (ATChain ty _ _) = ty
  getType (ATContainer ty _ _ _) = ty
  getType (ATContainerComp ty _ _) = ty
  getType (ATLet ty _) = ty
  getType (ATCase ty _) = ty
  getType (ATTest _ _) = TyProp

  setType ty (ATVar _ x) = ATVar ty x
  setType ty (ATPrim _ x) = ATPrim ty x
  setType _ ATUnit = ATUnit
  setType ty (ATBool _ b) = ATBool ty b
  setType ty (ATNat _ x) = ATNat ty x
  setType _ (ATRat r) = ATRat r
  setType _ (ATChar c) = ATChar c
  setType _ (ATString cs) = ATString cs
  setType ty (ATAbs q _ x) = ATAbs q ty x
  setType ty (ATApp _ x y) = ATApp ty x y
  setType ty (ATTup _ x) = ATTup ty x
  setType ty (ATTyOp _ x y) = ATTyOp ty x y
  setType ty (ATChain _ x y) = ATChain ty x y
  setType ty (ATContainer _ x y z) = ATContainer ty x y z
  setType ty (ATContainerComp _ x y) = ATContainerComp ty x y
  setType ty (ATLet _ x) = ATLet ty x
  setType ty (ATCase _ x) = ATCase ty x
  setType _ (ATTest vs x) = ATTest vs x

instance HasType APattern where
  getType (APVar ty _) = ty
  getType (APWild ty) = ty
  getType APUnit = TyUnit
  getType (APBool _) = TyBool
  getType (APChar _) = TyC
  getType (APString _) = TyList TyC
  getType (APTup ty _) = ty
  getType (APInj ty _ _) = ty
  getType (APNat ty _) = ty
  getType (APCons ty _ _) = ty
  getType (APList ty _) = ty
  getType (APAdd ty _ _ _) = ty
  getType (APMul ty _ _ _) = ty
  getType (APSub ty _ _) = ty
  getType (APNeg ty _) = ty
  getType (APFrac ty _ _) = ty

instance HasType ABranch where
  getType = getType . snd . unsafeUnbind

------------------------------------------------------------
-- subst
------------------------------------------------------------

substQT :: QName ATerm -> ATerm -> ATerm -> ATerm
substQT x s = transform $ \case
  t@(ATVar _ y)
    | x == y -> s
    | otherwise -> t
  t -> t

------------------------------------------------------------
-- Exploding a typed term into a surface term with annotations
------------------------------------------------------------

instance Pretty ATerm where
  pretty = pretty . explode

explode :: ATerm -> Term
explode = \case
  ATVar ty x -> TAscr (TVar (coerce (qname x))) (toPolyType ty)
  ATPrim ty x -> TAscr (TPrim x) (toPolyType ty)
  ATLet ty tel -> TAscr (TLet (explodeTelescope explodeBinding tel)) (toPolyType ty)
  ATUnit -> TUnit
  ATBool _ty b -> TBool b
  ATNat ty x -> TAscr (TNat x) (toPolyType ty)
  ATRat r -> TRat r
  ATChar c -> TChar c
  ATString cs -> TString cs
  ATAbs q ty a -> TAscr (TAbs q (explodeAbs a)) (toPolyType ty)
  ATApp ty x y -> TAscr (TApp (explode x) (explode y)) (toPolyType ty)
  ATTup ty xs -> TAscr (TTup (map explode xs)) (toPolyType ty)
  ATCase ty bs -> TAscr (TCase (map explodeBranch bs)) (toPolyType ty)
  ATChain ty t ls -> TAscr (TChain (explode t) (map explodeLink ls)) (toPolyType ty)
  ATTyOp ty x y -> TAscr (TTyOp x y) (toPolyType ty)
  ATContainer ty c ts el ->
    TAscr
      (TContainer c (map (explode *** fmap explode) ts) (fmap (fmap explode) el))
      (toPolyType ty)
  ATContainerComp ty c b -> TAscr (TContainerComp c (explodeTelescope explodeQual b)) (toPolyType ty)
  ATTest _vs x -> TAscr (explode x) (toPolyType TyProp)

explodeTelescope ::
  (Alpha a, Alpha b) =>
  (a -> b) ->
  Bind (Telescope a) ATerm ->
  Bind (Telescope b) Term
explodeTelescope explodeBinder (unsafeUnbind -> (xs, at)) = bind (mapTelescope explodeBinder xs) (explode at)

explodeBinding :: ABinding -> Binding
explodeBinding (ABinding m b (unembed -> n)) = Binding m (coerce b) (embed (explode n))

explodeAbs :: Bind [APattern] ATerm -> Bind [Pattern] Term
explodeAbs (unsafeUnbind -> (aps, at)) = bind (map explodePattern aps) (explode at)

explodePattern :: APattern -> Pattern
explodePattern = \case
  APVar ty x -> PAscr (PVar (coerce x)) ty
  APWild ty -> PAscr PWild ty
  APUnit -> PUnit
  APBool b -> PBool b
  APChar c -> PChar c
  APString s -> PString s
  APTup ty ps -> PAscr (PTup (map explodePattern ps)) ty
  APInj ty s p -> PAscr (PInj s (explodePattern p)) ty
  APNat ty n -> PAscr (PNat n) ty
  APCons ty p1 p2 -> PAscr (PCons (explodePattern p1) (explodePattern p2)) ty
  APList ty ps -> PAscr (PList (map explodePattern ps)) ty
  APAdd ty s p t -> PAscr (PAdd s (explodePattern p) (explode t)) ty
  APMul ty s p t -> PAscr (PMul s (explodePattern p) (explode t)) ty
  APSub ty p t -> PAscr (PSub (explodePattern p) (explode t)) ty
  APNeg ty p -> PAscr (PNeg (explodePattern p)) ty
  APFrac ty p q -> PAscr (PFrac (explodePattern p) (explodePattern q)) ty

explodeBranch :: ABranch -> Branch
explodeBranch = explodeTelescope explodeGuard

explodeGuard :: AGuard -> Guard
explodeGuard (AGBool (unembed -> at)) = GBool (embed (explode at))
explodeGuard (AGPat (unembed -> at) ap) = GPat (embed (explode at)) (explodePattern ap)
explodeGuard (AGLet ab) = GLet (explodeBinding ab)

explodeLink :: ALink -> Link
explodeLink (ATLink bop at) = TLink bop (explode at)

explodeQual :: AQual -> Qual
explodeQual (AQBind x (unembed -> at)) = QBind (coerce x) (embed (explode at))
explodeQual (AQGuard (unembed -> at)) = QGuard (embed (explode at))