@@ -3,13 +3,19 @@
3-- checks and ensure that `main` has an acceptable type.
3-- checks and ensure that `main` has an acceptable type.
4module Type.ExtraChecks (extraChecks) where
4module Type.ExtraChecks (extraChecks) where
6+import Control.Applicative ((<$>),(<*>))
6import qualified Data.Map as Map
7import qualified Data.Map as Map
8+import qualified Data.UnionFind.IO as UF
9+import Type.Type ( Variable, structure, Term1(..) )
7import Type.State (Env)
10import Type.State (Env)
8import Type.PrettyPrint ( pretty, ParensWhen(Never) )
11import Type.PrettyPrint ( pretty, ParensWhen(Never) )
9import Text.PrettyPrint as P
12import Text.PrettyPrint as P
11−extraChecks :: Env -> Either [P.Doc] Env
14+extraChecks :: Env -> IO (Either [P.Doc] Env)
12−extraChecks env = occursCheck =<< mainCheck env
15+extraChecks env =
16+ case mainCheck env of
17+ Left errs -> return $ Left errs
18+ Right env -> occursCheck env
14mainCheck :: Env -> Either [P.Doc] Env
20mainCheck :: Env -> Either [P.Doc] Env
15mainCheck env =
21mainCheck env =
@@ -19,7 +25,37 @@ mainCheck env =
19 | P.render (pretty Never var) `elem` ["Element","Signal Element"] -> Right env
25 | P.render (pretty Never var) `elem` ["Element","Signal Element"] -> Right env
20 | otherwise ->
26 | otherwise ->
21 Left [ P.vcat [ P.text "Type Error:"
27 Left [ P.vcat [ P.text "Type Error:"
22− , P.text "'main' must be an Element or a (Signal Element)" ] ]
28+ , P.text "'main' must be an Element or a (Signal Element)\n" ] ]
24−occursCheck :: Env -> Either [P.Doc] Env
30+occursCheck :: Env -> IO (Either [P.Doc] Env)
25−occursCheck env = return env
31+occursCheck env = do
32+ errors <- concat <$> mapM isFinite (Map.toList env)
33+ return $ if null errors then Right env else Left errors
35+isFinite :: (String, Variable) -> IO [P.Doc]
36+isFinite (name, var) =
37+ do varIsFinite <- go [] var
41+ False -> [ P.vcat [ P.text "Type Error:"
42+ , P.text $ "Cannot construct infinite type for '" ++ name ++ "'\n"
46+ go :: [Variable] -> Variable -> IO Bool
48+ let check = go (var:seen) in
49+ case var `elem` seen of
52+ desc <- UF.descriptor var
53+ case structure desc of
54+ Nothing -> return True
57+ App1 a b -> (&&) <$> check a <*> check b
58+ Fun1 a b -> (&&) <$> check a <*> check b
60+ EmptyRecord1 -> return True
61+ Record1 fields ext -> and <$> mapM check (ext : concat (Map.elems fields))