From 548b576aa13d644907c9ef1cbd0aaa7997dcf455 Mon Sep 17 00:00:00 2001 From: Sean Gillespie <sean@mistersg.net> Date: Wed, 8 Mar 2017 11:53:40 -0500 Subject: [PATCH] Update SystemF TypeChecker Implement Type Application --- src/Language/SystemF/TypeCheck.hs | 38 +++++++++++++++++++++++++- test/Language/SystemF/TypeCheckSpec.hs | 25 +++++++++++++++-- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/Language/SystemF/TypeCheck.hs b/src/Language/SystemF/TypeCheck.hs index 5cc824f..87928c8 100644 --- a/src/Language/SystemF/TypeCheck.hs +++ b/src/Language/SystemF/TypeCheck.hs @@ -18,7 +18,7 @@ typecheck uniqs ctx (Var v) = tcVar uniqs ctx v typecheck uniqs ctx (Abs n t body) = tcAbs uniqs ctx n t body typecheck uniqs ctx (App e1 e2) = tcApp uniqs ctx e1 e2 typecheck uniqs ctx (TyAbs t body) = tcTyAbs uniqs ctx t body -typecheck _ _ _ = undefined +typecheck uniqs ctx (TyApp e ty) = tcTyApp uniqs ctx e ty tcVar :: (Ord n, Eq n, PrettyPrint n) => UniqueSupply n @@ -67,12 +67,48 @@ tcTyAbs :: (Ord n, Eq n, PrettyPrint n) tcTyAbs uniqs ctx ty body = TyForAll ty <$> typecheck uniqs ctx' body where ctx' = insert ty (TyVar ty) ctx +tcTyApp :: (Ord n, Eq n, PrettyPrint n) + => UniqueSupply n + -> Context n (Ty n) + -> SystemFExpr n n + -> Ty n + -> Either String (Ty n) +tcTyApp uniqs ctx (TyAbs t expr) ty = typecheck uniqs ctx expr' + where expr' = sub t ty expr +tcTyApp uniqs ctx expr ty = typecheck uniqs ctx expr + -- Utilities unique :: UniqueSupply t -> Either String t unique (u:_) = return u unique _ = fail "Unique supply ran out" +sub :: Eq n + => n + -> Ty n + -> SystemFExpr n n + -> SystemFExpr n n +sub name ty (App e1 e2) = App (sub name ty e1) (sub name ty e2) +sub name ty (Abs n ty' e) = Abs n (subTy name ty ty') (sub name ty e) +sub name ty (TyAbs ty' e) = TyAbs ty' (sub name ty e) +sub name ty (TyApp e ty') = TyApp (sub name ty e) (subTy name ty ty') +sub name ty expr = expr + +subTy :: Eq n + => n + -> Ty n + -> Ty n + -> Ty n +subTy name ty (TyArrow t1 t2) + = TyArrow (subTy name ty t1) (subTy name ty t2) +subTy name ty ty'@(TyVar name') + | name == name' = ty + | otherwise = ty' +subTy name t1 t2@(TyForAll name' t2') + | name == name' = t2 + | otherwise = TyForAll name' (subTy name t2 t2') + + tyMismatchMsg :: (PrettyPrint t, PrettyPrint t') => t -> t' diff --git a/test/Language/SystemF/TypeCheckSpec.hs b/test/Language/SystemF/TypeCheckSpec.hs index 8676ba5..24274d6 100644 --- a/test/Language/SystemF/TypeCheckSpec.hs +++ b/test/Language/SystemF/TypeCheckSpec.hs @@ -5,9 +5,15 @@ import Data.Map import Test.Hspec +import Language.Lambda.Util.PrettyPrint import Language.SystemF.Expression import Language.SystemF.TypeCheck +tc :: (Ord n, Eq n, PrettyPrint n) + => UniqueSupply n + -> [(n, Ty n)] + -> SystemFExpr n n + -> Either String (Ty n) tc uniqs ctx = typecheck uniqs (fromList ctx) spec :: Spec @@ -51,6 +57,19 @@ spec = describe "typecheck" $ do tc ["A"] [] (TyAbs "X" (Var "x")) `shouldBe` Right (TyForAll "X" (TyVar "A")) it "typechecks type abstractions with simple abstraction" $ - tc [] [] (TyAbs "X" (Abs "x" (TyVar "X") (Var "X"))) `shouldBe` - Right (TyForAll "X" (TyArrow (TyVar "X") (TyVar "X"))) - + tc [] [] (TyAbs "X" (Abs "x" (TyVar "X") (Var "x"))) + `shouldBe` Right (TyForAll "X" (TyArrow (TyVar "X") (TyVar "X"))) + + it "typechecks type abstractions with application" $ + tc [] [("y", TyVar "Y")] + (App (TyApp (TyAbs "X" (Abs "x" (TyVar "X") (Var "x"))) (TyVar "Y")) + (Var "y")) + `shouldBe` Right (TyVar "Y") + + it "typechecks simple type applications" $ + tc [] [("x", TyVar "A")] (TyApp (TyAbs "X" (Var "x")) (TyVar "X")) + `shouldBe` Right (TyVar "A") + + it "typechecks type applications with simple abstraction" $ + tc [] [] (TyApp (TyAbs "X" (Abs "x" (TyVar "X") (Var "x"))) (TyVar "Y")) + `shouldBe` Right (TyArrow (TyVar "Y") (TyVar "Y")) -- GitLab