1 {-# LANGUAGE AllowAmbiguousTypes #-}
2 {-# LANGUAGE UndecidableInstances #-}
3 {-# OPTIONS_GHC -fno-warn-orphans #-}
4 module Typing.Test where
7 import Test.Tasty.HUnit
9 import Control.Applicative (Applicative(..))
10 import Control.Arrow (left)
11 import Data.Functor.Identity (Identity(..))
12 import Data.List.NonEmpty (NonEmpty)
13 import Data.Map.Strict (Map)
14 import Data.Maybe (isJust)
15 import Data.NonNull (NonNull)
17 import Data.Ratio (Ratio)
18 import Data.Text (Text)
19 import GHC.Exts (Constraint)
20 import Prelude hiding (exp)
21 import qualified Control.Monad.Classes.Run as MC
22 import qualified Control.Monad.Trans.State.Strict as SS
23 import qualified Data.Function as Fun
24 import qualified Data.Map.Strict as Map
25 import qualified Data.MonoTraversable as MT
26 import qualified Data.Sequences as Seqs
27 import qualified System.IO as IO
28 import qualified Text.Megaparsec as P
29 import qualified Text.Megaparsec.Prim as P
31 import Language.Symantic.Grammar
32 import Language.Symantic
33 import Language.Symantic.Lib hiding ((<$>), (<*), show)
35 import Grammar.Megaparsec ()
66 , Proxy MT.MonoFoldable
67 , Proxy MT.MonoFunctor
71 , Proxy Seqs.IsSequence
72 , Proxy Seqs.SemiSequence
76 type SRC = SrcTe (NonEmpty P.SourcePos) SS
78 impsTy :: Imports NameTy
79 impsTy = importTypes @SS []
81 modsTy :: Source src => ModulesTy src
83 Map.insert ([] `Mod` "String")
84 (TypeTLen $ \len -> TypeT $
85 tyConstLen @(K []) @[] len `tyApp`
86 tyConstLen @(K Char) @Char len) $
91 g ~ P.ParsecT err inp (SS.StateT (Imports NameTy, ModulesTy src) Identity) =>
92 P.MonadParsec err inp (P.ParsecT err inp g) =>
95 inp -> Either (P.ParseError Char err) (AST_Type src)
98 MC.evalStateStrict (impsTy, modsTy @src) $
100 where g = unCF $ g_type <* eoi
103 tests = testGroup "Typing" $
104 [ testGroup "readType" $
105 let run inp (TypeT exp :: TypeT SRC '[]) =
106 testCase inp $ got @?= Right (Right $ TypeVT exp)
108 got :: Either (P.ParseError Char P.Dec)
109 (Either (Error_Type SRC) (TypeVT SRC))
110 got = readType <$> parseTy inp
112 let (==>) = run; infixr 0 ==> in
113 [ "Bool" ==> TypeT $ tyBool
114 , "(->) Bool" ==> TypeT $ tyFun `tyApp` tyBool
115 , "[]" ==> TypeT $ tyConst @(K []) @[]
116 , "[Char]" ==> TypeT $ tyList tyChar
117 , "[Char -> [Char]]" ==> TypeT $ tyList (tyChar ~> tyList tyChar)
118 , "([])" ==> TypeT $ tyConst @(K []) @[]
119 , "[()]" ==> TypeT $ tyList tyUnit
120 , "()" ==> TypeT $ tyUnit
121 , "(())" ==> TypeT $ tyUnit
122 , "(,)" ==> TypeT $ tyConst @(K (,)) @(,)
123 , "((,))" ==> TypeT $ tyConst @(K (,)) @(,)
124 , "(,) Int" ==> TypeT $ tyConst @(K (,)) @(,) `tyApp` tyInt
125 , "(Bool)" ==> TypeT $ tyBool
126 , "((Bool))" ==> TypeT $ tyBool
127 , "(Bool, Int)" ==> TypeT $ tyBool `tyTuple2` tyInt
128 , "((Bool, Int))" ==> TypeT $ tyBool `tyTuple2` tyInt
129 , "((Bool, Int), Char)" ==> TypeT $ (tyBool `tyTuple2` tyInt) `tyTuple2` tyChar
130 , "(Bool, Int) -> Char" ==> TypeT $ (tyBool `tyTuple2` tyInt) ~> tyChar
131 , "(Bool -> Int)" ==> TypeT $ tyBool ~> tyInt
132 , "String" ==> TypeT $ tyList tyChar
133 , "[Char] -> String" ==> TypeT $ tyList tyChar ~> tyList tyChar
134 , "String -> [Char]" ==> TypeT $ tyList tyChar ~> tyList tyChar
135 , "Maybe Bool" ==> TypeT $ tyMaybe tyBool
136 , "Either Bool Int" ==> TypeT $ tyEither tyBool tyInt
137 , "Bool -> Int" ==> TypeT $ tyBool ~> tyInt
138 , "(Bool -> Int) -> Char" ==> TypeT $ (tyBool ~> tyInt) ~> tyChar
139 , "Bool -> (Int -> Char)" ==> TypeT $ tyBool ~> (tyInt ~> tyChar)
140 , "Bool -> Int -> Char" ==> TypeT $ tyBool ~> tyInt ~> tyChar
141 , "Bool -> (Int -> Char) -> ()" ==> TypeT $ tyBool ~> (tyInt ~> tyChar) ~> tyUnit
142 , "IO" ==> TypeT $ tyConst @(K IO) @IO
143 , "Traversable IO" ==> TypeT $ tyTraversable (tyConst @(K IO) @IO)
144 , "Monad IO" ==> TypeT $ tyMonad (tyConst @(K IO) @IO)
145 , "(->) (IO Bool)" ==> TypeT $ tyConst @(K (->)) @(->) `tyApp` (tyIO tyBool)
146 , "Monad IO" ==> TypeT $ tyMonad (tyConst @(K IO) @IO)
147 , "Eq" ==> TypeT $ tyConst @(K Eq) @Eq
148 , "Eq Bool" ==> TypeT $ tyEq tyBool
150 , testGroup "Parsing errors" $
151 let run inp = testCase inp $ got @?= Left ()
153 got :: Either () (AST_Type SRC)
154 got = left (\(_::P.ParseError (P.Token String) P.Dec) -> ()) $ parseTy inp in
157 , "(Bool -> Int) Char"
160 , testGroup "Compiling errors" $
161 let run inp = testCase inp $ got @?= Right (Left ())
163 got :: Either (P.ParseError Char P.Dec) (Either () (TypeVT SRC))
164 got = left (Fun.const ()) . readType <$> parseTy inp in
169 , "(->) Bool Int Char"
172 , testGroup "proveConstraint" $
173 let (==>) (typ::Type SRC SS (t::Constraint)) expected =
174 let imps = importTypes @SS [] in
175 let conf = config_Doc_Type{config_Doc_Type_imports = imps} in
176 testCase (showType conf typ) $
177 isJust (proveConstraint typ) @?= expected in
178 [ tyEq tyBool ==> True
179 , tyOrd tyBool ==> True
180 , tyFunctor (tyConst @(K Maybe) @Maybe) ==> True
181 , tyFunctor (tyConst @(K IO) @IO) ==> True
182 , tyMonad (tyConst @(K IO) @IO) ==> True
183 , tyTraversable (tyConst @(K IO) @IO) ==> False