Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PLT-1398 Set up typechecking property tests for all PIR compiler passes #5565

Merged
merged 29 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a8f4a1a
Add property tests.
thealmarty Sep 22, 2023
c1a24fb
Add module to cabal.
thealmarty Sep 26, 2023
d491312
Add tests for more passes.
thealmarty Sep 28, 2023
b42013d
Add expectFail tag.
thealmarty Sep 28, 2023
f4a9da8
Add changelog.
thealmarty Sep 28, 2023
1a330b7
Tidy up more, address some comments.
thealmarty Sep 29, 2023
a2cdf59
void doesn't compile on 9.6.
thealmarty Sep 29, 2023
c3a3b31
Add floatTerm test.
thealmarty Oct 2, 2023
bd4cc41
Add compileLets tests.
thealmarty Oct 2, 2023
f70a82f
Fix Lower.
thealmarty Oct 2, 2023
e0ed12c
Only typecheck after the pass.
thealmarty Oct 3, 2023
b468472
wip organize tests to eash pass's Test.hs.
thealmarty Oct 3, 2023
74eadff
Add deadcode pass test.
thealmarty Oct 4, 2023
85ab007
Add rename and recSplit tests.
thealmarty Oct 4, 2023
7775749
Avoid tasty discover picking up the property tests.
thealmarty Oct 5, 2023
18a6285
Add caseReduce test.
thealmarty Oct 5, 2023
e0d4935
Fix CI.
thealmarty Oct 5, 2023
ac9ccd5
Address comment.
thealmarty Oct 6, 2023
5a96a9f
Mark deadcode v2 as expected failure.
thealmarty Oct 6, 2023
67fb027
Make the test consistently fail to pass CI.
thealmarty Oct 6, 2023
4cbc103
Add more tests.
thealmarty Oct 6, 2023
2923dca
Try even more on deadcode test so that it fails consistently.
thealmarty Oct 6, 2023
9eebd12
Switch to camel case.
thealmarty Oct 10, 2023
6fd7048
Run runQuoteT stuff together.
thealmarty Oct 10, 2023
1631bc1
Fix some tests.
thealmarty Oct 10, 2023
0274a60
Let tasty-discover detect prop instead and have quickcheck generate a…
thealmarty Oct 11, 2023
0a45301
Add thunkRecursions test.
thealmarty Oct 11, 2023
03d0a7e
Ignore deadcode pass test to make CI pass.
thealmarty Oct 12, 2023
6278889
Fix after rebasing.
thealmarty Oct 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
### Added

- Typechecking property tests for all PIR compiler passes.

9 changes: 6 additions & 3 deletions plutus-core/plutus-core.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ library
PlutusCore.DeBruijn
PlutusCore.DeBruijn.Internal
PlutusCore.Default
PlutusCore.Default.Builtins
PlutusCore.Error
PlutusCore.Evaluation.Machine.BuiltinCostModel
PlutusCore.Evaluation.Machine.Ck
Expand Down Expand Up @@ -214,7 +215,6 @@ library
PlutusCore.Core.Plated
PlutusCore.Core.Type
PlutusCore.Crypto.Utils
PlutusCore.Default.Builtins
PlutusCore.Default.Universe
PlutusCore.Eq
PlutusCore.Parser.Builtin
Expand Down Expand Up @@ -479,8 +479,10 @@ library plutus-ir
PlutusIR.Compiler
PlutusIR.Compiler.Datatype
PlutusIR.Compiler.Definitions
PlutusIR.Compiler.Let
PlutusIR.Compiler.Names
PlutusIR.Compiler.Provenance
PlutusIR.Compiler.Types
PlutusIR.Contexts
PlutusIR.Core
PlutusIR.Core.Instance
Expand Down Expand Up @@ -525,10 +527,8 @@ library plutus-ir
PlutusIR.Analysis.Size
PlutusIR.Analysis.Usages
PlutusIR.Compiler.Error
PlutusIR.Compiler.Let
PlutusIR.Compiler.Lower
PlutusIR.Compiler.Recursion
PlutusIR.Compiler.Types
PlutusIR.Normalize

build-depends:
Expand Down Expand Up @@ -585,6 +585,7 @@ test-suite plutus-ir-test
PlutusIR.Scoping.Tests
PlutusIR.Transform.Beta.Tests
PlutusIR.Transform.CaseOfCase.Tests
PlutusIR.Transform.CaseReduce.Tests
PlutusIR.Transform.CommuteFnWithConst.Tests
PlutusIR.Transform.DeadCode.Tests
PlutusIR.Transform.EvaluateBuiltins.Tests
Expand Down Expand Up @@ -613,6 +614,7 @@ test-suite plutus-ir-test
, QuickCheck
, serialise
, tasty
, tasty-expected-failure
, tasty-hedgehog
, tasty-hunit
, tasty-quickcheck
Expand Down Expand Up @@ -701,6 +703,7 @@ library plutus-core-testlib
PlutusIR.Generators.QuickCheck.Common
PlutusIR.Generators.QuickCheck.GenerateTerms
PlutusIR.Generators.QuickCheck.ShrinkTerms
PlutusIR.Properties.Typecheck
PlutusIR.Test
Test.Tasty.Extras
UntypedPlutusCore.Test.DeBruijn.Bad
Expand Down
3 changes: 2 additions & 1 deletion plutus-core/plutus-ir/src/PlutusIR/Compiler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ module PlutusIR.Compiler (
PirTCConfig(..),
AllowEscape(..),
toDefaultCompilationCtx,
simplifyTerm) where
simplifyTerm
) where

import PlutusIR

Expand Down
4 changes: 2 additions & 2 deletions plutus-core/plutus-ir/src/PlutusIR/Compiler/Lower.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
-- editorconfig-checker-disable-file
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
Expand All @@ -16,7 +15,8 @@ import Control.Monad.Error.Lens
-- translating the constructors across.
lowerTerm :: Compiling m e uni fun a => PIRTerm uni fun a -> m (PLCTerm uni fun a)
lowerTerm = \case
Let x _ _ _ -> throwing _Error $ CompilationError x "Let bindings should have been eliminated before lowering"
Let x _ _ _ -> throwing _Error $
CompilationError x "Let bindings should have been eliminated before lowering"
Var x n -> pure $ PLC.Var x n
TyAbs x n k t -> PLC.TyAbs x n k <$> lowerTerm t
LamAbs x n ty t -> PLC.LamAbs x n ty <$> lowerTerm t
Expand Down
3 changes: 2 additions & 1 deletion plutus-core/plutus-ir/src/PlutusIR/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ data TypeErrorExt uni ann =
!ann
-- the expected constructor's type
!(PLC.Type PLC.TyName uni ann)
deriving stock (Show, Eq, Generic)
deriving stock (Show, Eq, Generic, Functor)
deriving anyclass (NFData)
makeClassyPrisms ''TypeErrorExt

Expand All @@ -42,6 +42,7 @@ data Error uni fun a = CompilationError !a !T.Text -- ^ A generic compilation er
| PLCError !(PLC.Error uni fun a) -- ^ An error from running some PLC function, lifted into this error type for convenience.
| PLCTypeError !(PLC.TypeError (PIR.Term PIR.TyName PIR.Name uni fun ()) uni fun a)
| PIRTypeError !(TypeErrorExt uni a)
deriving stock (Functor)
makeClassyPrisms ''Error

instance PLC.AsTypeError (Error uni fun a) (PIR.Term PIR.TyName PIR.Name uni fun ()) uni fun a where
Expand Down
1 change: 0 additions & 1 deletion plutus-core/plutus-ir/src/PlutusIR/Transform/Rename.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

{-# OPTIONS_GHC -fno-warn-orphans #-}
Expand Down
2 changes: 1 addition & 1 deletion plutus-core/plutus-ir/src/PlutusIR/TypeCheck.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Control.Monad ((>=>))
The PIR typechecker is an extension of the PLC typechecker; whereas the PLC typechecker
works on PLC terms, the PIR typechecker works on the PIR terms. A PIR term
can be thought of as a superset of the PLC term language: it adds the `LetRec` and
`LetNonRec` syntactic constructs. Because of ths, the PIR typechecker simply extends the
`LetNonRec` syntactic constructs. Because of this, the PIR typechecker simply extends the
PLC typechecker by adding checks for these two let constructs of PIR.

Since we already have a PIR->PLC compiler, some would say that it would suffice to first
Expand Down
33 changes: 33 additions & 0 deletions plutus-core/plutus-ir/test/PlutusIR/Compiler/Let/Test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,44 @@ module PlutusIR.Compiler.Let.Test where

import PlutusIR.Test

import PlutusIR.Compiler.Let
import PlutusIR.Properties.Typecheck
import Test.QuickCheck
import Test.Tasty
import Test.Tasty.ExpectedFailure (ignoreTest)
import Test.Tasty.Extras
import Test.Tasty.QuickCheck

test_lets :: TestTree
test_lets = runTestNestedIn ["plutus-ir/test/PlutusIR/Compiler"] $ testNested "Let"
[ goldenPlcFromPir pTermAsProg "letInLet"
, goldenPlcFromPir pTermAsProg "letDep"
]

-- FIXME
-- | Check that a term typechecks after a
-- `PlutusIR.Compiler.Let.compileLets` (recursive terms) pass.
prop_TypecheckCompileLetsRecTerms :: Property
Copy link
Contributor Author

@thealmarty thealmarty Oct 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could let it generate random LetKind too but I feel in this case it's more obviously useful to separate them. Let me know if you think otherwise.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, in this case it actually means "do something completely different", so I think it's good to separate them.

prop_TypecheckCompileLetsRecTerms =
expectFailure $ withMaxSuccess 10000 $ extraConstraintTypecheckProp (compileLets RecTerms)

-- | Check that a term typechecks after a
-- `PlutusIR.Compiler.Let.compileLets` (non-recursive terms) pass.
prop_TypecheckCompileLetsNonRecTerms :: Property
prop_TypecheckCompileLetsNonRecTerms =
withMaxSuccess 10000 $ extraConstraintTypecheckProp (compileLets NonRecTerms)

-- | Check that a term typechecks after a
-- `PlutusIR.Compiler.Let.compileLets` (types) pass.
prop_TypecheckCompileLetsTypes :: Property
prop_TypecheckCompileLetsTypes =
withMaxSuccess 10000 $ extraConstraintTypecheckProp (compileLets Types)

-- FIXME this test sometimes fails so ignoring it to make CI pass.
-- | Check that a term typechecks after a
-- `PlutusIR.Compiler.Let.compileLets` (data types) pass.
test_TypecheckCompileLetsDataTypes :: TestTree
test_TypecheckCompileLetsDataTypes =
ignoreTest $ testProperty "typechecking" $
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the reason we can't say it's expected to fail is because it sometimes passes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah.

withMaxSuccess 10000 $
extraConstraintTypecheckProp (compileLets DataTypes)
10 changes: 8 additions & 2 deletions plutus-core/plutus-ir/test/PlutusIR/Transform/Beta/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,23 @@ import Test.Tasty.Extras
import PlutusCore qualified as PLC
import PlutusCore.Quote
import PlutusIR.Parser
import PlutusIR.Properties.Typecheck
import PlutusIR.Test
import PlutusIR.Transform.Beta qualified as Beta
import PlutusIR.Transform.Beta
import Test.QuickCheck.Property (Property, withMaxSuccess)

test_beta :: TestTree
test_beta = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $
testNested "Beta" $
map
(goldenPir (Beta.beta . runQuote . PLC.rename) pTerm)
(goldenPir (beta . runQuote . PLC.rename) pTerm)
[ "lamapp"
, "lamapp2"
, "absapp"
, "multiapp"
, "multilet"
]

-- | Check that a term typechecks after a `PlutusIR.Transform.Beta.beta` pass.
prop_TypecheckBeta :: Property
prop_TypecheckBeta = withMaxSuccess 3000 (pureTypecheckProp beta)
11 changes: 11 additions & 0 deletions plutus-core/plutus-ir/test/PlutusIR/Transform/CaseReduce/Tests.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module PlutusIR.Transform.CaseReduce.Tests where

import PlutusIR.Transform.CaseReduce

import PlutusIR.Properties.Typecheck
import Test.QuickCheck.Property (Property, withMaxSuccess)

-- | Check that a term typechecks after a `PlutusIR.Transform.CaseReduce.caseReduce` pass.
prop_TypecheckCaseReduce :: Property
prop_TypecheckCaseReduce =
withMaxSuccess 3000 (pureTypecheckProp caseReduce)
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,24 @@ import Test.Tasty.Extras

import PlutusIR.Parser
import PlutusIR.Test
import PlutusIR.Transform.CommuteFnWithConst qualified as CommuteFnWithConst
import PlutusIR.Transform.CommuteFnWithConst

import PlutusIR.Properties.Typecheck
import Test.QuickCheck.Property (Property, withMaxSuccess)

test_commuteDefaultFun :: TestTree
test_commuteDefaultFun = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $
testNested "CommuteFnWithConst" $
map
(goldenPir CommuteFnWithConst.commuteDefaultFun pTerm)
(goldenPir commuteDefaultFun pTerm)
[ "equalsInt" -- this tests that the function works on equalInteger
, "divideInt" -- this tests that the function excludes not commutative functions
, "multiplyInt" -- this tests that the function works on multiplyInteger
, "let" -- this tests that it works in the subterms
]

-- | Check that a term typechecks after a `PlutusIR.Transform.CommuteFnWithConst.commuteFnWithConst`
-- pass.
prop_TypecheckCommuteFnWithConst :: Property
prop_TypecheckCommuteFnWithConst =
withMaxSuccess 3000 (pureTypecheckProp commuteFnWithConst)
19 changes: 17 additions & 2 deletions plutus-core/plutus-ir/test/PlutusIR/Transform/DeadCode/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@ module PlutusIR.Transform.DeadCode.Tests where
import Test.Tasty
import Test.Tasty.Extras

import PlutusCore.Default
import PlutusCore.Quote
import PlutusIR.Analysis.Builtins
import PlutusIR.Parser
import PlutusIR.Properties.Typecheck
import PlutusIR.Test
import PlutusIR.Transform.DeadCode qualified as DeadCode
import PlutusIR.Transform.DeadCode
import PlutusPrelude
import Test.Tasty.ExpectedFailure (ignoreTest)
import Test.Tasty.QuickCheck

test_deadCode :: TestTree
test_deadCode = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $
testNested "DeadCode" $
map
(goldenPir (runQuote . DeadCode.removeDeadBindings def) pTerm)
(goldenPir (runQuote . removeDeadBindings def) pTerm)
[ "typeLet"
, "termLet"
, "strictLet"
Expand All @@ -31,3 +36,13 @@ test_deadCode = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $
, "recBindingComplex"
, "pruneDatatype"
]

-- FIXME this test sometimes fails so ignoring it to make CI pass.
-- | Check that a term typechecks after a `PlutusIR.Transform.DeadCode.removeDeadBindings` pass.
typecheckRemoveDeadBindingsProp :: BuiltinSemanticsVariant DefaultFun -> Property
typecheckRemoveDeadBindingsProp biVariant =
withMaxSuccess 50000 $ nonPureTypecheckProp $ removeDeadBindings $
BuiltinsInfo biVariant defaultUniMatcherLike
test_TypecheckRemoveDeadBindings :: TestTree
test_TypecheckRemoveDeadBindings =
ignoreTest $ testProperty "typechecking" typecheckRemoveDeadBindingsProp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ module PlutusIR.Transform.EvaluateBuiltins.Tests where
import Test.Tasty
import Test.Tasty.Extras

import PlutusCore.Default.Builtins
import PlutusIR.Analysis.Builtins
import PlutusIR.Parser
import PlutusIR.Properties.Typecheck
import PlutusIR.Test
import PlutusIR.Transform.EvaluateBuiltins qualified as EvaluateBuiltins
import PlutusIR.Transform.EvaluateBuiltins
import PlutusPrelude
import Test.QuickCheck.Property (Property, withMaxSuccess)

test_evaluateBuiltins :: TestTree
test_evaluateBuiltins = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $
testNested "EvaluateBuiltins" $
map
(goldenPir (EvaluateBuiltins.evaluateBuiltins True def def) pTerm)
(goldenPir (evaluateBuiltins True def def) pTerm)
[ "addInteger"
, "ifThenElse"
, "trace"
Expand All @@ -21,3 +25,13 @@ test_evaluateBuiltins = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $
, "overApplication"
, "underApplication"
]

-- | Check that a term typechecks after a `PlutusIR.Transform.EvaluateBuiltins`
-- pass.
prop_TypecheckEvaluateBuiltins ::
Bool -> BuiltinSemanticsVariant DefaultFun -> Property
prop_TypecheckEvaluateBuiltins conservative biVariant =
withMaxSuccess 40000 $
pureTypecheckProp $
evaluateBuiltins conservative (BuiltinsInfo biVariant defaultUniMatcherLike) def

18 changes: 14 additions & 4 deletions plutus-core/plutus-ir/test/PlutusIR/Transform/Inline/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@
{-# LANGUAGE TypeApplications #-}
module PlutusIR.Transform.Inline.Tests where

import Test.Tasty
import Test.Tasty.Extras

import Control.Monad.Except
import PlutusCore qualified as PLC
import PlutusCore.Default.Builtins
import PlutusCore.Quote
import PlutusIR
import PlutusIR.Analysis.Builtins
import PlutusIR.Check.Uniques qualified as Uniques
import PlutusIR.Core.Instance.Pretty.Readable
import PlutusIR.Parser
import PlutusIR.Properties.Typecheck
import PlutusIR.Test
import PlutusIR.Transform.Inline.Inline qualified as Inline
import PlutusIR.Transform.Inline.Inline
import PlutusPrelude
import Test.QuickCheck.Property (Property, withMaxSuccess)
import Test.Tasty (TestTree)

-- | Tests of the inliner, include global uniqueness test.
test_inline :: TestTree
Expand All @@ -25,7 +29,7 @@ test_inline = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $
rethrow . asIfThrown @(PLC.UniqueError PLC.SrcSpan) $ do
let pirInlined = runQuote $ do
renamed <- PLC.rename pir
Inline.inline mempty def renamed
inline mempty def renamed
-- Make sure the inlined term is globally unique.
_ <- checkUniques pirInlined
pure pirInlined
Expand Down Expand Up @@ -83,7 +87,7 @@ test_nameCapture = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $
rethrow . asIfThrown @(PLC.UniqueError PLC.SrcSpan) $ do
let pirInlined = runQuote $ do
renamed <- PLC.rename pir
Inline.inline mempty def renamed
inline mempty def renamed
-- Make sure the inlined term is globally unique.
_ <- checkUniques pirInlined
pure . render $ prettyPirReadable pirInlined
Expand All @@ -97,3 +101,9 @@ test_nameCapture = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $
checkUniques :: (Ord a, MonadError (PLC.UniqueError a) m) => Term TyName Name uni fun a -> m ()
checkUniques =
Uniques.checkTerm (\case { Uniques.MultiplyDefined{} -> True; _ -> False})

-- | Check that a term typechecks after a `PlutusIR.Transform.Inline` pass.
prop_TypecheckInline :: BuiltinSemanticsVariant DefaultFun -> Property
prop_TypecheckInline biVariant =
withMaxSuccess 20000 $ nonPureTypecheckProp $
inline mempty (BuiltinsInfo biVariant defaultUniMatcherLike)
14 changes: 14 additions & 0 deletions plutus-core/plutus-ir/test/PlutusIR/Transform/LetFloatIn/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import PlutusIR.Transform.Rename ()
import PlutusIR.TypeCheck as TC
import PlutusPrelude

import PlutusCore.Builtin
import PlutusIR.Analysis.Builtins
import PlutusIR.Properties.Typecheck
import Test.QuickCheck.Property (Property, withMaxSuccess)

test_letFloatInConservative :: TestTree
test_letFloatInConservative = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform/LetFloatIn"] $
testNested "conservative" $
Expand Down Expand Up @@ -61,3 +66,12 @@ test_letFloatInRelaxed = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform/Let
_ <- runQuoteT . flip inferType (() <$ pirFloated) =<< TC.getDefTypeCheckConfig ()
-- letmerge is not necessary for floating, but is a nice visual transformation
pure $ LetMerge.letMerge pirFloated

-- | Check that a term typechecks after a
-- `PlutusIR.Transform.LetFloatIn.floatTerm` pass.
prop_TypecheckFloatTerm ::
BuiltinSemanticsVariant PLC.DefaultFun -> Bool -> Property
prop_TypecheckFloatTerm biVariant conservative =
withMaxSuccess 40000 $
nonPureTypecheckProp $
LetFloatIn.floatTerm (BuiltinsInfo biVariant defaultUniMatcherLike) conservative
Loading