packages feed

hypertypes-0.2.2: test/AlphaEqTest.hs

{-# LANGUAGE OverloadedStrings #-}

module AlphaEqTest (test) where

import qualified Control.Lens as Lens
import Control.Lens.Operators
import Control.Monad.RWS
import Control.Monad.ST (runST)
import Data.Functor.Identity (Identity (..))
import qualified Data.Map as Map
import qualified Data.Set as Set
import ExprUtils
import Hyper
import Hyper.Syntax.Scheme
import Hyper.Syntax.Scheme.AlphaEq (alphaEq)
import LangB
import Test.Tasty
import Test.Tasty.HUnit
import TypeLang

import Prelude

test :: TestTree
test =
    testGroup
        "alpha-eq"
        [ testAlphaEq (uniType TIntP) (uniType TIntP) True
        , testAlphaEq (uniType TIntP) intToInt False
        , testAlphaEq intToInt intToInt True
        , testAlphaEq (intsRecord ["a", "b"]) (intsRecord ["b", "a"]) True
        , testAlphaEq (intsRecord ["a", "b"]) (intsRecord ["b"]) False
        , testAlphaEq (intsRecord ["a", "b", "c"]) (intsRecord ["c", "b", "a"]) True
        , testAlphaEq (intsRecord ["a", "b", "c"]) (intsRecord ["b", "c", "a"]) True
        , testAlphaEq (forAll1 "a" id) (forAll1 "b" id) True
        , testAlphaEq (forAll1 "a" id) (uniType TIntP) False
        , testAlphaEq (forAll1r "a" TRecP) (uniType TIntP) False
        , testAlphaEq (forAll1r "a" TRecP) (forAll1r "b" TRecP) True
        , testAlphaEq (mkOpenRec "a" "x" "y") (mkOpenRec "b" "y" "x") True
        , testAlphaEq (valH0 (TVarP "a")) (valH0 (TRecP REmptyP)) False
        ]
    where
        valH0 x =
            TFunP (TVarP "a") (TRecP (RExtendP "t" x (RVarP "c"))) ^. hPlain
                & Scheme
                    ( Types
                        (QVars (mempty & Lens.at "a" ?~ mempty))
                        (QVars (mempty & Lens.at "c" ?~ RowConstraints (Set.fromList ["t"]) mempty))
                    )
                & Pure
        mkOpenRec a x y =
            _Pure
                # Scheme
                    ( Types
                        (QVars mempty)
                        (QVars (Map.fromList [(a, RowConstraints (Set.fromList [x, y]) mempty)]))
                    )
                    ( TRecP
                        ( RVarP a
                            & RExtendP x TIntP
                            & RExtendP y TIntP
                        )
                        ^. hPlain
                    )

testAlphaEq :: Pure # Scheme Types Typ -> Pure # Scheme Types Typ -> Bool -> TestTree
testAlphaEq x y expect =
    do
        assertEqual msg expect pureRes
        assertEqual ("ST: " <> msg) expect stRes
        & testCase (prettyStyle x <> sep <> prettyStyle y)
    where
        sep = if expect then " == " else " != "
        msg = "Alpha eq of " <> prettyStyle x <> " and " <> prettyStyle y
        pureRes = Lens.has Lens._Right (execPureInferB (alphaEq x y))
        stRes = Lens.has Lens._Right (runST (execSTInferB (alphaEq x y)))

uniType :: HPlain Typ -> Pure # Scheme Types Typ
uniType typ =
    _Pure
        # Scheme
            { _sForAlls = Types (QVars mempty) (QVars mempty)
            , _sTyp = typ ^. hPlain
            }

intsRecord :: [Name] -> Pure # Scheme Types Typ
intsRecord = uniType . TRecP . foldr (`RExtendP` TIntP) REmptyP

intToInt :: Pure # Scheme Types Typ
intToInt = TFunP TIntP TIntP & uniType

forAll1 ::
    Name ->
    (HPlain Typ -> HPlain Typ) ->
    Pure # Scheme Types Typ
forAll1 t body =
    forAll (Identity t) (Const ()) $ \(Identity tv) _ -> body tv

forAll1r ::
    Name ->
    (HPlain Row -> HPlain Typ) ->
    Pure # Scheme Types Typ
forAll1r t body =
    forAll (Const ()) (Identity t) $ \_ (Identity tv) -> body tv