{-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -ddump-splices #-} {-# OPTIONS_GHC -Wno-unused-binds #-} module Main ( main, ) where import Control.Carrier.State.Strict (evalState) import Control.Effect.State hiding (get, put) import Control.Effect.Reader hiding (ask, local) import Control.Effect.Writer hiding (tell, listen, censor) import Control.Effect.TH import Control.Exception (SomeException, try) import Data.Either import Language.Haskell.TH (runQ) import System.IO import Test.Tasty import Test.Tasty.HUnit import Data.Kind (Type) data Go (m :: Type -> Type) k where App :: String -> Go m () data Same (m :: Type -> Type) k where Same :: Same m () data Kinded (s :: Type) (m :: Type -> Type) k where Kinded :: s -> Kinded s m () data Constrained (m :: Type -> Type) k where Shown :: Show a => a -> Constrained m a makeSmartConstructors ''Go makeSmartConstructors ''State makeSmartConstructors ''Same makeSmartConstructors ''Kinded makeSmartConstructors ''Constrained -- Need to ensure that if a constructor introduces a new type variable, -- that it is introduced in the corresponding invocation. The question is -- where we can put it. Probably before `sig m`. assertThrows :: String -> IO a -> Assertion assertThrows msg go = fmap isLeft (try @SomeException go) >>= assertBool msg testState :: TestTree testState = testCase "Generated State functions" $ do assertEqual "get" (run $ evalState "hello" get) "hello" assertEqual "get-put" (run $ evalState "bad" (put "good" *> get)) "good" data BadGADT where BadGADT :: BadGADT testDataErrors :: TestTree testDataErrors = testCase "Bad data types" $ do assertThrows "Bool" (runQ (makeSmartConstructors ''Bool)) assertThrows "Ill-formed GADT" (runQ (makeSmartConstructors ''BadGADT)) main :: IO () main = do hClose stderr -- silences TH warnings defaultMain $ testGroup "Language.Haskell.TH" [ testGroup "Behavior" [ testState ], testGroup "Template Haskell errors" [ testDataErrors ] ]