sbv-14.8: SBVTestSuite/TestSuite/ADT/Registration.hs
-----------------------------------------------------------------------------
-- |
-- Module : TestSuite.ADT.Registration
-- Copyright : (c) Levent Erkok
-- License : BSD3
-- Maintainer: erkokl@gmail.com
-- Stability : experimental
--
-- Registration of ADT dependencies without incidental uses of their fields.
-----------------------------------------------------------------------------
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -Wall -Werror #-}
module TestSuite.ADT.Registration (tests) where
import Data.Proxy (Proxy(..))
import Control.DeepSeq (force)
import Control.Exception (evaluate)
import Control.Monad (void)
import Data.SBV.Control
import Test.Tasty.HUnit (assertEqual)
import Utils.SBVTestFramework
-- | A parameterized leaf whose definition must be discovered from its uses.
newtype RegistrationLeaf a = RegistrationLeaf a deriving (Eq, Ord, Show)
-- | An ADT reference underneath a tuple field.
newtype RegistrationTuple = RegistrationTuple (RegistrationLeaf Word8, Word8) deriving Show
-- | An ADT reference underneath a list field.
newtype RegistrationList = RegistrationList [RegistrationLeaf Word8] deriving Show
-- | An ADT reference underneath a set field.
newtype RegistrationSet = RegistrationSet (RCSet (RegistrationLeaf Word8)) deriving Show
-- | An ADT reference in an array's index type.
newtype RegistrationKey = RegistrationKey (ArrayModel (RegistrationLeaf Word8) Word8) deriving Show
-- | An ADT reference in an array's element type.
newtype RegistrationValue = RegistrationValue (ArrayModel Word8 (RegistrationLeaf Word8)) deriving Show
-- | A synonym must not hide dependencies from the registration traversal.
type RegistrationAlias = ([RegistrationLeaf Word8], Word8)
-- | A field whose container structure is supplied by a type synonym.
newtype RegistrationSynonym = RegistrationSynonym RegistrationAlias deriving Show
-- | Type arguments may themselves contain ADT references behind containers.
newtype RegistrationParameter a = RegistrationParameter (Maybe ([RegistrationLeaf a], a)) deriving Show
-- | Discover dependencies of an ADT that is itself only referenced by name.
newtype RegistrationChain = RegistrationChain RegistrationTuple deriving Show
-- | The root of a mutually recursive group, with a nested reference to its peer.
data RegistrationEven = RegistrationEnd | RegistrationEven (RegistrationOdd, Word8) deriving Show
-- | The return edge of the mutually recursive group.
newtype RegistrationOdd = RegistrationOdd RegistrationEven deriving Show
-- | Recursion through a type argument must not make retained metadata cyclic.
data RegistrationParamCycle = RegistrationParamEnd
| RegistrationParamNext (RegistrationParamLink RegistrationParamCycle)
deriving Show
-- | A parameter carrying the return edge of a recursive dependency.
newtype RegistrationParamLink a = RegistrationParamLink a deriving Show
-- | Generate all schemas without registering any symbolic values in advance.
mkSymbolic [''RegistrationLeaf, ''RegistrationTuple, ''RegistrationList, ''RegistrationSet, ''RegistrationKey, ''RegistrationValue, ''RegistrationSynonym, ''RegistrationParameter, ''RegistrationChain, ''RegistrationEven, ''RegistrationOdd, ''RegistrationParamCycle, ''RegistrationParamLink]
-- | Each fresh solver session uses only its root type, through either a literal
-- or a fresh variable. Field selectors and extra inner-type inputs must not mask
-- missing schemas.
tests :: TestTree
tests = testGroup "ADT.Registration" $
[ testCase "literal-only symbolic constraint" $ do
result <- runSMT $ do
constrain (uninterpret "observeRegistrationEnd" (literal RegistrationEnd) :: SBool)
query checkSat
assertEqual "A leaf literal must register its unused recursive partner" Sat result
, testCase "literal-only query constraint" $ do
result <- runSMT $ query $ do
constrain (uninterpret "observeRegistrationEnd" (literal RegistrationEnd) :: SBool)
checkSat
assertEqual "A query literal must register its unused recursive partner" Sat result
, testCase "finite parameter-mediated recursive metadata" $ do
let leaf = literal RegistrationParamEnd
void $ evaluate (force (kindOf leaf))
result <- runSMT $ do
constrain (uninterpret "observeRegistrationParamEnd" leaf :: SBool)
query checkSat
assertEqual "Recursive type arguments must retain a finite declaration registry" Sat result
] ++ [ testGroup phase
[ check interactive "tuple" (Proxy @RegistrationTuple)
, check interactive "list" (Proxy @RegistrationList)
, check interactive "set" (Proxy @RegistrationSet)
, check interactive "array key" (Proxy @RegistrationKey)
, check interactive "array value" (Proxy @RegistrationValue)
, check interactive "type synonym" (Proxy @RegistrationSynonym)
, check interactive "parameter" (Proxy @(RegistrationParameter Word8))
, check interactive "transitive" (Proxy @RegistrationChain)
, check interactive "mutual root" (Proxy @RegistrationEven)
, check interactive "mutual peer" (Proxy @RegistrationOdd)
]
| (phase, interactive) <- [("symbolic", Nothing), ("query named", Just False), ("query unnamed", Just True)]
]
where check :: forall a. SymVal a => Maybe Bool -> String -> Proxy a -> TestTree
check interactive testName _ = testCase testName $ do
result <- runSMT $ case interactive of
Just anonymous -> query $ do left <- if anonymous then freshVar_ @a else freshVar @a "left"
right <- if anonymous then freshVar_ @a else freshVar @a "right"
constrain (left ./= right)
checkSat
Nothing -> do left <- free "left" :: Symbolic (SBV a)
right <- free "right" :: Symbolic (SBV a)
constrain (left ./= right)
query checkSat
assertEqual "Distinct root values must be satisfiable without explicit subfield registration" Sat result