{-# LANGUAGE CPP #-}
module Env.TypeConstructor
( TypeInfo (..), tcKind, clsKind, varKind, clsMethods
, TCEnv, initTCEnv, bindTypeInfo, rebindTypeInfo
, lookupTypeInfo, qualLookupTypeInfo, qualLookupTypeInfoUnique
, getOrigName, reverseLookupByOrigName
) where
#if __GLASGOW_HASKELL__ >= 804
import Prelude hiding ((<>))
#endif
import Curry.Base.Ident
import Curry.Base.Pretty (Pretty(..), blankLine)
import Base.Kinds
import Base.Messages (internalError)
import Base.PrettyKinds ()
import Base.PrettyTypes ()
import Base.TopEnv
import Base.Types
import Base.Utils ((++!))
import Text.PrettyPrint
data TypeInfo
= DataType QualIdent Kind [DataConstr]
| RenamingType QualIdent Kind DataConstr
| AliasType QualIdent Kind Int Type
| TypeClass QualIdent Kind [ClassMethod]
| TypeVar Kind
deriving Show
instance Entity TypeInfo where
origName (DataType tc _ _) = tc
origName (RenamingType tc _ _) = tc
origName (AliasType tc _ _ _) = tc
origName (TypeClass cls _ _) = cls
origName (TypeVar _) =
internalError "Env.TypeConstructor.origName: type variable"
merge (DataType tc k cs) (DataType tc' k' cs')
| tc == tc' && k == k' && (null cs || null cs' || cs == cs') =
Just $ DataType tc k $ if null cs then cs' else cs
merge (DataType tc k _) (RenamingType tc' k' nc)
| tc == tc' && k == k' = Just (RenamingType tc k nc)
merge l@(RenamingType tc k _) (DataType tc' k' _)
| tc == tc' && k == k' = Just l
merge l@(RenamingType tc k _) (RenamingType tc' k' _)
| tc == tc' && k == k' = Just l
merge l@(AliasType tc k _ _) (AliasType tc' k' _ _)
| tc == tc' && k == k' = Just l
merge (TypeClass cls k ms) (TypeClass cls' k' ms')
| cls == cls' && k == k' && (null ms || null ms' || ms == ms') =
Just $ TypeClass cls k $ if null ms then ms' else ms
merge _ _ = Nothing
instance Pretty TypeInfo where
pPrint (DataType qid k cs) = text "data" <+> pPrint qid
<> text "/" <> pPrint k
<+> equals
<+> hsep (punctuate (text "|") (map pPrint cs))
pPrint (RenamingType qid k c) = text "newtype" <+> pPrint qid
<> text "/" <> pPrint k
<+> equals <+> pPrint c
pPrint (AliasType qid k ar ty)= text "type" <+> pPrint qid
<> text "/" <> pPrint k <> text "/" <> int ar
<+> equals <+> pPrint ty
pPrint (TypeClass qid k ms) = text "class" <+> pPrint qid
<> text "/" <> pPrint k
<+> equals
<+> vcat (blankLine : map pPrint ms)
pPrint (TypeVar _) =
internalError $ "Env.TypeConstructor.Pretty.TypeInfo.pPrint: type variable"
tcKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind
tcKind m tc tcEnv = case qualLookupTypeInfo tc tcEnv of
[DataType _ k _] -> k
[RenamingType _ k _] -> k
[AliasType _ k _ _] -> k
_ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of
[DataType _ k _] -> k
[RenamingType _ k _] -> k
[AliasType _ k _ _] -> k
_ -> internalError $
"Env.TypeConstructor.tcKind: no type constructor: " ++ show tc
clsKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind
clsKind m cls tcEnv = case qualLookupTypeInfo cls tcEnv of
[TypeClass _ k _] -> k
_ -> case qualLookupTypeInfo (qualQualify m cls) tcEnv of
[TypeClass _ k _] -> k
_ -> internalError $
"Env.TypeConstructor.clsKind: no type class: " ++ show cls
varKind :: Ident -> TCEnv -> Kind
varKind tv tcEnv
| isAnonId tv = KindStar
| otherwise = case lookupTypeInfo tv tcEnv of
[TypeVar k] -> k
_ -> internalError "Env.TypeConstructor.varKind: no type variable"
clsMethods :: ModuleIdent -> QualIdent -> TCEnv -> [Ident]
clsMethods m cls tcEnv = case qualLookupTypeInfo cls tcEnv of
[TypeClass _ _ ms] -> map methodName ms
_ -> case qualLookupTypeInfo (qualQualify m cls) tcEnv of
[TypeClass _ _ ms] -> map methodName ms
_ -> internalError $ "Env.TypeConstructor.clsMethods: " ++ show cls
type TCEnv = TopEnv TypeInfo
initTCEnv :: TCEnv
initTCEnv = foldr (uncurry $ predefTC . unapplyType False) emptyTopEnv predefTypes
where
predefTC (TypeConstructor tc, tys) =
predefTopEnv tc . DataType tc (simpleKind $ length tys)
predefTC _ =
internalError "Env.TypeConstructor.initTCEnv.predefTC: no type constructor"
bindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv
bindTypeInfo m ident ti = bindTopEnv ident ti . qualBindTopEnv qident ti
where
qident = qualifyWith m ident
rebindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv
rebindTypeInfo m ident ti = rebindTopEnv ident ti . qualRebindTopEnv qident ti
where
qident = qualifyWith m ident
lookupTypeInfo :: Ident -> TCEnv -> [TypeInfo]
lookupTypeInfo ident tcEnv = lookupTopEnv ident tcEnv ++! lookupTupleTC ident
qualLookupTypeInfo :: QualIdent -> TCEnv -> [TypeInfo]
qualLookupTypeInfo ident tcEnv =
qualLookupTopEnv ident tcEnv ++! lookupTupleTC (unqualify ident)
qualLookupTypeInfoUnique :: ModuleIdent -> QualIdent -> TCEnv -> [TypeInfo]
qualLookupTypeInfoUnique m qident tcEnv =
case qualLookupTypeInfo qident tcEnv of
[] -> []
[ti] -> [ti]
tis -> case qualLookupTypeInfo (qualQualify m qident) tcEnv of
[] -> tis
[ti] -> [ti]
tis' -> tis'
getOrigName :: ModuleIdent -> QualIdent -> TCEnv -> QualIdent
getOrigName m tc tcEnv = case qualLookupTypeInfo tc tcEnv of
[y] -> origName y
_ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of
[y] -> origName y
_ -> internalError $ "Env.TypeConstructor.getOrigName: " ++ show tc
reverseLookupByOrigName :: QualIdent -> TCEnv -> [QualIdent]
reverseLookupByOrigName on
| isQTupleId on = const [on]
| otherwise = map fst . filter ((== on) . origName . snd) . allBindings
lookupTupleTC :: Ident -> [TypeInfo]
lookupTupleTC tc | isTupleId tc = [tupleTCs !! (tupleArity tc - 2)]
| otherwise = []
tupleTCs :: [TypeInfo]
tupleTCs = map typeInfo tupleData
where
typeInfo dc@(DataConstr _ tys) =
let n = length tys in DataType (qTupleId n) (simpleKind n) [dc]
typeInfo (RecordConstr _ _ _) =
internalError "Env.TypeConstructor.tupleTCs: record constructor"