#if !MIN_VERSION_base(4,7,0)
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ExistentialQuantification #-}
#if !MIN_VERSION_base(4,6,0)
{-# LANGUAGE KindSignatures #-}
#endif
#endif
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
import Data.Rank1Typeable
import Data.Rank1Dynamic
#if MIN_VERSION_base(4,7,0)
import Data.Constraint (Dict(..))
#else
import qualified Data.Typeable as Typeable (Typeable(..),Typeable1(..), mkTyCon3, mkTyConApp)
#endif
import Test.HUnit hiding (Test)
import Test.Framework
import Test.Framework.Providers.HUnit
import Unsafe.Coerce
main :: IO ()
main = defaultMain tests
#if MIN_VERSION_base(4,7,0)
deriving instance Typeable Monad
#else
data MonadDict m = Monad m => MonadDict
instance Typeable.Typeable1 m => Typeable (MonadDict m) where
typeOf _ = Typeable.mkTyConApp (Typeable.mkTyCon3 "main" "Main" "MonadDict")
[ Typeable.typeOf1 (undefined :: m a) ]
returnD :: MonadDict m -> a -> m a
returnD MonadDict = return
#endif
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)
#if MIN_VERSION_base(4,7,0)
@?= Left "Cannot unify Skolem and (->)"
#else
@?= Left "Cannot unify Skolem and ->"
#endif
, testCase "CAN use a term of type 'forall a. a -> m a' as 'Int -> Maybe Int'" $
typeOf (undefined :: Int -> Maybe Int)
`isInstanceOf`
#if MIN_VERSION_base(4,6,0)
typeOf (undefined :: ANY1 -> ANY ANY1)
#else
typeOf (undefined :: ANY1 -> ANY (ANY1 :: *))
#endif
@?= Right ()
, testCase "CAN use a term of type 'forall a. Monad a => a -> m a' as 'Int -> Maybe Int'" $
#if MIN_VERSION_base(4,7,0)
typeOf ((\Dict -> return) :: Dict (Monad Maybe) -> Int -> Maybe Int)
`isInstanceOf`
typeOf ((\Dict -> return) :: Dict (Monad ANY) -> ANY1 -> ANY ANY1)
#else
typeOf (returnD :: MonadDict Maybe -> Int -> Maybe Int)
`isInstanceOf`
#if MIN_VERSION_base(4,6,0)
typeOf (returnD :: MonadDict ANY -> ANY1 -> ANY ANY1)
#else
typeOf (returnD :: MonadDict ANY -> ANY1 -> ANY (ANY1 :: *))
#endif
#endif
@?= Right ()
]
, 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)
#if MIN_VERSION_base(4,7,0)
@?= Left "Cannot unify Int and (->)"
#else
@?= Left "Cannot unify Int and ->"
#endif
, testCase "CAN use a term of type 'forall a. Monad a => a -> m a' as 'Int -> Maybe Int'" $
#if MIN_VERSION_base(4,7,0)
do f <- fromDynamic (toDynamic ((\Dict -> return) :: Dict (Monad Maybe) -> Int -> Maybe Int))
return $ (f :: Dict (Monad Maybe) -> Int -> Maybe Int) Dict 0
#else
do f <- fromDynamic (toDynamic (returnD :: MonadDict Maybe -> Int -> Maybe Int))
return $ ((f :: MonadDict Maybe -> Int -> Maybe Int) MonadDict) 0
#endif
@?= Right (Just 0)
]
, 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"
]
]