diff --git a/src/Language/SystemF/TypeCheck.hs b/src/Language/SystemF/TypeCheck.hs index 76616f967c36a58625cf7b7721a46957e72c9c13..522f208726ae51faf9395c81b0b5f76779748ba6 100644 --- a/src/Language/SystemF/TypeCheck.hs +++ b/src/Language/SystemF/TypeCheck.hs @@ -3,28 +3,31 @@ module Language.SystemF.TypeCheck where import Data.Map import Prelude hiding (lookup) +import Language.Lambda.Util.PrettyPrint import Language.SystemF.Expression type UniqueSupply n = [n] type Context n t = Map n t -typecheck :: (Ord n, Eq t) +typecheck :: (Ord n, Eq t, PrettyPrint t) => UniqueSupply t -> Context n (Ty t) -> SystemFExpr n t -> Either String (Ty t) 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 -tcVar :: (Ord n, Eq t) +tcVar :: (Ord n, Eq t, PrettyPrint t) => UniqueSupply t -> Context n (Ty t) -> n -> Either String (Ty t) tcVar uniqs ctx var = maybe (TyVar <$> unique uniqs) return (lookup var ctx) -tcAbs :: (Ord n, Eq t) +tcAbs :: (Ord n, Eq t, PrettyPrint t) => UniqueSupply t -> Context n (Ty t) -> n @@ -34,8 +37,46 @@ tcAbs :: (Ord n, Eq t) tcAbs uniqs ctx name ty body = TyArrow ty <$> typecheck uniqs ctx' body where ctx' = insert name ty ctx +tcApp :: (Ord n, Eq t, PrettyPrint t) + => UniqueSupply t + -> Context n (Ty t) + -> SystemFExpr n t + -> SystemFExpr n t + -> Either String (Ty t) +tcApp uniqs ctx e1 e2 = do + t1 <- typecheck uniqs ctx e1 + t2 <- typecheck uniqs ctx e2 + + -- Unwrap t1; Should be (t2 -> *) + (t2', t3) <- either genMismatchVar return (arrow t1) + + if t2' == t2 + then return t3 + else Left $ tyMismatchMsg (TyArrow t2 t3) (TyArrow t1 t3) + + where genMismatchVar expected = tyMismatchMsg expected <$> unique uniqs >>= Left + arrow (TyArrow t1 t2) = return (t1, t2) + arrow t = Left t + +tcTyAbs :: (Ord n, Eq t, PrettyPrint t) + => UniqueSupply t + -> Context n (Ty t) + -> t + -> SystemFExpr n t + -> Either String (Ty t) +tcTyAbs uniqs ctx ty body = undefined + -- Utilities unique :: UniqueSupply t -> Either String t unique (u:_) = return u unique _ = fail "Unique supply ran out" + +tyMismatchMsg :: (PrettyPrint t, PrettyPrint t') + => t + -> t' + -> String +tyMismatchMsg expected actual = "Couldn't match expected type " ++ + prettyPrint expected ++ + " with actual type " ++ + prettyPrint actual diff --git a/test/Language/SystemF/TypeCheckSpec.hs b/test/Language/SystemF/TypeCheckSpec.hs index 2776892691b47ea423d78d24fc27af289307015f..4a6d76b554c8a6b6649bee4d3bf1a6789251b6c2 100644 --- a/test/Language/SystemF/TypeCheckSpec.hs +++ b/test/Language/SystemF/TypeCheckSpec.hs @@ -1,5 +1,6 @@ module Language.SystemF.TypeCheckSpec (spec) where +import Data.Either import Data.Map import Test.Hspec @@ -20,3 +21,33 @@ spec = describe "typecheck" $ do it "typechecks simple abstractions" $ tc [] [] (Abs "x" (TyVar "A") (Var "x")) `shouldBe` Right (TyArrow (TyVar "A") (TyVar "A")) + + it "typechecks simple applications" $ do + let ctx = [ + ("f", TyArrow (TyVar "T") (TyVar "U")), + ("a", TyVar "T") + ] + + tc [] ctx (App (Var "f") (Var "a")) `shouldBe` Right (TyVar "U") + + it "apply variable to variable fails" $ do + let ctx = [ + ("a", TyVar "A"), + ("b", TyVar "B") + ] + + tc ["C"] ctx (App (Var "a") (Var "b")) + `shouldSatisfy` isLeft + + it "apply arrow to variable of wrong type fails" $ do + let ctx = [ + ("f", TyArrow (TyVar "F") (TyVar "G")), + ("b", TyVar "B") + ] + + tc [] ctx (App (Var "f") (Var "b")) `shouldSatisfy` isLeft + + it "typechecks simple type abstractions" $ do + pendingWith "Not implemented" + tc ["A"] [] (TyAbs "X" (Var "x")) `shouldBe` Right (TyForAll "X" (TyVar "A")) +