{-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} {- Data/Singletons/TH/Syntax.hs (c) Richard Eisenberg 2014 rae@cs.brynmawr.edu Converts a list of DLetDecs into a LetDecEnv for easier processing, and contains various other AST definitions. -} module Data.Singletons.TH.Syntax where import Prelude hiding ( exp ) import Data.Kind (Constraint, Type) import Language.Haskell.TH.Syntax hiding (Type) import Language.Haskell.TH.Desugar import qualified Language.Haskell.TH.Desugar.OMap.Strict as OMap import Language.Haskell.TH.Desugar.OMap.Strict (OMap) type VarPromotions = [(Name, Name)] -- from term-level name to type-level name -- A list of 'SingDSigPaInfos' is produced when singling pattern signatures, as we -- must case on the 'DExp's and match on them using the supplied 'DType's to -- bring the necessary singleton equality constraints into scope. -- See @Note [Singling pattern signatures]@. type SingDSigPaInfos = [(DExp, DType)] -- The parts of data declarations that are relevant to singletons-th. data DataDecl = DataDecl DataFlavor Name [DTyVarBndrUnit] [DCon] -- The parts of type synonyms that are relevant to singletons-th. data TySynDecl = TySynDecl Name [DTyVarBndrUnit] DType -- The parts of open type families that are relevant to singletons-th. type OpenTypeFamilyDecl = TypeFamilyDecl 'Open -- The parts of closed type families that are relevant to singletons-th. type ClosedTypeFamilyDecl = TypeFamilyDecl 'Closed -- The parts of type families that are relevant to singletons-th. newtype TypeFamilyDecl (info :: FamilyInfo) = TypeFamilyDecl { getTypeFamilyDecl :: DTypeFamilyHead } -- Whether a type family is open or closed. data FamilyInfo = Open | Closed data ClassDecl ann = ClassDecl { cd_cxt :: DCxt , cd_name :: Name , cd_tvbs :: [DTyVarBndrUnit] , cd_fds :: [FunDep] , cd_lde :: LetDecEnv ann , cd_atfs :: [OpenTypeFamilyDecl] -- Associated type families. Only recorded for -- defunctionalization purposes. -- See Note [Partitioning, type synonyms, and type families] -- in D.S.TH.Partition. } data InstDecl ann = InstDecl { id_cxt :: DCxt , id_name :: Name , id_arg_tys :: [DType] , id_sigs :: OMap Name DType , id_meths :: [(Name, LetDecRHS ann)] } type UClassDecl = ClassDecl Unannotated type UInstDecl = InstDecl Unannotated type AClassDecl = ClassDecl Annotated type AInstDecl = InstDecl Annotated {- We see below several datatypes beginning with "A". These are annotated structures, necessary for Promote to communicate key things to Single. In particular, promotion of expressions is *not* deterministic, due to the necessity to create unique names for lets, cases, and lambdas. So, we put these promotions into an annotated AST so that Single can use the right promotions. -} -- A DExp with let, lambda, and type-signature nodes annotated with their -- type-level equivalents data ADExp = ADVarE Name | ADConE Name | ADLitE Lit | ADAppE ADExp ADExp | ADLamE [Name] -- type-level names corresponding to term-level ones DType -- the promoted lambda [Name] ADExp | ADCaseE ADExp [ADMatch] DType -- the type is the return type | ADLetE ALetDecEnv ADExp | ADSigE DType -- the promoted expression ADExp DType -- A DPat with a pattern-signature node annotated with its type-level equivalent data ADPat = ADLitP Lit | ADVarP Name | ADConP Name [DType] [ADPat] | ADTildeP ADPat | ADBangP ADPat | ADSigP DType -- The promoted pattern. Will not contain any wildcards, -- as per Note [Singling pattern signatures] ADPat DType | ADWildP data ADMatch = ADMatch VarPromotions ADPat ADExp data ADClause = ADClause VarPromotions [ADPat] ADExp data AnnotationFlag = Annotated | Unannotated -- These are used at the type-level exclusively type Annotated = 'Annotated type Unannotated = 'Unannotated type family IfAnn (ann :: AnnotationFlag) (yes :: k) (no :: k) :: k where IfAnn Annotated yes no = yes IfAnn Unannotated yes no = no data family LetDecRHS :: AnnotationFlag -> Type data instance LetDecRHS Annotated = -- A function definition. Invariant: each ADClause contains at least one -- pattern. AFunction Int -- The number of arrows in the type. As a consequence of the invariant -- above, this is always a positive number. [ADClause] | -- A value whose definition is given by the DExp. Invariant: the value is -- not a function (i.e., there are no occurrences of (->) in the value's -- type). AValue ADExp data instance LetDecRHS Unannotated = UFunction [DClause] | UValue DExp type ALetDecRHS = LetDecRHS Annotated type ULetDecRHS = LetDecRHS Unannotated data LetDecEnv ann = LetDecEnv { lde_defns :: OMap Name (LetDecRHS ann) , lde_types :: OMap Name DType -- type signatures , lde_infix :: OMap Name Fixity -- infix declarations , lde_proms :: IfAnn ann (OMap Name DType) () -- possibly, promotions } type ALetDecEnv = LetDecEnv Annotated type ULetDecEnv = LetDecEnv Unannotated instance Semigroup ULetDecEnv where LetDecEnv defns1 types1 infx1 _ <> LetDecEnv defns2 types2 infx2 _ = LetDecEnv (defns1 <> defns2) (types1 <> types2) (infx1 <> infx2) () instance Monoid ULetDecEnv where mempty = LetDecEnv OMap.empty OMap.empty OMap.empty () valueBinding :: Name -> ULetDecRHS -> ULetDecEnv valueBinding n v = emptyLetDecEnv { lde_defns = OMap.singleton n v } typeBinding :: Name -> DType -> ULetDecEnv typeBinding n t = emptyLetDecEnv { lde_types = OMap.singleton n t } infixDecl :: Fixity -> Name -> ULetDecEnv infixDecl f n = emptyLetDecEnv { lde_infix = OMap.singleton n f } emptyLetDecEnv :: ULetDecEnv emptyLetDecEnv = mempty buildLetDecEnv :: Quasi q => [DLetDec] -> q ULetDecEnv buildLetDecEnv = go emptyLetDecEnv where go acc [] = return acc go acc (DFunD name clauses : rest) = go (valueBinding name (UFunction clauses) <> acc) rest go acc (DValD (DVarP name) exp : rest) = go (valueBinding name (UValue exp) <> acc) rest go acc (dec@(DValD {}) : rest) = do flattened <- flattenDValD dec go acc (flattened ++ rest) go acc (DSigD name ty : rest) = go (typeBinding name ty <> acc) rest go acc (DInfixD f n : rest) = go (infixDecl f n <> acc) rest go acc (DPragmaD{} : rest) = go acc rest -- See Note [DerivedDecl] data DerivedDecl (cls :: Type -> Constraint) = DerivedDecl { ded_mb_cxt :: Maybe DCxt , ded_type :: DType , ded_type_tycon :: Name , ded_decl :: DataDecl } type DerivedEqDecl = DerivedDecl Eq type DerivedShowDecl = DerivedDecl Show {- Note [DerivedDecl] ~~~~~~~~~~~~~~~~~~~~~ Most derived instances are wholly handled in Data.Singletons.TH.Partition.partitionDecs. There are two notable exceptions to this rule, however, that are partially handled outside of partitionDecs: Eq and Show instances. For these instances, we use a DerivedDecl data type to encode just enough information to recreate the derived instance: 1. Just the instance context, if it's standalone-derived, or Nothing if it's in a deriving clause (ded_mb_cxt) 2. The datatype, applied to some number of type arguments, as in the instance declaration (ded_type) 3. The datatype name (ded_type_tycon), cached for convenience 4. The datatype's constructors (ded_cons) Why are these instances handled outside of partitionDecs? * Deriving Eq in singletons-th not only derives PEq/SEq instances, but it also derives SDecide, TestEquality, and TestCoercion instances. Data.Singletons.TH.Single (depending on the task at hand). * Deriving Show in singletons-th not only derives PShow/SShow instances, but it also derives Show instances for singletons-th types. To make this work, we let partitionDecs handle the P{Eq,Show} and S{Eq,Show} instances, but we also stick the relevant info into a DerivedDecl value for later use in Data.Singletons.TH.Single, where we additionally generate SDecide, TestEquality, TestCoercion and Show instances for singleton types. -}