{-# Language CPP, FlexibleContexts, TypeFamilies, KindSignatures, TemplateHaskell, GADTs #-}
#if __GLASGOW_HASKELL__ >= 704
{-# LANGUAGE ConstraintKinds #-}
#endif
#if __GLASGOW_HASKELL__ >= 807
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
#endif
#if MIN_VERSION_template_haskell(2,8,0)
{-# Language PolyKinds #-}
#endif
{-|
Module : Main
Description : Test cases for the th-abstraction package
Copyright : Eric Mertens 2017
License : ISC
Maintainer : emertens@gmail.com
This module checks that the 'reifyDatatype' logic works consistently
across a wide range of datatypes. These tests are validated across
the versions of GHC supported by this package.
-}
module Main (main) where
#if __GLASGOW_HASKELL__ >= 704
import Control.Monad (zipWithM_)
#endif
import Control.Monad (unless)
import qualified Data.Map as Map
#if MIN_VERSION_base(4,7,0)
import Data.Type.Equality ((:~:)(..))
#endif
import Language.Haskell.TH
import Language.Haskell.TH.Datatype
import Language.Haskell.TH.Lib (starK)
import Harness
import Types
-- | Test entry point. Tests will pass or fail at compile time.
main :: IO ()
main =
do adt1Test
gadt1Test
gadt2Test
gadtrec1Test
equalTest
showableTest
recordTest
voidstosTest
strictDemoTest
recordVanillaTest
#if MIN_VERSION_template_haskell(2,6,0)
t43Test
t58Test
#endif
#if MIN_VERSION_template_haskell(2,7,0)
dataFamilyTest
ghc78bugTest
quotedTest
polyTest
gadtFamTest
famLocalDecTest1
famLocalDecTest2
recordFamTest
t46Test
#endif
fixityLookupTest
#if __GLASGOW_HASKELL__ >= 704
resolvePredSynonymsTest
#endif
reifyDatatypeWithConNameTest
reifyConstructorTest
#if MIN_VERSION_base(4,7,0)
importedEqualityTest
#endif
#if MIN_VERSION_template_haskell(2,8,0)
kindSubstTest
t59Test
t61Test
t66Test
#endif
#if __GLASGOW_HASKELL__ >= 800
t37Test
polyKindedExTyvarTest
#endif
#if __GLASGOW_HASKELL__ >= 807
resolveTypeSynonymsVKATest
#endif
regressionTest44
t63Test
t70Test
adt1Test :: IO ()
adt1Test =
$(do info <- reifyDatatype ''Adt1
let names = map mkName ["a","b"]
[aTvb,bTvb] = map (\v -> KindedTV v starK) names
vars@[aVar,bVar] = map (VarT . mkName) ["a","b"]
[aSig,bSig] = map (\v -> SigT v starK) vars
validateDI info
DatatypeInfo
{ datatypeName = ''Adt1
, datatypeContext = []
, datatypeVars = [aTvb,bTvb]
, datatypeInstTypes = [aSig, bSig]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'Adtc1
, constructorContext = []
, constructorVars = []
, constructorFields = [AppT (AppT (TupleT 2) aVar) bVar]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor }
, ConstructorInfo
{ constructorName = 'Adtc2
, constructorContext = []
, constructorVars = []
, constructorFields = [ConT ''Bool, ConT ''Int]
, constructorStrictness = [notStrictAnnot, notStrictAnnot]
, constructorVariant = InfixConstructor }
]
}
)
gadt1Test :: IO ()
gadt1Test =
$(do info <- reifyDatatype ''Gadt1
let a = mkName "a"
aVar = VarT a
validateDI info
DatatypeInfo
{ datatypeName = ''Gadt1
, datatypeContext = []
, datatypeVars = [KindedTV a starK]
, datatypeInstTypes = [SigT aVar starK]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'Gadtc1
, constructorVars = []
, constructorContext = [equalPred aVar (ConT ''Int)]
, constructorFields = [ConT ''Int]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor }
, ConstructorInfo
{ constructorName = 'Gadtc2
, constructorVars = []
, constructorContext = []
, constructorFields = [AppT (AppT (TupleT 2) aVar) aVar]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor }
, ConstructorInfo
{ constructorName = '(:**:)
, constructorVars = []
, constructorContext = [equalPred aVar (TupleT 0)]
, constructorFields = [ConT ''Bool, ConT ''Char]
, constructorStrictness = [notStrictAnnot, notStrictAnnot]
, constructorVariant = InfixConstructor }
, ConstructorInfo
{ constructorName = '(:!!:)
, constructorVars = []
, constructorContext = [equalPred aVar (ConT ''Double)]
, constructorFields = [ConT ''Char, ConT ''Bool]
, constructorStrictness = [notStrictAnnot, notStrictAnnot]
, constructorVariant = NormalConstructor }
]
}
)
gadtrec1Test :: IO ()
gadtrec1Test =
$(do info <- reifyDatatype ''Gadtrec1
let a = mkName "a"
con = gadtRecVanillaCI
validateDI info
DatatypeInfo
{ datatypeName = ''Gadtrec1
, datatypeContext = []
, datatypeVars = [KindedTV a starK]
, datatypeInstTypes = [SigT (VarT a) starK]
, datatypeVariant = Datatype
, datatypeCons =
[ con, con { constructorName = 'Gadtrecc2 } ]
}
)
equalTest :: IO ()
equalTest =
$(do info <- reifyDatatype ''Equal
let names = map mkName ["a","b","c"]
[aTvb,bTvb,cTvb] = map (\v -> KindedTV v starK) names
vars@[aVar,bVar,cVar] = map VarT names
[aSig,bSig,cSig] = map (\v -> SigT v starK) vars
validateDI info
DatatypeInfo
{ datatypeName = ''Equal
, datatypeContext = []
, datatypeVars = [aTvb, bTvb, cTvb]
, datatypeInstTypes = [aSig, bSig, cSig]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'Equalc
, constructorVars = []
, constructorContext =
[ equalPred aVar cVar
, equalPred bVar cVar
, classPred ''Read [cVar]
, classPred ''Show [cVar]
]
, constructorFields =
[ListT `AppT` cVar, ConT ''Maybe `AppT` cVar]
, constructorStrictness =
[notStrictAnnot, notStrictAnnot]
, constructorVariant = NormalConstructor }
]
}
)
showableTest :: IO ()
showableTest =
$(do info <- reifyDatatype ''Showable
let a = mkName "a"
validateDI info
DatatypeInfo
{ datatypeName = ''Showable
, datatypeContext = []
, datatypeVars = []
, datatypeInstTypes = []
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'Showable
, constructorVars = [KindedTV a starK]
, constructorContext = [classPred ''Show [VarT a]]
, constructorFields = [VarT a]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor }
]
}
)
recordTest :: IO ()
recordTest =
$(do info <- reifyDatatype ''R
validateDI info
DatatypeInfo
{ datatypeName = ''R
, datatypeContext = []
, datatypeVars = []
, datatypeInstTypes = []
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'R1
, constructorVars = []
, constructorContext = []
, constructorFields = [ConT ''Int, ConT ''Int]
, constructorStrictness = [notStrictAnnot, notStrictAnnot]
, constructorVariant = RecordConstructor ['field1, 'field2] }
]
}
)
gadt2Test :: IO ()
gadt2Test =
$(do info <- reifyDatatype ''Gadt2
let names = map mkName ["a","b"]
[aTvb,bTvb] = map (\v -> KindedTV v starK) names
vars@[aVar,bVar] = map VarT names
[aSig,bSig] = map (\v -> SigT v starK) vars
x = mkName "x"
con = ConstructorInfo
{ constructorName = undefined
, constructorVars = []
, constructorContext = []
, constructorFields = []
, constructorStrictness = []
, constructorVariant = NormalConstructor }
validateDI info
DatatypeInfo
{ datatypeName = ''Gadt2
, datatypeContext = []
, datatypeVars = [aTvb, bTvb]
, datatypeInstTypes = [aSig, bSig]
, datatypeVariant = Datatype
, datatypeCons =
[ con { constructorName = 'Gadt2c1
, constructorContext = [equalPred bVar (AppT ListT aVar)] }
, con { constructorName = 'Gadt2c2
, constructorContext = [equalPred aVar (AppT ListT bVar)] }
, con { constructorName = 'Gadt2c3
, constructorVars = [KindedTV x starK]
, constructorContext =
[equalPred aVar (AppT ListT (VarT x))
,equalPred bVar (AppT ListT (VarT x))] } ]
}
)
voidstosTest :: IO ()
voidstosTest =
$(do info <- reifyDatatype ''VoidStoS
let g = mkName "g"
validateDI info
DatatypeInfo
{ datatypeName = ''VoidStoS
, datatypeContext = []
, datatypeVars = [KindedTV g (arrowKCompat starK starK)]
, datatypeInstTypes = [SigT (VarT g) (arrowKCompat starK starK)]
, datatypeVariant = Datatype
, datatypeCons = []
}
)
strictDemoTest :: IO ()
strictDemoTest =
$(do info <- reifyDatatype ''StrictDemo
validateDI info
DatatypeInfo
{ datatypeName = ''StrictDemo
, datatypeContext = []
, datatypeVars = []
, datatypeInstTypes = []
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'StrictDemo
, constructorVars = []
, constructorContext = []
, constructorFields = [ConT ''Int, ConT ''Int, ConT ''Int]
, constructorStrictness = [ notStrictAnnot
, isStrictAnnot
, unpackedAnnot
]
, constructorVariant = NormalConstructor } ]
}
)
recordVanillaTest :: IO ()
recordVanillaTest =
$(do info <- reifyRecord 'gadtrec1a
validateCI info gadtRecVanillaCI)
#if MIN_VERSION_template_haskell(2,6,0)
t43Test :: IO ()
t43Test =
$(do [decPlain] <- [d| data T43Plain where MkT43Plain :: T43Plain |]
infoPlain <- normalizeDec decPlain
validateDI infoPlain
DatatypeInfo
{ datatypeName = mkName "T43Plain"
, datatypeContext = []
, datatypeVars = []
, datatypeInstTypes = []
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = mkName "MkT43Plain"
, constructorVars = []
, constructorContext = []
, constructorFields = []
, constructorStrictness = []
, constructorVariant = NormalConstructor } ]
}
[decFam] <- [d| data instance T43Fam where MkT43Fam :: T43Fam |]
infoFam <- normalizeDec decFam
validateDI infoFam
DatatypeInfo
{ datatypeName = mkName "T43Fam"
, datatypeContext = []
, datatypeVars = []
, datatypeInstTypes = []
, datatypeVariant = DataInstance
, datatypeCons =
[ ConstructorInfo
{ constructorName = mkName "MkT43Fam"
, constructorVars = []
, constructorContext = []
, constructorFields = []
, constructorStrictness = []
, constructorVariant = NormalConstructor } ]
}
)
t58Test :: IO ()
t58Test =
$(do [dec] <- [d| data Foo where
MkFoo :: a -> Foo |]
info <- normalizeDec dec
let a = mkName "a"
validateDI info
DatatypeInfo
{ datatypeName = mkName "Foo"
, datatypeContext = []
, datatypeVars = []
, datatypeInstTypes = []
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = mkName "MkFoo"
, constructorVars = [KindedTV a starK]
, constructorContext = []
, constructorFields = [VarT a]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor } ]
}
)
#endif
#if MIN_VERSION_template_haskell(2,7,0)
dataFamilyTest :: IO ()
dataFamilyTest =
$(do info <- reifyDatatype 'DFMaybe
let a = mkName "a"
validateDI info
DatatypeInfo
{ datatypeName = ''DF
, datatypeContext = []
, datatypeVars = [KindedTV a starK]
, datatypeInstTypes = [AppT (ConT ''Maybe) (VarT a)]
, datatypeVariant = DataInstance
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'DFMaybe
, constructorVars = []
, constructorContext = []
, constructorFields = [ConT ''Int, ListT `AppT` VarT a]
, constructorStrictness = [notStrictAnnot, notStrictAnnot]
, constructorVariant = NormalConstructor } ]
}
)
ghc78bugTest :: IO ()
ghc78bugTest =
$(do info <- reifyDatatype 'DF1
let c = mkName "c"
cVar = VarT c
validateDI info
DatatypeInfo
{ datatypeName = ''DF1
, datatypeContext = []
, datatypeVars = [KindedTV c starK]
, datatypeInstTypes = [SigT cVar starK]
, datatypeVariant = DataInstance
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'DF1
, constructorVars = []
, constructorContext = []
, constructorFields = [cVar]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor } ]
}
)
quotedTest :: IO ()
quotedTest =
$(do [dec] <- [d| data instance Quoted a = MkQuoted a |]
info <- normalizeDec dec
let a = mkName "a"
aVar = VarT a
validateDI info
DatatypeInfo
{ datatypeName = mkName "Quoted"
, datatypeContext = []
, datatypeVars = [KindedTV a starK]
, datatypeInstTypes = [SigT aVar starK]
, datatypeVariant = DataInstance
, datatypeCons =
[ ConstructorInfo
{ constructorName = mkName "MkQuoted"
, constructorVars = []
, constructorContext = []
, constructorFields = [aVar]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor } ]
}
)
polyTest :: IO ()
polyTest =
$(do info <- reifyDatatype 'MkPoly
let [a,k] = map mkName ["a","k"]
kVar = varKCompat k
validateDI info
DatatypeInfo
{ datatypeName = ''Poly
, datatypeContext = []
, datatypeVars = [
#if __GLASGOW_HASKELL__ >= 800
KindedTV k starK,
#endif
KindedTV a kVar ]
, datatypeInstTypes = [SigT (VarT a) kVar]
, datatypeVariant = DataInstance
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'MkPoly
, constructorVars = []
, constructorContext = []
, constructorFields = []
, constructorStrictness = []
, constructorVariant = NormalConstructor } ]
}
)
gadtFamTest :: IO ()
gadtFamTest =
$(do info <- reifyDatatype 'MkGadtFam1
let names@[c,d,e,q] = map mkName ["c","d","e","q"]
[cTvb,dTvb,eTvb,qTvb] = map (\v -> KindedTV v starK) names
[cTy,dTy,eTy,qTy] = map VarT names
[cSig,dSig] = map (\v -> SigT v starK) [cTy,dTy]
validateDI info
DatatypeInfo
{ datatypeName = ''GadtFam
, datatypeContext = []
, datatypeVars = [cTvb,dTvb]
, datatypeInstTypes = [cSig,dSig]
, datatypeVariant = DataInstance
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'MkGadtFam1
, constructorVars = []
, constructorContext = []
, constructorFields = [dTy,cTy]
, constructorStrictness = [notStrictAnnot, notStrictAnnot]
, constructorVariant = NormalConstructor }
, ConstructorInfo
{ constructorName = '(:&&:)
, constructorVars = [KindedTV e starK]
, constructorContext = [equalPred cTy (AppT ListT eTy)]
, constructorFields = [eTy,dTy]
, constructorStrictness = [notStrictAnnot, notStrictAnnot]
, constructorVariant = InfixConstructor }
, ConstructorInfo
{ constructorName = '(:^^:)
, constructorVars = []
, constructorContext = [ equalPred cTy (ConT ''Int)
, equalPred dTy (ConT ''Int)
]
, constructorFields = [ConT ''Int, ConT ''Int]
, constructorStrictness = [notStrictAnnot, notStrictAnnot]
, constructorVariant = NormalConstructor }
, gadtRecFamCI
, ConstructorInfo
{ constructorName = 'MkGadtFam4
, constructorVars = []
, constructorContext = [ equalPred cTy dTy
, equalPred (ConT ''Int) dTy
]
, constructorFields = [dTy]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor }
, ConstructorInfo
{ constructorName = 'MkGadtFam5
, constructorVars = [KindedTV q starK]
, constructorContext = [ equalPred cTy (ConT ''Bool)
, equalPred dTy (ConT ''Bool)
, equalPred qTy (ConT ''Char)
]
, constructorFields = [qTy]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor } ]
}
)
famLocalDecTest1 :: IO ()
famLocalDecTest1 =
$(do [dec] <- [d| data instance FamLocalDec1 Int = FamLocalDec1Int { mochi :: Double } |]
info <- normalizeDec dec
validateDI info
DatatypeInfo
{ datatypeName = ''FamLocalDec1
, datatypeContext = []
, datatypeVars = []
, datatypeInstTypes = [ConT ''Int]
, datatypeVariant = DataInstance
, datatypeCons =
[ ConstructorInfo
{ constructorName = mkName "FamLocalDec1Int"
, constructorVars = []
, constructorContext = []
, constructorFields = [ConT ''Double]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = RecordConstructor [mkName "mochi"] }]
}
)
famLocalDecTest2 :: IO ()
famLocalDecTest2 =
$(do [dec] <- [d| data instance FamLocalDec2 Int (a, b) a = FamLocalDec2Int { fm0 :: (b, a), fm1 :: Int } |]
info <- normalizeDec dec
let names = map mkName ["a", "b"]
[aTvb,bTvb] = map (\v -> KindedTV v starK) names
vars@[aVar,bVar] = map (VarT . mkName) ["a", "b"]
[aSig,bSig] = map (\v -> SigT v starK) vars
validateDI info
DatatypeInfo
{ datatypeName = ''FamLocalDec2
, datatypeContext = []
, datatypeVars = [aTvb,bTvb]
, datatypeInstTypes = [ConT ''Int, TupleT 2 `AppT` aVar `AppT` bVar, aSig]
, datatypeVariant = DataInstance
, datatypeCons =
[ ConstructorInfo
{ constructorName = mkName "FamLocalDec2Int"
, constructorVars = []
, constructorContext = []
, constructorFields = [TupleT 2 `AppT` bVar `AppT` aVar, ConT ''Int]
, constructorStrictness = [notStrictAnnot, notStrictAnnot]
, constructorVariant = RecordConstructor [mkName "fm0", mkName "fm1"] }]
}
)
recordFamTest :: IO ()
recordFamTest =
$(do info <- reifyRecord 'famRec1
validateCI info gadtRecFamCI)
t46Test :: IO ()
t46Test =
$(do info <- reifyDatatype 'MkT46
case info of
DatatypeInfo { datatypeCons = [ConstructorInfo { constructorContext = ctxt }]} ->
unless (null ctxt) (fail "regression test for ticket #46 failed")
_ -> fail "T46 should have exactly one constructor"
[| return () |])
#endif
fixityLookupTest :: IO ()
fixityLookupTest =
$(do Just (Fixity 6 InfixR) <- reifyFixityCompat '(:**:)
[| return () |])
#if __GLASGOW_HASKELL__ >= 704
resolvePredSynonymsTest :: IO ()
resolvePredSynonymsTest =
$(do info <- reifyDatatype ''PredSynT
[cxt1,cxt2,cxt3] <- sequence $ map (mapM resolvePredSynonyms . constructorContext)
$ datatypeCons info
let mkTest = zipWithM_ (equateCxt "resolvePredSynonymsTest")
test1 = mkTest cxt1 [classPred ''Show [ConT ''Int]]
test2 = mkTest cxt2 [classPred ''Show [ConT ''Int]]
test3 = mkTest cxt3 [equalPred (ConT ''Int) (ConT ''Int)]
mapM_ (either fail return) [test1,test2,test3]
[| return () |])
#endif
reifyDatatypeWithConNameTest :: IO ()
reifyDatatypeWithConNameTest =
$(do info <- reifyDatatype 'Just
let a = mkName "a"
validateDI info
DatatypeInfo
{ datatypeContext = []
, datatypeName = ''Maybe
, datatypeVars = [KindedTV a starK]
, datatypeInstTypes = [SigT (VarT a) starK]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'Nothing
, constructorVars = []
, constructorContext = []
, constructorFields = []
, constructorStrictness = []
, constructorVariant = NormalConstructor
}
, justCI
]
}
)
reifyConstructorTest :: IO ()
reifyConstructorTest =
$(do info <- reifyConstructor 'Just
validateCI info justCI)
#if MIN_VERSION_base(4,7,0)
importedEqualityTest :: IO ()
importedEqualityTest =
$(do info <- reifyDatatype ''(:~:)
let names@[a,b] = map mkName ["a","b"]
[aVar,bVar] = map VarT names
k = mkName "k"
kKind = varKCompat k
validateDI info
DatatypeInfo
{ datatypeContext = []
, datatypeName = ''(:~:)
, datatypeVars = [
#if __GLASGOW_HASKELL__ >= 800
KindedTV k starK,
#endif
KindedTV a kKind, KindedTV b kKind]
, datatypeInstTypes = [SigT aVar kKind, SigT bVar kKind]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'Refl
, constructorVars = []
, constructorContext = [equalPred aVar bVar]
, constructorFields = []
, constructorStrictness = []
, constructorVariant = NormalConstructor } ]
}
)
#endif
#if MIN_VERSION_template_haskell(2,8,0)
kindSubstTest :: IO ()
kindSubstTest =
$(do k1 <- newName "k1"
k2 <- newName "k2"
a <- newName "a"
let ty = ForallT [KindedTV a (VarT k1)] [] (VarT a)
substTy = applySubstitution (Map.singleton k1 (VarT k2)) ty
checkFreeVars :: Type -> [Name] -> Q ()
checkFreeVars t freeVars =
unless (freeVariables t == freeVars) $
fail $ "free variables of " ++ show t ++ " should be " ++ show freeVars
checkFreeVars ty [k1]
checkFreeVars substTy [k2]
[| return () |])
t59Test :: IO ()
t59Test =
$(do k <- newName "k"
a <- newName "a"
let proxyAK = ConT (mkName "Proxy") `AppT` SigT (VarT a) (VarT k)
-- Proxy (a :: k)
expected = ForallT
#if __GLASGOW_HASKELL__ >= 800
[PlainTV k, KindedTV a (VarT k)]
#else
[KindedTV a (VarT k)]
#endif
[] proxyAK
actual = quantifyType proxyAK
unless (expected == actual) $
fail $ "quantifyType does not respect dependency order: "
++ unlines [ "Expected: " ++ pprint expected
, "Actual: " ++ pprint actual
]
[| return () |])
t61Test :: IO ()
t61Test =
$(do let test :: Type -> Type -> Q ()
test orig expected = do
actual <- resolveTypeSynonyms orig
unless (expected == actual) $
fail $ "Type synonym expansion failed: "
++ unlines [ "Expected: " ++ pprint expected
, "Actual: " ++ pprint actual
]
idAppT = (ConT ''Id `AppT`)
a = mkName "a"
test (SigT (idAppT $ ConT ''Int) (idAppT StarT))
(SigT (ConT ''Int) StarT)
#if MIN_VERSION_template_haskell(2,10,0)
test (ForallT [KindedTV a (idAppT StarT)]
[idAppT (ConT ''Show `AppT` VarT a)]
(idAppT $ VarT a))
(ForallT [KindedTV a StarT]
[ConT ''Show `AppT` VarT a]
(VarT a))
#endif
#if MIN_VERSION_template_haskell(2,11,0)
test (InfixT (idAppT $ ConT ''Int) ''Either (idAppT $ ConT ''Int))
(InfixT (ConT ''Int) ''Either (ConT ''Int))
test (ParensT (idAppT $ ConT ''Int))
(ConT ''Int)
#endif
[| return () |])
t66Test :: IO ()
t66Test =
$(do [dec] <- [d| data Foo a b :: (* -> *) -> * -> * where
MkFoo :: a -> b -> f x -> Foo a b f x |]
info <- normalizeDec dec
let [a,b,f,x] = map mkName ["a","b","f","x"]
fKind = arrowKCompat starK starK
validateDI info
DatatypeInfo
{ datatypeName = mkName "Foo"
, datatypeContext = []
, datatypeVars = [ KindedTV a starK ,KindedTV b starK
, KindedTV f fKind, KindedTV x starK ]
, datatypeInstTypes = [ SigT (VarT a) starK, SigT (VarT b) starK
, SigT (VarT f) fKind, SigT (VarT x) starK ]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = mkName "MkFoo"
, constructorVars = []
, constructorContext = []
, constructorFields = [VarT a, VarT b, VarT f `AppT` VarT x]
, constructorStrictness = [notStrictAnnot, notStrictAnnot, notStrictAnnot]
, constructorVariant = NormalConstructor } ]
}
)
#endif
#if __GLASGOW_HASKELL__ >= 800
t37Test :: IO ()
t37Test =
$(do infoA <- reifyDatatype ''T37a
let names@[k,a] = map mkName ["k","a"]
[kVar,aVar] = map VarT names
kSig = SigT kVar starK
aSig = SigT aVar kVar
kTvb = KindedTV k starK
aTvb = KindedTV a kVar
validateDI infoA
DatatypeInfo
{ datatypeContext = []
, datatypeName = ''T37a
, datatypeVars = [kTvb, aTvb]
, datatypeInstTypes = [kSig, aSig]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'MkT37a
, constructorVars = []
, constructorContext = [equalPred kVar (ConT ''Bool)]
, constructorFields = []
, constructorStrictness = []
, constructorVariant = NormalConstructor } ]
}
infoB <- reifyDatatype ''T37b
validateDI infoB
DatatypeInfo
{ datatypeContext = []
, datatypeName = ''T37b
, datatypeVars = [kTvb, aTvb]
, datatypeInstTypes = [aSig]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'MkT37b
, constructorVars = []
, constructorContext = [equalPred kVar (ConT ''Bool)]
, constructorFields = []
, constructorStrictness = []
, constructorVariant = NormalConstructor } ]
}
infoC <- reifyDatatype ''T37c
validateDI infoC
DatatypeInfo
{ datatypeContext = []
, datatypeName = ''T37c
, datatypeVars = [kTvb, aTvb]
, datatypeInstTypes = [aSig]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'MkT37c
, constructorVars = []
, constructorContext = [equalPred aVar (ConT ''Bool)]
, constructorFields = []
, constructorStrictness = []
, constructorVariant = NormalConstructor } ]
}
)
polyKindedExTyvarTest :: IO ()
polyKindedExTyvarTest =
$(do info <- reifyDatatype ''T48
let [a,x] = map mkName ["a","x"]
aVar = VarT a
validateDI info
DatatypeInfo
{ datatypeContext = []
, datatypeName = ''T48
, datatypeVars = [KindedTV a starK]
, datatypeInstTypes = [SigT aVar starK]
, datatypeVariant = Datatype
, datatypeCons =
[ ConstructorInfo
{ constructorName = 'MkT48
, constructorVars = [KindedTV x aVar]
, constructorContext = []
, constructorFields = [ConT ''Prox `AppT` VarT x]
, constructorStrictness = [notStrictAnnot]
, constructorVariant = NormalConstructor } ]
}
-- Because validateCI uses a type variable substitution to normalize
-- away any alpha-renaming differences between constructors, it
-- unfortunately does not check if the uses of `a` in datatypeVars and
-- constructorVars are the same. We perform this check explicitly here.
case info of
DatatypeInfo { datatypeVars = [KindedTV a1 starK]
, datatypeCons =
[ ConstructorInfo
{ constructorVars = [KindedTV _ (VarT a2)] } ] } ->
unless (a1 == a2) $
fail $ "Two occurrences of the same variable have different names: "
++ show [a1, a2]
[| return () |]
)
#endif
#if __GLASGOW_HASKELL__ >= 807
resolveTypeSynonymsVKATest :: IO ()
resolveTypeSynonymsVKATest =
$(do t <- [t| T37b @Bool True |]
t' <- resolveTypeSynonyms t
unless (t == t') $
fail $ "Type synonym expansion breaks with visible kind application: "
++ show [t, t']
[| return () |])
#endif
regressionTest44 :: IO ()
regressionTest44 =
$(do intToInt <- [t| Int -> Int |]
unified <- unifyTypes [intToInt, intToInt]
unless (Map.null unified) (fail "regression test for ticket #44 failed")
[| return () |])
t63Test :: IO ()
t63Test =
$(do a <- newName "a"
b <- newName "b"
t <- newName "T"
let tauType = ArrowT `AppT` VarT a `AppT` (ArrowT `AppT` VarT b
`AppT` (ConT t `AppT` VarT a))
sigmaType = ForallT [PlainTV b] [] tauType
expected = ForallT [PlainTV a, PlainTV b] [] tauType
actual = quantifyType sigmaType
unless (expected == actual) $
fail $ "quantifyType does not collapse consecutive foralls: "
++ unlines [ "Expected: " ++ pprint expected
, "Actual: " ++ pprint actual
]
[| return () |])
t70Test :: IO ()
t70Test =
$(do a <- newName "a"
b <- newName "b"
let [aVar, bVar] = map VarT [a, b]
[aTvb, bTvb] = map PlainTV [a, b]
let fvsABExpected = [aTvb, bTvb]
fvsABActual = freeVariablesWellScoped [aVar, bVar]
fvsBAExpected = [bTvb, aTvb]
fvsBAActual = freeVariablesWellScoped [bVar, aVar]
check expected actual =
unless (expected == actual) $
fail $ "freeVariablesWellScoped does not preserve left-to-right order: "
++ unlines [ "Expected: " ++ pprint expected
, "Actual: " ++ pprint actual
]
check fvsABExpected fvsABActual
check fvsBAExpected fvsBAActual
[| return () |])