{-# LANGUAGE CPP #-} import Data.Rank1Dynamic import Data.Rank1Typeable import Test.Framework import Test.Framework.Providers.HUnit import Test.HUnit hiding (Test) import Unsafe.Coerce funKindStr :: String #if __GLASGOW_HASKELL__ >= 804 funKindStr = "->" #else funKindStr = "(->)" #endif main :: IO () main = defaultMain tests tests :: [Test] tests = [ testGroup "Examples of isInstanceOf" [ testCase "CANNOT use a term of type 'Int -> Bool' as 'Int -> Int'" $ typeOf (undefined :: Int -> Int) `isInstanceOf` typeOf (undefined :: Int -> Bool) @?= Left "Cannot unify Int and Bool" , testCase "CAN use a term of type 'forall a. a -> Int' as 'Int -> Int'" $ typeOf (undefined :: Int -> Int) `isInstanceOf` typeOf (undefined :: ANY -> Int) @?= Right () , testCase "CAN use a term of type 'forall a b. a -> b' as 'forall a. a -> a'" $ typeOf (undefined :: ANY -> ANY) `isInstanceOf` typeOf (undefined :: ANY -> ANY1) @?= Right () , testCase "CANNOT use a term of type 'forall a. a -> a' as 'forall a b. a -> b'" $ typeOf (undefined :: ANY -> ANY1) `isInstanceOf` typeOf (undefined :: ANY -> ANY) @?= Left "Cannot unify Succ and Zero" , testCase "CAN use a term of type 'forall a. a' as 'forall a. a -> a'" $ typeOf (undefined :: ANY -> ANY) `isInstanceOf` typeOf (undefined :: ANY) @?= Right () , testCase "CANNOT use a term of type 'forall a. a -> a' as 'forall a. a'" $ typeOf (undefined :: ANY) `isInstanceOf` typeOf (undefined :: ANY -> ANY) @?= Left ("Cannot unify Skolem and " ++ funKindStr) ] , testGroup "Examples of funResultTy" [ testCase "Apply fn of type (forall a. a -> a) to arg of type Bool gives Bool" $ show (funResultTy (typeOf (undefined :: ANY -> ANY)) (typeOf (undefined :: Bool))) @?= "Right Bool" , testCase "Apply fn of type (forall a b. a -> b -> a) to arg of type Bool gives forall a. a -> Bool" $ show (funResultTy (typeOf (undefined :: ANY -> ANY1 -> ANY)) (typeOf (undefined :: Bool))) @?= "Right (ANY -> Bool)" -- forall a. a -> Bool , testCase "Apply fn of type (forall a. (Bool -> a) -> a) to argument of type (forall a. a -> a) gives Bool" $ show (funResultTy (typeOf (undefined :: (Bool -> ANY) -> ANY)) (typeOf (undefined :: ANY -> ANY))) @?= "Right Bool" , testCase "Apply fn of type (forall a b. a -> b -> a) to arg of type (forall a. a -> a) gives (forall a b. a -> b -> b)" $ show (funResultTy (typeOf (undefined :: ANY -> ANY1 -> ANY)) (typeOf (undefined :: ANY1 -> ANY1))) @?= "Right (ANY -> ANY1 -> ANY1)" , testCase "Cannot apply function of type (forall a. (a -> a) -> a -> a) to arg of type (Int -> Bool)" $ show (funResultTy (typeOf (undefined :: (ANY -> ANY) -> (ANY -> ANY))) (typeOf (undefined :: Int -> Bool))) @?= "Left \"Cannot unify Int and Bool\"" ] , testGroup "Examples of fromDynamic" [ testCase "CANNOT use a term of type 'Int -> Bool' as 'Int -> Int'" $ do f <- fromDynamic (toDynamic (even :: Int -> Bool)) return $ (f :: Int -> Int) 0 @?= Left "Cannot unify Int and Bool" , testCase "CAN use a term of type 'forall a. a -> Int' as 'Int -> Int'" $ do f <- fromDynamic (toDynamic (const 1 :: ANY -> Int)) return $ (f :: Int -> Int) 0 @?= Right 1 , testCase "CAN use a term of type 'forall a b. a -> b' as 'forall a. a -> a'" $ do f <- fromDynamic (toDynamic (unsafeCoerce :: ANY1 -> ANY2)) return $ (f :: Int -> Int) 0 @?= Right 0 , testCase "CANNOT use a term of type 'forall a. a -> a' as 'forall a b. a -> b'" $ do f <- fromDynamic (toDynamic (id :: ANY -> ANY)) return $ (f :: Int -> Bool) 0 @?= Left "Cannot unify Bool and Int" , testCase "CAN use a term of type 'forall a. a' as 'forall a. a -> a'" $ case do f <- fromDynamic (toDynamic (undefined :: ANY)) return $ (f :: Int -> Int) 0 of Right _ -> return () result -> assertFailure $ "Expected 'Right _' but got '" ++ show result ++ "'" , testCase "CANNOT use a term of type 'forall a. a -> a' as 'forall a. a'" $ do f <- fromDynamic (toDynamic (id :: ANY -> ANY)) ; return $ (f :: Int) @?= Left ("Cannot unify Int and " ++ funKindStr) ] , testGroup "Examples of dynApply" [ testCase "Apply fn of type (forall a. a -> a) to arg of type Bool gives Bool" $ do app <- toDynamic (id :: ANY -> ANY) `dynApply` toDynamic True f <- fromDynamic app return $ (f :: Bool) @?= Right True , testCase "Apply fn of type (forall a b. a -> b -> a) to arg of type Bool gives forall a. a -> Bool" $ do app <- toDynamic (const :: ANY -> ANY1 -> ANY) `dynApply` toDynamic True f <- fromDynamic app return $ (f :: Int -> Bool) 0 @?= Right True , testCase "Apply fn of type (forall a. (Bool -> a) -> a) to argument of type (forall a. a -> a) gives Bool" $ do app <- toDynamic (($ True) :: (Bool -> ANY) -> ANY) `dynApply` toDynamic (id :: ANY -> ANY) f <- fromDynamic app return (f :: Bool) @?= Right True , testCase "Apply fn of type (forall a b. a -> b -> a) to arg of type (forall a. a -> a) gives (forall a b. a -> b -> b)" $ do app <- toDynamic (const :: ANY -> ANY1 -> ANY) `dynApply` toDynamic (id :: ANY -> ANY) f <- fromDynamic app ; return $ (f :: Int -> Bool -> Bool) 0 True @?= Right True , testCase "Cannot apply function of type (forall a. (a -> a) -> a -> a) to arg of type (Int -> Bool)" $ do app <- toDynamic ((\f -> f . f) :: (ANY -> ANY) -> ANY -> ANY) `dynApply` toDynamic (even :: Int -> Bool) ; f <- fromDynamic app ; return (f :: ()) @?= Left "Cannot unify Int and Bool" ] ]