Fixed pattern match bug in HM, removed some unused code, added debug

help in main
This commit is contained in:
sebastian 2023-05-16 23:32:29 +02:00
parent 0fd8a9bc74
commit 0e7d485e9e
3 changed files with 43 additions and 30 deletions

View file

@ -155,6 +155,7 @@ main' opts s =
when check (removeDirectoryRecursive "output") when check (removeDirectoryRecursive "output")
createDirectory "output" createDirectory "output"
createDirectory "output/logs" createDirectory "output/logs"
when opts.logIL (writeFile "output/logs/tc.log" (printTree typechecked))
when opts.debug $ do when opts.debug $ do
printToErr "\n -- Compiler --" printToErr "\n -- Compiler --"
writeFile "output/llvm.ll" generatedCode writeFile "output/llvm.ll" generatedCode

View file

@ -2,7 +2,6 @@
{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QualifiedDo #-} {-# LANGUAGE QualifiedDo #-}
{-# OPTIONS_GHC -Wno-incomplete-patterns #-}
-- | A module for type checking and inference using algorithm W, Hindley-Milner -- | A module for type checking and inference using algorithm W, Hindley-Milner
module TypeChecker.TypeCheckerHm where module TypeChecker.TypeCheckerHm where
@ -17,10 +16,8 @@ import Control.Monad.Writer
import Data.Coerce (coerce) import Data.Coerce (coerce)
import Data.Function (on) import Data.Function (on)
import Data.List (foldl') import Data.List (foldl')
import Data.List.Extra (unsnoc)
import Data.Map (Map) import Data.Map (Map)
import Data.Map qualified as M import Data.Map qualified as M
import Data.Maybe (fromJust)
import Data.Set (Set) import Data.Set (Set)
import Data.Set qualified as S import Data.Set qualified as S
import Grammar.Abs import Grammar.Abs
@ -333,7 +330,7 @@ algoW = \case
withBinding (coerce name) fr $ do withBinding (coerce name) fr $ do
(s1, e@(_, t0)) <- algoW (makeLambda e (coerce args)) (s1, e@(_, t0)) <- algoW (makeLambda e (coerce args))
env <- asks vars env <- asks vars
let t' = generalize (apply s1 env) t0 let t' = generalize (apply s1 (M.elems env)) t0
withBinding (coerce name) t' $ do withBinding (coerce name) t' $ do
(s2, (e1', t2)) <- algoW e1 (s2, (e1', t2)) <- algoW e1
let comp = s2 <> s1 let comp = s2 <> s1
@ -355,6 +352,7 @@ checkCase _ [] = do
return (nullSubst, [], fr) return (nullSubst, [], fr)
checkCase expT brnchs = do checkCase expT brnchs = do
(subs, branchTs, injs, returns) <- unzip4 <$> mapM inferBranch brnchs (subs, branchTs, injs, returns) <- unzip4 <$> mapM inferBranch brnchs
-- compose all probably wrong
let sub0 = composeAll subs let sub0 = composeAll subs
(sub1, _) <- (sub1, _) <-
foldM foldM
@ -431,8 +429,7 @@ inferPattern = \case
) )
t t
let numArgs = typeLength t - 1 let numArgs = typeLength t - 1
let (vs, ret) = fromJust (unsnoc $ flattenType t) (pats, typs) <- mapAndUnzipM inferPattern patterns
patterns <- mapM inferPattern patterns
unless unless
(length patterns == numArgs) (length patterns == numArgs)
( catchableErr $ Aux.do ( catchableErr $ Aux.do
@ -443,10 +440,11 @@ inferPattern = \case
" arguments but has been given " " arguments but has been given "
show (length patterns) show (length patterns)
) )
sub <- composeAll <$> zipWithM unify vs (map snd patterns) fr <- fresh
sub <- unify t (foldr TFun fr typs)
return return
( T.PInj (coerce constr) (apply sub patterns) ( T.PInj (coerce constr) (apply sub $ zip pats typs)
, apply sub ret , apply sub fr
) )
-- | Unify two types producing a new substitution -- | Unify two types producing a new substitution
@ -485,15 +483,6 @@ unify t0 t1 = case (t0, t1) of
"does not match with:" "does not match with:"
printTree name' printTree name'
quote $ printTree t' quote $ printTree t'
(TEVar a, TEVar b) ->
if a == b
then return nullSubst
else catchableErr $
Aux.do
"Can not unify"
quote $ printTree (TEVar a)
"with"
quote $ printTree (TEVar b)
(a, b) -> do (a, b) -> do
catchableErr $ catchableErr $
Aux.do Aux.do
@ -507,7 +496,6 @@ I.E. { a = a -> b } is an unsolvable constraint since there is no substitution
where these are equal where these are equal
-} -}
occurs :: TVar -> Type -> Infer Subst occurs :: TVar -> Type -> Infer Subst
occurs i t@(TEVar _) = return (singleton i t)
occurs i t@(TVar _) = return (singleton i t) occurs i t@(TVar _) = return (singleton i t)
occurs i t occurs i t
| S.member i (free t) = | S.member i (free t) =
@ -526,7 +514,7 @@ occurs i t
Type checks: let f = \x. x in (f True, f 'a') Type checks: let f = \x. x in (f True, f 'a')
Does not type check: (\f. (f True, f 'a')) (\x. x) Does not type check: (\f. (f True, f 'a')) (\x. x)
-} -}
generalize :: Map T.Ident Type -> Type -> Type generalize :: [Type] -> Type -> Type
generalize env t = go (S.toList $ free t S.\\ free env) (removeForalls t) generalize env t = go (S.toList $ free t S.\\ free env) (removeForalls t)
where where
go :: [TVar] -> Type -> Type go :: [TVar] -> Type -> Type
@ -570,6 +558,7 @@ fresh = do
return . TVar . MkTVar . LIdent $ letters !! n return . TVar . MkTVar . LIdent $ letters !! n
-- Is the left more general than the right -- Is the left more general than the right
-- TODO: A bug might exist
(<<=) :: Type -> Type -> Infer Bool (<<=) :: Type -> Type -> Infer Bool
(<<=) a b = case (a, b) of (<<=) a b = case (a, b) of
(TVar _, _) -> return True (TVar _, _) -> return True
@ -592,7 +581,6 @@ fresh = do
where where
go :: [TVar] -> Type -> Type -> Infer Bool go :: [TVar] -> Type -> Type -> Infer Bool
go tvars t1 t2 = do go tvars t1 t2 = do
-- probably not necessary
freshies <- mapM (const fresh) tvars freshies <- mapM (const fresh) tvars
let sub = Subst . M.fromList $ zip tvars freshies let sub = Subst . M.fromList $ zip tvars freshies
let t1' = apply sub t1 let t1' = apply sub t1
@ -638,7 +626,6 @@ instance FreeVars Type where
free (TLit _) = mempty free (TLit _) = mempty
free (TFun a b) = free a `S.union` free b free (TFun a b) = free a `S.union` free b
free (TData _ a) = free a free (TData _ a) = free a
free (TEVar _) = S.empty
instance FreeVars a => FreeVars [a] where instance FreeVars a => FreeVars [a] where
free = let f acc x = acc `S.union` free x in foldl' f S.empty free = let f acc x = acc `S.union` free x in foldl' f S.empty
@ -656,9 +643,6 @@ instance SubstType Type where
Just _ -> apply sub t Just _ -> apply sub t
TFun a b -> TFun (apply sub a) (apply sub b) TFun a b -> TFun (apply sub a) (apply sub b)
TData name a -> TData name (apply sub a) TData name a -> TData name (apply sub a)
TEVar (MkTEVar a) -> case find (MkTVar a) sub of
Nothing -> TEVar (MkTEVar $ coerce a)
Just t -> t
instance FreeVars (Map T.Ident Type) where instance FreeVars (Map T.Ident Type) where
free :: Map T.Ident Type -> Set TVar free :: Map T.Ident Type -> Set TVar

View file

@ -1,6 +1,34 @@
main = sigma 0 10 data Maybe a where
Nothing : Maybe a
Just : a -> Maybe a
data Either a b where
Left : a -> Either a b
Right : b -> Either a b
data List a where
Nil : List a
Cons : a -> List a -> List a
data Foo a where
Foo : List a -> Foo a
data Bar a where
Bar : Foo a -> Bar a
test = \x . case x of
Left (Just (Bar (Foo (Cons 1 Nil)))) => 1
_ => 0
main = 0
-- pattern1 = PInj (UIdent "Foo") [PInj (UIdent "Cons") [PLit (LInt 1), PEnum (UIdent "Nil")]]
-- env = Env { sigs = mempty, count = 0, nextChar = 'a', declaredBinds = mempty, takenTypeVars = mempty, injections = M.insert (T.Ident "Foo") (TFun list foo) $ M.insert (T.Ident "Nil") list $ M.singleton (T.Ident "Cons") (TFun a (TFun list list))}
-- list = TData (UIdent "List") [a]
-- foo = TData (UIdent "Foo") [a]
-- a = TVar $ MkTVar "a"
-- pattern2 = PInj (UIdent "Foo") [PInj (UIdent "Cons") [PLit (LInt 1),PEnum (UIdent "Nil")]]
-- (snd . fst) <$> run' env initCtx (inferPattern pattern1)
-- (snd . fst) <$> run' env initCtx (inferPattern pattern2)
sigma : Int -> Int -> Int
sigma from to = case from == to of
True => from
False => to + sigma from (to - 1)