module Language.Haskell.TypeCheck.InternalTypes where
import Text.PrettyPrint.HughesPJ
import Data.IORef
import Data.List( nub, intersperse )
import Data.Maybe( fromMaybe )
import Language.Haskell.Exts.Syntax
import Language.Haskell.Exts.Pretty ( Pretty, prettyPrint )
infixr 4 -->
type Sigma = TcType
type Rho = TcType
type Tau = TcType
type Kappa = TcType
data TcType = TcForAll [TcTyVarBind] [TcAsst] Rho
| TcTyFun TcType TcType
| TcTyCon QName
| TcTyVar TyVar
| TcTyApp TcType TcType
| MetaTv MetaTv
deriving Eq
data TcAsst = TcClassA QName [Tau]
deriving (Eq, Show)
type TcCtxt = [TcAsst]
data TcAxiom = TcAxiom [TcTyVarBind] TcCtxt TcAsst
deriving (Eq, Show)
data TcTyVarBind = TcTyVarBind TyVar Kappa
deriving (Eq, Show)
unTvBind :: TcTyVarBind -> TyVar
unTvBind (TcTyVarBind t _) = t
data TyVar = BoundTv String
| SkolemTv String Uniq
data MetaTv = Meta Uniq TyRef
type TyRef = IORef (Maybe TcType)
instance Eq MetaTv where
(Meta u1 _) == (Meta u2 _) = u1 == u2
instance Show MetaTv where
show (Meta u _) = "$$" ++ show u
instance Eq TyVar where
(BoundTv s1) == (BoundTv s2) = s1 == s2
(SkolemTv _ u1) == (SkolemTv _ u2) = u1 == u2
instance Show TyVar where
show (BoundTv s) = s
show (SkolemTv s _) = s
type Uniq = Int
(-->) :: Sigma -> Sigma -> Sigma
arg --> res = TcTyFun arg res
(@@) :: Sigma -> Sigma -> Sigma
fun @@ arg = TcTyApp fun arg
con :: String -> Sigma
con = TcTyCon . UnQual . Ident
forAll :: [TcTyVarBind] -> TcCtxt -> Rho -> Sigma
forAll [] [] ty = ty
forAll tvbs cx (TcForAll bndrs ctxt ty) = TcForAll (tvbs ++ bndrs) (cx ++ ctxt) ty
forAll tvbs cx ty = TcForAll tvbs cx ty
isSimple :: Sigma -> Bool
isSimple (TcTyApp t _) = isSimple t
isSimple (TcTyCon _) = True
isSimple _ = False
metaTvs :: [TcType] -> [MetaTv]
metaTvs tys = foldr go [] tys
where
go (MetaTv tv) acc
| tv `elem` acc = acc
| otherwise = tv : acc
go (TcTyVar _) acc = acc
go (TcTyCon _) acc = acc
go (TcTyFun arg res) acc = go arg (go res acc)
go (TcTyApp fun arg) acc = go fun (go arg acc)
go (TcForAll _ _ ty) acc = go ty acc
freeTyVars :: [TcType] -> [TyVar]
freeTyVars tys = foldr (go []) [] tys
where
go :: [TyVar]
-> TcType
-> [TyVar]
-> [TyVar]
go bound (TcTyVar tv) acc
| tv `elem` bound = acc
| tv `elem` acc = acc
| otherwise = tv : acc
go bound (MetaTv _) acc = acc
go bound (TcTyCon _) acc = acc
go bound (TcTyFun arg res) acc = go bound arg (go bound res acc)
go bound (TcTyApp fun arg) acc = go bound fun (go bound arg acc)
go bound (TcForAll tvbs _ ty) acc = go (map unTvBind tvbs ++ bound) ty acc
tyVarBndrs :: Rho -> [TyVar]
tyVarBndrs ty = nub (bndrs ty)
where
bndrs (TcForAll tvbs _ body) = map unTvBind tvbs ++ bndrs body
bndrs (TcTyFun arg res) = bndrs arg ++ bndrs res
bndrs (TcTyApp fun arg) = bndrs fun ++ bndrs arg
bndrs _ = []
tyVarName :: TyVar -> String
tyVarName (BoundTv n) = n
tyVarName (SkolemTv n _) = n
type Env = [(TyVar, Tau)]
substTy :: [TyVar] -> [TcType] -> TcType -> TcType
substTy tvs tys ty = subst_ty (tvs `zip` tys) ty
subst_ty :: Env -> TcType -> TcType
subst_ty env (TcTyFun arg res) = TcTyFun (subst_ty env arg) (subst_ty env res)
subst_ty env (TcTyApp fun arg) = TcTyApp (subst_ty env fun) (subst_ty env arg)
subst_ty env (TcTyVar n) = fromMaybe (TcTyVar n) (lookup n env)
subst_ty env (MetaTv tv) = MetaTv tv
subst_ty env (TcTyCon tc) = TcTyCon tc
subst_ty env (TcForAll ns ctxt rho) = TcForAll ns (subst_ctxt env' ctxt) (subst_ty env' rho)
where
env' = [(n,ty') | (n,ty') <- env, not (n `elem` map unTvBind ns)]
substCtxt :: [TyVar] -> [TcType] -> TcCtxt -> TcCtxt
substCtxt tvs tys ctxt = subst_ctxt (tvs `zip` tys) ctxt
subst_ctxt :: Env -> TcCtxt -> TcCtxt
subst_ctxt env = map (subst_asst env)
substAsst :: [TyVar] -> [TcType] -> TcAsst -> TcAsst
substAsst tvs tys asst = head $ substCtxt tvs tys [asst]
subst_asst :: Env -> TcAsst -> TcAsst
subst_asst env (TcClassA qn ts) = TcClassA qn (map (subst_ty env) ts)
fromSrcKind :: Kind -> Kappa
fromSrcKind sk = case sk of
KindStar -> starK
KindFn k1 k2 -> TcTyFun (fromSrcKind k1) (fromSrcKind k2)
KindParen k -> fromSrcKind k
_ -> error "fromSrcKind: unsupported kind"
starK = TcTyCon $ UnQual $ Symbol "*"
class Outputable a where
ppr :: a -> Doc
docToString :: Doc -> String
docToString = render
dcolon, dot :: Doc
dcolon = text "::"
dot = char '.'
instance Outputable TcType where
ppr ty = pprType topPrec ty
instance Outputable MetaTv where
ppr (Meta u _) = text "$" <> int u
instance Outputable TyVar where
ppr (BoundTv n) = text n
ppr (SkolemTv n u) = text n <+> int u
instance Outputable TcTyVarBind where
ppr (TcTyVarBind t k) = ppr t
instance Show TcType where
show t = docToString (ppr t)
instance Outputable TcAsst where
ppr (TcClassA qn ts) = text (prettyPrint qn) <+> hsep (map (pprType atomicPrec) ts)
type Precedence = Int
topPrec, arrPrec, tcPrec, atomicPrec :: Precedence
topPrec = 0
arrPrec = 1
tcPrec = 2
atomicPrec = 3
precType :: TcType -> Precedence
precType (TcForAll _ _ _) = topPrec
precType (TcTyFun _ _) = arrPrec
precType (TcTyApp _ _) = tcPrec
precType _ = atomicPrec
pprParendType :: TcType -> Doc
pprParendType ty = pprType tcPrec ty
pprType :: Precedence -> TcType -> Doc
pprType p ty | p >= precType ty = parens (ppr_type ty)
| otherwise = ppr_type ty
ppr_type :: TcType -> Doc
ppr_type (TcForAll ns ctxt ty) = sep [text "forall" <+> hsep (map ppr ns) <> dot, ppr_ctxt ctxt, ppr ty]
ppr_type (TcTyFun arg res) = sep [pprType arrPrec arg <+> text "->", pprType (arrPrec1) res]
ppr_type (TcTyApp fun arg) = sep [pprType tcPrec fun, pprType (tcPrec1) arg]
ppr_type (TcTyCon qn) = text $ prettyPrint qn
ppr_type (TcTyVar n) = ppr n
ppr_type (MetaTv tv) = ppr tv
ppr_ctxt :: TcCtxt -> Doc
ppr_ctxt [] = empty
ppr_ctxt as = (parens $ sep $ intersperse (char ',') $ map ppr as) <+> text "=>"