diff --git a/.github/workflows/add-triage-label.yml b/.github/workflows/add-triage-label.yml index 963b4a3ba56..d896fb0ec22 100644 --- a/.github/workflows/add-triage-label.yml +++ b/.github/workflows/add-triage-label.yml @@ -1,9 +1,13 @@ +# Whenever a new issue is opened, this workflow adds the "status: needs triage" +# label, unless the issue already has one of the "Internal" labels. + name: Add Triage Label on: issues: types: - reopened - opened + jobs: add-triage-label: runs-on: ubuntu-latest @@ -13,10 +17,41 @@ jobs: - name: Run uses: actions/github-script@v7 with: - script: | - github.rest.issues.addLabels({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - labels: ["status: needs triage"] - }) \ No newline at end of file + script: | + const INTERNAL_LABELS = ["Internal", "status: triaged"]; + + async function getIssueLabels() { + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }); + return labels.map(label => label.name); + } + + async function issueHasInternalLabels() { + const labels = await getIssueLabels(); + return INTERNAL_LABELS.some(item => labels.includes(item)); + } + + async function addNeedsTriageLabelToIssue() { + await github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ["status: needs triage"] + }); + } + + try { + if (!await issueHasInternalLabels()) { + await addNeedsTriageLabelToIssue(); + } + } catch (error) { + core.setFailed(`Error: ${error}`); + } + + + + + \ No newline at end of file diff --git a/.github/workflows/longitudinal-benchmark.yml b/.github/workflows/longitudinal-benchmark.yml index 0b704711783..26c74321742 100644 --- a/.github/workflows/longitudinal-benchmark.yml +++ b/.github/workflows/longitudinal-benchmark.yml @@ -41,7 +41,7 @@ jobs: run: git config core.hooksPath no-hooks - name: Store benchmark result - uses: benchmark-action/github-action-benchmark@v1.19.3 + uses: benchmark-action/github-action-benchmark@v1.20.3 with: name: Plutus Benchmarks tool: 'customSmallerIsBetter' diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index c7f14577e29..01dddffcaf0 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -3,32 +3,32 @@ name: Nightly Test Suite on: schedule: - cron: 0 0 * * * # daily at midnight + workflow_dispatch: # or manually dispatch the job + inputs: + hedgehog-tests: + description: Numer of tests to run (--hedgehog-tests XXXXX) + required: false + default: "100000" + +env: + HEDGEHOG_TESTS: ${{ github.event.inputs.hedgehog-tests || 100000 }} jobs: nightly-test-suite: - runs-on: ubuntu-latest + runs-on: [self-hosted, plutus-benchmark] steps: - name: Checkout uses: actions/checkout@v4 - - name: Quick Install Nix - uses: cachix/install-nix-action@V27 - with: - extra_nix_config: | - experimental-features = nix-command flakes - accept-flake-config = true - - name: plutus-core-nightly - if: always() - run: | + run: | pushd plutus-core - nix run --no-warn-dirty --accept-flake-config .#plutus-core-test -- --hedgehog-tests 10000 + nix run --no-warn-dirty --accept-flake-config .#plutus-core-test -- --hedgehog-tests $HEDGEHOG_TESTS popd - name: plutus-ir-nightly - if: always() run: | pushd plutus-core - nix run --no-warn-dirty --accept-flake-config .#plutus-ir-test -- --hedgehog-tests 10000 + nix run --no-warn-dirty --accept-flake-config .#plutus-ir-test -- --hedgehog-tests $HEDGEHOG_TESTS popd diff --git a/RELEASE.adoc b/RELEASE.adoc index 2bc8e778281..797060bd304 100644 --- a/RELEASE.adoc +++ b/RELEASE.adoc @@ -75,19 +75,11 @@ This updates versions and version bounds, and assembles the changelogs.open a PR - Choose as git tag `x.y.z.0` - Choose as target the git commit hash which points to the release commit - Click `Generate release notes` to automatically fill in the details of what's changed -- Create and attach pir&uplc executables to the release by running the following commands inside the repository where its HEAD is at the release commit: -- -+ -[source,bash] -------------- -nix build .#hydraJobs.x86_64-linux.musl64.ghc96.pir -cp ./result/bin/pir ./pir-x86_64-linux-ghc96 - -nix build .#hydraJobs.x86_64-linux.musl64.ghc96.uplc -cp ./result/bin/uplc ./uplc-x86_64-linux-ghc96 -------------- +- Create and attach pir&uplc executables to the release by running the following script inside the repository where its HEAD is at the release commit: `./scripts/prepare-bins.sh`. This will create `pir-x86_64-linux-ghc96` and `uplc-x86_64-linux-ghc96` executables, compress them and put in the project's root folder. Upload them to the release draft. - Click `Publish release`. -7. Open a PR in the https://github.com/IntersectMBO/cardano-haskell-packages[CHaP repository] for publishing the new version. Run `./scripts/add-from-github.sh "https://github.com/IntersectMBO/plutus" COMMIT-SHA LIST-OF-UPDATED-PACKAGES` (see https://github.com/IntersectMBO/cardano-haskell-packages#-from-github[the README on CHaP]). Example: https://github.com/IntersectMBO/cardano-haskell-packages/pull/394. +7. Open a PR in the https://github.com/IntersectMBO/cardano-haskell-packages[CHaP repository] for publishing the new version. + +If you are making PR from your own fork then don't forget to sync your fork with the upstream first. + +Run `./scripts/add-from-github.sh "https://github.com/IntersectMBO/plutus" COMMIT-SHA LIST-OF-UPDATED-PACKAGES` (see https://github.com/IntersectMBO/cardano-haskell-packages#-from-github[the README on CHaP]). Example: https://github.com/IntersectMBO/cardano-haskell-packages/pull/764. - If issues are found, create a release branch `release/x.y.z`, fix the issues on master, backport the fixes to `release/x.y.z`, tag `x.y.z.0-rc2`, and go to step 4. - Why not just fix the issues on master and tag `x.y.z.0-rc2` from master? It is desirable to minimize the amount of change between `rc1` and `rc2`, because it may reduce the tests and checks that need to be performed against `rc2`. diff --git a/cabal.project b/cabal.project index 07ec151e6f4..fbdc55dea12 100644 --- a/cabal.project +++ b/cabal.project @@ -26,6 +26,7 @@ packages: doc/read-the-docs-site plutus-metatheory plutus-tx plutus-tx-plugin + plutus-tx-test-util prettyprinter-configurable stubs/plutus-ghc-stub diff --git a/doc/notes/plutus-core/cek-budgeting-profiling/CostingDetails.md b/doc/notes/plutus-core/cek-budgeting-profiling/CostingDetails.md index 173dccdf2de..73af0aaba22 100644 --- a/doc/notes/plutus-core/cek-budgeting-profiling/CostingDetails.md +++ b/doc/notes/plutus-core/cek-budgeting-profiling/CostingDetails.md @@ -70,7 +70,7 @@ instance (Eq fun, Hashable fun, ToExMemory term) => Restricting resb -> when (exceedsBudget resb newBudget) $ throwingWithCause _EvaluationError - (UserEvaluationError $ CekOutOfExError resb newBudget) + (OperationalEvaluationError $ CekOutOfExError resb newBudget) Nothing -- No value available for error ``` @@ -96,7 +96,7 @@ to the current mode: newBudget <- exBudgetStateBudget <%= (<> budget) when (exceedsBudget resb newBudget) $ throwingWithCause _EvaluationError - (UserEvaluationError $ CekOutOfExError resb newBudget) + (OperationalEvaluationError $ CekOutOfExError resb newBudget) Nothing ``` @@ -114,7 +114,7 @@ of memory very quickly. Changing the code to Restricting resb -> when (exceedsBudget resb newBudget) $ throwingWithCause _EvaluationError - (UserEvaluationError $ CekOutOfExError resb newBudget) + (OperationalEvaluationError $ CekOutOfExError resb newBudget) Nothing ``` diff --git a/doc/read-the-docs-site/plutus-doc.cabal b/doc/read-the-docs-site/plutus-doc.cabal index 1c31b3d75b1..86f51515c0c 100644 --- a/doc/read-the-docs-site/plutus-doc.cabal +++ b/doc/read-the-docs-site/plutus-doc.cabal @@ -17,13 +17,6 @@ source-repository head type: git location: https://github.com/IntersectMBO/plutus -flag defer-plugin-errors - description: - Defer errors from the plugin, useful for things like Haddock that can't handle it. - - default: False - manual: True - common lang default-language: Haskell2010 default-extensions: @@ -47,8 +40,6 @@ common lang -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas - if flag(defer-plugin-errors) - common ghc-version-support -- See the section on GHC versions in CONTRIBUTING if (impl(ghc <9.6) || impl(ghc >=9.7)) diff --git a/nix/project.nix b/nix/project.nix index cec73f42e64..9945c6c116f 100644 --- a/nix/project.nix +++ b/nix/project.nix @@ -141,6 +141,14 @@ let ssreflect equations ]; + + plutus-core.components.tests.plutus-core-test.postInstall = '' + wrapProgram $out/bin/plutus-core-test --set PATH ${lib.makeBinPath [ pkgs.diffutils ]} + ''; + + plutus-core.components.tests.plutus-ir-test.postInstall = '' + wrapProgram $out/bin/plutus-ir-test --set PATH ${lib.makeBinPath [ pkgs.diffutils ]} + ''; }; } diff --git a/plutus-benchmark/common/PlutusBenchmark/Common.hs b/plutus-benchmark/common/PlutusBenchmark/Common.hs index 4db0cc4453c..5afef1d06fd 100644 --- a/plutus-benchmark/common/PlutusBenchmark/Common.hs +++ b/plutus-benchmark/common/PlutusBenchmark/Common.hs @@ -35,14 +35,13 @@ import PlutusBenchmark.ProtocolParameters as PP import PlutusLedgerApi.Common qualified as LedgerApi -import PlutusTx qualified as Tx - import PlutusCore qualified as PLC import PlutusCore.Default import PlutusCore.Evaluation.Machine.ExBudget (ExBudget (..)) import PlutusCore.Evaluation.Machine.ExBudgetingDefaults qualified as PLC import PlutusCore.Evaluation.Machine.ExMemory (ExCPU (..), ExMemory (..)) +import PlutusTx.Test.Util.Compiled import UntypedPlutusCore qualified as UPLC import UntypedPlutusCore.Evaluation.Machine.Cek as Cek import UntypedPlutusCore.Evaluation.Machine.Cek qualified as UPLC @@ -52,7 +51,6 @@ import Criterion.Main import Criterion.Types (Config (..)) import Data.ByteString qualified as BS import Data.SatInt (fromSatInt) -import Data.Text (Text) import Flat qualified import GHC.IO.Encoding (setLocaleEncoding) import System.Directory @@ -78,58 +76,6 @@ getConfig limit = do timeLimit = limit } -type Term = UPLC.Term PLC.NamedDeBruijn DefaultUni DefaultFun () -type Program = UPLC.Program PLC.NamedDeBruijn DefaultUni DefaultFun () - -{- | Given a DeBruijn-named term, give every variable the name "v". If we later - call unDeBruijn, that will rename the variables to things like "v123", where - 123 is the relevant de Bruijn index.-} -toNamedDeBruijnTerm - :: UPLC.Term UPLC.DeBruijn DefaultUni DefaultFun () - -> UPLC.Term UPLC.NamedDeBruijn DefaultUni DefaultFun () -toNamedDeBruijnTerm = UPLC.termMapNames UPLC.fakeNameDeBruijn - -{- | Remove the textual names from a NamedDeBruijn term -} -toAnonDeBruijnTerm - :: Term - -> UPLC.Term UPLC.DeBruijn DefaultUni DefaultFun () -toAnonDeBruijnTerm = UPLC.termMapNames UPLC.unNameDeBruijn - -toAnonDeBruijnProg - :: UPLC.Program UPLC.NamedDeBruijn DefaultUni DefaultFun () - -> UPLC.Program UPLC.DeBruijn DefaultUni DefaultFun () -toAnonDeBruijnProg (UPLC.Program () ver body) = - UPLC.Program () ver $ toAnonDeBruijnTerm body - - -{- | Just extract the body of a program wrapped in a 'CompiledCodeIn'. We use this a lot. -} -compiledCodeToTerm - :: Tx.CompiledCodeIn DefaultUni DefaultFun a -> Term -compiledCodeToTerm (Tx.getPlcNoAnn -> UPLC.Program _ _ body) = body - -{- | Lift a Haskell value to a PLC term. The constraints get a bit out of control - if we try to do this over an arbitrary universe.-} -haskellValueToTerm - :: Tx.Lift DefaultUni a => a -> Term -haskellValueToTerm = compiledCodeToTerm . Tx.liftCodeDef - -{- | Just run a term to obtain an `EvaluationResult` (used for tests etc.) -} -unsafeRunTermCek :: Term -> EvaluationResult Term -unsafeRunTermCek = - unsafeExtractEvaluationResult - . (\(res, _, _) -> res) - . runCekDeBruijn PLC.defaultCekParameters Cek.restrictingEnormous Cek.noEmitter - --- | Just run a term. -runTermCek :: - Term -> - ( Either (CekEvaluationException UPLC.NamedDeBruijn DefaultUni DefaultFun) Term - , [Text] - ) -runTermCek = - (\(res, _, logs) -> (res, logs)) - . runCekDeBruijn PLC.defaultCekParameters Cek.restrictingEnormous Cek.logEmitter - -- | Evaluate a script and return the CPU and memory costs (according to the cost model) getCostsCek :: UPLC.Program UPLC.NamedDeBruijn DefaultUni DefaultFun () -> (Integer, Integer) getCostsCek (UPLC.Program _ _ prog) = @@ -138,21 +84,6 @@ getCostsCek (UPLC.Program _ _ prog) = let ExBudget (ExCPU cpu)(ExMemory mem) = budget in (fromSatInt cpu, fromSatInt mem) -{- | Evaluate a PLC term and check that the result matches a given Haskell value - (perhaps obtained by running the Haskell code that the term was compiled - from). We evaluate the lifted Haskell value as well, because lifting may - produce reducible terms. The function is polymorphic in the comparison - operator so that we can use it with both HUnit Assertions and QuickCheck - Properties. -} -cekResultMatchesHaskellValue - :: Tx.Lift DefaultUni a - => Term - -> (EvaluationResult Term -> EvaluationResult Term -> b) - -> a - -> b -cekResultMatchesHaskellValue term matches value = - (unsafeRunTermCek term) `matches` (unsafeRunTermCek $ haskellValueToTerm value) - -- | Create the evaluation context for the benchmarks. This doesn't exactly match how it's done -- on-chain, but that's okay because the evaluation context is cached by the ledger, so we're -- deliberately not including it in the benchmarks. diff --git a/plutus-benchmark/lists/test/Lookup/Spec.hs b/plutus-benchmark/lists/test/Lookup/Spec.hs index 941f8e80e11..132ead7ec62 100644 --- a/plutus-benchmark/lists/test/Lookup/Spec.hs +++ b/plutus-benchmark/lists/test/Lookup/Spec.hs @@ -1,7 +1,7 @@ module Lookup.Spec (tests) where import Test.Tasty -import Test.Tasty.Extras (TestNested, runTestGroupNestedGhc) +import Test.Tasty.Extras (TestNested, runTestNested, testNestedGhc) import PlutusBenchmark.Lists.Lookup.Compiled qualified as Compiled @@ -9,12 +9,12 @@ import PlutusTx.Test qualified as Tx -- Make a set of golden tests with results stored in a given subdirectory -- inside a subdirectory determined by the GHC version. -testGroupGhcIn :: [FilePath] -> [TestNested] -> TestTree -testGroupGhcIn dir = runTestGroupNestedGhc (["lists", "test"] ++ dir) +runTestGhc :: [FilePath] -> [TestNested] -> TestTree +runTestGhc path = runTestNested (["lists", "test"] ++ path) . pure . testNestedGhc tests :: TestTree tests = - testGroupGhcIn ["Lookup"] $ + runTestGhc ["Lookup"] $ flip concatMap sizes $ \sz -> [ Tx.goldenBudget ("match-scott-list-" ++ show sz) $ Compiled.mkMatchWithListsCode (Compiled.workloadOfSize sz) diff --git a/plutus-benchmark/lists/test/Sum/Spec.hs b/plutus-benchmark/lists/test/Sum/Spec.hs index d62dc551b4a..89892581fd0 100644 --- a/plutus-benchmark/lists/test/Sum/Spec.hs +++ b/plutus-benchmark/lists/test/Sum/Spec.hs @@ -2,7 +2,7 @@ module Sum.Spec (tests) where import Test.Tasty -import Test.Tasty.Extras (TestNested, runTestGroupNestedGhc) +import Test.Tasty.Extras (TestNested, runTestNested, testNestedGhc) import Test.Tasty.QuickCheck import PlutusBenchmark.Common (Term, cekResultMatchesHaskellValue) @@ -14,8 +14,8 @@ import PlutusTx.Test qualified as Tx -- Make a set of golden tests with results stored in a given subdirectory -- inside a subdirectory determined by the GHC version. -testGroupGhcIn :: [FilePath] -> [TestNested] -> TestTree -testGroupGhcIn dir = runTestGroupNestedGhc (["lists", "test"] ++ dir) +runTestGhc :: [FilePath] -> [TestNested] -> TestTree +runTestGhc path = runTestNested (["lists", "test"] ++ path) . pure . testNestedGhc -- | Check that the various summation functions all give the same result as 'sum' @@ -37,7 +37,7 @@ tests = , testProperty "Compiled left fold (built-in lists)" $ prop_sum Compiled.mkSumLeftBuiltinTerm , testProperty "Compiled left fold (data lists)" $ prop_sum Compiled.mkSumLeftDataTerm ] - , testGroupGhcIn ["Sum"] + , runTestGhc ["Sum"] [ Tx.goldenBudget "right-fold-scott" $ Compiled.mkSumRightScottCode input , Tx.goldenBudget "right-fold-built-in" $ Compiled.mkSumRightBuiltinCode input , Tx.goldenBudget "right-fold-data" $ Compiled.mkSumRightDataCode input diff --git a/plutus-benchmark/marlowe/test/Spec.hs b/plutus-benchmark/marlowe/test/Spec.hs index 2603e9da0e6..e3591c2f4b1 100644 --- a/plutus-benchmark/marlowe/test/Spec.hs +++ b/plutus-benchmark/marlowe/test/Spec.hs @@ -4,7 +4,7 @@ module Main (main) where import Test.Tasty -import Test.Tasty.Extras (TestNested, runTestGroupNestedGhc) +import Test.Tasty.Extras (TestNested, runTestNested, testNestedGhc) import PlutusBenchmark.Marlowe.BenchUtil (benchmarkToUPLC, rolePayoutBenchmarks, semanticsBenchmarks) @@ -30,8 +30,8 @@ mkBudgetTest validator bm@M.Benchmark{..} = -- Make a set of golden tests with results stored in a given subdirectory -- inside a subdirectory determined by the GHC version. -testGroupGhcIn :: [FilePath] -> [TestNested] -> TestTree -testGroupGhcIn path = runTestGroupNestedGhc (["marlowe", "test"] ++ path) +runTestGhc :: [FilePath] -> [TestNested] -> TestTree +runTestGhc path = runTestNested (["marlowe", "test"] ++ path) . pure . testNestedGhc main :: IO () main = do @@ -45,13 +45,13 @@ main = do let allTests :: TestTree allTests = testGroup "plutus-benchmark Marlowe tests" - [ testGroupGhcIn ["semantics"] $ + [ runTestGhc ["semantics"] $ goldenSize "semantics" marloweValidator : [ goldenUEvalBudget name [value] | bench <- semanticsMBench , let (name, value) = mkBudgetTest marloweValidator bench ] - , testGroupGhcIn ["role-payout"] $ + , runTestGhc ["role-payout"] $ goldenSize "role-payout" rolePayoutValidator : [ goldenUEvalBudget name [value] | bench <- rolePayoutMBench diff --git a/plutus-benchmark/nofib/exe/Main.hs b/plutus-benchmark/nofib/exe/Main.hs index ca88a42c653..c2dd8e7e9c3 100644 --- a/plutus-benchmark/nofib/exe/Main.hs +++ b/plutus-benchmark/nofib/exe/Main.hs @@ -202,7 +202,7 @@ options = hsubparser ---------------- Evaluation ---------------- evaluateWithCek :: UPLC.Term UPLC.NamedDeBruijn DefaultUni DefaultFun () -> UPLC.EvaluationResult (UPLC.Term UPLC.NamedDeBruijn DefaultUni DefaultFun ()) -evaluateWithCek = UPLC.unsafeExtractEvaluationResult . (\(fstT,_,_) -> fstT) . UPLC.runCekDeBruijn PLC.defaultCekParameters UPLC.restrictingEnormous UPLC.noEmitter +evaluateWithCek = UPLC.unsafeToEvaluationResult . (\(fstT,_,_) -> fstT) . UPLC.runCekDeBruijn PLC.defaultCekParameters UPLC.restrictingEnormous UPLC.noEmitter writeFlatNamed :: UPLC.Program UPLC.NamedDeBruijn DefaultUni DefaultFun () -> IO () writeFlatNamed prog = BS.putStr . Flat.flat . UPLC.UnrestrictedProgram $ prog diff --git a/plutus-benchmark/nofib/test/Spec.hs b/plutus-benchmark/nofib/test/Spec.hs index 3a2d81c828a..d7722d27ad9 100644 --- a/plutus-benchmark/nofib/test/Spec.hs +++ b/plutus-benchmark/nofib/test/Spec.hs @@ -8,7 +8,7 @@ run to completion. -} module Main where import Test.Tasty -import Test.Tasty.Extras (TestNested, runTestGroupNestedGhc) +import Test.Tasty.Extras (TestNested, runTestNested, testNestedGhc) import Test.Tasty.HUnit import Test.Tasty.QuickCheck @@ -26,8 +26,8 @@ import PlutusTx.Test qualified as Tx -- Make a set of golden tests with results stored in subdirectories determined -- by the GHC version. -testGroupGhc :: [TestNested] -> TestTree -testGroupGhc = runTestGroupNestedGhc ["nofib", "test"] +runTestGhc :: [TestNested] -> TestTree +runTestGhc = runTestNested ["nofib", "test"] . pure . testNestedGhc -- Unit tests comparing PLC and Haskell computations on given inputs @@ -47,7 +47,7 @@ testClausify = testGroup "clausify" , testCase "formula3" $ mkClausifyTest Clausify.F3 , testCase "formula4" $ mkClausifyTest Clausify.F4 , testCase "formula5" $ mkClausifyTest Clausify.F5 - , testGroupGhc + , runTestGhc [ Tx.goldenPirReadable "clausify-F5" formula5example , Tx.goldenSize "clausify-F5" formula5example , Tx.goldenBudget "clausify-F5" formula5example @@ -70,7 +70,7 @@ testKnights = testGroup "knights" -- Odd sizes call "error" because there are n , testCase "depth 100, 4x4" $ mkKnightsTest 100 4 , testCase "depth 100, 6x6" $ mkKnightsTest 100 6 , testCase "depth 100, 8x8" $ mkKnightsTest 100 8 - , testGroupGhc + , runTestGhc [ Tx.goldenPirReadable "knights10-4x4" knightsExample , Tx.goldenSize "knights10-4x4" knightsExample , Tx.goldenBudget "knights10-4x4" knightsExample @@ -93,7 +93,7 @@ testQueens = testGroup "queens" , testCase "Bjbt1" $ mkQueensTest 4 Queens.Bjbt1 , testCase "Bjbt2" $ mkQueensTest 4 Queens.Bjbt2 , testCase "Fc" $ mkQueensTest 4 Queens.Fc - , testGroupGhc + , runTestGhc [ Tx.goldenPirReadable "queens4-bt" queens4btExample , Tx.goldenSize "queens4-bt" queens4btExample , Tx.goldenBudget "queens4-bt" queens4btExample @@ -106,7 +106,7 @@ testQueens = testGroup "queens" , testCase "Bjbt1" $ mkQueensTest 5 Queens.Bjbt1 , testCase "Bjbt2" $ mkQueensTest 5 Queens.Bjbt2 , testCase "Fc" $ mkQueensTest 5 Queens.Fc - , testGroupGhc + , runTestGhc [ Tx.goldenPirReadable "queens5-fc" queens5fcExample , Tx.goldenSize "queens5-fc" queens5fcExample , Tx.goldenBudget "queens5-fc" queens5fcExample diff --git a/plutus-benchmark/plutus-benchmark.cabal b/plutus-benchmark/plutus-benchmark.cabal index 7631eed7d28..35a906f7ddf 100644 --- a/plutus-benchmark/plutus-benchmark.cabal +++ b/plutus-benchmark/plutus-benchmark.cabal @@ -8,8 +8,8 @@ license-files: maintainer: michael.peyton-jones@iohk.io author: Plutus Core Team -homepage: https://github.com/iohk/plutus#readme -bug-reports: https://github.com/iohk/plutus/issues +homepage: https://github.com/IntersectMBO/plutus +bug-reports: https://github.com/IntersectMBO/plutus/issues description: Please see the README on GitHub at @@ -22,7 +22,7 @@ data-files: source-repository head type: git - location: https://github.com/iohk/plutus + location: https://github.com/IntersectMBO/plutus -- Any files that use a `$$(...)` splice from the plugin should mention -- `PlutusTx.Plugin()` somewhere, even if it's just `import PlutusTx.Plugin()`. @@ -83,20 +83,19 @@ library plutus-benchmark-common other-modules: Paths_plutus_benchmark build-depends: - , base >=4.9 && <5 + , base >=4.9 && <5 , bytestring , criterion , deepseq , directory , filepath - , flat ^>=0.6 - , plutus-core ^>=1.28 - , plutus-ledger-api ^>=1.28 - , plutus-tx ^>=1.28 + , flat ^>=0.6 + , plutus-core ^>=1.28 + , plutus-ledger-api ^>=1.28 + , plutus-tx-test-util , tasty , tasty-golden , temporary - , text ---------------- nofib ---------------- diff --git a/plutus-benchmark/script-contexts/test/Spec.hs b/plutus-benchmark/script-contexts/test/Spec.hs index fad9a3815b0..62557c4ccb5 100644 --- a/plutus-benchmark/script-contexts/test/Spec.hs +++ b/plutus-benchmark/script-contexts/test/Spec.hs @@ -5,7 +5,7 @@ module Main (main) where import Data.Text qualified as Text import Test.Tasty -import Test.Tasty.Extras (TestNested, runTestGroupNestedGhc) +import Test.Tasty.Extras (TestNested, runTestNested, testNestedGhc) import Test.Tasty.HUnit import PlutusBenchmark.Common (Term, compiledCodeToTerm, runTermCek, unsafeRunTermCek) @@ -17,8 +17,8 @@ import PlutusTx.Test qualified as Tx -- Make a set of golden tests with results stored in subdirectories determined -- by the GHC version. -testGroupGhc :: [TestNested] -> TestTree -testGroupGhc = runTestGroupNestedGhc ["script-contexts", "test"] +runTestGhc :: [TestNested] -> TestTree +runTestGhc = runTestNested ["script-contexts", "test"] . pure . testNestedGhc assertSucceeded :: Term -> Assertion assertSucceeded t = @@ -43,7 +43,7 @@ testCheckSc1 = testGroup "checkScriptContext1" compiledCodeToTerm $ mkCheckScriptContext1Code (mkScriptContext 4) , testCase "fails on 5" . assertFailed $ compiledCodeToTerm $ mkCheckScriptContext1Code (mkScriptContext 5) - , testGroupGhc [ Tx.goldenSize "checkScriptContext1" $ + , runTestGhc [ Tx.goldenSize "checkScriptContext1" $ mkCheckScriptContext1Code (mkScriptContext 1) , Tx.goldenPirReadable "checkScriptContext1" $ mkCheckScriptContext1Code (mkScriptContext 1) @@ -64,7 +64,7 @@ testCheckSc2 = testGroup "checkScriptContext2" compiledCodeToTerm $ mkCheckScriptContext2Code (mkScriptContext 4) , testCase "succeed on 5" . assertSucceeded $ compiledCodeToTerm $ mkCheckScriptContext2Code (mkScriptContext 5) - , testGroupGhc [ Tx.goldenSize "checkScriptContext2" $ + , runTestGhc [ Tx.goldenSize "checkScriptContext2" $ mkCheckScriptContext2Code (mkScriptContext 1) , Tx.goldenPirReadable "checkScriptContext2" $ mkCheckScriptContext2Code (mkScriptContext 1) @@ -81,7 +81,7 @@ testCheckSc2 = testGroup "checkScriptContext2" testCheckScEquality :: TestTree testCheckScEquality = testGroup "checkScriptContextEquality" - [ testGroupGhc [ Tx.goldenBudget "checkScriptContextEqualityData-20" $ + [ runTestGhc [ Tx.goldenBudget "checkScriptContextEqualityData-20" $ mkScriptContextEqualityDataCode (mkScriptContext 20) , Tx.goldenEvalCekCatch "checkScriptContextEqualityData-20" $ [mkScriptContextEqualityDataCode (mkScriptContext 20)] diff --git a/plutus-core/changelog.d/20240517_094957_unsafeFixIO_v2_new_prims.md b/plutus-core/changelog.d/20240517_094957_unsafeFixIO_v2_new_prims.md new file mode 100644 index 00000000000..1cd71254e72 --- /dev/null +++ b/plutus-core/changelog.d/20240517_094957_unsafeFixIO_v2_new_prims.md @@ -0,0 +1,5 @@ + +### Added + +- Primitives `integerToByteString` and `byteStringToInteger` are added to PlutusV2, + enabled at protocol version 10. diff --git a/plutus-core/changelog.d/20240517_191403_effectfully_polish_evaluation_errors.md b/plutus-core/changelog.d/20240517_191403_effectfully_polish_evaluation_errors.md new file mode 100644 index 00000000000..fb19345a29b --- /dev/null +++ b/plutus-core/changelog.d/20240517_191403_effectfully_polish_evaluation_errors.md @@ -0,0 +1,7 @@ +### Removed + +- `unsafeRunCekNoEmit` and all `unsafeEvaluate*` functions in #6043. To replace e.g. `unsafeEvaluateCek` you can use `evaluateCek` in combination with `unsafeToEvaluationResult`. + +### Changed + +- Renamed `unsafeExtractEvaluationResult` to `unsafeToEvaluationResult`. diff --git a/plutus-core/changelog.d/20240520_192738_effectfully_remove_UnknownBuiltin.md b/plutus-core/changelog.d/20240520_192738_effectfully_remove_UnknownBuiltin.md new file mode 100644 index 00000000000..5fe160f9919 --- /dev/null +++ b/plutus-core/changelog.d/20240520_192738_effectfully_remove_UnknownBuiltin.md @@ -0,0 +1,3 @@ +### Removed + +- `UnknownBuiltin` and `UnknownBuiltinType` in #6064. diff --git a/plutus-core/cost-model/budgeting-bench/Common.hs b/plutus-core/cost-model/budgeting-bench/Common.hs index a314102ffda..617307cf454 100644 --- a/plutus-core/cost-model/budgeting-bench/Common.hs +++ b/plutus-core/cost-model/budgeting-bench/Common.hs @@ -78,13 +78,11 @@ benchWith -> String -> PlainTerm DefaultUni fun -> Benchmark -benchWith params name term = bench name $ whnf (unsafeEvaluateCekNoEmit params) term -{- ^ Note that to get sensible results with whnf, we must use an evaluation - function that looks at the result, so eg unsafeEvaluateCek won't work - properly because it returns a pair whose components won't be evaluated by - whnf. We can't use nf because it does too much work: for instance if it gets - back a 'Data' value it'll traverse all of it. --} +-- Note that to get sensible results with 'whnf', we must use an evaluation function that looks at +-- the result, so e.g. 'evaluateCek' won't work properly because it returns a pair whose components +-- won't be evaluated by 'whnf'. We can't use 'nf' because it does too much work: for instance if it +-- gets back a 'Data' value it'll traverse all of it. +benchWith params name term = bench name $ whnf (evaluateCekNoEmit params) term benchDefault :: String -> PlainTerm DefaultUni DefaultFun -> Benchmark benchDefault = benchWith defaultCekParameters diff --git a/plutus-core/executables/plutus/AnyProgram/Compile.hs b/plutus-core/executables/plutus/AnyProgram/Compile.hs index 1bbb1a9d91f..e71faad1abd 100644 --- a/plutus-core/executables/plutus/AnyProgram/Compile.hs +++ b/plutus-core/executables/plutus/AnyProgram/Compile.hs @@ -131,7 +131,7 @@ compileProgram = curry $ \case (SUplc _ _, SPir SName _) -> throwingPIR "Cannot compile uplc to pir" embedProgram :: PLC.Program tyname name uni fun ann -> PIR.Program tyname name uni fun ann -embedProgram (PLC.Program a v t) = PIR.Program a v $ embed t +embedProgram (PLC.Program a v t) = PIR.Program a v $ embedTerm t toOutAnn :: (Functor f, PIR.AsError e uni fun a, MonadError e m) => SAnn s1 diff --git a/plutus-core/executables/plutus/AnyProgram/Run.hs b/plutus-core/executables/plutus/AnyProgram/Run.hs index 1fb24679edb..2f94ce7d838 100644 --- a/plutus-core/executables/plutus/AnyProgram/Run.hs +++ b/plutus-core/executables/plutus/AnyProgram/Run.hs @@ -19,7 +19,6 @@ import Types import UntypedPlutusCore as UPLC import UntypedPlutusCore.Evaluation.Machine.Cek as UPLC -import Data.Foldable import Data.Text as Text runRun :: (?opts :: Opts) diff --git a/plutus-core/executables/plutus/Debugger/TUI/Main.hs b/plutus-core/executables/plutus/Debugger/TUI/Main.hs index f5e13c08c19..35478d47759 100644 --- a/plutus-core/executables/plutus/Debugger/TUI/Main.hs +++ b/plutus-core/executables/plutus/Debugger/TUI/Main.hs @@ -46,7 +46,6 @@ import Control.Concurrent import Control.Monad.Except (runExcept) import Control.Monad.Primitive (unsafeIOToPrim) import Control.Monad.ST (RealWorld) -import Data.Foldable import Data.Maybe import GHC.IO (stToIO) import Graphics.Vty qualified as Vty diff --git a/plutus-core/executables/src/PlutusCore/Executable/Common.hs b/plutus-core/executables/src/PlutusCore/Executable/Common.hs index 5c678b0a589..c673d9221e2 100644 --- a/plutus-core/executables/src/PlutusCore/Executable/Common.hs +++ b/plutus-core/executables/src/PlutusCore/Executable/Common.hs @@ -71,7 +71,6 @@ import PlutusIR.Parser qualified as PIR (parse, program) import Control.Monad.Except import Data.Aeson qualified as Aeson import Data.ByteString.Lazy qualified as BSL -import Data.Foldable (traverse_) import Data.HashMap.Monoidal qualified as H import Data.Kind (Type) import Data.List (intercalate) diff --git a/plutus-core/plutus-core.cabal b/plutus-core/plutus-core.cabal index d854c5c895e..a8d4bfff1c2 100644 --- a/plutus-core/plutus-core.cabal +++ b/plutus-core/plutus-core.cabal @@ -821,6 +821,7 @@ library plutus-core-testlib , data-default-class , dependent-map >=0.4.0.0 , filepath + , free , hashable , hedgehog >=1.0 , lazy-search diff --git a/plutus-core/plutus-core/src/PlutusCore/Check/Normal.hs b/plutus-core/plutus-core/src/PlutusCore/Check/Normal.hs index 9043abcde05..7ea2a4fc5ce 100644 --- a/plutus-core/plutus-core/src/PlutusCore/Check/Normal.hs +++ b/plutus-core/plutus-core/src/PlutusCore/Check/Normal.hs @@ -16,7 +16,6 @@ import PlutusCore.Core import PlutusCore.Error import Control.Monad.Except -import Data.Foldable (traverse_) -- | Ensure that all types in the 'Program' are normalized. checkProgram diff --git a/plutus-core/plutus-core/src/PlutusCore/Core/Instance/Eq.hs b/plutus-core/plutus-core/src/PlutusCore/Core/Instance/Eq.hs index 3c94ba83002..3fda5974720 100644 --- a/plutus-core/plutus-core/src/PlutusCore/Core/Instance/Eq.hs +++ b/plutus-core/plutus-core/src/PlutusCore/Core/Instance/Eq.hs @@ -22,8 +22,6 @@ import PlutusCore.Rename.Monad import Universe -import Data.Foldable (for_) - instance (GEq uni, Eq ann) => Eq (Type TyName uni ann) where ty1 == ty2 = runEqRename @TypeRenaming $ eqTypeM ty1 ty2 diff --git a/plutus-core/plutus-core/src/PlutusCore/Error.hs b/plutus-core/plutus-core/src/PlutusCore/Error.hs index 7b4b1e8d42a..7ec30398602 100644 --- a/plutus-core/plutus-core/src/PlutusCore/Error.hs +++ b/plutus-core/plutus-core/src/PlutusCore/Error.hs @@ -55,8 +55,7 @@ throwingEither r e = case e of -- | An error encountered during parsing. data ParserError - = UnknownBuiltinType !T.Text !SourcePos - | BuiltinTypeNotAStar !T.Text !SourcePos + = BuiltinTypeNotAStar !T.Text !SourcePos | UnknownBuiltinFunction !T.Text !SourcePos ![T.Text] | InvalidBuiltinConstant !T.Text !T.Text !SourcePos deriving stock (Eq, Ord, Generic) @@ -171,8 +170,6 @@ instance Pretty SourcePos where pretty = pretty . sourcePosPretty instance Pretty ParserError where - pretty (UnknownBuiltinType s loc) = - "Unknown built-in type" <+> squotes (pretty s) <+> "at" <+> pretty loc pretty (BuiltinTypeNotAStar ty loc) = "Expected a type of kind star (to later parse a constant), but got:" <+> squotes (pretty ty) <+> "at" <+> pretty loc diff --git a/plutus-core/plutus-core/src/PlutusCore/Evaluation/ErrorWithCause.hs b/plutus-core/plutus-core/src/PlutusCore/Evaluation/ErrorWithCause.hs index 15d3123338e..32bdc30d797 100644 --- a/plutus-core/plutus-core/src/PlutusCore/Evaluation/ErrorWithCause.hs +++ b/plutus-core/plutus-core/src/PlutusCore/Evaluation/ErrorWithCause.hs @@ -37,11 +37,14 @@ instance (Pretty err, Pretty cause) => Pretty (ErrorWithCause err cause) where instance (PrettyBy config cause, PrettyBy config err) => PrettyBy config (ErrorWithCause err cause) where - prettyBy config (ErrorWithCause err mayCause) = - "An error has occurred: " <+> prettyBy config err <> - case mayCause of - Nothing -> mempty - Just cause -> hardline <> "Caused by:" <+> prettyBy config cause + prettyBy config (ErrorWithCause err mayCause) = fold + [ "An error has occurred:" + , hardline + , prettyBy config err + , case mayCause of + Nothing -> mempty + Just cause -> hardline <> "Caused by:" <+> prettyBy config cause + ] instance (PrettyPlc cause, PrettyPlc err) => Show (ErrorWithCause err cause) where diff --git a/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/Ck.hs b/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/Ck.hs index e188b2cfa73..d1b7abab36f 100644 --- a/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/Ck.hs +++ b/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/Ck.hs @@ -17,12 +17,11 @@ module PlutusCore.Evaluation.Machine.Ck , CkEvaluationException , CkM , CkValue - , extractEvaluationResult , runCk + , extractEvaluationResult + , unsafeToEvaluationResult , evaluateCk , evaluateCkNoEmit - , unsafeEvaluateCk - , unsafeEvaluateCkNoEmit , readKnownCk ) where @@ -195,7 +194,7 @@ stack |> Constr _ ty i es = case es of t : ts -> FrameConstr ty i ts [] : stack |> t stack |> Case _ _ arg cs = FrameCase cs : stack |> arg _ |> Error{} = - throwingWithCause _EvaluationError (UserEvaluationError CkEvaluationFailure) Nothing + throwingWithCause _EvaluationError (OperationalEvaluationError CkEvaluationFailure) Nothing _ |> var@Var{} = throwingWithCause _MachineError OpenTermEvaluatedMachineError $ Just var @@ -312,22 +311,6 @@ evaluateCkNoEmit -> Either (CkEvaluationException uni fun) (Term TyName Name uni fun ()) evaluateCkNoEmit runtime = fst . runCk runtime False --- | Evaluate a term using the CK machine with logging enabled. May throw a 'CkEvaluationException'. -unsafeEvaluateCk - :: ThrowableBuiltins uni fun - => BuiltinsRuntime fun (CkValue uni fun) - -> Term TyName Name uni fun () - -> (EvaluationResult (Term TyName Name uni fun ()), [Text]) -unsafeEvaluateCk runtime = first unsafeExtractEvaluationResult . evaluateCk runtime - --- | Evaluate a term using the CK machine with logging disabled. May throw a 'CkEvaluationException'. -unsafeEvaluateCkNoEmit - :: ThrowableBuiltins uni fun - => BuiltinsRuntime fun (CkValue uni fun) - -> Term TyName Name uni fun () - -> EvaluationResult (Term TyName Name uni fun ()) -unsafeEvaluateCkNoEmit runtime = unsafeExtractEvaluationResult . evaluateCkNoEmit runtime - -- | Unlift a value using the CK machine. readKnownCk :: ReadKnown (Term TyName Name uni fun ()) a diff --git a/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/Exception.hs b/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/Exception.hs index 2ffd78de907..bd10f0267fe 100644 --- a/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/Exception.hs +++ b/plutus-core/plutus-core/src/PlutusCore/Evaluation/Machine/Exception.hs @@ -29,7 +29,7 @@ module PlutusCore.Evaluation.Machine.Exception , throwing_ , throwingWithCause , extractEvaluationResult - , unsafeExtractEvaluationResult + , unsafeToEvaluationResult ) where import PlutusPrelude @@ -55,24 +55,41 @@ data MachineError fun | OpenTermEvaluatedMachineError -- ^ An attempt to evaluate an open term. | UnliftingMachineError UnliftingError - -- ^ An attempt to compute a constant application resulted in 'ConstAppError'. + -- ^ An attempt to compute a constant application resulted in 'UnliftingError'. | BuiltinTermArgumentExpectedMachineError - -- ^ A builtin expected a term argument, but something else was received + -- ^ A builtin expected a term argument, but something else was received. | UnexpectedBuiltinTermArgumentMachineError -- ^ A builtin received a term argument when something else was expected - | UnknownBuiltin fun | NonConstrScrutinized | MissingCaseBranch Word64 deriving stock (Show, Eq, Functor, Generic) deriving anyclass (NFData) --- | The type of errors (all of them) which can occur during evaluation --- (some are used-caused, some are internal). -data EvaluationError user internal - = InternalEvaluationError !internal - -- ^ Indicates bugs. - | UserEvaluationError !user - -- ^ Indicates user errors. +{- | The type of errors that can occur during evaluation. There are two kinds of errors: + +1. Operational ones -- these are errors that are indicative of the _logic_ of the program being + wrong. For example, 'Error' was executed, 'tailList' was applied to an empty list or evaluation + ran out of gas. +2. Structural ones -- these are errors that are indicative of the _structure_ of the program being + wrong. For example, a free variable was encountered during evaluation, or a non-function was + applied to an argument. + +On the chain both of these are just regular failures and we don't distinguish between them there: +if a script fails, it fails, it doesn't matter what the reason was. However in the tests it does +matter why the failure occurred: a structural error may indicate that the test was written +incorrectly while an operational error may be entirely expected. + +In other words, operational errors are regular runtime errors and structural errors are \"runtime +type errors\". Which means that evaluating an (erased) well-typed program should never produce a +structural error, only an operational one. This creates a sort of \"runtime type system\" for UPLC +and it would be great to stick to it and enforce in tests etc, but we currently don't. For example, +a built-in function expecting a list but getting something else should throw a structural error, +but currently it'll throw an operational one. This is something that we plan to improve upon in +future. +-} +data EvaluationError operational structural + = OperationalEvaluationError !operational + | StructuralEvaluationError !structural deriving stock (Show, Eq, Functor, Generic) deriving anyclass (NFData) @@ -81,47 +98,50 @@ mtraverse makeClassyPrisms , ''EvaluationError ] -instance internal ~ MachineError fun => AsMachineError (EvaluationError user internal) fun where - _MachineError = _InternalEvaluationError -instance AsUnliftingError internal => AsUnliftingError (EvaluationError user internal) where - _UnliftingError = _InternalEvaluationError . _UnliftingError +instance structural ~ MachineError fun => + AsMachineError (EvaluationError operational structural) fun where + _MachineError = _StructuralEvaluationError +instance AsUnliftingError structural => + AsUnliftingError (EvaluationError operational structural) where + _UnliftingError = _StructuralEvaluationError . _UnliftingError instance AsUnliftingError (MachineError fun) where _UnliftingError = _UnliftingMachineError -instance AsEvaluationFailure user => AsEvaluationFailure (EvaluationError user internal) where - _EvaluationFailure = _UserEvaluationError . _EvaluationFailure - -type EvaluationException user internal = - ErrorWithCause (EvaluationError user internal) - -{- Note [Ignoring context in UserEvaluationError] -The UserEvaluationError error has a term argument, but -extractEvaluationResult just discards this and returns -EvaluationFailure. This means that, for example, if we use the `plc` -command to execute a program containing a division by zero, plc exits -silently without reporting that anything has gone wrong (but returning -a non-zero exit code to the shell via `exitFailure`). This is because -UserEvaluationError is used in cases when a PLC program itself goes -wrong (for example, a failure due to `(error)`, a failure during -builtin evaluation, or exceeding the gas limit). This is used to -signal unsuccessful in validation and so is not regarded as a real -error; in contrast, machine errors, typechecking failures, -and so on are genuine errors and we report their context if available. - -} - --- | Turn any 'UserEvaluationError' into an 'EvaluationFailure'. +instance AsEvaluationFailure operational => + AsEvaluationFailure (EvaluationError operational structural) where + _EvaluationFailure = _OperationalEvaluationError . _EvaluationFailure + +type EvaluationException operational structural = + ErrorWithCause (EvaluationError operational structural) + +{- Note [Ignoring context in OperationalEvaluationError] +The 'OperationalEvaluationError' error has a term argument, but 'extractEvaluationResult' just +discards this and returns 'EvaluationFailure'. This means that, for example, if we use the @plc@ +command to execute a program containing a division by zero, @plc@ exits silently without reporting +that anything has gone wrong (but returning a non-zero exit code to the shell via 'exitFailure'). +This is because 'OperationalEvaluationError' is used in cases when a PLC program itself goes wrong +(see the Haddocks of 'EvaluationError'). This is used to signal unsuccessful validation and so is +not regarded as a real error; in contrast structural errors are genuine errors and we report their +context if available. +-} + +-- See Note [Ignoring context in OperationalEvaluationError]. +-- | Preserve the contents of an 'StructuralEvaluationError' as a 'Left' and turn an +-- 'OperationalEvaluationError' into a @Right EvaluationFailure@. extractEvaluationResult - :: Either (EvaluationException user internal term) a - -> Either (ErrorWithCause internal term) (EvaluationResult a) + :: Either (EvaluationException operational structural term) a + -> Either (ErrorWithCause structural term) (EvaluationResult a) extractEvaluationResult (Right term) = Right $ EvaluationSuccess term extractEvaluationResult (Left (ErrorWithCause evalErr cause)) = case evalErr of - InternalEvaluationError err -> Left $ ErrorWithCause err cause - UserEvaluationError _ -> Right $ EvaluationFailure + StructuralEvaluationError err -> Left $ ErrorWithCause err cause + OperationalEvaluationError _ -> Right $ EvaluationFailure -unsafeExtractEvaluationResult +-- | Throw on a 'StructuralEvaluationError' and turn an 'OperationalEvaluationError' into an +-- 'EvaluationFailure'. +unsafeToEvaluationResult :: (PrettyPlc internal, PrettyPlc term, Typeable internal, Typeable term) => Either (EvaluationException user internal term) a -> EvaluationResult a -unsafeExtractEvaluationResult = unsafeFromEither . extractEvaluationResult +unsafeToEvaluationResult = unsafeFromEither . extractEvaluationResult instance (HasPrettyDefaults config ~ 'True, Pretty fun) => PrettyBy config (MachineError fun) where @@ -139,8 +159,6 @@ instance (HasPrettyDefaults config ~ 'True, Pretty fun) => "A builtin received a term argument when something else was expected" prettyBy _ (UnliftingMachineError unliftingError) = pretty unliftingError - prettyBy _ (UnknownBuiltin fun) = - "Encountered an unknown built-in function:" <+> pretty fun prettyBy _ NonConstrScrutinized = "A non-constructor value was scrutinized in a case expression" prettyBy _ (MissingCaseBranch i) = @@ -148,13 +166,7 @@ instance (HasPrettyDefaults config ~ 'True, Pretty fun) => instance ( HasPrettyDefaults config ~ 'True - , PrettyBy config internal, Pretty user - ) => PrettyBy config (EvaluationError user internal) where - prettyBy config (InternalEvaluationError err) = fold - [ "error:", hardline - , prettyBy config err - ] - prettyBy _ (UserEvaluationError err) = fold - [ "User error:", hardline - , pretty err - ] + , Pretty operational, PrettyBy config structural + ) => PrettyBy config (EvaluationError operational structural) where + prettyBy _ (OperationalEvaluationError operational) = pretty operational + prettyBy config (StructuralEvaluationError structural) = prettyBy config structural diff --git a/plutus-core/plutus-core/src/PlutusCore/MkPlc.hs b/plutus-core/plutus-core/src/PlutusCore/MkPlc.hs index afc44d0d92d..cef4f70725e 100644 --- a/plutus-core/plutus-core/src/PlutusCore/MkPlc.hs +++ b/plutus-core/plutus-core/src/PlutusCore/MkPlc.hs @@ -29,7 +29,7 @@ module PlutusCore.MkPlc , mkTyVar , tyDeclVar , Def (..) - , embed + , embedTerm , TermDef , TypeDef , FunctionType (..) @@ -121,20 +121,20 @@ instance TermLike (Term tyname name uni fun) tyname name uni fun where constr = Constr kase = Case -embed :: TermLike term tyname name uni fun => Term tyname name uni fun ann -> term ann -embed = \case +embedTerm :: TermLike term tyname name uni fun => Term tyname name uni fun ann -> term ann +embedTerm = \case Var a n -> var a n - TyAbs a tn k t -> tyAbs a tn k (embed t) - LamAbs a n ty t -> lamAbs a n ty (embed t) - Apply a t1 t2 -> apply a (embed t1) (embed t2) + TyAbs a tn k t -> tyAbs a tn k (embedTerm t) + LamAbs a n ty t -> lamAbs a n ty (embedTerm t) + Apply a t1 t2 -> apply a (embedTerm t1) (embedTerm t2) Constant a c -> constant a c Builtin a bi -> builtin a bi - TyInst a t ty -> tyInst a (embed t) ty + TyInst a t ty -> tyInst a (embedTerm t) ty Error a ty -> error a ty - Unwrap a t -> unwrap a (embed t) - IWrap a ty1 ty2 t -> iWrap a ty1 ty2 (embed t) - Constr a ty i es -> constr a ty i (fmap embed es) - Case a ty arg cs -> kase a ty (embed arg) (fmap embed cs) + Unwrap a t -> unwrap a (embedTerm t) + IWrap a ty1 ty2 t -> iWrap a ty1 ty2 (embedTerm t) + Constr a ty i es -> constr a ty i (fmap embedTerm es) + Case a ty arg cs -> kase a ty (embedTerm arg) (fmap embedTerm cs) -- | Make a 'Var' referencing the given 'VarDecl'. mkVar :: TermLike term tyname name uni fun => ann -> VarDecl tyname name uni ann -> term ann diff --git a/plutus-core/plutus-core/src/PlutusCore/TypeCheck.hs b/plutus-core/plutus-core/src/PlutusCore/TypeCheck.hs index b71f193d2db..995f944c372 100644 --- a/plutus-core/plutus-core/src/PlutusCore/TypeCheck.hs +++ b/plutus-core/plutus-core/src/PlutusCore/TypeCheck.hs @@ -36,9 +36,9 @@ import PlutusCore.Quote import PlutusCore.Rename import PlutusCore.TypeCheck.Internal --- | The constraint for built-in types/functions are kind/type-checkable. +-- | The constraint for built-in types\/functions are kind\/type-checkable. -- --- We keep this separate from 'MonadKindCheck'/'MonadTypeCheck', because those mainly constrain the +-- We keep this separate from 'MonadKindCheck'\/'MonadTypeCheck', because those mainly constrain the -- monad and 'Typecheckable' constraints only the builtins. In particular useful when the monad gets -- instantiated and builtins don't. Another reason is that 'Typecheckable' is not required during -- type checking, since it's only needed for computing 'BuiltinTypes', which is passed as a regular diff --git a/plutus-core/plutus-core/test/Evaluation/Machines.hs b/plutus-core/plutus-core/test/Evaluation/Machines.hs index 0d662124ce3..e47c3aceeee 100644 --- a/plutus-core/plutus-core/test/Evaluation/Machines.hs +++ b/plutus-core/plutus-core/test/Evaluation/Machines.hs @@ -20,10 +20,12 @@ import Test.Tasty import Test.Tasty.Hedgehog testMachine - :: (uni ~ DefaultUni, fun ~ DefaultFun, PrettyPlc internal) + :: (uni ~ DefaultUni, fun ~ DefaultFun, PrettyPlc structural) => String -> (Term TyName Name uni fun () -> - Either (EvaluationException user internal (Term TyName Name uni fun ())) (Term TyName Name uni fun ())) + Either + (EvaluationException operational structural (Term TyName Name uni fun ())) + (Term TyName Name uni fun ())) -> TestTree testMachine machine eval = testGroup machine $ fromInterestingTermGens $ \name -> diff --git a/plutus-core/plutus-core/test/Pretty/Readable.hs b/plutus-core/plutus-core/test/Pretty/Readable.hs index 0a1f91cfb5d..a346e264b71 100644 --- a/plutus-core/plutus-core/test/Pretty/Readable.hs +++ b/plutus-core/plutus-core/test/Pretty/Readable.hs @@ -31,8 +31,7 @@ test_PrettyReadable = where folder :: Pretty fun => PlcFolderContents DefaultUni fun -> TestTree folder - = runTestNestedIn ["plutus-core", "test", "Pretty", "Golden"] - . testNested "Readable" + = runTestNested ["plutus-core", "test", "Pretty", "Golden", "Readable"] . foldPlcFolderContents testNested testReadable testReadable test_Pretty :: TestTree diff --git a/plutus-core/plutus-core/test/Spec.hs b/plutus-core/plutus-core/test/Spec.hs index df56d7f15b4..daf13d8b770 100644 --- a/plutus-core/plutus-core/test/Spec.hs +++ b/plutus-core/plutus-core/test/Spec.hs @@ -36,7 +36,6 @@ import PlutusCore.Test import Control.Monad.Except import Data.ByteString.Lazy qualified as BSL -import Data.Foldable (for_) import Data.Proxy import Data.Text qualified as T import Data.Text.Encoding (encodeUtf8) diff --git a/plutus-core/plutus-core/test/TypeSynthesis/Spec.hs b/plutus-core/plutus-core/test/TypeSynthesis/Spec.hs index 7d0f7d76810..b07512262cc 100644 --- a/plutus-core/plutus-core/test/TypeSynthesis/Spec.hs +++ b/plutus-core/plutus-core/test/TypeSynthesis/Spec.hs @@ -67,8 +67,7 @@ foldAssertWell -> PlcFolderContents DefaultUni fun -> TestTree foldAssertWell semvar - = runTestNestedIn ["plutus-core", "test", "TypeSynthesis"] - . testNested "Golden" + = runTestNested ["plutus-core", "test", "TypeSynthesis", "Golden"] . foldPlcFolderContents testNested (\name -> nestedGoldenVsErrorOrThing name . kindcheck) (\name -> nestedGoldenVsErrorOrThing name . typecheck semvar) @@ -128,27 +127,27 @@ test_typecheckIllTyped = ] test_typecheckAllFun - :: forall fun. (ToBuiltinMeaning DefaultUni fun, Show fun) + :: forall fun. (ToBuiltinMeaning DefaultUni fun, Show fun, Show (BuiltinSemanticsVariant fun)) => String -> BuiltinSemanticsVariant fun - -> TestTree -test_typecheckAllFun name semvar - = runTestNestedIn ["plutus-core", "test", "TypeSynthesis", "Golden"] - . testNested name + -> TestNested +test_typecheckAllFun name semVar + = testNestedNamed name (show semVar) . map testFun $ enumerate @fun where testFun fun = - nestedGoldenVsErrorOrThing (show fun) . kindcheck $ typeOfBuiltinFunction semvar fun + nestedGoldenVsErrorOrThing (show fun) . kindcheck $ typeOfBuiltinFunction semVar fun test_typecheckDefaultFuns :: TestTree test_typecheckDefaultFuns = -- This checks that for each set of builtins the Plutus type of every builtin is the same -- regardless of versioning. - testGroup "builtins" $ concat - [ map (test_typecheckAllFun @DefaultFun "DefaultFun") enumerate - , map (test_typecheckAllFun @ExtensionFun "ExtensionFun") enumerate - ] + testGroup "builtins" . pure $ + runTestNested ["plutus-core", "test", "TypeSynthesis", "Golden"] $ concat + [ map (test_typecheckAllFun @DefaultFun "DefaultFun") enumerate + , map (test_typecheckAllFun @ExtensionFun "ExtensionFun") enumerate + ] test_typecheck :: TestTree test_typecheck = diff --git a/plutus-core/plutus-ir/test/PlutusIR/Analysis/RetainedSize/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Analysis/RetainedSize/Tests.hs index d01b58b2f60..f7d91041b37 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Analysis/RetainedSize/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Analysis/RetainedSize/Tests.hs @@ -13,8 +13,8 @@ import PlutusIR.Test import PlutusPrelude test_retainedSize :: TestTree -test_retainedSize = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Analysis"] $ - testNested "RetainedSize" $ +test_retainedSize = + runTestNested ["plutus-ir", "test", "PlutusIR", "Analysis", "RetainedSize"] $ map (goldenPir renameAndAnnotate pTerm) [ "typeLet" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Datatype/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Datatype/Tests.hs index b203e842d7b..8f6239dc040 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Datatype/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Datatype/Tests.hs @@ -8,15 +8,15 @@ import Test.Tasty.Extras test_datatypes :: TestTree test_datatypes = - runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Compiler"] $ testNested "Datatype" - [ goldenPlcFromPir pTermAsProg "maybe" - , goldenPlcFromPir pTermAsProg "listMatch" - , goldenPlcFromPir pTermAsProg "idleAll" - , goldenPlcFromPir pTermAsProg "some" - , goldenEvalPir pTermAsProg "listMatchEval" - , goldenTypeFromPir topSrcSpan pTerm "dataEscape" - , testNested "scott" - [ goldenPlcFromPirScott pTermAsProg "maybe" - , goldenPlcFromPirScott pTermAsProg "listMatch" + runTestNested ["plutus-ir", "test", "PlutusIR", "Compiler", "Datatype"] + [ goldenPlcFromPir pTermAsProg "maybe" + , goldenPlcFromPir pTermAsProg "listMatch" + , goldenPlcFromPir pTermAsProg "idleAll" + , goldenPlcFromPir pTermAsProg "some" + , goldenEvalPir pTermAsProg "listMatchEval" + , goldenTypeFromPir topSrcSpan pTerm "dataEscape" + , testNested "scott" + [ goldenPlcFromPirScott pTermAsProg "maybe" + , goldenPlcFromPirScott pTermAsProg "listMatch" + ] ] - ] diff --git a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Error/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Error/Tests.hs index 142a50592a8..f0029cb077e 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Error/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Error/Tests.hs @@ -6,7 +6,8 @@ import Test.Tasty import Test.Tasty.Extras test_error :: TestTree -test_error = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Compiler"] $ testNested "Error" - [ goldenPlcFromPir pTermAsProg "mutuallyRecursiveTypes" - , goldenPlcFromPir pTermAsProg "recursiveTypeBind" - ] +test_error = + runTestNested ["plutus-ir", "test", "PlutusIR", "Compiler", "Error"] + [ goldenPlcFromPir pTermAsProg "mutuallyRecursiveTypes" + , goldenPlcFromPir pTermAsProg "recursiveTypeBind" + ] diff --git a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Let/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Let/Tests.hs index 4cb37e52e70..478ea013cac 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Let/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Let/Tests.hs @@ -22,10 +22,11 @@ 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" - ] +test_lets = + runTestNested ["plutus-ir", "test", "PlutusIR", "Compiler", "Let"] + [ goldenPlcFromPir pTermAsProg "letInLet" + , goldenPlcFromPir pTermAsProg "letDep" + ] -- FIXME: this fails because some of the let passes expect certain things to be -- gone, e.g. non-strict bindings. We should a) add pre-/post-conditions for these, diff --git a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Recursion/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Recursion/Tests.hs index 17926d14a6e..7d6963954e5 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Recursion/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Recursion/Tests.hs @@ -7,11 +7,11 @@ import Test.Tasty.Extras test_recursion :: TestTree test_recursion = - runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Compiler"] $ testNested "Recursion" - [ goldenNamedUPlcFromPir pTermAsProg "factorial" - , goldenPlcFromPir pTermAsProg "even3" - , goldenEvalPir pTermAsProg "even3Eval" - , goldenPlcFromPir pTermAsProg "stupidZero" - , goldenPlcFromPir pTermAsProg "mutuallyRecursiveValues" - , goldenEvalPir pTermAsProg "errorBinding" - ] + runTestNested ["plutus-ir", "test", "PlutusIR", "Compiler", "Recursion"] + [ goldenNamedUPlcFromPir pTermAsProg "factorial" + , goldenPlcFromPir pTermAsProg "even3" + , goldenEvalPir pTermAsProg "even3Eval" + , goldenPlcFromPir pTermAsProg "stupidZero" + , goldenPlcFromPir pTermAsProg "mutuallyRecursiveValues" + , goldenEvalPir pTermAsProg "errorBinding" + ] diff --git a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Recursion/errorBinding.golden b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Recursion/errorBinding.golden index 26a2b45bb82..4efbe91da20 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Compiler/Recursion/errorBinding.golden +++ b/plutus-core/plutus-ir/test/PlutusIR/Compiler/Recursion/errorBinding.golden @@ -1,4 +1,4 @@ -An error has occurred: User error: +An error has occurred: The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'. Final budget: ({cpu: 100 | mem: 100}) diff --git a/plutus-core/plutus-ir/test/PlutusIR/Core/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Core/Tests.hs index 306b053749e..4f4275370d1 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Core/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Core/Tests.hs @@ -13,42 +13,45 @@ import Data.Functor import Flat test_prettyprinting :: TestTree -test_prettyprinting = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Core"] $ - testNested "prettyprinting" - $ map (goldenPir id pTerm) - [ "basic" - , "maybe" - ] +test_prettyprinting = + runTestNested ["plutus-ir", "test", "PlutusIR", "Core", "prettyprinting"] $ + map + (goldenPir id pTerm) + [ "basic" + , "maybe" + ] test_prettyprintingReadable :: TestTree -test_prettyprintingReadable = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Core"] $ - testNested "prettyprintingReadable" - $ map (goldenPirDoc prettyPirReadable pTerm) - [ "basic" - , "maybe" - , "letInLet" - , "letDep" - , "listMatch" - , "idleAll" - , "some" - , "even3" - , "stupidZero" - , "mutuallyRecursiveValues" - , "errorBinding" - , "some" - , "stupidZero" - , "recursiveTypeBind" - ] +test_prettyprintingReadable = + runTestNested ["plutus-ir", "test", "PlutusIR", "Core", "prettyprintingReadable"] $ + map + (goldenPirDoc prettyPirReadable pTerm) + [ "basic" + , "maybe" + , "letInLet" + , "letDep" + , "listMatch" + , "idleAll" + , "some" + , "even3" + , "stupidZero" + , "mutuallyRecursiveValues" + , "errorBinding" + , "some" + , "stupidZero" + , "recursiveTypeBind" + ] test_serialization :: TestTree -test_serialization = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Core"] $ - testNested "serialization" - $ map (goldenPir roundTripPirTerm pTerm) - [ "serializeBasic" - , "serializeMaybePirTerm" - , "serializeEvenOdd" - , "serializeListMatch" - ] +test_serialization = + runTestNested ["plutus-ir", "test", "PlutusIR", "Core", "serialization"] $ + map + (goldenPir roundTripPirTerm pTerm) + [ "serializeBasic" + , "serializeMaybePirTerm" + , "serializeEvenOdd" + , "serializeListMatch" + ] roundTripPirTerm :: Term TyName Name PLC.DefaultUni PLC.DefaultFun a diff --git a/plutus-core/plutus-ir/test/PlutusIR/Purity/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Purity/Tests.hs index 6fbfe364824..e947317a266 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Purity/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Purity/Tests.hs @@ -41,11 +41,13 @@ dangerTerm = runQuote $ do pure $ Apply () (Apply () (Var () n) (Var () m)) undefined test_evalOrder :: TestTree -test_evalOrder = runTestNestedIn ["plutus-ir", "test", "PlutusIR"] $ testNested "Purity" - [ goldenEvalOrder "letFun" - , goldenEvalOrder "builtinAppUnsaturated" - , goldenEvalOrder "builtinAppSaturated" - , goldenEvalOrder "pureLet" - , goldenEvalOrder "nestedLets1" - , pure $ testCase "evalOrderLazy" $ 4 @=? length (unEvalOrder $ computeEvalOrderCoarse dangerTerm) - ] +test_evalOrder = + runTestNested ["plutus-ir", "test", "PlutusIR", "Purity"] + [ goldenEvalOrder "letFun" + , goldenEvalOrder "builtinAppUnsaturated" + , goldenEvalOrder "builtinAppSaturated" + , goldenEvalOrder "pureLet" + , goldenEvalOrder "nestedLets1" + , embed $ testCase "evalOrderLazy" $ + 4 @=? length (unEvalOrder $ computeEvalOrderCoarse dangerTerm) + ] diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/Beta/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/Beta/Tests.hs index 17d72f900a7..c19a221d010 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/Beta/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/Beta/Tests.hs @@ -10,8 +10,8 @@ import Test.Tasty import Test.Tasty.Extras test_beta :: TestTree -test_beta = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "Beta" $ +test_beta = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "Beta"] $ map (goldenPir (runQuote . runTestPass betaPassSC) pTerm) [ "lamapp" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/CaseOfCase/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/CaseOfCase/Tests.hs index 9732d9f4a3a..221f02c5cbb 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/CaseOfCase/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/CaseOfCase/Tests.hs @@ -12,8 +12,8 @@ import PlutusPrelude import Test.QuickCheck.Property (Property, withMaxSuccess) test_caseOfCase :: TestTree -test_caseOfCase = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "CaseOfCase" $ +test_caseOfCase = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "CaseOfCase"] $ map (goldenPir (runQuote . runTestPass (\tc -> CaseOfCase.caseOfCasePassSC tc def True mempty)) pTerm) diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/DeadCode/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/DeadCode/Tests.hs index 4b4e74cb0af..70b4fe7f9de 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/DeadCode/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/DeadCode/Tests.hs @@ -16,8 +16,8 @@ import Test.Tasty.QuickCheck test_deadCode :: TestTree -test_deadCode = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "DeadCode" $ +test_deadCode = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "DeadCode"] $ map (goldenPir (runQuote . runTestPass (\tc -> removeDeadBindingsPassSC tc def)) pTerm) [ "typeLet" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/EvaluateBuiltins/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/EvaluateBuiltins/Tests.hs index 8d6aca9048d..da91258a806 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/EvaluateBuiltins/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/EvaluateBuiltins/Tests.hs @@ -14,8 +14,8 @@ import PlutusPrelude import Test.QuickCheck.Property (Property, withMaxSuccess) test_evaluateBuiltins :: TestTree -test_evaluateBuiltins = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "EvaluateBuiltins" $ +test_evaluateBuiltins = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "EvaluateBuiltins"] $ conservative ++ nonConservative where conservative = diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/Inline/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/Inline/Tests.hs index beb34587714..e90a4097458 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/Inline/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/Inline/Tests.hs @@ -15,8 +15,8 @@ import Test.Tasty (TestTree) -- | Tests of the inliner, include global uniqueness test. test_inline :: TestTree -test_inline = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "Inline" $ +test_inline = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "Inline"] $ map (runTest withConstantInlining) [ "var" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/KnownCon/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/KnownCon/Tests.hs index afa0335080f..7eb7f7ac053 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/KnownCon/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/KnownCon/Tests.hs @@ -11,8 +11,8 @@ import PlutusIR.Transform.KnownCon qualified as KnownCon import Test.QuickCheck test_knownCon :: TestTree -test_knownCon = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "KnownCon" $ +test_knownCon = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "KnownCon"] $ map (goldenPir (runQuote . runTestPass KnownCon.knownConPassSC) pTerm) [ "applicative" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/LetFloatIn/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/LetFloatIn/Tests.hs index 1ee11a89a51..cd75a35e967 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/LetFloatIn/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/LetFloatIn/Tests.hs @@ -18,8 +18,7 @@ import Test.QuickCheck.Property (Property, withMaxSuccess) test_letFloatInConservative :: TestTree test_letFloatInConservative = - runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform", "LetFloatIn"] $ - testNested "conservative" $ + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "LetFloatIn", "conservative"] $ map (goldenPir (runQuote . runTestPass testPass) pTerm) [ "avoid-floating-into-lam" @@ -32,8 +31,7 @@ test_letFloatInConservative = test_letFloatInRelaxed :: TestTree test_letFloatInRelaxed = - runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform", "LetFloatIn"] $ - testNested "relaxed" $ + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "LetFloatIn", "relaxed"] $ map (goldenPir (runQuote . runTestPass testPass) pTerm) [ "avoid-floating-into-RHS" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/LetFloatOut/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/LetFloatOut/Tests.hs index 7eefa7ad929..806f6616cb3 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/LetFloatOut/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/LetFloatOut/Tests.hs @@ -19,8 +19,8 @@ import PlutusPrelude import Test.QuickCheck.Property (Property, withMaxSuccess) test_letFloatOut :: TestTree -test_letFloatOut = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "LetFloatOut" $ +test_letFloatOut = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "LetFloatOut"] $ map (goldenPir (runQuote . runTestPass testPass) pTerm) [ "letInLet" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/NonStrict/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/NonStrict/Tests.hs index e9574329bef..ead1b734693 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/NonStrict/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/NonStrict/Tests.hs @@ -12,8 +12,8 @@ import PlutusIR.Transform.Rename () import Test.QuickCheck test_nonStrict :: TestTree -test_nonStrict = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "NonStrict" $ +test_nonStrict = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "NonStrict"] $ map (goldenPir (runQuote . runTestPass (\tc -> NonStrict.compileNonStrictBindingsPassSC tc False)) pTerm) diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/RecSplit/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/RecSplit/Tests.hs index 02cc57ad0a5..57d46d0fd77 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/RecSplit/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/RecSplit/Tests.hs @@ -12,8 +12,8 @@ import PlutusIR.Transform.RecSplit import Test.Tasty.QuickCheck test_recSplit :: TestTree -test_recSplit = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "RecSplit" $ +test_recSplit = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "RecSplit"] $ map (goldenPir (runQuote . runTestPass recSplitPass) pTerm) [ "truenonrec" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/Rename/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/Rename/Tests.hs index 5857f13358f..c767ecf4cca 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/Rename/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/Rename/Tests.hs @@ -13,8 +13,8 @@ import PlutusIR.Transform.Rename () import Test.Tasty.QuickCheck test_rename :: TestTree -test_rename = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "Rename" $ +test_rename = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "Rename"] $ map (goldenPir (PLC.AttachPrettyConfig debugConfig . runQuote . runTestPass (const renamePass)) pTerm) diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/RewriteRules/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/RewriteRules/Tests.hs index 0cdbfc797ca..a4afde2d2fc 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/RewriteRules/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/RewriteRules/Tests.hs @@ -13,25 +13,24 @@ import Test.QuickCheck import Test.Tasty test_rewriteRules :: TestTree -test_rewriteRules = runTestNestedIn ["plutus-ir/test/PlutusIR/Transform"] $ - testNested "RewriteRules" $ - (fmap - (goldenPir (runQuote . runTestPass (\tc -> rewritePassSC tc def)) pTerm) - [ "equalsInt.pir" -- this tests that the function works on equalInteger - , "divideInt.pir" -- this tests that the function excludes not commutative functions - , "multiplyInt.pir" -- this tests that the function works on multiplyInteger - , "let.pir" -- this tests that it works in the subterms - , "unConstrConstrDataFst.pir" - , "unConstrConstrDataSnd.pir" - ] - ) - ++ - (fmap - (goldenPirEvalTrace pTermAsProg) - [ "unConstrConstrDataFst.pir.eval" - ] - ) - +test_rewriteRules = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "RewriteRules"] $ + (fmap + (goldenPir (runQuote . runTestPass (\tc -> rewritePassSC tc def)) pTerm) + [ "equalsInt.pir" -- this tests that the function works on equalInteger + , "divideInt.pir" -- this tests that the function excludes not commutative functions + , "multiplyInt.pir" -- this tests that the function works on multiplyInteger + , "let.pir" -- this tests that it works in the subterms + , "unConstrConstrDataFst.pir" + , "unConstrConstrDataSnd.pir" + ] + ) + ++ + (fmap + (goldenPirEvalTrace pTermAsProg) + [ "unConstrConstrDataFst.pir.eval" + ] + ) where goldenPirEvalTrace = goldenPirM $ \ast -> ppCatch $ do -- we need traces to remain for checking the evaluation-order diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictLetRec/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictLetRec/Tests.hs index 073126e3ce9..c40a4a5a22c 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictLetRec/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictLetRec/Tests.hs @@ -20,7 +20,7 @@ import PlutusIR.Transform.StrictLetRec.Tests.Lib (defaultCompilationCtx, pirTermFromFile) import System.FilePath.Posix (joinPath, ()) import Test.Tasty (TestTree) -import Test.Tasty.Extras (runTestNestedIn, testNested) +import Test.Tasty.Extras (embed, runTestNested, testNested) import Test.Tasty.HUnit (testCase, (@?=)) import UntypedPlutusCore.Evaluation.Machine.Cek (EvaluationResult (..)) @@ -28,9 +28,7 @@ path :: [FilePath] path = ["plutus-ir", "test", "PlutusIR", "Transform"] test_letRec :: TestTree -test_letRec = runTestNestedIn path do - testNested - "StrictLetRec" +test_letRec = runTestNested path . pure $ testNested "StrictLetRec" [ let runCompilationM m = either (fail . show) pure do ctx <- defaultCompilationCtx @@ -40,7 +38,7 @@ test_letRec = runTestNestedIn path do (runCompilationM . runTestPass (`compileLetsPassSC` RecTerms)) (const noProvenance <<$>> pTerm) "strictLetRec" - , pure $ testCase "traces" do + , embed $ testCase "traces" do (result, traces) <- do pirTerm <- pirTermFromFile (joinPath path "StrictLetRec" "strictLetRec") evalPirProgramWithTracesOrFail (pirTermAsProgram (void pirTerm)) diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictLetRec/Tests/Lib.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictLetRec/Tests/Lib.hs index f07c3210a2c..3421d896f9e 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictLetRec/Tests/Lib.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictLetRec/Tests/Lib.hs @@ -29,8 +29,8 @@ import PlutusIR.Compiler qualified as PIR import PlutusIR.Core qualified as PIR import PlutusIR.Parser (pTerm) import UntypedPlutusCore.Core qualified as UPLC -import UntypedPlutusCore.Evaluation.Machine.Cek (CekValue, EvaluationResult (..), logEmitter, - unsafeEvaluateCek) +import UntypedPlutusCore.Evaluation.Machine.Cek (CekValue, EvaluationResult (..), evaluateCek, + logEmitter, unsafeToEvaluationResult) import UntypedPlutusCore.Evaluation.Machine.Cek.CekMachineCosts (CekMachineCosts) pirTermFromFile @@ -66,7 +66,7 @@ compilePirProgramOrFail pirProgram = do & runExceptT >>= \case Left (er :: PIR.Error DefaultUni DefaultFun (Provenance ())) -> fail $ show er - Right p -> pure (void p) + Right p -> pure (void p) compileTplcProgramOrFail :: (MonadFail m) @@ -83,7 +83,8 @@ evaluateUplcProgramWithTraces :: UPLC.Program Name DefaultUni DefaultFun () -> (EvaluationResult (UPLC.Term Name DefaultUni DefaultFun ()), [Text]) evaluateUplcProgramWithTraces uplcProg = - unsafeEvaluateCek logEmitter machineParameters (uplcProg ^. UPLC.progTerm) + first unsafeToEvaluationResult $ + evaluateCek logEmitter machineParameters (uplcProg ^. UPLC.progTerm) where costModel :: CostModel CekMachineCosts BuiltinCostModel = CostModel defaultCekMachineCosts defaultBuiltinCostModel @@ -102,5 +103,5 @@ defaultCompilationCtx = do handlePirErrorByFailing :: (Pretty ann, MonadFail m) => Either (PIR.Error DefaultUni DefaultFun ann) a -> m a handlePirErrorByFailing = \case - Left e -> fail $ show e + Left e -> fail $ show e Right x -> pure x diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictifyBindings/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictifyBindings/Tests.hs index fc2af546710..7869ccc9ab1 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictifyBindings/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/StrictifyBindings/Tests.hs @@ -14,8 +14,8 @@ import PlutusPrelude import Test.QuickCheck.Property (Property, withMaxSuccess) test_strictifyBindings :: TestTree -test_strictifyBindings = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "StrictifyBindings" $ +test_strictifyBindings = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "StrictifyBindings"] $ map (goldenPir (runIdentity . runTestPass (\tc -> strictifyBindingsPass tc def)) pTerm) [ "pure1" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/ThunkRecursions/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/ThunkRecursions/Tests.hs index 1b80679868c..021ed53e695 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/ThunkRecursions/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/ThunkRecursions/Tests.hs @@ -16,8 +16,8 @@ import PlutusPrelude import Test.QuickCheck.Property (Property, withMaxSuccess) test_thunkRecursions :: TestTree -test_thunkRecursions = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "ThunkRecursions" $ +test_thunkRecursions = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "ThunkRecursions"] $ map (goldenPir (runIdentity . runTestPass (\tc -> thunkRecursionsPass tc def)) pTerm) [ "listFold" diff --git a/plutus-core/plutus-ir/test/PlutusIR/Transform/Unwrap/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/Transform/Unwrap/Tests.hs index 5c4aa3a31dd..265682b9961 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/Transform/Unwrap/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/Transform/Unwrap/Tests.hs @@ -12,8 +12,8 @@ import Data.Functor.Identity import Test.QuickCheck.Property (Property, withMaxSuccess) test_unwrap :: TestTree -test_unwrap = runTestNestedIn ["plutus-ir", "test", "PlutusIR", "Transform"] $ - testNested "Unwrap" $ +test_unwrap = + runTestNested ["plutus-ir", "test", "PlutusIR", "Transform", "Unwrap"] $ map (goldenPir (runIdentity . runTestPass unwrapCancelPass) pTerm) [ "unwrapWrap" diff --git a/plutus-core/plutus-ir/test/PlutusIR/TypeCheck/Tests.hs b/plutus-core/plutus-ir/test/PlutusIR/TypeCheck/Tests.hs index 0b3b22880a3..52ea41e0f64 100644 --- a/plutus-core/plutus-ir/test/PlutusIR/TypeCheck/Tests.hs +++ b/plutus-core/plutus-ir/test/PlutusIR/TypeCheck/Tests.hs @@ -8,42 +8,43 @@ import PlutusIR.Test import PlutusIR.Transform.Rename () test_types :: TestTree -test_types = runTestNestedIn ["plutus-ir", "test", "PlutusIR"] $ - testNested "TypeCheck" - $ map (goldenTypeFromPir topSrcSpan pTerm) - [ "letInLet" - ,"listMatch" - ,"maybe" - ,"ifError" - ,"mutuallyRecursiveTypes" - ,"mutuallyRecursiveValues" - ,"nonrec1" - ,"nonrec2" - ,"nonrec3" - ,"nonrec4" - ,"nonrec6" - ,"nonrec7" - ,"nonrec8" - ,"rec1" - ,"rec2" - ,"rec3" - ,"rec4" - ,"nonrecToRec" - ,"nonrecToNonrec" - ,"oldLength" - ,"strictValue" - ,"strictNonValue" - ,"strictNonValue2" - ,"strictNonValue3" - ,"strictValueNonValue" - ,"strictValueValue" - ,"strictNonValueDeep" - ,"even3Eval" - ,"sameNameDifferentEnv" - , "typeLet" - , "typeLetRec" - -- errrors - , "wrongDataConstrReturnType" - , "nonSelfRecursive" - , "typeLetWrong" - ] +test_types = + runTestNested ["plutus-ir", "test", "PlutusIR", "TypeCheck"] $ + map + (goldenTypeFromPir topSrcSpan pTerm) + [ "letInLet" + , "listMatch" + , "maybe" + , "ifError" + , "mutuallyRecursiveTypes" + , "mutuallyRecursiveValues" + , "nonrec1" + , "nonrec2" + , "nonrec3" + , "nonrec4" + , "nonrec6" + , "nonrec7" + , "nonrec8" + , "rec1" + , "rec2" + , "rec3" + , "rec4" + , "nonrecToRec" + , "nonrecToNonrec" + , "oldLength" + , "strictValue" + , "strictNonValue" + , "strictNonValue2" + , "strictNonValue3" + , "strictValueNonValue" + , "strictValueValue" + , "strictNonValueDeep" + , "even3Eval" + , "sameNameDifferentEnv" + , "typeLet" + , "typeLetRec" + -- errors + , "wrongDataConstrReturnType" + , "nonSelfRecursive" + , "typeLetWrong" + ] diff --git a/plutus-core/prelude/PlutusPrelude.hs b/plutus-core/prelude/PlutusPrelude.hs index f0353c63814..16f7182dac3 100644 --- a/plutus-core/prelude/PlutusPrelude.hs +++ b/plutus-core/prelude/PlutusPrelude.hs @@ -22,6 +22,8 @@ module PlutusPrelude , fromMaybe , guard , foldl' + , for_ + , traverse_ , fold , for , throw @@ -114,7 +116,7 @@ import Data.Char (toLower) import Data.Coerce (Coercible, coerce) import Data.Default.Class import Data.Either (fromRight, isLeft, isRight) -import Data.Foldable (fold, toList) +import Data.Foldable (fold, for_, toList, traverse_) import Data.Function (on) import Data.Functor (($>)) import Data.List (foldl') diff --git a/plutus-core/testlib/PlutusCore/Generators/Hedgehog/Test.hs b/plutus-core/testlib/PlutusCore/Generators/Hedgehog/Test.hs index 3c6921b1780..ab045c191d2 100644 --- a/plutus-core/testlib/PlutusCore/Generators/Hedgehog/Test.hs +++ b/plutus-core/testlib/PlutusCore/Generators/Hedgehog/Test.hs @@ -95,11 +95,11 @@ sampleProgramValueGolden folder name genTerm = do propEvaluate :: ( uni ~ DefaultUni, fun ~ DefaultFun , KnownTypeAst TyName uni a, MakeKnown (Term TyName Name uni fun ()) a - , PrettyPlc internal + , PrettyPlc structural ) => (Term TyName Name uni fun () -> Either - (EvaluationException user internal (Term TyName Name uni fun ())) + (EvaluationException operational structural (Term TyName Name uni fun ())) (Term TyName Name uni fun ())) -- ^ An evaluator. -> TermGen a -- ^ A term/value generator. diff --git a/plutus-core/testlib/PlutusCore/Generators/Hedgehog/TypeEvalCheck.hs b/plutus-core/testlib/PlutusCore/Generators/Hedgehog/TypeEvalCheck.hs index 45d585448d6..c005bd7a963 100644 --- a/plutus-core/testlib/PlutusCore/Generators/Hedgehog/TypeEvalCheck.hs +++ b/plutus-core/testlib/PlutusCore/Generators/Hedgehog/TypeEvalCheck.hs @@ -94,11 +94,11 @@ type TypeEvalCheckM uni fun = Either (TypeEvalCheckError uni fun) typeEvalCheckBy :: ( uni ~ DefaultUni, fun ~ DefaultFun , KnownTypeAst TyName uni a, MakeKnown (Term TyName Name uni fun ()) a - , PrettyPlc internal + , PrettyPlc structural ) => (Term TyName Name uni fun () -> Either - (EvaluationException user internal (Term TyName Name uni fun ())) + (EvaluationException operational structural (Term TyName Name uni fun ())) (Term TyName Name uni fun ())) -- ^ An evaluator. -> TermOf (Term TyName Name uni fun ()) a diff --git a/plutus-core/testlib/PlutusCore/Generators/NEAT/Spec.hs b/plutus-core/testlib/PlutusCore/Generators/NEAT/Spec.hs index e3fc6fb1e6a..a66684842c3 100644 --- a/plutus-core/testlib/PlutusCore/Generators/NEAT/Spec.hs +++ b/plutus-core/testlib/PlutusCore/Generators/NEAT/Spec.hs @@ -111,21 +111,21 @@ not exploited. -- handle a user error and turn it back into an error term handleError :: Type TyName DefaultUni () - -> U.ErrorWithCause (U.EvaluationError user internal) term - -> Either (U.ErrorWithCause (U.EvaluationError user internal) term) + -> U.ErrorWithCause (U.EvaluationError operational structural) term + -> Either (U.ErrorWithCause (U.EvaluationError operational structural) term) (Term TyName Name DefaultUni DefaultFun ()) handleError ty e = case U._ewcError e of - U.UserEvaluationError _ -> return (Error () ty) - U.InternalEvaluationError _ -> throwError e + U.OperationalEvaluationError _ -> return (Error () ty) + U.StructuralEvaluationError _ -> throwError e -- untyped version of `handleError` handleUError :: - U.ErrorWithCause (U.EvaluationError user internal) term - -> Either (U.ErrorWithCause (U.EvaluationError user internal) term) + U.ErrorWithCause (U.EvaluationError operational structural) term + -> Either (U.ErrorWithCause (U.EvaluationError operational structural) term) (U.Term Name DefaultUni DefaultFun ()) handleUError e = case U._ewcError e of - U.UserEvaluationError _ -> return (U.Error ()) - U.InternalEvaluationError _ -> throwError e + U.OperationalEvaluationError _ -> return (U.Error ()) + U.StructuralEvaluationError _ -> throwError e -- |Property: check if the type is preserved by evaluation. -- diff --git a/plutus-core/testlib/PlutusCore/Generators/QuickCheck/Unification.hs b/plutus-core/testlib/PlutusCore/Generators/QuickCheck/Unification.hs index 5fa9afc2940..6cf5107cfb7 100644 --- a/plutus-core/testlib/PlutusCore/Generators/QuickCheck/Unification.hs +++ b/plutus-core/testlib/PlutusCore/Generators/QuickCheck/Unification.hs @@ -17,7 +17,6 @@ import Control.Monad (when) import Control.Monad.Except (MonadError, throwError) import Control.Monad.Reader (ReaderT, ask, local, runReaderT) import Control.Monad.State.Strict (StateT, execStateT, get, put) -import Data.Foldable import Data.Map.Strict.Internal qualified as Map import Data.Set (Set) import Data.Set qualified as Set diff --git a/plutus-core/testlib/PlutusIR/Test.hs b/plutus-core/testlib/PlutusIR/Test.hs index fe5ad055e70..b7422409eb3 100644 --- a/plutus-core/testlib/PlutusIR/Test.hs +++ b/plutus-core/testlib/PlutusIR/Test.hs @@ -21,7 +21,7 @@ import Test.Tasty.Extras import Control.Exception import Control.Lens hiding (op, transform) import Control.Monad.Except -import Control.Monad.Morph +import Control.Monad.Morph (hoist) import Control.Monad.Reader as Reader import PlutusCore qualified as PLC @@ -125,7 +125,7 @@ withGoldenFileM name op = do dir <- currentDir let testFile = dir name goldenFile = dir name ++ ".golden" - return $ goldenVsTextM name goldenFile (op =<< T.readFile testFile) + embed $ goldenVsTextM name goldenFile (op =<< T.readFile testFile) where currentDir = joinPath <$> ask diff --git a/plutus-core/testlib/Test/Tasty/Extras.hs b/plutus-core/testlib/Test/Tasty/Extras.hs index 2537a07416e..86e183241ee 100644 --- a/plutus-core/testlib/Test/Tasty/Extras.hs +++ b/plutus-core/testlib/Test/Tasty/Extras.hs @@ -1,10 +1,24 @@ +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE TypeSynonymInstances #-} + module Test.Tasty.Extras - ( TestNested - , runTestNestedIn + ( Layer (..) + , embed + , nestWith + , TestNestedM (..) + , TestNested + , runTestNestedM + , testNestedNamedM + , testNestedM + , testNestedGhcM , runTestNested + , testNestedNamed , testNested , testNestedGhc - , runTestGroupNestedGhc , goldenVsText , goldenVsTextM , goldenVsDoc @@ -16,19 +30,20 @@ module Test.Tasty.Extras , makeVersionedFilePath ) where -import PlutusPrelude +import PlutusPrelude hiding (toList) +import Control.Monad.Free.Church (F (runF), MonadFree, liftF) import Control.Monad.Reader import Data.ByteString.Lazy qualified as BSL import Data.Text (Text) import Data.Text.Encoding (encodeUtf8) import Data.Version +import GHC.Exts import System.FilePath (joinPath, ()) import System.Info import Test.Tasty import Test.Tasty.Golden - -- | We use the GHC version number to create directories with names like `9.2` -- and `9.6` containing golden files whose contents depend on the GHC version. -- For consistency all such directories should be leaves in the directory @@ -50,31 +65,124 @@ ghcVersion = showVersion compilerVersion makeVersionedFilePath :: [FilePath] -> FilePath -> FilePath makeVersionedFilePath path file = joinPath path ghcVersion file --- | A 'TestTree' of tests under some name prefix. -type TestNested = Reader [FilePath] TestTree +{- | A monad allowing one to emit elements of type @a@. Semantically equivalent to +@Writer (DList a) r@, but: + +1. is faster, being based on the Church-encoded free monad +2. implements 'Monoid', so that all the "Data.Foldable" convenience is supported +3. has better ergonomics as it doesn't require the user to wrap @a@ values into 'DList's + +This type is also semantically equivalent to @Stream (Of a) Identity r@. + +Useful for monadically creating tree-like structures, for example the following + +> import Data.Tree +> yield = embed . pure +> main = putStrLn . drawTree . Node "a" . toList $ do +> yield "b" +> nestWith (Node "c") $ do +> yield "d" +> yield "e" +> yield "f" + +will produce + +> -a +> | +> +- b +> | +> +- c +> | | +> | +- d +> | | +> | `- e +> | +> `- f +-} +newtype Layer a r = Layer + { unLayer :: F ((,) a) r + } deriving newtype (Functor, Applicative, Monad, MonadFree ((,) a)) --- | Run a 'TestTree' of tests with a given name prefix. This doesn't actually --- run the tests: instead it runs a computation in the Reader monad. -runTestNestedIn :: [FilePath] -> TestNested -> TestTree -runTestNestedIn path test = runReader test path +instance unit ~ () => Semigroup (Layer a unit) where + (<>) = (*>) --- | Run a 'TestTree' of tests with an empty prefix. This doesn't actually run --- the tests: instead it runs a computation in the Reader monad. -runTestNested :: TestNested -> TestTree -runTestNested = runTestNestedIn [] +instance unit ~ () => Monoid (Layer a unit) where + mempty = pure () --- | Descend into a name prefix. -testNested :: FilePath -> [TestNested] -> TestNested -testNested folderName = - local (++ [folderName]) . fmap (testGroup folderName) . sequence +instance unit ~ () => IsList (Layer a unit) where + type Item (Layer a unit) = a + fromList = traverse_ embed + toList layer = runF (unLayer layer) mempty $ uncurry (:) --- | Like `testNested` but adds a subdirectory corresponding to the GHC version being used. -testNestedGhc :: FilePath -> [TestNested] -> TestNested -testNestedGhc folderName = testNested (folderName ghcVersion) +-- | Embed the given value into a 'Layer'-like type (either 'Layer' itself or a monad transformer +-- stack with 'Layer' at the bottom). +embed :: MonadFree ((,) a) m => a -> m () +embed x = liftF (x, ()) + +-- | Collapse the given 'Layer' into a single element by converting it into a list, applying the +-- given function to the result and 'embed'ding it back. +nestWith :: ([a] -> a) -> Layer a () -> Layer a () +nestWith f = embed . f . toList + +newtype TestNestedM r = TestNestedM + { unTestNestedM :: ReaderT [FilePath] (Layer TestTree) r + } deriving newtype + (Functor, Applicative, Monad, MonadReader [FilePath], MonadFree ((,) TestTree)) + +-- | A 'TestTree' of tests under some name prefix. +type TestNested = TestNestedM () + +instance unit ~ () => Semigroup (TestNestedM unit) where + (<>) = (*>) + +instance unit ~ () => Monoid (TestNestedM unit) where + mempty = pure () + +-- | Run a 'TestNested' computation to produce a 'TestTree' (without actually executing the tests). +runTestNestedM :: [String] -> TestNested -> TestTree +runTestNestedM [] _ = error "Path cannot be empty" +runTestNestedM path test = testGroup (last path) . toList $ runReaderT (unTestNestedM test) path + +-- | Descend into a folder. +testNestedNamedM + :: FilePath -- ^ The name of the folder. + -> String -- ^ The name of the test group to render in CLI. + -> TestNested + -> TestNested +testNestedNamedM folderName testName + = TestNestedM + . local (++ [folderName]) + . mapReaderT (nestWith $ testGroup testName) + . unTestNestedM + +-- | Descend into a folder for a 'TestNested' computation. +testNestedM :: FilePath -> TestNested -> TestNested +testNestedM folderName = testNestedNamedM folderName folderName + +-- | Like 'testNestedM' but adds a subdirectory corresponding to the GHC version being used. +testNestedGhcM :: TestNested -> TestNested +testNestedGhcM = testNestedM ghcVersion + +-- | Run a list of 'TestNested' computation to produce a 'TestTree' (without actually executing the +-- tests). +runTestNested :: [String] -> [TestNested] -> TestTree +runTestNested path = runTestNestedM path . fold + +-- | Descend into a folder for a list of tests. +testNestedNamed + :: FilePath -- ^ The name of the folder. + -> String -- ^ The name of the test group to render in CLI. + -> [TestNested] + -> TestNested +testNestedNamed folderName testName = testNestedNamedM folderName testName . fold + +-- | Descend into a folder for a list of 'TestNested' computations. +testNested :: FilePath -> [TestNested] -> TestNested +testNested folderName = testNestedM folderName . fold --- Create a TestTree which runs in the directory 'path/ -runTestGroupNestedGhc :: [FilePath] -> [TestNested] -> TestTree -runTestGroupNestedGhc path = runTestNested . testNestedGhc (joinPath path) +-- | Like 'testNested' but adds a subdirectory corresponding to the GHC version being used. +testNestedGhc :: [TestNested] -> TestNested +testNestedGhc = testNestedGhcM . fold -- | Check the contents of a file against a 'Text'. goldenVsText :: TestName -> FilePath -> Text -> TestTree @@ -84,7 +192,7 @@ goldenVsText name ref = goldenVsTextM name ref . pure goldenVsTextM :: TestName -> FilePath -> IO Text -> TestTree goldenVsTextM name ref val = goldenVsStringDiff name (\expected actual -> ["diff", "-u", expected, actual]) ref $ - BSL.fromStrict . encodeUtf8 <$> val + BSL.fromStrict . encodeUtf8 <$> val -- | Check the contents of a file against a 'Doc'. goldenVsDoc :: TestName -> FilePath -> Doc ann -> TestTree @@ -102,8 +210,7 @@ nestedGoldenVsText name ext = nestedGoldenVsTextM name ext . pure nestedGoldenVsTextM :: TestName -> FilePath -> IO Text -> TestNested nestedGoldenVsTextM name ext text = do path <- ask - -- TODO: make more generic - return $ goldenVsTextM name (foldr () (name ++ ext ++ ".golden") path) text + embed $ goldenVsTextM name (foldr () (name ++ ext ++ ".golden") path) text -- | Check the contents of a file under a name prefix against a 'Text'. nestedGoldenVsDoc :: TestName -> FilePath -> Doc ann -> TestNested diff --git a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Core/Instance/Eq.hs b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Core/Instance/Eq.hs index d90a9fb0994..64d617ad9d0 100644 --- a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Core/Instance/Eq.hs +++ b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Core/Instance/Eq.hs @@ -19,7 +19,6 @@ import PlutusCore.Rename.Monad import Universe -import Data.Foldable (for_) import Data.Hashable import Data.Vector qualified as V diff --git a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek.hs b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek.hs index ee43e07dc11..8593d87c31e 100644 --- a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek.hs +++ b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek.hs @@ -7,14 +7,11 @@ module UntypedPlutusCore.Evaluation.Machine.Cek runCek , runCekDeBruijn , runCekNoEmit - , unsafeRunCekNoEmit , evaluateCek , evaluateCekNoEmit - , unsafeEvaluateCek - , unsafeEvaluateCekNoEmit , EvaluationResult(..) , extractEvaluationResult - , unsafeExtractEvaluationResult + , unsafeToEvaluationResult -- * Errors , CekUserError(..) , ErrorWithCause(..) @@ -59,7 +56,6 @@ import UntypedPlutusCore.Evaluation.Machine.Cek.Internal import UntypedPlutusCore.Evaluation.Machine.CommonAPI qualified as Common import PlutusCore.Builtin -import PlutusCore.Evaluation.Machine.Exception import PlutusCore.Evaluation.Machine.MachineParameters import PlutusCore.Name.Unique @@ -88,18 +84,6 @@ runCekNoEmit -> (Either (CekEvaluationException Name uni fun) (Term Name uni fun ()), cost) runCekNoEmit = Common.runCekNoEmit runCekDeBruijn -{-| Unsafely evaluate a term using the CEK machine with logging disabled and keep track of costing. -May throw a 'CekMachineException'. -*THIS FUNCTION IS PARTIAL if the input term contains free variables* --} -unsafeRunCekNoEmit - :: ThrowableBuiltins uni fun - => MachineParameters CekMachineCosts fun (CekValue uni fun ann) - -> ExBudgetMode cost uni fun - -> Term Name uni fun ann - -> (EvaluationResult (Term Name uni fun ()), cost) -unsafeRunCekNoEmit = Common.unsafeRunCekNoEmit runCekDeBruijn - -- | Evaluate a term using the CEK machine with logging enabled. -- *THIS FUNCTION IS PARTIAL if the input term contains free variables* evaluateCek @@ -119,25 +103,6 @@ evaluateCekNoEmit -> Either (CekEvaluationException Name uni fun) (Term Name uni fun ()) evaluateCekNoEmit = Common.evaluateCekNoEmit runCekDeBruijn --- | Evaluate a term using the CEK machine with logging enabled. May throw a 'CekMachineException'. --- *THIS FUNCTION IS PARTIAL if the input term contains free variables* -unsafeEvaluateCek - :: ThrowableBuiltins uni fun - => EmitterMode uni fun - -> MachineParameters CekMachineCosts fun (CekValue uni fun ann) - -> Term Name uni fun ann - -> (EvaluationResult (Term Name uni fun ()), [Text]) -unsafeEvaluateCek = Common.unsafeEvaluateCek runCekDeBruijn - --- | Evaluate a term using the CEK machine with logging disabled. May throw a 'CekMachineException'. --- *THIS FUNCTION IS PARTIAL if the input term contains free variables* -unsafeEvaluateCekNoEmit - :: ThrowableBuiltins uni fun - => MachineParameters CekMachineCosts fun (CekValue uni fun ann) - -> Term Name uni fun ann - -> EvaluationResult (Term Name uni fun ()) -unsafeEvaluateCekNoEmit = Common.unsafeEvaluateCekNoEmit runCekDeBruijn - -- | Unlift a value using the CEK machine. -- *THIS FUNCTION IS PARTIAL if the input term contains free variables* readKnownCek diff --git a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek/ExBudgetMode.hs b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek/ExBudgetMode.hs index 0d376a47b02..a2f15197f96 100644 --- a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek/ExBudgetMode.hs +++ b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek/ExBudgetMode.hs @@ -144,7 +144,7 @@ restricting (ExRestrictingBudget initB@(ExBudget cpuInit memInit)) = ExBudgetMod when (cpuLeft' < 0 || memLeft' < 0) $ do let budgetLeft = ExBudget cpuLeft' memLeft' throwingWithCause _EvaluationError - (UserEvaluationError . CekOutOfExError $ ExRestrictingBudget budgetLeft) + (OperationalEvaluationError . CekOutOfExError $ ExRestrictingBudget budgetLeft) Nothing spender = CekBudgetSpender spend remaining = ExBudget <$> readCpu <*> readMem diff --git a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek/Internal.hs b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek/Internal.hs index fc755a41f2c..113abb8699a 100644 --- a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek/Internal.hs +++ b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/Cek/Internal.hs @@ -48,6 +48,7 @@ module UntypedPlutusCore.Evaluation.Machine.Cek.Internal , StepKind(..) , ThrowableBuiltins , extractEvaluationResult + , unsafeToEvaluationResult , spendBudgetStreamCek , runCekDeBruijn , dischargeCekValue diff --git a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/CommonAPI.hs b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/CommonAPI.hs index fa24c961b5c..a9c2bf023f8 100644 --- a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/CommonAPI.hs +++ b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/CommonAPI.hs @@ -11,14 +11,11 @@ module UntypedPlutusCore.Evaluation.Machine.CommonAPI runCek , runCekDeBruijn , runCekNoEmit - , unsafeRunCekNoEmit , evaluateCek , evaluateCekNoEmit - , unsafeEvaluateCek - , unsafeEvaluateCekNoEmit , EvaluationResult(..) , extractEvaluationResult - , unsafeExtractEvaluationResult + , unsafeToEvaluationResult -- * Errors , CekUserError(..) , ErrorWithCause(..) @@ -63,7 +60,6 @@ import UntypedPlutusCore.Evaluation.Machine.Cek.ExBudgetMode import UntypedPlutusCore.Evaluation.Machine.Cek.Internal import PlutusCore.Builtin -import PlutusCore.Evaluation.Machine.Exception import PlutusCore.Evaluation.Machine.MachineParameters import PlutusCore.Name.Unique import PlutusCore.Quote @@ -137,21 +133,6 @@ runCekNoEmit runner params mode = -- throw away the logs (\(res, cost, _logs) -> (res, cost)) . runCek runner params mode noEmitter -{-| Unsafely evaluate a term a machine with logging disabled and keep track of costing. -May throw a 'CekMachineException'. -*THIS FUNCTION IS PARTIAL if the input term contains free variables* --} -unsafeRunCekNoEmit - :: ThrowableBuiltins uni fun - => MachineRunner cost uni fun ann - -> MachineParameters CekMachineCosts fun (CekValue uni fun ann) - -> ExBudgetMode cost uni fun - -> Term Name uni fun ann - -> (EvaluationResult (Term Name uni fun ()), cost) -unsafeRunCekNoEmit runner params mode = - -- Don't use 'first': https://github.com/IntersectMBO/plutus/issues/3876 - (\(e, l) -> (unsafeExtractEvaluationResult e, l)) . runCekNoEmit runner params mode - -- | Evaluate a term using a machine with logging enabled. -- *THIS FUNCTION IS PARTIAL if the input term contains free variables* evaluateCek @@ -175,29 +156,6 @@ evaluateCekNoEmit -> Either (CekEvaluationException Name uni fun) (Term Name uni fun ()) evaluateCekNoEmit runner params = fst . runCekNoEmit runner params restrictingEnormous --- | Evaluate a term using a machine with logging enabled. May throw a 'CekMachineException'. --- *THIS FUNCTION IS PARTIAL if the input term contains free variables* -unsafeEvaluateCek - :: ThrowableBuiltins uni fun - => MachineRunner RestrictingSt uni fun ann - -> EmitterMode uni fun - -> MachineParameters CekMachineCosts fun (CekValue uni fun ann) - -> Term Name uni fun ann - -> (EvaluationResult (Term Name uni fun ()), [Text]) -unsafeEvaluateCek runner emitTime params = - -- Don't use 'first': https://github.com/IntersectMBO/plutus/issues/3876 - (\(e, l) -> (unsafeExtractEvaluationResult e, l)) . evaluateCek runner emitTime params - --- | Evaluate a term using a machine with logging disabled. May throw a 'CekMachineException'. --- *THIS FUNCTION IS PARTIAL if the input term contains free variables* -unsafeEvaluateCekNoEmit - :: ThrowableBuiltins uni fun - => MachineRunner RestrictingSt uni fun ann - -> MachineParameters CekMachineCosts fun (CekValue uni fun ann) - -> Term Name uni fun ann - -> EvaluationResult (Term Name uni fun ()) -unsafeEvaluateCekNoEmit runner params = unsafeExtractEvaluationResult . evaluateCekNoEmit runner params - -- | Unlift a value using a machine. -- *THIS FUNCTION IS PARTIAL if the input term contains free variables* readKnownCek diff --git a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/SteppableCek.hs b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/SteppableCek.hs index e81bf9ac973..9caacf82789 100644 --- a/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/SteppableCek.hs +++ b/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Evaluation/Machine/SteppableCek.hs @@ -7,14 +7,11 @@ module UntypedPlutusCore.Evaluation.Machine.SteppableCek runCek , runCekDeBruijn , runCekNoEmit - , unsafeRunCekNoEmit , evaluateCek , evaluateCekNoEmit - , unsafeEvaluateCek - , unsafeEvaluateCekNoEmit , EvaluationResult(..) , extractEvaluationResult - , unsafeExtractEvaluationResult + , unsafeToEvaluationResult -- * Errors , CekUserError(..) , ErrorWithCause(..) @@ -57,7 +54,6 @@ import UntypedPlutusCore.Evaluation.Machine.CommonAPI qualified as Common import UntypedPlutusCore.Evaluation.Machine.SteppableCek.Internal as S import PlutusCore.Builtin -import PlutusCore.Evaluation.Machine.Exception import PlutusCore.Evaluation.Machine.MachineParameters import PlutusCore.Name.Unique @@ -87,19 +83,6 @@ runCekNoEmit -> (Either (CekEvaluationException Name uni fun) (Term Name uni fun ()), cost) runCekNoEmit = Common.runCekNoEmit S.runCekDeBruijn -{-| Unsafely evaluate a term using the Steppable CEK machine with logging disabled --- and keep track of costing. -May throw a 'CekMachineException'. -*THIS FUNCTION IS PARTIAL if the input term contains free variables* --} -unsafeRunCekNoEmit - :: ThrowableBuiltins uni fun - => MachineParameters CekMachineCosts fun (CekValue uni fun ann) - -> ExBudgetMode cost uni fun - -> Term Name uni fun ann - -> (EvaluationResult (Term Name uni fun ()), cost) -unsafeRunCekNoEmit = Common.unsafeRunCekNoEmit S.runCekDeBruijn - -- | Evaluate a term using the Steppable CEK machine with logging enabled. -- *THIS FUNCTION IS PARTIAL if the input term contains free variables* evaluateCek @@ -119,27 +102,6 @@ evaluateCekNoEmit -> Either (CekEvaluationException Name uni fun) (Term Name uni fun ()) evaluateCekNoEmit = Common.evaluateCekNoEmit S.runCekDeBruijn --- | Evaluate a term using the Steppable CEK machine with logging enabled. --- May throw a 'CekMachineException'. --- *THIS FUNCTION IS PARTIAL if the input term contains free variables* -unsafeEvaluateCek - :: ThrowableBuiltins uni fun - => EmitterMode uni fun - -> MachineParameters CekMachineCosts fun (CekValue uni fun ann) - -> Term Name uni fun ann - -> (EvaluationResult (Term Name uni fun ()), [Text]) -unsafeEvaluateCek = Common.unsafeEvaluateCek S.runCekDeBruijn - --- | Evaluate a term using the Steppable CEK machine with logging disabled. --- May throw a 'CekMachineException'. --- *THIS FUNCTION IS PARTIAL if the input term contains free variables* -unsafeEvaluateCekNoEmit - :: ThrowableBuiltins uni fun - => MachineParameters CekMachineCosts fun (CekValue uni fun ann) - -> Term Name uni fun ann - -> EvaluationResult (Term Name uni fun ()) -unsafeEvaluateCekNoEmit = Common.unsafeEvaluateCekNoEmit S.runCekDeBruijn - -- | Unlift a value using the Steppable CEK machine. -- *THIS FUNCTION IS PARTIAL if the input term contains free variables* readKnownCek diff --git a/plutus-core/untyped-plutus-core/test/Analysis/Spec.hs b/plutus-core/untyped-plutus-core/test/Analysis/Spec.hs index dd8e045dd4c..78b8efec252 100644 --- a/plutus-core/untyped-plutus-core/test/Analysis/Spec.hs +++ b/plutus-core/untyped-plutus-core/test/Analysis/Spec.hs @@ -49,9 +49,10 @@ letImpure = runQuote $ do (Apply () (Var () m) intConst) evalOrder :: TestTree -evalOrder = runTestNestedIn ["untyped-plutus-core", "test", "Analysis"] $ testNested "evalOrder" - [ goldenEvalOrder "letFun" letFun - , goldenEvalOrder "letImpure" letImpure - , pure $ testCase "evalOrderLazy" $ - 4 @=? length (unEvalOrder $ termEvaluationOrder def dangerTerm) - ] +evalOrder = + runTestNested ["untyped-plutus-core", "test", "Analysis", "evalOrder"] + [ goldenEvalOrder "letFun" letFun + , goldenEvalOrder "letImpure" letImpure + , embed . testCase "evalOrderLazy" $ + 4 @=? length (unEvalOrder $ termEvaluationOrder def dangerTerm) + ] diff --git a/plutus-core/untyped-plutus-core/test/DeBruijn/FlatNatWord.hs b/plutus-core/untyped-plutus-core/test/DeBruijn/FlatNatWord.hs index b95fbc41e85..b4165d57ff7 100644 --- a/plutus-core/untyped-plutus-core/test/DeBruijn/FlatNatWord.hs +++ b/plutus-core/untyped-plutus-core/test/DeBruijn/FlatNatWord.hs @@ -73,13 +73,14 @@ prop_OldVsNewIndex = testProperty "oldVsNew Index" $ property $ do Hedgehog.assert $ unflat @Index encoded `isCompatible` unflat @OldIndex encoded test_flatNatWord :: TestNested -test_flatNatWord = testNested "FlatNatWord" $ fmap pure - [ test_MinBound - , test_MaxBound - , prop_CompatInBounds - , prop_DecLarger - , prop_OldVsNewIndex - ] +test_flatNatWord = + testNested "FlatNatWord" $ map embed + [ test_MinBound + , test_MaxBound + , prop_CompatInBounds + , prop_DecLarger + , prop_OldVsNewIndex + ] -- * Old implementation of Flat Index copy-pasted and renamed to OldIndex diff --git a/plutus-core/untyped-plutus-core/test/DeBruijn/Scope.hs b/plutus-core/untyped-plutus-core/test/DeBruijn/Scope.hs index 1b17ef34857..f6b08829132 100644 --- a/plutus-core/untyped-plutus-core/test/DeBruijn/Scope.hs +++ b/plutus-core/untyped-plutus-core/test/DeBruijn/Scope.hs @@ -43,7 +43,7 @@ testsFail = ] test_scope :: TestNested -test_scope = testNested "Scope" $ pure . uncurry testCase <$> +test_scope = testNested "Scope" $ embed . uncurry testCase <$> (second testPasses <$> testsOk) <> (second testThrows <$> testsFail) where diff --git a/plutus-core/untyped-plutus-core/test/DeBruijn/Spec.hs b/plutus-core/untyped-plutus-core/test/DeBruijn/Spec.hs index f79266ccb81..9d3dc471891 100644 --- a/plutus-core/untyped-plutus-core/test/DeBruijn/Spec.hs +++ b/plutus-core/untyped-plutus-core/test/DeBruijn/Spec.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE TypeFamilies #-} module DeBruijn.Spec (test_debruijn) where import DeBruijn.FlatNatWord (test_flatNatWord) @@ -8,9 +7,9 @@ import Test.Tasty import Test.Tasty.Extras test_debruijn :: TestTree -test_debruijn = runTestNestedIn ["untyped-plutus-core","test"] $ - testNested "DeBruijn" - [ test_undebruijnify - , test_scope - , test_flatNatWord - ] +test_debruijn = + runTestNested ["untyped-plutus-core", "test", "DeBruijn"] $ + [ test_undebruijnify + , test_scope + , test_flatNatWord + ] diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Builtins/Common.hs b/plutus-core/untyped-plutus-core/test/Evaluation/Builtins/Common.hs index 285059ed8f2..46700d430ac 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Builtins/Common.hs +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Builtins/Common.hs @@ -3,8 +3,9 @@ {-# LANGUAGE TypeOperators #-} module Evaluation.Builtins.Common - ( unsafeEvaluateCek - , unsafeEvaluateCekNoEmit + ( unsafeToEvaluationResult + , evaluateCek + , evaluateCekNoEmit , readKnownCek , typecheckAnd , typecheckEvaluateCek @@ -27,6 +28,7 @@ import UntypedPlutusCore qualified as UPLC import UntypedPlutusCore.Evaluation.Machine.Cek import Control.Monad.Except +import Data.Bifunctor import Data.Text (Text) -- | Type check and evaluate a term. @@ -39,14 +41,12 @@ typecheckAnd UPLC.Term Name uni fun () -> a) -> CostingPart uni fun -> TPLC.Term TyName Name uni fun () -> m a typecheckAnd semvar action costingPart term = TPLC.runQuoteT $ do - -- Here we don't use `getDefTypeCheckConfig`, to cover the absurd case where - -- builtins can change their type according to their BuiltinSemanticsVariant + -- Here we don't use 'getDefTypeCheckConfig', to cover the absurd case where + -- builtins can change their type according to their 'BuiltinSemanticsVariant'. tcConfig <- TypeCheckConfig defKindCheckConfig <$> builtinMeaningsToTypes semvar () _ <- TPLC.inferType tcConfig term + let runtime = mkMachineParameters semvar $ CostModel defaultCekMachineCosts costingPart return . action runtime $ TPLC.eraseTerm term - where - runtime = mkMachineParameters semvar $ - CostModel defaultCekMachineCosts costingPart -- | Type check and evaluate a term, logging enabled. typecheckEvaluateCek @@ -57,7 +57,9 @@ typecheckEvaluateCek -> CostingPart uni fun -> TPLC.Term TyName Name uni fun () -> m (EvaluationResult (UPLC.Term Name uni fun ()), [Text]) -typecheckEvaluateCek semvar = typecheckAnd semvar $ unsafeEvaluateCek logEmitter +typecheckEvaluateCek semvar = + typecheckAnd semvar $ \params -> + first unsafeToEvaluationResult . evaluateCek logEmitter params -- | Type check and evaluate a term, logging disabled. typecheckEvaluateCekNoEmit @@ -68,7 +70,9 @@ typecheckEvaluateCekNoEmit -> CostingPart uni fun -> TPLC.Term TyName Name uni fun () -> m (EvaluationResult (UPLC.Term Name uni fun ())) -typecheckEvaluateCekNoEmit semvar = typecheckAnd semvar unsafeEvaluateCekNoEmit +typecheckEvaluateCekNoEmit semvar = + typecheckAnd semvar $ \params -> + unsafeToEvaluationResult . evaluateCekNoEmit params -- | Type check and convert a Plutus Core term to a Haskell value. typecheckReadKnownCek @@ -80,4 +84,5 @@ typecheckReadKnownCek -> CostingPart uni fun -> TPLC.Term TyName Name uni fun () -> m (Either (CekEvaluationException Name uni fun) a) -typecheckReadKnownCek semvar = typecheckAnd semvar readKnownCek +typecheckReadKnownCek semvar = + typecheckAnd semvar readKnownCek diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Builtins/Definition.hs b/plutus-core/untyped-plutus-core/test/Evaluation/Builtins/Definition.hs index c7d6eb915e8..25ccd044ea2 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Builtins/Definition.hs +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Builtins/Definition.hs @@ -89,8 +89,10 @@ test_Const = tB = mkConstant () b text = toTypeAst @_ @_ @DefaultUni @Text Proxy runConst con = mkIterAppNoAnn (mkIterInstNoAnn con [text, bool]) [tC, tB] - lhs = typecheckReadKnownCek def defaultBuiltinCostModelExt $ runConst $ builtin () (Right Const) - rhs = typecheckReadKnownCek def defaultBuiltinCostModelExt $ runConst $ mapFun @DefaultFun Left Plc.const + lhs = typecheckReadKnownCek def defaultBuiltinCostModelExt $ + runConst $ builtin () (Right Const) + rhs = typecheckReadKnownCek def defaultBuiltinCostModelExt $ + runConst $ mapFun @DefaultFun Left Plc.const lhs === Right (Right c) lhs === rhs @@ -125,7 +127,8 @@ test_Id = . LamAbs () i integer . LamAbs () j integer $ Var () i - typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= Right (EvaluationSuccess oneU) + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= + Right (EvaluationSuccess oneU) -- | Test that a polymorphic built-in function can have a higher-kinded type variable in its -- signature. @@ -140,7 +143,8 @@ test_IdFInteger = = apply () (mapFun Left Scott.sum) . apply () (tyInst () (builtin () $ Right IdFInteger) Scott.listTy) $ mkIterAppNoAnn (mapFun Left Scott.enumFromTo) [one, ten] - typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= Right (EvaluationSuccess res) + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= + Right (EvaluationSuccess res) test_IdList :: TestTree test_IdList = @@ -158,7 +162,8 @@ test_IdList = . apply () (tyInst () (builtin () $ Right IdList) integer) $ mkIterAppNoAnn (mapFun Left Scott.enumFromTo) [one, ten] tyAct @?= tyExp - typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= Right (EvaluationSuccess res) + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= + Right (EvaluationSuccess res) {- Note [Higher-rank built-in functions] We can't unlift a monomorphic function passed to a built-in function, let alone unlift a polymorphic @@ -194,7 +199,8 @@ test_IdRank2 = = apply () (mapFun Left Scott.sum) . tyInst () (apply () (tyInst () (builtin () $ Right IdRank2) Scott.listTy) Scott.nil) $ integer - typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= Right (EvaluationSuccess res) + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= + Right (EvaluationSuccess res) -- | Test that a builtin can be applied to a non-constant term. test_ScottToMetaUnit :: TestTree @@ -207,7 +213,8 @@ test_ScottToMetaUnit = let runtime = mkMachineParameters def $ CostModel defaultCekMachineCosts () -- @scottToMetaUnit Scott.map@ is ill-typed, but still runs successfully, since the builtin -- doesn't look at the argument. - unsafeEvaluateCekNoEmit runtime (eraseTerm $ applyTerm Scott.map) @?= res + unsafeToEvaluationResult (evaluateCekNoEmit runtime (eraseTerm $ applyTerm Scott.map)) @?= + res -- | Test that an exception thrown in the builtin application code does not get caught in the CEK -- machine and blows in the caller face instead. Uses a one-argument built-in function. @@ -218,8 +225,10 @@ test_FailingSucc = apply () (builtin () $ Right FailingSucc) $ mkConstant @Integer @DefaultUni @DefaultFunExt () 0 typeErrOrEvalExcOrRes :: Either _ (Either BuiltinErrorCall _) <- - -- Here we rely on 'typecheckAnd' lazily running the action after type checking the term. - traverse (try . evaluate) $ typecheckEvaluateCek def defaultBuiltinCostModelExt term + -- Here we rely on 'typecheckAnd' lazily running the action after type checking the + -- term. + traverse (try . evaluate) $ + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term typeErrOrEvalExcOrRes @?= Right (Left BuiltinErrorCall) -- | Test that evaluating a PLC builtin application that is expensive enough to exceed the budget @@ -232,7 +241,8 @@ test_ExpensiveSucc = apply () (builtin () $ Right ExpensiveSucc) $ mkConstant @Integer @DefaultUni @DefaultFunExt () 0 typeErrOrEvalExcOrRes :: Either _ (Either BuiltinErrorCall _) <- - traverse (try . evaluate) $ typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term + traverse (try . evaluate) $ + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term typeErrOrEvalExcOrRes @?= Right (Right EvaluationFailure) -- | Test that an exception thrown in the builtin application code does not get caught in the CEK @@ -246,8 +256,10 @@ test_FailingPlus = , mkConstant @Integer @DefaultUni () 1 ] typeErrOrEvalExcOrRes :: Either _ (Either BuiltinErrorCall _) <- - -- Here we rely on 'typecheckAnd' lazily running the action after type checking the term. - traverse (try . evaluate) $ typecheckEvaluateCek def defaultBuiltinCostModelExt term + -- Here we rely on 'typecheckAnd' lazily running the action after type checking the + -- term. + traverse (try . evaluate) $ + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term typeErrOrEvalExcOrRes @?= Right (Left BuiltinErrorCall) -- | Test that evaluating a PLC builtin application that is expensive enough to exceed the budget @@ -262,7 +274,8 @@ test_ExpensivePlus = , mkConstant @Integer @DefaultUni () 1 ] typeErrOrEvalExcOrRes :: Either _ (Either BuiltinErrorCall _) <- - traverse (try . evaluate) $ typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term + traverse (try . evaluate) $ + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term typeErrOrEvalExcOrRes @?= Right (Right EvaluationFailure) -- | Test that @Null@, @Head@ and @Tail@ are enough to get pattern matching on built-in lists. @@ -277,7 +290,8 @@ test_BuiltinList = , mkConstant @Integer () 0 , mkConstant @[Integer] () xs ] - typecheckEvaluateCekNoEmit def defaultBuiltinCostModel term @?= Right (EvaluationSuccess res) + typecheckEvaluateCekNoEmit def defaultBuiltinCostModel term @?= + Right (EvaluationSuccess res) -- | Test that right-folding a built-in list with built-in 'Cons' recreates that list. test_IdBuiltinList :: TestTree @@ -287,12 +301,14 @@ test_IdBuiltinList = xsTerm = mkConstant @[Integer] () [1..10] listOfInteger = mkTyBuiltin @_ @[Integer] () term - = mkIterAppNoAnn (mkIterInstNoAnn (mapFun Left Builtin.foldrList) [integer, listOfInteger]) + = mkIterAppNoAnn + (mkIterInstNoAnn (mapFun Left Builtin.foldrList) [integer, listOfInteger]) [ tyInst () (builtin () $ Left MkCons) integer , mkConstant @[Integer] () [] , xsTerm ] - typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= Right (EvaluationSuccess xsTerm) + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= + Right (EvaluationSuccess xsTerm) test_BuiltinPair :: TestTree test_BuiltinPair = @@ -343,7 +359,8 @@ test_SwapEls = , mkConstant @Integer () 0 , mkConstant () xs ] - typecheckEvaluateCekNoEmit def defaultBuiltinCostModel term @?= Right (EvaluationSuccess res) + typecheckEvaluateCekNoEmit def defaultBuiltinCostModel term @?= + Right (EvaluationSuccess res) -- | Test that right-folding a built-in 'Data' with the constructors of 'Data' recreates the -- original value. @@ -361,7 +378,8 @@ test_IdBuiltinData = , emb BData , dTerm ] - typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= Right (EvaluationSuccess dTerm) + typecheckEvaluateCekNoEmit def defaultBuiltinCostModelExt term @?= + Right (EvaluationSuccess dTerm) -- | For testing how an evaluator instantiated at a particular 'ExBudgetMode' handles the -- 'TrackCosts' builtin. @@ -425,7 +443,7 @@ test_SerialiseDataImpossible = dataLoop = Apply () (Builtin () SerialiseData) $ mkConstant () loop where loop = List [loop] budgetMode = restricting . ExRestrictingBudget $ ExBudget 10000000000 10000000 - evalRestricting params = fst . unsafeRunCekNoEmit params budgetMode + evalRestricting params = unsafeToEvaluationResult . fst . runCekNoEmit params budgetMode typecheckAnd def evalRestricting defaultBuiltinCostModel dataLoop @?= Right EvaluationFailure diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Debug/ex3.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Debug/ex3.golden index bd65974e19d..569eea1d5ad 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Debug/ex3.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Debug/ex3.golden @@ -7,5 +7,5 @@ OldState: Computing NewState: Returning Driver is going to do a single step OldState: Returning NewState: Computing Driver is going to do a single step -OldState: Computing NewState is Error: An error has occurred: User error: +OldState: Computing NewState is Error: An error has occurred: The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'. diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Debug/ex4.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Debug/ex4.golden index 79a5ab7f1cf..a3e13d2a057 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Debug/ex4.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Debug/ex4.golden @@ -1,5 +1,5 @@ Driver is going to do a single step OldState: Starting NewState: Computing Driver is going to do a single step -OldState: Computing NewState is Error: An error has occurred: User error: +OldState: Computing NewState is Error: An error has occurred: The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'. diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNoBranch.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNoBranch.plc.golden index 1436661e809..e229d959ca8 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNoBranch.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNoBranch.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: Case expression missing the branch required by the scrutinee tag: 0 Caused by: (constr 0 (con integer 1))) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNoBranch.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNoBranch.uplc.golden index 1436661e809..e229d959ca8 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNoBranch.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNoBranch.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: Case expression missing the branch required by the scrutinee tag: 0 Caused by: (constr 0 (con integer 1))) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNonTag.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNonTag.plc.golden index f48798f54d0..1bd7d1fbdda 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNonTag.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNonTag.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A non-constructor value was scrutinized in a case expression Caused by: (con integer 1)) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNonTag.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNonTag.uplc.golden index f48798f54d0..1bd7d1fbdda 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNonTag.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/caseNonTag.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A non-constructor value was scrutinized in a case expression Caused by: (con integer 1)) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/diFullyApplied.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/diFullyApplied.plc.golden index f177b6623f1..7f60668f62e 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/diFullyApplied.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/diFullyApplied.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: User error: +(Left An error has occurred: The provided Plutus code called 'error'. Caused by: [ [ (builtin divideInteger) (con integer 1) ] (con integer 0) ]) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/diFullyApplied.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/diFullyApplied.uplc.golden index 6ef7aa04f30..6388d69ceea 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/diFullyApplied.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/diFullyApplied.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: User error: +(Left An error has occurred: The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'. Caused by: [ [ (builtin divideInteger) (con integer 1) ] (con integer 0) ]) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerAtInteger.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerAtInteger.plc.golden index d3afe69b18d..8c9074010e3 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerAtInteger.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerAtInteger.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin expected a term argument, but something else was received Caused by: (force (force (builtin ifThenElse)))) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerAtInteger.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerAtInteger.uplc.golden index d3afe69b18d..8c9074010e3 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerAtInteger.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerAtInteger.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin expected a term argument, but something else was received Caused by: (force (force (builtin ifThenElse)))) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerWrongCondTypeSat.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerWrongCondTypeSat.plc.golden index 0baa2734b4e..9cb5f80b598 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerWrongCondTypeSat.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerWrongCondTypeSat.plc.golden @@ -1,4 +1,4 @@ -(Left An error has occurred: error: +(Left An error has occurred: Could not unlift a value: Type mismatch: expected: bool; actual: string Caused by: [ diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerWrongCondTypeSat.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerWrongCondTypeSat.uplc.golden index 0baa2734b4e..9cb5f80b598 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerWrongCondTypeSat.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteAtIntegerWrongCondTypeSat.uplc.golden @@ -1,4 +1,4 @@ -(Left An error has occurred: error: +(Left An error has occurred: Could not unlift a value: Type mismatch: expected: bool; actual: string Caused by: [ diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteTypeTermType.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteTypeTermType.plc.golden index 1aeab826898..5db27720294 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteTypeTermType.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteTypeTermType.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin expected a term argument, but something else was received Caused by: (force [ (force (builtin ifThenElse)) (con bool True) ])) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteTypeTermType.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteTypeTermType.uplc.golden index 1aeab826898..5db27720294 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteTypeTermType.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteTypeTermType.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin expected a term argument, but something else was received Caused by: (force [ (force (builtin ifThenElse)) (con bool True) ])) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedFullyApplied.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedFullyApplied.plc.golden index 8672ef77c8e..984aefc089d 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedFullyApplied.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedFullyApplied.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin received a term argument when something else was expected Caused by: [ (builtin ifThenElse) (con bool True) ]) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedFullyApplied.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedFullyApplied.uplc.golden index 8672ef77c8e..984aefc089d 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedFullyApplied.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedFullyApplied.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin received a term argument when something else was expected Caused by: [ (builtin ifThenElse) (con bool True) ]) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedWithCond.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedWithCond.plc.golden index 8672ef77c8e..984aefc089d 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedWithCond.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedWithCond.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin received a term argument when something else was expected Caused by: [ (builtin ifThenElse) (con bool True) ]) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedWithCond.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedWithCond.uplc.golden index 8672ef77c8e..984aefc089d 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedWithCond.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/iteUninstantiatedWithCond.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin received a term argument when something else was expected Caused by: [ (builtin ifThenElse) (con bool True) ]) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError1.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError1.plc.golden index cbb14ee9289..c9322a9f0b0 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError1.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError1.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin expected a term argument, but something else was received Caused by: (force (builtin multiplyInteger))) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError1.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError1.uplc.golden index cbb14ee9289..c9322a9f0b0 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError1.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError1.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin expected a term argument, but something else was received Caused by: (force (builtin multiplyInteger))) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError2.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError2.plc.golden index 5591ce3bdb2..e68a5566eed 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError2.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError2.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin expected a term argument, but something else was received Caused by: (force [ (builtin multiplyInteger) (con integer 11) ])) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError2.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError2.uplc.golden index 5591ce3bdb2..e68a5566eed 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError2.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError2.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: A builtin expected a term argument, but something else was received Caused by: (force [ (builtin multiplyInteger) (con integer 11) ])) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError3.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError3.plc.golden index 2f90b39bb7f..bec5ef97c9d 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError3.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError3.plc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: Attempted to instantiate a non-polymorphic term. Caused by: (con integer 242)) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError3.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError3.uplc.golden index 2f90b39bb7f..bec5ef97c9d 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError3.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/mulInstError3.uplc.golden @@ -1,3 +1,3 @@ -(Left An error has occurred: error: +(Left An error has occurred: Attempted to instantiate a non-polymorphic term. Caused by: (con integer 242)) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/polyErrorInst.plc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/polyErrorInst.plc.golden index d9c90ef72de..faaf84c1554 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/polyErrorInst.plc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/polyErrorInst.plc.golden @@ -1,2 +1,2 @@ -(Left An error has occurred: User error: +(Left An error has occurred: The provided Plutus code called 'error'.) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/polyErrorInst.uplc.golden b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/polyErrorInst.uplc.golden index fccaddb46c4..cc268b310d6 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Golden/polyErrorInst.uplc.golden +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Golden/polyErrorInst.uplc.golden @@ -1,2 +1,2 @@ -(Left An error has occurred: User error: +(Left An error has occurred: The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'.) \ No newline at end of file diff --git a/plutus-core/untyped-plutus-core/test/Evaluation/Machines.hs b/plutus-core/untyped-plutus-core/test/Evaluation/Machines.hs index f2d25e512bc..3113a9923ad 100644 --- a/plutus-core/untyped-plutus-core/test/Evaluation/Machines.hs +++ b/plutus-core/untyped-plutus-core/test/Evaluation/Machines.hs @@ -5,7 +5,6 @@ module Evaluation.Machines ( test_machines - --, test_memory , test_budget , test_tallying ) where @@ -41,16 +40,20 @@ import Test.Tasty.Golden import Test.Tasty.Hedgehog testMachine - :: (uni ~ DefaultUni, fun ~ DefaultFun, PrettyPlc internal) + :: (uni ~ DefaultUni, fun ~ DefaultFun, PrettyPlc structural) => String -> (Term Name uni fun () -> - Either (EvaluationException user internal (Term Name uni fun ())) (Term Name uni fun ())) + Either + (EvaluationException operational structural (Term Name uni fun ())) + (Term Name uni fun ())) -> TestTree testMachine machine eval = testGroup machine $ fromInterestingTermGens $ \name genTermOfTbv -> testPropertyNamed name (fromString name) . withTests 200 . property $ do TermOf term val <- forAllWith mempty genTermOfTbv - let resExp = eraseTerm <$> makeKnownOrFail @_ @(Plc.Term TyName Name DefaultUni DefaultFun ()) val + let resExp = + eraseTerm <$> + makeKnownOrFail @_ @(Plc.Term TyName Name DefaultUni DefaultFun ()) val case extractEvaluationResult . eval $ eraseTerm term of Left err -> fail $ show err Right resAct -> resAct === resExp @@ -119,8 +122,7 @@ test_budget :: TestTree test_budget -- Error diffs are very big = localOption (SizeCutoff 1000000) - . runTestNestedIn ["untyped-plutus-core", "test", "Evaluation", "Machines"] - . testNested "Budget" + . runTestNested ["untyped-plutus-core", "test", "Evaluation", "Machines", "Budget"] $ concat [ folder Plc.defaultBuiltinsRuntime bunchOfFibs , folder (toBuiltinsRuntime def ()) bunchOfIdNats @@ -128,10 +130,7 @@ test_budget ] where folder runtime = - foldPlcFolderContents - testNested - (\name _ -> pure $ testGroup name []) - (\name -> testBudget runtime name . eraseTerm) + foldPlcFolderContents testNested mempty (\name -> testBudget runtime name . eraseTerm) testTallying :: TestName -> Term Name DefaultUni DefaultFun () -> TestNested testTallying name term = @@ -145,9 +144,6 @@ test_tallying :: TestTree test_tallying = -- Error diffs are very big localOption (SizeCutoff 1000000) - . runTestNestedIn ["untyped-plutus-core", "test", "Evaluation", "Machines"] - . testNested "Tallying" - . foldPlcFolderContents testNested - (\name _ -> pure $ testGroup name []) - (\name -> testTallying name . eraseTerm) + . runTestNested ["untyped-plutus-core", "test", "Evaluation", "Machines", "Tallying"] + . foldPlcFolderContents testNested mempty (\name -> testTallying name . eraseTerm) $ bunchOfFibs diff --git a/plutus-core/untyped-plutus-core/test/Transform/CaseOfCase/Test.hs b/plutus-core/untyped-plutus-core/test/Transform/CaseOfCase/Test.hs index 21ba8f2f45b..30862d0f4d6 100644 --- a/plutus-core/untyped-plutus-core/test/Transform/CaseOfCase/Test.hs +++ b/plutus-core/untyped-plutus-core/test/Transform/CaseOfCase/Test.hs @@ -23,7 +23,7 @@ import Test.Tasty.HUnit (testCase, (@?=)) import UntypedPlutusCore (DefaultFun, DefaultUni, Name, Term (..)) import UntypedPlutusCore.Core qualified as UPLC import UntypedPlutusCore.Evaluation.Machine.Cek (CekMachineCosts, CekValue, EvaluationResult (..), - noEmitter, unsafeEvaluateCek) + evaluateCek, noEmitter, unsafeToEvaluationResult) import UntypedPlutusCore.Transform.CaseOfCase (caseOfCase) test_caseOfCase :: TestTree @@ -119,7 +119,7 @@ testCaseOfCaseWithError = evaluateUplc :: UPLC.Term Name DefaultUni DefaultFun () -> EvaluationResult (UPLC.Term Name DefaultUni DefaultFun ()) -evaluateUplc = fst <$> unsafeEvaluateCek noEmitter machineParameters +evaluateUplc = unsafeToEvaluationResult . fst <$> evaluateCek noEmitter machineParameters where costModel :: CostModel CekMachineCosts BuiltinCostModel = CostModel defaultCekMachineCosts defaultBuiltinCostModel diff --git a/plutus-ledger-api/exe/analyse-script-events/Main.hs b/plutus-ledger-api/exe/analyse-script-events/Main.hs index 9b4be82bc36..62a881d0f2c 100644 --- a/plutus-ledger-api/exe/analyse-script-events/Main.hs +++ b/plutus-ledger-api/exe/analyse-script-events/Main.hs @@ -37,7 +37,7 @@ import Data.Primitive.PrimArray qualified as P import Data.SatInt (fromSatInt) import System.Directory.Extra (listFiles) import System.Environment (getArgs, getProgName) -import System.FilePath (isExtensionOf) +import System.FilePath (isExtensionOf, takeFileName) import System.IO (stderr) import Text.Printf (hPrintf, printf) @@ -302,6 +302,70 @@ countBuiltins eventFiles = do P.itraversePrimArray_ printEntry finalCounts where printEntry i c = printf "%-35s %12d\n" (show (toEnum i :: DefaultFun)) c + +data EvaluationResult = OK ExBudget | Failed | DeserialisationError + +-- Convert to a string for use in an R frame +toRString :: EvaluationResult -> String +toRString = \case + OK _ -> "T" + Failed -> "F" + DeserialisationError -> "NA" + +-- Print out the actual and claimed CPU and memory cost of every script. +analyseCosts :: EventAnalyser +analyseCosts ctx _ ev = + case ev of + PlutusV1Event ScriptEvaluationData{..} _ -> + let result = + case deserialiseScript PlutusV1 dataProtocolVersion dataScript of + Left _ -> DeserialisationError + Right script -> + case + V1.evaluateScriptRestricting + dataProtocolVersion + V1.Quiet + ctx + dataBudget + script + dataInputs + of + (_, Left _) -> Failed + (_, Right cost) -> OK cost + in printCost result dataBudget + + PlutusV2Event ScriptEvaluationData{..} _ -> + let result = + case deserialiseScript PlutusV2 dataProtocolVersion dataScript of + Left _ -> DeserialisationError + Right script -> + case + V2.evaluateScriptRestricting + dataProtocolVersion + V2.Quiet + ctx + dataBudget + script + dataInputs + of + (_, Left _) -> Failed + (_, Right cost) -> OK cost + in printCost result dataBudget + + where printCost :: EvaluationResult -> ExBudget -> IO () + printCost result claimedCost = + let (claimedCPU, claimedMem) = costAsInts claimedCost + in case result of + OK cost -> + let (actualCPU, actualMem) = costAsInts cost + in printf "%15d %15d %15d %15d %2s\n" actualCPU claimedCPU actualMem claimedMem (toRString result) + -- Something went wrong; print the cost as "NA" ("Not Available" in R) so that R can + -- still process it. + _ -> + printf "%15s %15d %15s %15d %2s\n" "NA" claimedCPU "NA" claimedMem (toRString result) + costAsInts :: ExBudget -> (Int, Int) + costAsInts (ExBudget (V2.ExCPU cpu) (V2.ExMemory mem)) = (fromSatInt cpu, fromSatInt mem) + -- Extract the script from an evaluation event and apply some analysis function analyseUnappliedScript :: (Term NamedDeBruijn DefaultUni DefaultFun () -> IO ()) @@ -325,6 +389,10 @@ analyseOneFile -> IO () analyseOneFile analyse eventFile = do events <- loadEvents eventFile + printf "# %s\n" $ takeFileName eventFile + -- Print the file in the output so we can narrow down the location of + -- interesting/anomalous data. This may not be helpful for some of the + -- analyses. case ( mkContext V1.mkEvaluationContext (eventsCostParamsV1 events) , mkContext V2.mkEvaluationContext (eventsCostParamsV2 events) ) of @@ -354,29 +422,6 @@ analyseOneFile analyse eventFile = do Nothing -> putStrLn "*** ctxV2 missing ***" -max_tx_ex_steps :: Double -max_tx_ex_steps = 10_000_000_000 - -max_tx_ex_mem :: Double -max_tx_ex_mem = 14_000_000 - --- Print out the CPU and memory budgets of each script event. These are the costs --- paid for by the submitters, not the actual costs consumed during execution. --- TODO: add a version that tells us the actual execution costs. -getBudgets :: EventAnalyser -getBudgets _ctx _params ev = - let printFractions d = - let ExBudget (V2.ExCPU cpu) (V2.ExMemory mem) = dataBudget d - in printf "%15d %10.8f %15d %10.8f\n" - (fromSatInt cpu :: Int) - ((fromSatInt cpu) / max_tx_ex_steps) - (fromSatInt mem :: Int) - ((fromSatInt mem) / max_tx_ex_mem) - - in case ev of - PlutusV1Event evdata _expected -> printFractions evdata - PlutusV2Event evdata _expected -> printFractions evdata - main :: IO () main = let analyses = @@ -400,10 +445,10 @@ main = , "count the total number of occurrences of each builtin in validator scripts" , countBuiltins ) - , ( "budgets" - , "print (claimed) budgets of scripts" - , putStrLn " cpu cpuFraction mem memFraction" - `thenDoAnalysis` getBudgets + , ( "costs" + , "print actual and claimed costs of scripts" + , putStrLn " cpuActual cpuClaimed memActual memClaimed status" + `thenDoAnalysis` analyseCosts ) ] @@ -411,17 +456,21 @@ main = (prelude `thenDoAnalysis` analyser) files = prelude >> doAnalysis analyser files usage = do - getProgName >>= hPrintf stderr "Usage: %s \n" + getProgName >>= hPrintf stderr "Usage: %s []\n" + hPrintf stderr "Analyse the .event files in (default = current directory)\n" hPrintf stderr "Avaliable analyses:\n" mapM_ printDescription analyses where printDescription (n,h,_) = hPrintf stderr " %-16s: %s\n" n h + go name dir = + case find (\(n,_,_) -> n == name) analyses of + Nothing -> printf "Unknown analysis: %s\n" name >> usage + Just (_,_,analysis) -> + filter ("event" `isExtensionOf`) <$> listFiles dir >>= \case + [] -> printf "No .event files in %s\n" dir + eventFiles -> analysis eventFiles + in getArgs >>= \case - [dir, name] -> - case find (\(n,_,_) -> n == name) analyses of - Nothing -> printf "Unknown analysis: %s\n" name >> usage - Just (_,_,analysis) -> - filter ("event" `isExtensionOf`) <$> listFiles dir >>= \case - [] -> printf "No event files in %s\n" dir - eventFiles -> analysis eventFiles - _ -> usage + [name] -> go name "." + [name, dir] -> go name dir + _ -> usage diff --git a/plutus-ledger-api/src/PlutusLedgerApi/Common/ProtocolVersions.hs b/plutus-ledger-api/src/PlutusLedgerApi/Common/ProtocolVersions.hs index fdf7fbc08a5..158c57fde4a 100644 --- a/plutus-ledger-api/src/PlutusLedgerApi/Common/ProtocolVersions.hs +++ b/plutus-ledger-api/src/PlutusLedgerApi/Common/ProtocolVersions.hs @@ -11,6 +11,7 @@ module PlutusLedgerApi.Common.ProtocolVersions , vasilPV , valentinePV , conwayPV + , conwayPlus1PV , knownPVs , futurePV ) where @@ -68,10 +69,25 @@ valentinePV = MajorProtocolVersion 8 conwayPV :: MajorProtocolVersion conwayPV = MajorProtocolVersion 9 +-- | The next HF after Conway. It doesn't yet have a name, and it's not +-- yet known whether it will be an intra-era HF or introduce a new era. +conwayPlus1PV :: MajorProtocolVersion +conwayPlus1PV = MajorProtocolVersion 10 + -- | The set of protocol versions that are "known", i.e. that have been released -- and have actual differences associated with them. knownPVs :: Set.Set MajorProtocolVersion -knownPVs = Set.fromList [ shelleyPV, allegraPV, maryPV, alonzoPV, vasilPV, valentinePV, conwayPV ] +knownPVs = + Set.fromList + [ shelleyPV + , allegraPV + , maryPV + , alonzoPV + , vasilPV + , valentinePV + , conwayPV + , conwayPlus1PV + ] -- | This is a placeholder for when we don't yet know what protocol version will -- be used for something. It's a very high protocol version that should never diff --git a/plutus-ledger-api/src/PlutusLedgerApi/Common/Versions.hs b/plutus-ledger-api/src/PlutusLedgerApi/Common/Versions.hs index 728b096ea3c..24a553dd651 100644 --- a/plutus-ledger-api/src/PlutusLedgerApi/Common/Versions.hs +++ b/plutus-ledger-api/src/PlutusLedgerApi/Common/Versions.hs @@ -81,7 +81,6 @@ instance Pretty PlutusLedgerLanguage where pretty = viaShow {-| A map indicating which builtin functions were introduced in which 'MajorProtocolVersion'. -Each builtin function should appear at most once. This __must__ be updated when new builtins are added. See Note [New builtins/language versions and protocol versions] @@ -107,6 +106,9 @@ builtinsIntroducedIn = Map.fromList [ ((PlutusV2, valentinePV), Set.fromList [ VerifyEcdsaSecp256k1Signature, VerifySchnorrSecp256k1Signature ]), + ((PlutusV2, conwayPlus1PV), Set.fromList [ + IntegerToByteString, ByteStringToInteger + ]), ((PlutusV3, conwayPV), Set.fromList [ Bls12_381_G1_add, Bls12_381_G1_neg, Bls12_381_G1_scalarMul, Bls12_381_G1_equal, Bls12_381_G1_hashToGroup, @@ -173,10 +175,10 @@ and 'MajorProtocolVersion'? See Note [New builtins/language versions and protocol versions] -} builtinsAvailableIn :: PlutusLedgerLanguage -> MajorProtocolVersion -> Set.Set DefaultFun -builtinsAvailableIn thisLv thisPv = fold $ Map.elems $ - Map.takeWhileAntitone builtinAvailableIn builtinsIntroducedIn +builtinsAvailableIn thisLv thisPv = fold $ + Map.filterWithKey (const . alreadyIntroduced) builtinsIntroducedIn where - builtinAvailableIn :: (PlutusLedgerLanguage, MajorProtocolVersion) -> Bool - builtinAvailableIn (introducedInLv,introducedInPv) = + alreadyIntroduced :: (PlutusLedgerLanguage, MajorProtocolVersion) -> Bool + alreadyIntroduced (introducedInLv,introducedInPv) = -- both should be satisfied introducedInLv <= thisLv && introducedInPv <= thisPv diff --git a/plutus-ledger-api/src/PlutusLedgerApi/V2/ParamName.hs b/plutus-ledger-api/src/PlutusLedgerApi/V2/ParamName.hs index 292ea06f506..1f6ef6f5610 100644 --- a/plutus-ledger-api/src/PlutusLedgerApi/V2/ParamName.hs +++ b/plutus-ledger-api/src/PlutusLedgerApi/V2/ParamName.hs @@ -190,5 +190,15 @@ data ParamName = | VerifySchnorrSecp256k1Signature'cpu'arguments'intercept | VerifySchnorrSecp256k1Signature'cpu'arguments'slope | VerifySchnorrSecp256k1Signature'memory'arguments + | IntegerToByteString'cpu'arguments'c0 + | IntegerToByteString'cpu'arguments'c1 + | IntegerToByteString'cpu'arguments'c2 + | IntegerToByteString'memory'arguments'intercept + | IntegerToByteString'memory'arguments'slope + | ByteStringToInteger'cpu'arguments'c0 + | ByteStringToInteger'cpu'arguments'c1 + | ByteStringToInteger'cpu'arguments'c2 + | ByteStringToInteger'memory'arguments'intercept + | ByteStringToInteger'memory'arguments'slope deriving stock (Eq, Ord, Enum, Ix, Bounded, Generic) deriving IsParamName via (GenericParamName ParamName) diff --git a/plutus-ledger-api/test-plugin/Spec/Budget.hs b/plutus-ledger-api/test-plugin/Spec/Budget.hs index f2393bf912f..f0376041e84 100644 --- a/plutus-ledger-api/test-plugin/Spec/Budget.hs +++ b/plutus-ledger-api/test-plugin/Spec/Budget.hs @@ -27,8 +27,7 @@ import PlutusTx.TH (compile) tests :: TestTree tests = - runTestNestedIn ["test-plugin", "Spec"] $ - testNestedGhc "Budget" $ + runTestNested ["test-plugin", "Spec", "Budget"] . pure . testNestedGhc $ [ goldenPirReadable "gt" compiledGt , goldenPirReadable "currencySymbolValueOf" compiledCurrencySymbolValueOf ] diff --git a/plutus-ledger-api/test-plugin/Spec/Value.hs b/plutus-ledger-api/test-plugin/Spec/Value.hs index 45a66451fe9..80ee939c7bb 100644 --- a/plutus-ledger-api/test-plugin/Spec/Value.hs +++ b/plutus-ledger-api/test-plugin/Spec/Value.hs @@ -223,8 +223,7 @@ test_EqCurrencyList name currencyLists = test_EqValue :: TestTree test_EqValue = - runTestNestedIn ["test-plugin", "Spec"] $ - testNestedGhc "Value" - [ test_EqCurrencyList "Short" currencyListOptions - , test_EqCurrencyList "Long" currencyLongListOptions - ] + runTestNested ["test-plugin", "Spec", "Value"] . pure . testNestedGhc $ + [ test_EqCurrencyList "Short" currencyListOptions + , test_EqCurrencyList "Long" currencyLongListOptions + ] diff --git a/plutus-ledger-api/test/Spec/CostModelParams.hs b/plutus-ledger-api/test/Spec/CostModelParams.hs index 6cff19826ac..3edb933edc4 100644 --- a/plutus-ledger-api/test/Spec/CostModelParams.hs +++ b/plutus-ledger-api/test/Spec/CostModelParams.hs @@ -30,8 +30,8 @@ tests = [ testCase "length" $ do 166 @=? length v1_ParamNames 166 @=? length V1.costModelParamsForTesting - 175 @=? length v2_ParamNames - 175 @=? length V2.costModelParamsForTesting + 185 @=? length v2_ParamNames + 185 @=? length V2.costModelParamsForTesting 233 @=? length v3_ParamNames 233 @=? length V3.costModelParamsForTesting , testCase "tripping paramname" $ do diff --git a/plutus-ledger-api/test/Spec/Eval.hs b/plutus-ledger-api/test/Spec/Eval.hs index 42871a0fca4..d3d63735153 100644 --- a/plutus-ledger-api/test/Spec/Eval.hs +++ b/plutus-ledger-api/test/Spec/Eval.hs @@ -26,7 +26,6 @@ import UntypedPlutusCore.Test.DeBruijn.Good import Control.Exception (evaluate) import Control.Monad.Extra (whenJust) import Control.Monad.Writer -import Data.Foldable (for_) import Data.Int (Int64) import Data.Map qualified as Map import Data.Maybe (fromJust) diff --git a/plutus-ledger-api/test/Spec/Versions.hs b/plutus-ledger-api/test/Spec/Versions.hs index 2a6888385a8..61b180ea852 100644 --- a/plutus-ledger-api/test/Spec/Versions.hs +++ b/plutus-ledger-api/test/Spec/Versions.hs @@ -21,7 +21,6 @@ import PlutusLedgerApi.V3 qualified as V3 import Data.ByteString qualified as BS import Data.ByteString.Short qualified as BSS import Data.Either -import Data.Foldable (for_) import Data.Map qualified as Map import Data.Set qualified as Set import Test.Tasty diff --git a/plutus-ledger-api/testlib/PlutusLedgerApi/Test/V2/EvaluationContext.hs b/plutus-ledger-api/testlib/PlutusLedgerApi/Test/V2/EvaluationContext.hs index a95463039cd..e7bbec6cd2d 100644 --- a/plutus-ledger-api/testlib/PlutusLedgerApi/Test/V2/EvaluationContext.hs +++ b/plutus-ledger-api/testlib/PlutusLedgerApi/Test/V2/EvaluationContext.hs @@ -52,4 +52,6 @@ clearBuiltinCostModel r = r { paramSerialiseData = mempty , paramVerifyEcdsaSecp256k1Signature = mempty , paramVerifySchnorrSecp256k1Signature = mempty + , paramIntegerToByteString = mempty + , paramByteStringToInteger = mempty } diff --git a/plutus-ledger-api/testlib/PlutusLedgerApi/Test/V3/EvaluationContext.hs b/plutus-ledger-api/testlib/PlutusLedgerApi/Test/V3/EvaluationContext.hs index e4e7e74c3ed..62ae7ccab21 100644 --- a/plutus-ledger-api/testlib/PlutusLedgerApi/Test/V3/EvaluationContext.hs +++ b/plutus-ledger-api/testlib/PlutusLedgerApi/Test/V3/EvaluationContext.hs @@ -67,6 +67,4 @@ clearBuiltinCostModel r = r , paramBls12_381_finalVerify = mempty , paramKeccak_256 = mempty , paramBlake2b_224 = mempty - , paramIntegerToByteString = mempty - , paramByteStringToInteger = mempty } diff --git a/plutus-tx-plugin/plutus-tx-plugin.cabal b/plutus-tx-plugin/plutus-tx-plugin.cabal index 2ebff4e86e2..61975f056fb 100644 --- a/plutus-tx-plugin/plutus-tx-plugin.cabal +++ b/plutus-tx-plugin/plutus-tx-plugin.cabal @@ -128,6 +128,7 @@ test-suite plutus-tx-plugin-tests other-modules: AsData.Budget.Spec AsData.Budget.Types + AssocMap.Spec Blueprint.Tests Blueprint.Tests.Lib Blueprint.Tests.Lib.AsData.Blueprint @@ -184,6 +185,7 @@ test-suite plutus-tx-plugin-tests , mtl , plutus-core:{plutus-core, plutus-core-testlib} ^>=1.28 , plutus-tx-plugin ^>=1.28 + , plutus-tx-test-util , plutus-tx:{plutus-tx, plutus-tx-testlib} ^>=1.28 , serialise , tasty @@ -192,6 +194,7 @@ test-suite plutus-tx-plugin-tests , tasty-hunit , template-haskell , text + , these default-extensions: Strict ghc-options: -threaded -rtsopts -with-rtsopts=-N diff --git a/plutus-tx-plugin/src/PlutusTx/Compiler/Builtins.hs b/plutus-tx-plugin/src/PlutusTx/Compiler/Builtins.hs index b0d8e6b15aa..e75dde029ec 100644 --- a/plutus-tx-plugin/src/PlutusTx/Compiler/Builtins.hs +++ b/plutus-tx-plugin/src/PlutusTx/Compiler/Builtins.hs @@ -49,11 +49,10 @@ import Language.Haskell.TH.Syntax qualified as TH import Control.Monad.Reader (asks) import Data.ByteString qualified as BS -import Data.Foldable (for_) import Data.Functor import Data.Proxy import Data.Text (Text) -import PlutusPrelude (enumerate) +import PlutusPrelude (enumerate, for_) {- Note [Mapping builtins] We want the user to be able to call the Plutus builtins as normal Haskell functions. diff --git a/plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs b/plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs index f8f4b8459ea..61d50b7c0a0 100644 --- a/plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs +++ b/plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs @@ -120,7 +120,7 @@ compileLiteral :: m (PIRTerm uni fun) compileLiteral = \case -- Just accept any kind of number literal, we'll complain about types we don't support elsewhere - (GHC.LitNumber _ i) -> pure $ PIR.embed $ PLC.mkConstant annMayInline i + (GHC.LitNumber _ i) -> pure $ PIR.embedTerm $ PLC.mkConstant annMayInline i GHC.LitString _ -> throwPlain $ UnsupportedError "Literal string (maybe you need to use OverloadedStrings)" GHC.LitChar _ -> throwPlain $ UnsupportedError "Literal char" GHC.LitFloat _ -> throwPlain $ UnsupportedError "Literal float" diff --git a/plutus-tx-plugin/test/AsData/Budget/Spec.hs b/plutus-tx-plugin/test/AsData/Budget/Spec.hs index f17e22b94c2..d1041a54c47 100644 --- a/plutus-tx-plugin/test/AsData/Budget/Spec.hs +++ b/plutus-tx-plugin/test/AsData/Budget/Spec.hs @@ -20,8 +20,7 @@ import AsData.Budget.Types tests :: TestNested tests = - testNestedGhc - ("AsData" "Budget") + testNested ("AsData" "Budget") . pure $ testNestedGhc [ goldenPirReadable "onlyUseFirstField" onlyUseFirstField , goldenUPlcReadable "onlyUseFirstField" onlyUseFirstField , goldenEvalCekCatch "onlyUseFirstField" [onlyUseFirstField `unsafeApplyCode` inp] diff --git a/plutus-tx-plugin/test/AssocMap/Spec.hs b/plutus-tx-plugin/test/AssocMap/Spec.hs new file mode 100644 index 00000000000..2f3982ccf84 --- /dev/null +++ b/plutus-tx-plugin/test/AssocMap/Spec.hs @@ -0,0 +1,806 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NegativeLiterals #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE ViewPatterns #-} +{-# OPTIONS_GHC -fplugin-opt PlutusTx.Plugin:context-level=0 #-} +{-# OPTIONS_GHC -fplugin-opt PlutusTx.Plugin:defer-errors #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MonoLocalBinds #-} + +module AssocMap.Spec where + +import Test.Tasty.Extras + +import Data.List (nubBy, sort) +import Data.Map.Strict qualified as Map +import Data.These qualified as Haskell +import Hedgehog (Gen, MonadTest, Property, Range, forAll, property, (===)) +import Hedgehog.Gen qualified as Gen +import Hedgehog.Range qualified as Range +import PlutusTx.AssocMap qualified as AssocMap +import PlutusTx.Builtins qualified as PlutusTx +import PlutusTx.Code +import PlutusTx.Data.AssocMap qualified as Data.AssocMap +import PlutusTx.IsData () +import PlutusTx.IsData qualified as P +import PlutusTx.Lift (liftCodeDef, makeLift) +import PlutusTx.List qualified as PlutusTx +import PlutusTx.Prelude qualified as PlutusTx +import PlutusTx.Show qualified as PlutusTx +import PlutusTx.Test +import PlutusTx.Test.Util.Compiled (cekResultMatchesHaskellValue, compiledCodeToTerm, + unsafeRunTermCek) +import PlutusTx.TH (compile) +import PlutusTx.These (These (..), these) +import Test.Tasty (TestTree, testGroup) +import Test.Tasty.Hedgehog (testProperty) + + +-- | Test the performance and interaction between 'insert', 'delete' and 'lookup'. +map1 :: + CompiledCode + ( Integer -> + ( Maybe PlutusTx.BuiltinByteString + , Maybe PlutusTx.BuiltinByteString + , Maybe PlutusTx.BuiltinByteString + , Maybe PlutusTx.BuiltinByteString + , Maybe PlutusTx.BuiltinByteString + ) + ) +map1 = + $$( compile + [|| + \n -> + let m :: Data.AssocMap.Map Integer PlutusTx.BuiltinByteString + m = + foldr + (\i -> + Data.AssocMap.insert + (n PlutusTx.+ i) + (PlutusTx.encodeUtf8 (PlutusTx.show i)) + ) + (Data.AssocMap.singleton n "0") + (PlutusTx.enumFromTo 1 10) + m' = Data.AssocMap.delete (n PlutusTx.+ 5) m + in ( Data.AssocMap.lookup n m + , Data.AssocMap.lookup (n PlutusTx.+ 5) m + , Data.AssocMap.lookup (n PlutusTx.+ 10) m + , Data.AssocMap.lookup (n PlutusTx.+ 20) m + , Data.AssocMap.lookup (n PlutusTx.+ 5) m' + ) + ||] + ) + +-- | Test that 'unionWith' is implemented correctly. Due to the nature of 'Map k v', +-- some type errors are only caught when running the PlutusTx compiler on code which uses +-- 'unionWith'. +map2 :: CompiledCode (Integer -> [(Integer, PlutusTx.BuiltinString)]) +map2 = + $$( compile + [|| + \n -> + let m1 = + Data.AssocMap.unsafeFromList + [ (n PlutusTx.+ 1, "one") + , (n PlutusTx.+ 2, "two") + , (n PlutusTx.+ 3, "three") + , (n PlutusTx.+ 4, "four") + , (n PlutusTx.+ 5, "five") + ] + m2 = + Data.AssocMap.unsafeFromList + [ (n PlutusTx.+ 3, "THREE") + , (n PlutusTx.+ 4, "FOUR") + , (n PlutusTx.+ 6, "SIX") + , (n PlutusTx.+ 7, "SEVEN") + ] + m = Data.AssocMap.unionWith PlutusTx.appendByteString m1 m2 + in PlutusTx.fmap (\(k, v) -> (k, PlutusTx.decodeUtf8 v)) (Data.AssocMap.toList m) + ||] + ) + +-- | Similar to map2, but uses 'union' instead of 'unionWith'. Evaluating 'map3' and 'map2' +-- should yield the same result. +map3 :: CompiledCode (Integer -> [(Integer, PlutusTx.BuiltinString)]) +map3 = + $$( compile + [|| + \n -> + let m1 = + Data.AssocMap.unsafeFromList + [ (n PlutusTx.+ 1, "one") + , (n PlutusTx.+ 2, "two") + , (n PlutusTx.+ 3, "three") + , (n PlutusTx.+ 4, "four") + , (n PlutusTx.+ 5, "five") + ] + m2 = + Data.AssocMap.unsafeFromList + [ (n PlutusTx.+ 3, "THREE") + , (n PlutusTx.+ 4, "FOUR") + , (n PlutusTx.+ 6, "SIX") + , (n PlutusTx.+ 7, "SEVEN") + ] + m = Data.AssocMap.union m1 m2 + f = these id id PlutusTx.appendByteString + in PlutusTx.fmap (\(k, v) -> (k, PlutusTx.decodeUtf8 (f v))) (Data.AssocMap.toList m) + ||] + ) + +lookupProgram :: CompiledCode (Integer -> AssocMap.Map Integer Integer -> Maybe Integer) +lookupProgram = $$(compile [|| AssocMap.lookup ||]) + +dataLookupProgram :: CompiledCode (Integer -> Data.AssocMap.Map Integer Integer -> Maybe Integer) +dataLookupProgram = $$(compile [|| Data.AssocMap.lookup ||]) + +memberProgram :: CompiledCode (Integer -> AssocMap.Map Integer Integer -> Bool) +memberProgram = $$(compile [|| AssocMap.member ||]) + +dataMemberProgram :: CompiledCode (Integer -> Data.AssocMap.Map Integer Integer -> Bool) +dataMemberProgram = $$(compile [|| Data.AssocMap.member ||]) + +insertProgram + :: CompiledCode + ( Integer + -> Integer + -> AssocMap.Map Integer Integer + -> [(Integer, Integer)] + ) +insertProgram = + $$(compile + [|| \k v m -> + PlutusTx.sort $ AssocMap.toList $ AssocMap.insert k v m + ||]) + +dataInsertProgram + :: CompiledCode + ( Integer + -> Integer + -> Data.AssocMap.Map Integer Integer + -> [(Integer, Integer)] + ) +dataInsertProgram = + $$(compile + [|| \k v m -> + PlutusTx.sort $ Data.AssocMap.toList $ Data.AssocMap.insert k v m + ||]) + +deleteProgram + :: CompiledCode + ( Integer + -> AssocMap.Map Integer Integer + -> [(Integer, Integer)] + ) +deleteProgram = + $$(compile + [|| \k m -> + PlutusTx.sort $ AssocMap.toList $ AssocMap.delete k m + ||]) + +dataDeleteProgram + :: CompiledCode + ( Integer + -> Data.AssocMap.Map Integer Integer + -> [(Integer, Integer)] + ) +dataDeleteProgram = + $$(compile + [|| \k m -> + PlutusTx.sort $ Data.AssocMap.toList $ Data.AssocMap.delete k m + ||]) + +allProgram + :: CompiledCode + ( Integer + -> AssocMap.Map Integer Integer + -> Bool + ) +allProgram = + $$(compile [|| \num m -> AssocMap.all (\x -> x PlutusTx.< num) m ||]) + +dataAllProgram + :: CompiledCode + ( Integer + -> Data.AssocMap.Map Integer Integer + -> Bool + ) +dataAllProgram = + $$(compile [|| \num m -> Data.AssocMap.all (\x -> x PlutusTx.< num) m ||]) + +dataAnyProgram + :: CompiledCode + ( Integer + -> Data.AssocMap.Map Integer Integer + -> Bool + ) +dataAnyProgram = + $$(compile [|| \num m -> Data.AssocMap.any (\x -> x PlutusTx.< num) m ||]) + +keysProgram + :: CompiledCode + ( AssocMap.Map Integer Integer + -> [Integer] + ) +keysProgram = + $$(compile [|| AssocMap.keys ||]) + +dataNoDuplicateKeysProgram + :: CompiledCode + ( Data.AssocMap.Map Integer Integer + -> Bool + ) +dataNoDuplicateKeysProgram = + $$(compile [|| Data.AssocMap.noDuplicateKeys ||]) + +unionProgram + :: CompiledCode + ( AssocMap.Map Integer Integer + -> AssocMap.Map Integer Integer + -> [(Integer, These Integer Integer)] + ) +unionProgram = + $$(compile + [|| \m1 m2 -> + PlutusTx.sort $ AssocMap.toList $ AssocMap.union m1 m2 + ||]) + +dataUnionProgram + :: CompiledCode + ( Data.AssocMap.Map Integer Integer + -> Data.AssocMap.Map Integer Integer + -> [(Integer, These Integer Integer)] + ) +dataUnionProgram = + $$(compile + [|| \m1 m2 -> + PlutusTx.sort $ Data.AssocMap.toList $ Data.AssocMap.union m1 m2 + ||]) + +unionWithProgram + :: CompiledCode + ( AssocMap.Map Integer Integer + -> AssocMap.Map Integer Integer + -> [(Integer, Integer)] + ) +unionWithProgram = + $$(compile + [|| \m1 m2 -> + PlutusTx.sort $ AssocMap.toList $ AssocMap.unionWith (\x _ -> x) m1 m2 + ||]) + +dataUnionWithProgram + :: CompiledCode + ( Data.AssocMap.Map Integer Integer + -> Data.AssocMap.Map Integer Integer + -> [(Integer, Integer)] + ) +dataUnionWithProgram = + $$(compile + [|| \m1 m2 -> + PlutusTx.sort $ Data.AssocMap.toList $ Data.AssocMap.unionWith (\x _ -> x) m1 m2 + ||]) + +encodedDataAssocMap + :: CompiledCode + ( Data.AssocMap.Map Integer Integer + -> PlutusTx.BuiltinData + ) +encodedDataAssocMap = $$(compile [|| P.toBuiltinData ||]) + +encodedAssocMap + :: CompiledCode + ( AssocMap.Map Integer Integer + -> PlutusTx.BuiltinData + ) +encodedAssocMap = $$(compile [|| P.toBuiltinData ||]) + +mDecodedDataAssocMap + :: CompiledCode + ( Data.AssocMap.Map Integer Integer + -> PlutusTx.Maybe [(Integer, Integer)] + ) +mDecodedDataAssocMap = + $$(compile + [|| fmap (PlutusTx.sort . Data.AssocMap.toList) . P.fromBuiltinData . P.toBuiltinData + ||]) + +mDecodedAssocMap + :: CompiledCode + ( AssocMap.Map Integer Integer + -> PlutusTx.Maybe [(Integer, Integer)] + ) +mDecodedAssocMap = + $$(compile + [|| fmap (PlutusTx.sort . AssocMap.toList) . P.fromBuiltinData . P.toBuiltinData + ||]) + +decodedDataAssocMap + :: CompiledCode + ( Data.AssocMap.Map Integer Integer + -> [(Integer, Integer)] + ) +decodedDataAssocMap = + $$(compile + [|| PlutusTx.sort . Data.AssocMap.toList . P.unsafeFromBuiltinData . P.toBuiltinData + ||]) + +decodedAssocMap + :: CompiledCode + ( AssocMap.Map Integer Integer + -> [(Integer, Integer)] + ) +decodedAssocMap = + $$(compile + [|| PlutusTx.sort . AssocMap.toList . P.unsafeFromBuiltinData . P.toBuiltinData + ||]) + +-- | The semantics of PlutusTx maps and their operations. +-- The 'PlutusTx' implementations maps ('Data.AssocMap.Map' and 'AssocMap.Map') +-- are checked against the semantics to ensure correctness. +newtype AssocMapS k v = AssocMapS [(k, v)] + deriving stock (Show, Eq) + +semanticsToAssocMap :: AssocMapS k v -> AssocMap.Map k v +semanticsToAssocMap = AssocMap.unsafeFromList . toListS + +semanticsToDataAssocMap + :: (P.ToData k, P.ToData v) + => AssocMapS k v -> Data.AssocMap.Map k v +semanticsToDataAssocMap = Data.AssocMap.unsafeFromList . toListS + +assocMapToSemantics :: AssocMap.Map k v -> AssocMapS k v +assocMapToSemantics = unsafeFromListS . AssocMap.toList + +dataAssocMapToSemantics + :: (P.UnsafeFromData k, P.UnsafeFromData v) + => Data.AssocMap.Map k v -> AssocMapS k v +dataAssocMapToSemantics = unsafeFromListS . Data.AssocMap.toList + +nullS :: AssocMapS k v -> Bool +nullS (AssocMapS l) = null l + +sortS :: (Ord k, Ord v) => AssocMapS k v -> AssocMapS k v +sortS (AssocMapS l) = AssocMapS $ sort l + +toListS :: AssocMapS k v -> [(k, v)] +toListS (AssocMapS l) = l + +unsafeFromListS :: [(k, v)] -> AssocMapS k v +unsafeFromListS = AssocMapS + +safeFromListS :: Ord k => [(k, v)] -> AssocMapS k v +safeFromListS = AssocMapS . Map.toList . Map.fromList + +lookupS :: Integer -> AssocMapS Integer Integer -> Maybe Integer +lookupS k (AssocMapS l) = Map.lookup k . Map.fromList $ l + +memberS :: Integer -> AssocMapS Integer Integer -> Bool +memberS k (AssocMapS l) = Map.member k . Map.fromList $ l + +insertS :: Integer -> Integer -> AssocMapS Integer Integer -> AssocMapS Integer Integer +insertS k v (AssocMapS l) = + AssocMapS . Map.toList . Map.insert k v . Map.fromList $ l + +deleteS :: Integer -> AssocMapS Integer Integer -> AssocMapS Integer Integer +deleteS k (AssocMapS l) = + AssocMapS . Map.toList . Map.delete k . Map.fromList $ l + +allS :: (Integer -> Bool) -> AssocMapS Integer Integer -> Bool +allS p (AssocMapS l) = all (p . snd) l + +anyS :: (Integer -> Bool) -> AssocMapS Integer Integer -> Bool +anyS p (AssocMapS l) = any (p . snd) l + +keysS :: AssocMapS Integer Integer -> [Integer] +keysS (AssocMapS l) = map fst l + +noDuplicateKeysS :: AssocMapS Integer Integer -> Bool +noDuplicateKeysS (AssocMapS l) = + length l == length (nubBy (\(k1, _) (k2, _) -> k1 == k2) l) + +mapS :: (a -> b) -> AssocMapS k a -> AssocMapS k b +mapS f (AssocMapS l) = AssocMapS $ map (\(k, v) -> (k, f v)) l + +makeLift ''AssocMapS + +-- | The semantics of 'union' is based on the 'AssocMap' implementation. +-- The code is duplicated here to avoid any issues if the 'AssocMap' implementation changes. +unionS + :: AssocMapS Integer Integer + -> AssocMapS Integer Integer + -> AssocMapS Integer (Haskell.These Integer Integer) +unionS (AssocMapS ls) (AssocMapS rs) = + let + f a b' = case b' of + Nothing -> Haskell.This a + Just b -> Haskell.These a b + + ls' = fmap (\(c, i) -> (c, f i (lookupS c (AssocMapS rs)))) ls + + -- Keeps only those keys which don't appear in the left map. + rs' = filter (\(c, _) -> not (any (\(c', _) -> c' == c) ls)) rs + + rs'' = fmap (fmap Haskell.That) rs' + in + AssocMapS (ls' ++ rs'') + +haskellToPlutusThese :: Haskell.These a b -> These a b +haskellToPlutusThese = \case + Haskell.This a -> This a + Haskell.That b -> That b + Haskell.These a b -> These a b + +unionWithS + :: (Integer -> Integer -> Integer) + -> AssocMapS Integer Integer + -> AssocMapS Integer Integer + -> AssocMapS Integer Integer +unionWithS merge (AssocMapS ls) (AssocMapS rs) = + AssocMapS + . Map.toList + $ Map.unionWith merge (Map.fromList ls) (Map.fromList rs) + +genAssocMapS :: Gen (AssocMapS Integer Integer) +genAssocMapS = + AssocMapS . Map.toList <$> Gen.map rangeLength genPair + where + genPair :: Gen (Integer, Integer) + genPair = do + (,) <$> Gen.integral rangeElem <*> Gen.integral rangeElem + +genUnsafeAssocMapS :: Gen (AssocMapS Integer Integer) +genUnsafeAssocMapS = do + AssocMapS <$> Gen.list rangeLength genPair + where + genPair :: Gen (Integer, Integer) + genPair = do + (,) <$> Gen.integral rangeElem <*> Gen.integral rangeElem + +-- | The 'Equivalence' class is used to define an equivalence relation +-- between `AssocMapS` and the 'PlutusTx' implementations. +class Equivalence l where + (~~) :: + ( MonadTest m + , Show k + , Show v + , Ord k + , Ord v + , P.UnsafeFromData k + , P.UnsafeFromData v + ) => AssocMapS k v -> l k v -> m () + +-- | An `AssocMap.Map` is equivalent to an `AssocMapS` if they have the same elements. +instance Equivalence AssocMap.Map where + assocMapS ~~ assocMap = + sortS assocMapS === sortS (assocMapToSemantics assocMap) + +-- | An `Data.AssocMap.Map` is equivalent to an `AssocMapS` if they have the same elements. +instance Equivalence Data.AssocMap.Map where + assocMapS ~~ dataAssocMap = + sortS assocMapS === sortS (dataAssocMapToSemantics dataAssocMap) + +rangeElem :: Range Integer +rangeElem = Range.linear 0 100 + +rangeLength :: Range Int +rangeLength = Range.linear 0 100 + +safeFromListSpec :: Property +safeFromListSpec = property $ do + assocMapS <- forAll genAssocMapS + let assocMap = AssocMap.safeFromList . toListS $ assocMapS + dataAssocMap = Data.AssocMap.safeFromList . toListS $ assocMapS + assocMapS ~~ assocMap + assocMapS ~~ dataAssocMap + +unsafeFromListSpec :: Property +unsafeFromListSpec = property $ do + assocMapS <- forAll genAssocMapS + let assocMap = AssocMap.unsafeFromList . toListS $ assocMapS + dataAssocMap = Data.AssocMap.unsafeFromList . toListS $ assocMapS + assocMapS ~~ assocMap + assocMapS ~~ dataAssocMap + +lookupSpec :: Property +lookupSpec = property $ do + assocMapS <- forAll genAssocMapS + key <- forAll $ Gen.integral rangeElem + let assocMap = semanticsToAssocMap assocMapS + dataAssocMap = semanticsToDataAssocMap assocMapS + expected = lookupS key assocMapS + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ lookupProgram + `unsafeApplyCode` (liftCodeDef key) + `unsafeApplyCode` (liftCodeDef assocMap) + ) + (===) + expected + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ dataLookupProgram + `unsafeApplyCode` (liftCodeDef key) + `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + (===) + expected + +memberSpec :: Property +memberSpec = property $ do + assocMapS <- forAll genAssocMapS + key <- forAll $ Gen.integral rangeElem + let assocMap = semanticsToAssocMap assocMapS + dataAssocMap = semanticsToDataAssocMap assocMapS + expected = memberS key assocMapS + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ memberProgram + `unsafeApplyCode` (liftCodeDef key) + `unsafeApplyCode` (liftCodeDef assocMap) + ) + (===) + expected + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ dataMemberProgram + `unsafeApplyCode` (liftCodeDef key) + `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + (===) + expected + +insertSpec :: Property +insertSpec = property $ do + assocMapS <- forAll genAssocMapS + key <- forAll $ Gen.integral rangeElem + value <- forAll $ Gen.integral rangeElem + let assocMap = semanticsToAssocMap assocMapS + dataAssocMap = semanticsToDataAssocMap assocMapS + expected = sortS $ insertS key value assocMapS + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ insertProgram + `unsafeApplyCode` (liftCodeDef key) + `unsafeApplyCode` (liftCodeDef value) + `unsafeApplyCode` (liftCodeDef assocMap) + ) + (===) + expected + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ dataInsertProgram + `unsafeApplyCode` (liftCodeDef key) + `unsafeApplyCode` (liftCodeDef value) + `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + (===) + expected + +deleteSpec :: Property +deleteSpec = property $ do + assocMapS <- forAll genAssocMapS + key <- forAll $ Gen.integral rangeElem + let assocMap = semanticsToAssocMap assocMapS + dataAssocMap = semanticsToDataAssocMap assocMapS + expected = sortS $ deleteS key assocMapS + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ deleteProgram + `unsafeApplyCode` (liftCodeDef key) + `unsafeApplyCode` (liftCodeDef assocMap) + ) + (===) + expected + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ dataDeleteProgram + `unsafeApplyCode` (liftCodeDef key) + `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + (===) + expected + +allSpec :: Property +allSpec = property $ do + assocMapS <- forAll genAssocMapS + num <- forAll $ Gen.integral rangeElem + let assocMap = semanticsToAssocMap assocMapS + dataAssocMap = semanticsToDataAssocMap assocMapS + expected = allS (< num) assocMapS + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ allProgram + `unsafeApplyCode` (liftCodeDef num) + `unsafeApplyCode` (liftCodeDef assocMap) + ) + (===) + expected + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ dataAllProgram + `unsafeApplyCode` (liftCodeDef num) + `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + (===) + expected + +anySpec :: Property +anySpec = property $ do + assocMapS <- forAll genAssocMapS + num <- forAll $ Gen.integral rangeElem + let dataAssocMap = semanticsToDataAssocMap assocMapS + expected = anyS (< num) assocMapS + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ dataAnyProgram + `unsafeApplyCode` (liftCodeDef num) + `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + (===) + expected + +keysSpec :: Property +keysSpec = property $ do + assocMapS <- forAll genAssocMapS + let assocMap = semanticsToAssocMap assocMapS + expected = keysS assocMapS + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ keysProgram + `unsafeApplyCode` (liftCodeDef assocMap) + ) + (===) + expected + +noDuplicateKeysSpec :: Property +noDuplicateKeysSpec = property $ do + assocMapS <- forAll genAssocMapS + let dataAssocMap = semanticsToDataAssocMap assocMapS + expected = noDuplicateKeysS assocMapS + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ dataNoDuplicateKeysProgram + `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + (===) + expected + +unionSpec :: Property +unionSpec = property $ do + -- resizing the generator for performance + assocMapS1 <- forAll (Gen.resize 20 genAssocMapS) + assocMapS2 <- forAll (Gen.resize 20 genAssocMapS) + let assocMap1 = semanticsToAssocMap assocMapS1 + assocMap2 = semanticsToAssocMap assocMapS2 + dataAssocMap1 = semanticsToDataAssocMap assocMapS1 + dataAssocMap2 = semanticsToDataAssocMap assocMapS2 + expected = mapS haskellToPlutusThese $ sortS $ unionS assocMapS1 assocMapS2 + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ unionProgram + `unsafeApplyCode` (liftCodeDef assocMap1) + `unsafeApplyCode` (liftCodeDef assocMap2) + ) + (===) + expected + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ dataUnionProgram + `unsafeApplyCode` (liftCodeDef dataAssocMap1) + `unsafeApplyCode` (liftCodeDef dataAssocMap2) + ) + (===) + expected + +unionWithSpec :: Property +unionWithSpec = property $ do + -- resizing the generator for performance + assocMapS1 <- forAll (Gen.resize 20 genAssocMapS) + assocMapS2 <- forAll (Gen.resize 20 genAssocMapS) + let assocMap1 = semanticsToAssocMap assocMapS1 + assocMap2 = semanticsToAssocMap assocMapS2 + dataAssocMap1 = semanticsToDataAssocMap assocMapS1 + dataAssocMap2 = semanticsToDataAssocMap assocMapS2 + merge i1 _ = i1 + expected = unionWithS merge assocMapS1 assocMapS2 + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ unionWithProgram + `unsafeApplyCode` (liftCodeDef assocMap1) + `unsafeApplyCode` (liftCodeDef assocMap2) + ) + (===) + expected + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ dataUnionWithProgram + `unsafeApplyCode` (liftCodeDef dataAssocMap1) + `unsafeApplyCode` (liftCodeDef dataAssocMap2) + ) + (===) + expected + +builtinDataEncodingSpec :: Property +builtinDataEncodingSpec = property $ do + assocMapS <- forAll genAssocMapS + let assocMap = semanticsToAssocMap assocMapS + dataAssocMap = semanticsToDataAssocMap assocMapS + unsafeRunTermCek + ( compiledCodeToTerm + $ encodedDataAssocMap `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + === + unsafeRunTermCek + ( compiledCodeToTerm + $ encodedAssocMap `unsafeApplyCode` (liftCodeDef assocMap) + ) + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ mDecodedAssocMap + `unsafeApplyCode` (liftCodeDef assocMap) + ) + (===) + (Just assocMapS) + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ mDecodedDataAssocMap + `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + (===) + (Just assocMapS) + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ decodedAssocMap + `unsafeApplyCode` (liftCodeDef assocMap) + ) + (===) + assocMapS + cekResultMatchesHaskellValue + ( compiledCodeToTerm + $ decodedDataAssocMap + `unsafeApplyCode` (liftCodeDef dataAssocMap) + ) + (===) + assocMapS + +goldenTests :: TestNested +goldenTests = + testNested "Budget" . pure $ testNestedGhc + [ goldenPirReadable "map1" map1 + , goldenUPlcReadable "map1" map1 + , goldenEvalCekCatch "map1" $ [map1 `unsafeApplyCode` (liftCodeDef 100)] + , goldenBudget "map1-budget" $ map1 `unsafeApplyCode` (liftCodeDef 100) + , goldenPirReadable "map2" map2 + , goldenUPlcReadable "map2" map2 + , goldenEvalCekCatch "map2" $ [map2 `unsafeApplyCode` (liftCodeDef 100)] + , goldenBudget "map2-budget" $ map2 `unsafeApplyCode` (liftCodeDef 100) + , goldenPirReadable "map3" map2 + , goldenUPlcReadable "map3" map2 + , goldenEvalCekCatch "map3" $ [map2 `unsafeApplyCode` (liftCodeDef 100)] + , goldenBudget "map3-budget" $ map2 `unsafeApplyCode` (liftCodeDef 100) + ] + +propertyTests :: TestTree +propertyTests = + testGroup "Map property tests" + [ testProperty "safeFromList" safeFromListSpec + , testProperty "unsafeFromList" unsafeFromListSpec + , testProperty "lookup" lookupSpec + , testProperty "member" memberSpec + , testProperty "insert" insertSpec + , testProperty "all" allSpec + , testProperty "any" anySpec + , testProperty "keys" keysSpec + , testProperty "noDuplicateKeys" noDuplicateKeysSpec + , testProperty "delete" deleteSpec + , testProperty "union" unionSpec + , testProperty "unionWith" unionWithSpec + , testProperty "builtinDataEncoding" builtinDataEncodingSpec + ] diff --git a/plutus-tx-plugin/test/Blueprint/Tests/Lib.hs b/plutus-tx-plugin/test/Blueprint/Tests/Lib.hs index 8965828178a..21c609e72bb 100644 --- a/plutus-tx-plugin/test/Blueprint/Tests/Lib.hs +++ b/plutus-tx-plugin/test/Blueprint/Tests/Lib.hs @@ -44,7 +44,7 @@ import PlutusTx.TH qualified as PlutusTx import Prelude import System.FilePath (()) import Test.Tasty (TestName) -import Test.Tasty.Extras (TestNested) +import Test.Tasty.Extras (TestNested, embed) import Test.Tasty.Golden (goldenVsFile) import UntypedPlutusCore qualified as UPLC @@ -172,4 +172,4 @@ goldenJson name cb = do goldenPath <- asks $ foldr () name let actual = goldenPath ++ ".actual.json" let golden = goldenPath ++ ".golden.json" - pure $ goldenVsFile name golden actual (cb actual) + embed $ goldenVsFile name golden actual (cb actual) diff --git a/plutus-tx-plugin/test/Budget/9.6/map1-budget.budget.golden b/plutus-tx-plugin/test/Budget/9.6/map1-budget.budget.golden new file mode 100644 index 00000000000..3a0c427ec3e --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map1-budget.budget.golden @@ -0,0 +1,2 @@ +({cpu: 390169748 +| mem: 869909}) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map1.eval.golden b/plutus-tx-plugin/test/Budget/9.6/map1.eval.golden new file mode 100644 index 00000000000..2976eddf5c9 --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map1.eval.golden @@ -0,0 +1,8 @@ +(constr + 0 + (constr 0 (con bytestring #30)) + (constr 0 (con bytestring #35)) + (constr 0 (con bytestring #3130)) + (constr 1) + (constr 1) +) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map1.pir.golden b/plutus-tx-plugin/test/Budget/9.6/map1.pir.golden new file mode 100644 index 00000000000..dc42876c182 --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map1.pir.golden @@ -0,0 +1,404 @@ +letrec + data (List :: * -> *) a | List_match where + Nil : List a + Cons : a -> List a -> List a +in +letrec + !`$fEnumBool_$cenumFromTo` : integer -> integer -> List integer + = \(x : integer) (lim : integer) -> + ifThenElse + {all dead. List integer} + (lessThanEqualsInteger x lim) + (/\dead -> + Cons {integer} x (`$fEnumBool_$cenumFromTo` (addInteger 1 x) lim)) + (/\dead -> Nil {integer}) + {all dead. dead} +in +letrec + !go : List integer -> integer -> List integer + = \(acc : List integer) (n : integer) -> + let + !x : integer = quotientInteger n 10 + in + ifThenElse + {all dead. List integer} + (equalsInteger 0 x) + (/\dead -> Cons {integer} (remainderInteger n 10) acc) + (/\dead -> go (Cons {integer} (remainderInteger n 10) acc) x) + {all dead. dead} +in +letrec + !go : + List integer -> List string -> List string + = \(ds : List integer) -> + List_match + {integer} + ds + {all dead. List string -> List string} + (/\dead -> \(x : List string) -> x) + (\(x : integer) + (xs : List integer) -> + /\dead -> + let + !acc : List string -> List string = go xs + in + \(eta : List string) -> + Cons + {string} + (ifThenElse + {all dead. string} + (equalsInteger 0 x) + (/\dead -> "0") + (/\dead -> + ifThenElse + {all dead. string} + (equalsInteger 1 x) + (/\dead -> "1") + (/\dead -> + ifThenElse + {all dead. string} + (equalsInteger 2 x) + (/\dead -> "2") + (/\dead -> + ifThenElse + {all dead. string} + (equalsInteger 3 x) + (/\dead -> "3") + (/\dead -> + ifThenElse + {all dead. string} + (equalsInteger 4 x) + (/\dead -> "4") + (/\dead -> + ifThenElse + {all dead. string} + (equalsInteger 5 x) + (/\dead -> "5") + (/\dead -> + ifThenElse + {all dead. string} + (equalsInteger 6 x) + (/\dead -> "6") + (/\dead -> + ifThenElse + {all dead. string} + (equalsInteger 7 x) + (/\dead -> "7") + (/\dead -> + ifThenElse + {all dead. string} + (equalsInteger + 8 + x) + (/\dead -> "8") + (/\dead -> + ifThenElse + {string} + (equalsInteger + 9 + x) + "9" + "") + {all dead. dead}) + {all dead. dead}) + {all dead. dead}) + {all dead. dead}) + {all dead. dead}) + {all dead. dead}) + {all dead. dead}) + {all dead. dead}) + {all dead. dead}) + (acc eta)) + {all dead. dead} +in +letrec + !`$fShowBuiltinByteString_$cshowsPrec` : + integer -> integer -> List string -> List string + = \(p : integer) (n : integer) -> + ifThenElse + {all dead. List string -> List string} + (lessThanInteger n 0) + (/\dead -> + \(eta : List string) -> + Cons + {string} + "-" + (`$fShowBuiltinByteString_$cshowsPrec` + p + (subtractInteger 0 n) + eta)) + (/\dead -> go (go (Nil {integer}) n)) + {all dead. dead} +in +let + data (Tuple5 :: * -> * -> * -> * -> * -> *) a b c d e | Tuple5_match where + Tuple5 : a -> b -> c -> d -> e -> Tuple5 a b c d e + data (Tuple2 :: * -> * -> *) a b | Tuple2_match where + Tuple2 : a -> b -> Tuple2 a b +in +letrec + !go : all a. integer -> List a -> Tuple2 (List a) (List a) + = /\a -> + \(ds : integer) (ds : List a) -> + List_match + {a} + ds + {all dead. Tuple2 (List a) (List a)} + (/\dead -> Tuple2 {List a} {List a} (Nil {a}) (Nil {a})) + (\(y : a) (ys : List a) -> + /\dead -> + ifThenElse + {all dead. Tuple2 (List a) (List a)} + (equalsInteger 1 ds) + (/\dead -> + Tuple2 + {List a} + {List a} + ((let + a = List a + in + \(c : a -> a -> a) (n : a) -> c y n) + (\(ds : a) (ds : List a) -> Cons {a} ds ds) + (Nil {a})) + ys) + (/\dead -> + Tuple2_match + {List a} + {List a} + (go {a} (subtractInteger ds 1) ys) + {Tuple2 (List a) (List a)} + (\(zs : List a) (ws : List a) -> + Tuple2 {List a} {List a} (Cons {a} y zs) ws)) + {all dead. dead}) + {all dead. dead} +in +letrec + !go : List string -> integer + = \(ds : List string) -> + List_match + {string} + ds + {all dead. integer} + (/\dead -> 0) + (\(x : string) (xs : List string) -> /\dead -> addInteger 1 (go xs)) + {all dead. dead} +in +letrec + !concatBuiltinStrings : List string -> string + = \(ds : List string) -> + List_match + {string} + ds + {string} + "" + (\(x : string) (ds : List string) -> + List_match + {string} + ds + {all dead. string} + (/\dead -> x) + (\(ipv : string) (ipv : List string) -> + /\dead -> + Tuple2_match + {List string} + {List string} + (let + !n : integer = divideInteger (go ds) 2 + in + ifThenElse + {all dead. Tuple2 (List string) (List string)} + (lessThanEqualsInteger n 0) + (/\dead -> + Tuple2 {List string} {List string} (Nil {string}) ds) + (/\dead -> go {string} n ds) + {all dead. dead}) + {string} + (\(ipv : List string) (ipv : List string) -> + appendString + (concatBuiltinStrings ipv) + (concatBuiltinStrings ipv))) + {all dead. dead}) +in +let + data Unit | Unit_match where + Unit : Unit + data (Maybe :: * -> *) a | Maybe_match where + Just : a -> Maybe a + Nothing : Maybe a + !lookup : + all k a. + (\a -> a -> data) k -> + (\a -> data -> a) a -> + k -> + (\k a -> list (pair data data)) k a -> + Maybe a + = /\k a -> + \(`$dToData` : (\a -> a -> data) k) + (`$dUnsafeFromData` : (\a -> data -> a) a) + (ds : k) + (ds : (\k a -> list (pair data data)) k a) -> + Maybe_match + {data} + (let + !k : data = `$dToData` ds + in + letrec + !go : list (pair data data) -> Maybe data + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> Maybe data} + xs + (\(ds : Unit) -> Nothing {data}) + (\(ds : Unit) -> + let + !hd : pair data data = headList {pair data data} xs + in + ifThenElse + {all dead. Maybe data} + (equalsData k (fstPair {data} {data} hd)) + (/\dead -> + let + !ds : list (pair data data) + = tailList {pair data data} xs + in + Just {data} (sndPair {data} {data} hd)) + (/\dead -> go (tailList {pair data data} xs)) + {all dead. dead}) + Unit + in + go ds) + {all dead. Maybe a} + (\(a : data) -> /\dead -> Just {a} (`$dUnsafeFromData` a)) + (/\dead -> Nothing {a}) + {all dead. dead} + data Bool | Bool_match where + True : Bool + False : Bool +in +\(n : integer) -> + let + !nt : list (pair data data) + = (let + b = (\k a -> list (pair data data)) integer bytestring + in + \(k : integer -> b -> b) (z : b) -> + letrec + !go : List integer -> b + = \(ds : List integer) -> + List_match + {integer} + ds + {all dead. b} + (/\dead -> z) + (\(y : integer) (ys : List integer) -> + /\dead -> k y (go ys)) + {all dead. dead} + in + \(eta : List integer) -> go eta) + (\(i : integer) -> + let + !ds : integer = addInteger n i + !ds : bytestring + = encodeUtf8 + (concatBuiltinStrings + (`$fShowBuiltinByteString_$cshowsPrec` + 0 + i + (Nil {string}))) + in + \(ds : (\k a -> list (pair data data)) integer bytestring) -> + let + !k : data = iData ds + !a : data = bData ds + in + letrec + !go : list (pair data data) -> list (pair data data) + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> list (pair data data)} + xs + (\(ds : Unit) -> + mkCons {pair data data} (mkPairData k a) []) + (\(ds : Unit) -> + let + !hd : pair data data + = headList {pair data data} xs + !tl : list (pair data data) + = tailList {pair data data} xs + in + ifThenElse + {all dead. list (pair data data)} + (equalsData k (fstPair {data} {data} hd)) + (/\dead -> + mkCons {pair data data} (mkPairData k a) tl) + (/\dead -> mkCons {pair data data} hd (go tl)) + {all dead. dead}) + Unit + in + go ds) + (mkCons {pair data data} (mkPairData (iData n) (B #30)) []) + (`$fEnumBool_$cenumFromTo` 1 10) + !nt : list (pair data data) + = let + !k : data = iData (addInteger 5 n) + in + letrec + !go : list (pair data data) -> list (pair data data) + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> list (pair data data)} + xs + (\(ds : Unit) -> []) + (\(ds : Unit) -> + let + !hd : pair data data = headList {pair data data} xs + !tl : list (pair data data) = tailList {pair data data} xs + in + ifThenElse + {all dead. list (pair data data)} + (equalsData k (fstPair {data} {data} hd)) + (/\dead -> tl) + (/\dead -> mkCons {pair data data} hd (go tl)) + {all dead. dead}) + Unit + in + go nt + in + Tuple5 + {Maybe bytestring} + {Maybe bytestring} + {Maybe bytestring} + {Maybe bytestring} + {Maybe bytestring} + (lookup {integer} {bytestring} (\(i : integer) -> iData i) unBData n nt) + (lookup + {integer} + {bytestring} + (\(i : integer) -> iData i) + unBData + (addInteger 5 n) + nt) + (lookup + {integer} + {bytestring} + (\(i : integer) -> iData i) + unBData + (addInteger 10 n) + nt) + (lookup + {integer} + {bytestring} + (\(i : integer) -> iData i) + unBData + (addInteger 20 n) + nt) + (lookup + {integer} + {bytestring} + (\(i : integer) -> iData i) + unBData + (addInteger 5 n) + nt) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map1.uplc.golden b/plutus-tx-plugin/test/Budget/9.6/map1.uplc.golden new file mode 100644 index 00000000000..9553f47f06b --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map1.uplc.golden @@ -0,0 +1,412 @@ +program + 1.1.0 + ((\fix1 -> + (\`$fEnumBool_$cenumFromTo` -> + (\go -> + (\go -> + (\`$fShowBuiltinByteString_$cshowsPrec` -> + (\go -> + (\go -> + (\concatBuiltinStrings + n -> + (\nt -> + (\cse -> + (\nt -> + (\lookup -> + constr 0 + [ (lookup (\i -> iData i) unBData n nt) + , (lookup + (\i -> iData i) + unBData + cse + nt) + , (lookup + (\i -> iData i) + unBData + (addInteger 10 n) + nt) + , (lookup + (\i -> iData i) + unBData + (addInteger 20 n) + nt) + , (lookup + (\i -> iData i) + unBData + cse + nt) ]) + (\`$dToData` + `$dUnsafeFromData` + ds + ds -> + force + (case + ((\k -> + fix1 + (\go + xs -> + force + (force chooseList) + xs + (\ds -> constr 1 []) + (\ds -> + (\hd -> + force + (force + ifThenElse + (equalsData + k + (force + (force + fstPair) + hd)) + (delay + ((\ds -> + constr 0 + [ (force + (force + sndPair) + hd) ]) + (force + tailList + xs))) + (delay + (go + (force + tailList + xs))))) + (force headList + xs)) + (constr 0 [])) + ds) + (`$dToData` ds)) + [ (\a -> + delay + (constr 0 + [ (`$dUnsafeFromData` + a) ])) + , (delay (constr 1 [])) ]))) + ((\k -> + fix1 + (\go xs -> + force (force chooseList) + xs + (\ds -> []) + (\ds -> + (\hd -> + (\tl -> + force + (force ifThenElse + (equalsData + k + (force + (force + fstPair) + hd)) + (delay tl) + (delay + (force mkCons + hd + (go tl))))) + (force tailList xs)) + (force headList xs)) + (constr 0 [])) + nt) + (iData cse))) + (addInteger 5 n)) + ((\z -> + (\go eta -> + go eta) + (fix1 + (\go + ds -> + force + (case + ds + [ (delay z) + , (\y + ys -> + delay + ((\ds -> + (\ds + ds -> + (\k -> + (\a -> + fix1 + (\go + xs -> + force + (force + chooseList) + xs + (\ds -> + force + mkCons + (mkPairData + k + a) + [ ]) + (\ds -> + (\hd -> + (\tl -> + force + (force + ifThenElse + (equalsData + k + (force + (force + fstPair) + hd)) + (delay + (force + mkCons + (mkPairData + k + a) + tl)) + (delay + (force + mkCons + hd + (go + tl))))) + (force + tailList + xs)) + (force + headList + xs)) + (constr 0 + [])) + ds) + (bData ds)) + (iData ds)) + (encodeUtf8 + (concatBuiltinStrings + (`$fShowBuiltinByteString_$cshowsPrec` + 0 + y + (constr 0 + []))))) + (addInteger n y) + (go ys))) ])))) + (force mkCons (mkPairData (iData n) (B #30)) []) + (`$fEnumBool_$cenumFromTo` 1 10))) + (fix1 + (\concatBuiltinStrings + ds -> + case + ds + [ "" + , (\x + ds -> + force + (case + ds + [ (delay x) + , (\ipv + ipv -> + delay + (case + ((\n -> + force + (force + ifThenElse + (lessThanEqualsInteger + n + 0) + (delay + (constr 0 + [ (constr 0 + []) + , ds ])) + (delay + (force go + n + ds)))) + (divideInteger + (go ds) + 2)) + [ (\ipv + ipv -> + appendString + (concatBuiltinStrings + ipv) + (concatBuiltinStrings + ipv)) ])) ])) ]))) + (fix1 + (\go ds -> + force + (case + ds + [ (delay 0) + , (\x xs -> + delay (addInteger 1 (go xs))) ])))) + (fix1 + (\go + arg -> + delay + (\ds + ds -> + force + (case + ds + [ (delay + (constr 0 + [(constr 0 []), (constr 0 [])])) + , (\y + ys -> + delay + (force + (force + ifThenElse + (equalsInteger 1 ds) + (delay + (constr 0 + [ (constr 1 + [y, (constr 0 [])]) + , ys ])) + (delay + (case + (force + (go (delay (\x -> x))) + (subtractInteger ds 1) + ys) + [ (\zs + ws -> + constr 0 + [ (constr 1 + [y, zs]) + , ws ]) ]))))) ]))) + (delay (\x -> x)))) + (fix1 + (\`$fShowBuiltinByteString_$cshowsPrec` p n -> + force + (force ifThenElse + (lessThanInteger n 0) + (delay + (\eta -> + constr 1 + [ "-" + , (`$fShowBuiltinByteString_$cshowsPrec` + p + (subtractInteger 0 n) + eta) ])) + (delay (go (go (constr 0 []) n))))))) + (fix1 + (\go + ds -> + force + (case + ds + [ (delay (\x -> x)) + , (\x + xs -> + delay + ((\acc + eta -> + constr 1 + [ (force + (force + ifThenElse + (equalsInteger 0 x) + (delay "0") + (delay + (force + (force + ifThenElse + (equalsInteger 1 x) + (delay "1") + (delay + (force + (force + ifThenElse + (equalsInteger + 2 + x) + (delay "2") + (delay + (force + (force + ifThenElse + (equalsInteger + 3 + x) + (delay + "3") + (delay + (force + (force + ifThenElse + (equalsInteger + 4 + x) + (delay + "4") + (delay + (force + (force + ifThenElse + (equalsInteger + 5 + x) + (delay + "5") + (delay + (force + (force + ifThenElse + (equalsInteger + 6 + x) + (delay + "6") + (delay + (force + (force + ifThenElse + (equalsInteger + 7 + x) + (delay + "7") + (delay + (force + (force + ifThenElse + (equalsInteger + 8 + x) + (delay + "8") + (delay + (force + ifThenElse + (equalsInteger + 9 + x) + "9" + "")))))))))))))))))))))))))))) + , (acc eta) ]) + (go xs))) ])))) + (fix1 + (\go acc n -> + (\x -> + force + (force ifThenElse + (equalsInteger 0 x) + (delay (constr 1 [(remainderInteger n 10), acc])) + (delay + (go (constr 1 [(remainderInteger n 10), acc]) x)))) + (quotientInteger n 10)))) + (fix1 + (\`$fEnumBool_$cenumFromTo` x lim -> + force + (force ifThenElse + (lessThanEqualsInteger x lim) + (delay + (constr 1 + [x, (`$fEnumBool_$cenumFromTo` (addInteger 1 x) lim)])) + (delay (constr 0 [])))))) + (\f -> (\s -> s s) (\s -> f (\x -> s s x)))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map2-budget.budget.golden b/plutus-tx-plugin/test/Budget/9.6/map2-budget.budget.golden new file mode 100644 index 00000000000..2c63bc124a1 --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map2-budget.budget.golden @@ -0,0 +1,2 @@ +({cpu: 155458417 +| mem: 394122}) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map2.eval.golden b/plutus-tx-plugin/test/Budget/9.6/map2.eval.golden new file mode 100644 index 00000000000..e8e3b12565c --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map2.eval.golden @@ -0,0 +1,27 @@ +(constr + 1 + (constr 0 (con integer 105) (con string "five")) + (constr + 1 + (constr 0 (con integer 104) (con string "fourFOUR")) + (constr + 1 + (constr 0 (con integer 103) (con string "threeTHREE")) + (constr + 1 + (constr 0 (con integer 102) (con string "two")) + (constr + 1 + (constr 0 (con integer 101) (con string "one")) + (constr + 1 + (constr 0 (con integer 106) (con string "SIX")) + (constr + 1 (constr 0 (con integer 107) (con string "SEVEN")) (constr 0) + ) + ) + ) + ) + ) + ) +) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map2.pir.golden b/plutus-tx-plugin/test/Budget/9.6/map2.pir.golden new file mode 100644 index 00000000000..c735c68c517 --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map2.pir.golden @@ -0,0 +1,338 @@ +let + data Unit | Unit_match where + Unit : Unit + data (Tuple2 :: * -> * -> *) a b | Tuple2_match where + Tuple2 : a -> b -> Tuple2 a b +in +letrec + data (List :: * -> *) a | List_match where + Nil : List a + Cons : a -> List a -> List a +in +letrec + !go : list (pair data data) -> List (Tuple2 integer bytestring) + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> List (Tuple2 integer bytestring)} + xs + (\(ds : Unit) -> Nil {Tuple2 integer bytestring}) + (\(ds : Unit) -> + let + !hd : pair data data = headList {pair data data} xs + !tl : list (pair data data) = tailList {pair data data} xs + in + Cons + {Tuple2 integer bytestring} + (Tuple2 + {integer} + {bytestring} + (unIData (fstPair {data} {data} hd)) + (unBData (sndPair {data} {data} hd))) + (go tl)) + Unit +in +letrec + !go : list (pair data data) -> list (pair data data) -> list (pair data data) + = \(acc : list (pair data data)) (xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> list (pair data data)} + xs + (\(ds : Unit) -> acc) + (\(ds : Unit) -> + go + (mkCons {pair data data} (headList {pair data data} xs) acc) + (tailList {pair data data} xs)) + Unit +in +let + data (Maybe :: * -> *) a | Maybe_match where + Just : a -> Maybe a + Nothing : Maybe a + data Bool | Bool_match where + True : Bool + False : Bool +in +letrec + !goList : List (Tuple2 data data) -> list (pair data data) + = \(ds : List (Tuple2 data data)) -> + List_match + {Tuple2 data data} + ds + {all dead. list (pair data data)} + (/\dead -> []) + (\(d : Tuple2 data data) (ds : List (Tuple2 data data)) -> + /\dead -> + mkCons + {pair data data} + (Tuple2_match + {data} + {data} + d + {pair data data} + (\(d : data) (d : data) -> mkPairData d d)) + (goList ds)) + {all dead. dead} +in +let + !unsafeFromList : + all k a. + (\a -> a -> data) k -> + (\a -> a -> data) a -> + List (Tuple2 k a) -> + (\k a -> list (pair data data)) k a + = /\k a -> + \(`$dToData` : (\a -> a -> data) k) + (`$dToData` : (\a -> a -> data) a) -> + letrec + !go : List (Tuple2 k a) -> List (Tuple2 data data) + = \(ds : List (Tuple2 k a)) -> + List_match + {Tuple2 k a} + ds + {all dead. List (Tuple2 data data)} + (/\dead -> Nil {Tuple2 data data}) + (\(x : Tuple2 k a) (xs : List (Tuple2 k a)) -> + /\dead -> + Cons + {Tuple2 data data} + (Tuple2_match + {k} + {a} + x + {Tuple2 data data} + (\(k : k) (a : a) -> + Tuple2 + {data} + {data} + (`$dToData` k) + (`$dToData` a))) + (go xs)) + {all dead. dead} + in + \(eta : List (Tuple2 k a)) -> + let + !eta : List (Tuple2 data data) = go eta + in + goList eta +in +\(n : integer) -> + let + !nt : list (pair data data) + = unsafeFromList + {integer} + {bytestring} + (\(i : integer) -> iData i) + bData + ((let + a = Tuple2 integer bytestring + in + \(g : all b. (a -> b -> b) -> b -> b) -> + g {List a} (\(ds : a) (ds : List a) -> Cons {a} ds ds) (Nil {a})) + (/\a -> + \(c : Tuple2 integer bytestring -> a -> a) (n : a) -> + c + (Tuple2 {integer} {bytestring} (addInteger 3 n) #5448524545) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 4 n) + #464f5552) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 6 n) + #534958) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 7 n) + #534556454e) + n))))) + in + letrec + !go : list (pair data data) -> list (pair data data) + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> list (pair data data)} + xs + (\(ds : Unit) -> []) + (\(ds : Unit) -> + let + !hd : pair data data = headList {pair data data} xs + !tl : list (pair data data) = tailList {pair data data} xs + !v' : data = sndPair {data} {data} hd + !k' : data = fstPair {data} {data} hd + in + letrec + !go : list (pair data data) -> Maybe data + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> Maybe data} + xs + (\(ds : Unit) -> Nothing {data}) + (\(ds : Unit) -> + let + !hd : pair data data + = headList {pair data data} xs + in + ifThenElse + {all dead. Maybe data} + (equalsData k' (fstPair {data} {data} hd)) + (/\dead -> + let + !ds : list (pair data data) + = tailList {pair data data} xs + in + Just {data} (sndPair {data} {data} hd)) + (/\dead -> go (tailList {pair data data} xs)) + {all dead. dead}) + Unit + in + Maybe_match + {data} + (go nt) + {all dead. list (pair data data)} + (\(r : data) -> + /\dead -> + mkCons + {pair data data} + (mkPairData + k' + (bData (appendByteString (unBData v') (unBData r)))) + (go tl)) + (/\dead -> mkCons {pair data data} (mkPairData k' v') (go tl)) + {all dead. dead}) + Unit + in + let + !nt : list (pair data data) + = unsafeFromList + {integer} + {bytestring} + (\(i : integer) -> iData i) + bData + ((let + a = Tuple2 integer bytestring + in + \(g : all b. (a -> b -> b) -> b -> b) -> + g {List a} (\(ds : a) (ds : List a) -> Cons {a} ds ds) (Nil {a})) + (/\a -> + \(c : Tuple2 integer bytestring -> a -> a) (n : a) -> + c + (Tuple2 {integer} {bytestring} (addInteger 1 n) #6f6e65) + (c + (Tuple2 {integer} {bytestring} (addInteger 2 n) #74776f) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 3 n) + #7468726565) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 4 n) + #666f7572) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 5 n) + #66697665) + n)))))) + in + letrec + !go : list (pair data data) -> list (pair data data) + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> list (pair data data)} + xs + (\(ds : Unit) -> []) + (\(ds : Unit) -> + let + !hd : pair data data = headList {pair data data} xs + !tl' : list (pair data data) + = go (tailList {pair data data} xs) + in + Bool_match + (let + !k : data = fstPair {data} {data} hd + in + letrec + !go : list (pair data data) -> Bool + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> Bool} + xs + (\(ds : Unit) -> False) + (\(ds : Unit) -> + ifThenElse + {all dead. Bool} + (equalsData + k + (fstPair + {data} + {data} + (headList {pair data data} xs))) + (/\dead -> + let + !ds : list (pair data data) + = tailList {pair data data} xs + in + True) + (/\dead -> go (tailList {pair data data} xs)) + {all dead. dead}) + Unit + in + go nt) + {all dead. list (pair data data)} + (/\dead -> tl') + (/\dead -> mkCons {pair data data} hd tl') + {all dead. dead}) + Unit + in + let + !nt : list (pair data data) + = let + !rs' : list (pair data data) = go nt + !ls' : list (pair data data) = go nt + in + go rs' ls' + in + (let + a = Tuple2 integer bytestring + in + /\b -> + \(f : a -> b) -> + letrec + !go : List a -> List b + = \(ds : List a) -> + List_match + {a} + ds + {all dead. List b} + (/\dead -> Nil {b}) + (\(x : a) (xs : List a) -> /\dead -> Cons {b} (f x) (go xs)) + {all dead. dead} + in + \(eta : List a) -> go eta) + {Tuple2 integer string} + (\(ds : Tuple2 integer bytestring) -> + Tuple2_match + {integer} + {bytestring} + ds + {Tuple2 integer string} + (\(k : integer) (v : bytestring) -> + Tuple2 {integer} {string} k (decodeUtf8 v))) + (go nt) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map2.uplc.golden b/plutus-tx-plugin/test/Budget/9.6/map2.uplc.golden new file mode 100644 index 00000000000..f1bf99b0f21 --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map2.uplc.golden @@ -0,0 +1,272 @@ +program + 1.1.0 + ((\fix1 -> + (\go -> + (\go -> + (\goList + n -> + (\unsafeFromList -> + (\cse -> + (\cse -> + (\nt -> + (\go -> + (\nt -> + (\nt -> + fix1 + (\go + ds -> + force + (case + ds + [ (delay (constr 0 [])) + , (\x + xs -> + delay + (constr 1 + [ (case + x + [ (\k + v -> + constr 0 + [ k + , (decodeUtf8 + v) ]) ]) + , (go xs) ])) ])) + (go nt)) + ((\rs' -> + (\ls' -> go rs' ls') (go nt)) + (fix1 + (\go + xs -> + force + (force chooseList) + xs + (\ds -> []) + (\ds -> + (\hd -> + (\tl' -> + force + (case + ((\k -> + fix1 + (\go + xs -> + force + (force + chooseList) + xs + (\ds -> + constr 1 + []) + (\ds -> + force + (force + ifThenElse + (equalsData + k + (force + (force + fstPair) + (force + headList + xs))) + (delay + ((\ds -> + constr 0 + [ ]) + (force + tailList + xs))) + (delay + (go + (force + tailList + xs))))) + (constr 0 + [])) + nt) + (force + (force + fstPair) + hd)) + [ (delay tl') + , (delay + (force mkCons + hd + tl')) ])) + (go (force tailList xs))) + (force headList xs)) + (constr 0 [])) + nt))) + (unsafeFromList + (\i -> iData i) + bData + (constr 1 + [ (constr 0 [(addInteger 1 n), #6f6e65]) + , (constr 1 + [ (constr 0 + [(addInteger 2 n), #74776f]) + , (constr 1 + [ (constr 0 [cse, #7468726565]) + , (constr 1 + [ (constr 0 + [cse, #666f7572]) + , (constr 1 + [ (constr 0 + [ (addInteger + 5 + n) + , #66697665 ]) + , (constr 0 + [ ]) ]) ]) ]) ]) ]))) + (fix1 + (\go + xs -> + force + (force chooseList) + xs + (\ds -> []) + (\ds -> + (\hd -> + (\tl -> + (\v' -> + (\k' -> + force + (case + (fix1 + (\go + xs -> + force + (force + chooseList) + xs + (\ds -> + constr 1 []) + (\ds -> + (\hd -> + force + (force + ifThenElse + (equalsData + k' + (force + (force + fstPair) + hd)) + (delay + ((\ds -> + constr 0 + [ (force + (force + sndPair) + hd) ]) + (force + tailList + xs))) + (delay + (go + (force + tailList + xs))))) + (force + headList + xs)) + (constr 0 [])) + nt) + [ (\r -> + delay + (force + mkCons + (mkPairData + k' + (bData + (appendByteString + (unBData + v') + (unBData + r)))) + (go tl))) + , (delay + (force mkCons + (mkPairData + k' + v') + (go tl))) ])) + (force (force fstPair) hd)) + (force (force sndPair) hd)) + (force tailList xs)) + (force headList xs)) + (constr 0 [])))) + (unsafeFromList + (\i -> iData i) + bData + (constr 1 + [ (constr 0 [cse, #5448524545]) + , (constr 1 + [ (constr 0 [cse, #464f5552]) + , (constr 1 + [ (constr 0 + [(addInteger 6 n), #534958]) + , (constr 1 + [ (constr 0 + [ (addInteger 7 n) + , #534556454e ]) + , (constr 0 []) ]) ]) ]) ]))) + (addInteger 4 n)) + (addInteger 3 n)) + (\`$dToData` `$dToData` -> + (\go eta -> goList (go eta)) + (fix1 + (\go ds -> + force + (case + ds + [ (delay (constr 0 [])) + , (\x xs -> + delay + (constr 1 + [ (case + x + [ (\k a -> + constr 0 + [ (`$dToData` k) + , (`$dToData` a) ]) ]) + , (go xs) ])) ]))))) + (fix1 + (\goList ds -> + force + (case + ds + [ (delay []) + , (\d ds -> + delay + (force mkCons + (case d [(\d d -> mkPairData d d)]) + (goList ds))) ])))) + (fix1 + (\go acc xs -> + force (force chooseList) + xs + (\ds -> acc) + (\ds -> + go + (force mkCons (force headList xs) acc) + (force tailList xs)) + (constr 0 [])))) + (fix1 + (\go xs -> + force (force chooseList) + xs + (\ds -> constr 0 []) + (\ds -> + (\hd -> + (\tl -> + constr 1 + [ (constr 0 + [ (unIData (force (force fstPair) hd)) + , (unBData (force (force sndPair) hd)) ]) + , (go tl) ]) + (force tailList xs)) + (force headList xs)) + (constr 0 [])))) + (\f -> (\s -> s s) (\s -> f (\x -> s s x)))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map3-budget.budget.golden b/plutus-tx-plugin/test/Budget/9.6/map3-budget.budget.golden new file mode 100644 index 00000000000..2c63bc124a1 --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map3-budget.budget.golden @@ -0,0 +1,2 @@ +({cpu: 155458417 +| mem: 394122}) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map3.eval.golden b/plutus-tx-plugin/test/Budget/9.6/map3.eval.golden new file mode 100644 index 00000000000..e8e3b12565c --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map3.eval.golden @@ -0,0 +1,27 @@ +(constr + 1 + (constr 0 (con integer 105) (con string "five")) + (constr + 1 + (constr 0 (con integer 104) (con string "fourFOUR")) + (constr + 1 + (constr 0 (con integer 103) (con string "threeTHREE")) + (constr + 1 + (constr 0 (con integer 102) (con string "two")) + (constr + 1 + (constr 0 (con integer 101) (con string "one")) + (constr + 1 + (constr 0 (con integer 106) (con string "SIX")) + (constr + 1 (constr 0 (con integer 107) (con string "SEVEN")) (constr 0) + ) + ) + ) + ) + ) + ) +) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map3.pir.golden b/plutus-tx-plugin/test/Budget/9.6/map3.pir.golden new file mode 100644 index 00000000000..c735c68c517 --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map3.pir.golden @@ -0,0 +1,338 @@ +let + data Unit | Unit_match where + Unit : Unit + data (Tuple2 :: * -> * -> *) a b | Tuple2_match where + Tuple2 : a -> b -> Tuple2 a b +in +letrec + data (List :: * -> *) a | List_match where + Nil : List a + Cons : a -> List a -> List a +in +letrec + !go : list (pair data data) -> List (Tuple2 integer bytestring) + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> List (Tuple2 integer bytestring)} + xs + (\(ds : Unit) -> Nil {Tuple2 integer bytestring}) + (\(ds : Unit) -> + let + !hd : pair data data = headList {pair data data} xs + !tl : list (pair data data) = tailList {pair data data} xs + in + Cons + {Tuple2 integer bytestring} + (Tuple2 + {integer} + {bytestring} + (unIData (fstPair {data} {data} hd)) + (unBData (sndPair {data} {data} hd))) + (go tl)) + Unit +in +letrec + !go : list (pair data data) -> list (pair data data) -> list (pair data data) + = \(acc : list (pair data data)) (xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> list (pair data data)} + xs + (\(ds : Unit) -> acc) + (\(ds : Unit) -> + go + (mkCons {pair data data} (headList {pair data data} xs) acc) + (tailList {pair data data} xs)) + Unit +in +let + data (Maybe :: * -> *) a | Maybe_match where + Just : a -> Maybe a + Nothing : Maybe a + data Bool | Bool_match where + True : Bool + False : Bool +in +letrec + !goList : List (Tuple2 data data) -> list (pair data data) + = \(ds : List (Tuple2 data data)) -> + List_match + {Tuple2 data data} + ds + {all dead. list (pair data data)} + (/\dead -> []) + (\(d : Tuple2 data data) (ds : List (Tuple2 data data)) -> + /\dead -> + mkCons + {pair data data} + (Tuple2_match + {data} + {data} + d + {pair data data} + (\(d : data) (d : data) -> mkPairData d d)) + (goList ds)) + {all dead. dead} +in +let + !unsafeFromList : + all k a. + (\a -> a -> data) k -> + (\a -> a -> data) a -> + List (Tuple2 k a) -> + (\k a -> list (pair data data)) k a + = /\k a -> + \(`$dToData` : (\a -> a -> data) k) + (`$dToData` : (\a -> a -> data) a) -> + letrec + !go : List (Tuple2 k a) -> List (Tuple2 data data) + = \(ds : List (Tuple2 k a)) -> + List_match + {Tuple2 k a} + ds + {all dead. List (Tuple2 data data)} + (/\dead -> Nil {Tuple2 data data}) + (\(x : Tuple2 k a) (xs : List (Tuple2 k a)) -> + /\dead -> + Cons + {Tuple2 data data} + (Tuple2_match + {k} + {a} + x + {Tuple2 data data} + (\(k : k) (a : a) -> + Tuple2 + {data} + {data} + (`$dToData` k) + (`$dToData` a))) + (go xs)) + {all dead. dead} + in + \(eta : List (Tuple2 k a)) -> + let + !eta : List (Tuple2 data data) = go eta + in + goList eta +in +\(n : integer) -> + let + !nt : list (pair data data) + = unsafeFromList + {integer} + {bytestring} + (\(i : integer) -> iData i) + bData + ((let + a = Tuple2 integer bytestring + in + \(g : all b. (a -> b -> b) -> b -> b) -> + g {List a} (\(ds : a) (ds : List a) -> Cons {a} ds ds) (Nil {a})) + (/\a -> + \(c : Tuple2 integer bytestring -> a -> a) (n : a) -> + c + (Tuple2 {integer} {bytestring} (addInteger 3 n) #5448524545) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 4 n) + #464f5552) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 6 n) + #534958) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 7 n) + #534556454e) + n))))) + in + letrec + !go : list (pair data data) -> list (pair data data) + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> list (pair data data)} + xs + (\(ds : Unit) -> []) + (\(ds : Unit) -> + let + !hd : pair data data = headList {pair data data} xs + !tl : list (pair data data) = tailList {pair data data} xs + !v' : data = sndPair {data} {data} hd + !k' : data = fstPair {data} {data} hd + in + letrec + !go : list (pair data data) -> Maybe data + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> Maybe data} + xs + (\(ds : Unit) -> Nothing {data}) + (\(ds : Unit) -> + let + !hd : pair data data + = headList {pair data data} xs + in + ifThenElse + {all dead. Maybe data} + (equalsData k' (fstPair {data} {data} hd)) + (/\dead -> + let + !ds : list (pair data data) + = tailList {pair data data} xs + in + Just {data} (sndPair {data} {data} hd)) + (/\dead -> go (tailList {pair data data} xs)) + {all dead. dead}) + Unit + in + Maybe_match + {data} + (go nt) + {all dead. list (pair data data)} + (\(r : data) -> + /\dead -> + mkCons + {pair data data} + (mkPairData + k' + (bData (appendByteString (unBData v') (unBData r)))) + (go tl)) + (/\dead -> mkCons {pair data data} (mkPairData k' v') (go tl)) + {all dead. dead}) + Unit + in + let + !nt : list (pair data data) + = unsafeFromList + {integer} + {bytestring} + (\(i : integer) -> iData i) + bData + ((let + a = Tuple2 integer bytestring + in + \(g : all b. (a -> b -> b) -> b -> b) -> + g {List a} (\(ds : a) (ds : List a) -> Cons {a} ds ds) (Nil {a})) + (/\a -> + \(c : Tuple2 integer bytestring -> a -> a) (n : a) -> + c + (Tuple2 {integer} {bytestring} (addInteger 1 n) #6f6e65) + (c + (Tuple2 {integer} {bytestring} (addInteger 2 n) #74776f) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 3 n) + #7468726565) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 4 n) + #666f7572) + (c + (Tuple2 + {integer} + {bytestring} + (addInteger 5 n) + #66697665) + n)))))) + in + letrec + !go : list (pair data data) -> list (pair data data) + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> list (pair data data)} + xs + (\(ds : Unit) -> []) + (\(ds : Unit) -> + let + !hd : pair data data = headList {pair data data} xs + !tl' : list (pair data data) + = go (tailList {pair data data} xs) + in + Bool_match + (let + !k : data = fstPair {data} {data} hd + in + letrec + !go : list (pair data data) -> Bool + = \(xs : list (pair data data)) -> + chooseList + {pair data data} + {Unit -> Bool} + xs + (\(ds : Unit) -> False) + (\(ds : Unit) -> + ifThenElse + {all dead. Bool} + (equalsData + k + (fstPair + {data} + {data} + (headList {pair data data} xs))) + (/\dead -> + let + !ds : list (pair data data) + = tailList {pair data data} xs + in + True) + (/\dead -> go (tailList {pair data data} xs)) + {all dead. dead}) + Unit + in + go nt) + {all dead. list (pair data data)} + (/\dead -> tl') + (/\dead -> mkCons {pair data data} hd tl') + {all dead. dead}) + Unit + in + let + !nt : list (pair data data) + = let + !rs' : list (pair data data) = go nt + !ls' : list (pair data data) = go nt + in + go rs' ls' + in + (let + a = Tuple2 integer bytestring + in + /\b -> + \(f : a -> b) -> + letrec + !go : List a -> List b + = \(ds : List a) -> + List_match + {a} + ds + {all dead. List b} + (/\dead -> Nil {b}) + (\(x : a) (xs : List a) -> /\dead -> Cons {b} (f x) (go xs)) + {all dead. dead} + in + \(eta : List a) -> go eta) + {Tuple2 integer string} + (\(ds : Tuple2 integer bytestring) -> + Tuple2_match + {integer} + {bytestring} + ds + {Tuple2 integer string} + (\(k : integer) (v : bytestring) -> + Tuple2 {integer} {string} k (decodeUtf8 v))) + (go nt) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.6/map3.uplc.golden b/plutus-tx-plugin/test/Budget/9.6/map3.uplc.golden new file mode 100644 index 00000000000..f1bf99b0f21 --- /dev/null +++ b/plutus-tx-plugin/test/Budget/9.6/map3.uplc.golden @@ -0,0 +1,272 @@ +program + 1.1.0 + ((\fix1 -> + (\go -> + (\go -> + (\goList + n -> + (\unsafeFromList -> + (\cse -> + (\cse -> + (\nt -> + (\go -> + (\nt -> + (\nt -> + fix1 + (\go + ds -> + force + (case + ds + [ (delay (constr 0 [])) + , (\x + xs -> + delay + (constr 1 + [ (case + x + [ (\k + v -> + constr 0 + [ k + , (decodeUtf8 + v) ]) ]) + , (go xs) ])) ])) + (go nt)) + ((\rs' -> + (\ls' -> go rs' ls') (go nt)) + (fix1 + (\go + xs -> + force + (force chooseList) + xs + (\ds -> []) + (\ds -> + (\hd -> + (\tl' -> + force + (case + ((\k -> + fix1 + (\go + xs -> + force + (force + chooseList) + xs + (\ds -> + constr 1 + []) + (\ds -> + force + (force + ifThenElse + (equalsData + k + (force + (force + fstPair) + (force + headList + xs))) + (delay + ((\ds -> + constr 0 + [ ]) + (force + tailList + xs))) + (delay + (go + (force + tailList + xs))))) + (constr 0 + [])) + nt) + (force + (force + fstPair) + hd)) + [ (delay tl') + , (delay + (force mkCons + hd + tl')) ])) + (go (force tailList xs))) + (force headList xs)) + (constr 0 [])) + nt))) + (unsafeFromList + (\i -> iData i) + bData + (constr 1 + [ (constr 0 [(addInteger 1 n), #6f6e65]) + , (constr 1 + [ (constr 0 + [(addInteger 2 n), #74776f]) + , (constr 1 + [ (constr 0 [cse, #7468726565]) + , (constr 1 + [ (constr 0 + [cse, #666f7572]) + , (constr 1 + [ (constr 0 + [ (addInteger + 5 + n) + , #66697665 ]) + , (constr 0 + [ ]) ]) ]) ]) ]) ]))) + (fix1 + (\go + xs -> + force + (force chooseList) + xs + (\ds -> []) + (\ds -> + (\hd -> + (\tl -> + (\v' -> + (\k' -> + force + (case + (fix1 + (\go + xs -> + force + (force + chooseList) + xs + (\ds -> + constr 1 []) + (\ds -> + (\hd -> + force + (force + ifThenElse + (equalsData + k' + (force + (force + fstPair) + hd)) + (delay + ((\ds -> + constr 0 + [ (force + (force + sndPair) + hd) ]) + (force + tailList + xs))) + (delay + (go + (force + tailList + xs))))) + (force + headList + xs)) + (constr 0 [])) + nt) + [ (\r -> + delay + (force + mkCons + (mkPairData + k' + (bData + (appendByteString + (unBData + v') + (unBData + r)))) + (go tl))) + , (delay + (force mkCons + (mkPairData + k' + v') + (go tl))) ])) + (force (force fstPair) hd)) + (force (force sndPair) hd)) + (force tailList xs)) + (force headList xs)) + (constr 0 [])))) + (unsafeFromList + (\i -> iData i) + bData + (constr 1 + [ (constr 0 [cse, #5448524545]) + , (constr 1 + [ (constr 0 [cse, #464f5552]) + , (constr 1 + [ (constr 0 + [(addInteger 6 n), #534958]) + , (constr 1 + [ (constr 0 + [ (addInteger 7 n) + , #534556454e ]) + , (constr 0 []) ]) ]) ]) ]))) + (addInteger 4 n)) + (addInteger 3 n)) + (\`$dToData` `$dToData` -> + (\go eta -> goList (go eta)) + (fix1 + (\go ds -> + force + (case + ds + [ (delay (constr 0 [])) + , (\x xs -> + delay + (constr 1 + [ (case + x + [ (\k a -> + constr 0 + [ (`$dToData` k) + , (`$dToData` a) ]) ]) + , (go xs) ])) ]))))) + (fix1 + (\goList ds -> + force + (case + ds + [ (delay []) + , (\d ds -> + delay + (force mkCons + (case d [(\d d -> mkPairData d d)]) + (goList ds))) ])))) + (fix1 + (\go acc xs -> + force (force chooseList) + xs + (\ds -> acc) + (\ds -> + go + (force mkCons (force headList xs) acc) + (force tailList xs)) + (constr 0 [])))) + (fix1 + (\go xs -> + force (force chooseList) + xs + (\ds -> constr 0 []) + (\ds -> + (\hd -> + (\tl -> + constr 1 + [ (constr 0 + [ (unIData (force (force fstPair) hd)) + , (unBData (force (force sndPair) hd)) ]) + , (go tl) ]) + (force tailList xs)) + (force headList xs)) + (constr 0 [])))) + (\f -> (\s -> s s) (\s -> f (\x -> s s x)))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/Spec.hs b/plutus-tx-plugin/test/Budget/Spec.hs index b9200ed45c8..34868950752 100644 --- a/plutus-tx-plugin/test/Budget/Spec.hs +++ b/plutus-tx-plugin/test/Budget/Spec.hs @@ -19,7 +19,7 @@ import Test.Tasty.Extras import Budget.WithGHCOptimisations qualified as WithGHCOptTest import Budget.WithoutGHCOptimisations qualified as WithoutGHCOptTest import PlutusTx.AsData qualified as AsData -import PlutusTx.Builtins qualified as PlutusTx +import PlutusTx.Builtins qualified as PlutusTx hiding (null) import PlutusTx.Builtins.Internal qualified as BI import PlutusTx.Code import PlutusTx.IsData qualified as IsData @@ -36,8 +36,8 @@ AsData.asData [d| makeLift ''MaybeD tests :: TestNested -tests = testNestedGhc "Budget" [ - goldenBudget "sum" compiledSum +tests = testNested "Budget" . pure $ testNestedGhc + [ goldenBudget "sum" compiledSum , goldenUPlcReadable "sum" compiledSum , goldenPirReadable "sum" compiledSum , goldenEvalCekCatch "sum" [compiledSum] diff --git a/plutus-tx-plugin/test/IntegerLiterals/NoStrict/NegativeLiterals/Spec.hs b/plutus-tx-plugin/test/IntegerLiterals/NoStrict/NegativeLiterals/Spec.hs index 90a328e54b1..f18db70247e 100644 --- a/plutus-tx-plugin/test/IntegerLiterals/NoStrict/NegativeLiterals/Spec.hs +++ b/plutus-tx-plugin/test/IntegerLiterals/NoStrict/NegativeLiterals/Spec.hs @@ -20,7 +20,7 @@ import PlutusTx.TH (compile) import Test.Tasty.Extras tests :: TestNested -tests = testNestedGhc "IntegerLiterals" +tests = testNested "IntegerLiterals" . pure $ testNestedGhc [ goldenPir "integerLiterals-NoStrict-NegativeLiterals" integerLiterals ] diff --git a/plutus-tx-plugin/test/IntegerLiterals/NoStrict/NoNegativeLiterals/Spec.hs b/plutus-tx-plugin/test/IntegerLiterals/NoStrict/NoNegativeLiterals/Spec.hs index 9928b6f0607..131ced5b40a 100644 --- a/plutus-tx-plugin/test/IntegerLiterals/NoStrict/NoNegativeLiterals/Spec.hs +++ b/plutus-tx-plugin/test/IntegerLiterals/NoStrict/NoNegativeLiterals/Spec.hs @@ -19,7 +19,7 @@ import PlutusTx.TH (compile) import Test.Tasty.Extras tests :: TestNested -tests = testNestedGhc "IntegerLiterals" +tests = testNested "IntegerLiterals" . pure $ testNestedGhc [ goldenPir "integerLiterals-NoStrict-NoNegativeLiterals" integerLiterals ] diff --git a/plutus-tx-plugin/test/IntegerLiterals/Strict/NegativeLiterals/Spec.hs b/plutus-tx-plugin/test/IntegerLiterals/Strict/NegativeLiterals/Spec.hs index c38f8a80ddd..027974207dc 100644 --- a/plutus-tx-plugin/test/IntegerLiterals/Strict/NegativeLiterals/Spec.hs +++ b/plutus-tx-plugin/test/IntegerLiterals/Strict/NegativeLiterals/Spec.hs @@ -20,7 +20,7 @@ import PlutusTx.TH (compile) import Test.Tasty.Extras tests :: TestNested -tests = testNestedGhc "IntegerLiterals" +tests = testNested "IntegerLiterals" . pure $ testNestedGhc [ goldenPir "integerLiterals-Strict-NegativeLiterals" integerLiterals ] diff --git a/plutus-tx-plugin/test/IntegerLiterals/Strict/NoNegativeLiterals/Spec.hs b/plutus-tx-plugin/test/IntegerLiterals/Strict/NoNegativeLiterals/Spec.hs index 9476f8c94ed..ac458116d06 100644 --- a/plutus-tx-plugin/test/IntegerLiterals/Strict/NoNegativeLiterals/Spec.hs +++ b/plutus-tx-plugin/test/IntegerLiterals/Strict/NoNegativeLiterals/Spec.hs @@ -19,7 +19,7 @@ import PlutusTx.TH (compile) import Test.Tasty.Extras tests :: TestNested -tests = testNestedGhc "IntegerLiterals" +tests = testNested "IntegerLiterals" . pure $ testNestedGhc [ goldenPir "integerLiterals-Strict-NoNegativeLiterals" integerLiterals ] diff --git a/plutus-tx-plugin/test/IsData/Spec.hs b/plutus-tx-plugin/test/IsData/Spec.hs index 9bd5f538b95..2cd9edab9ac 100644 --- a/plutus-tx-plugin/test/IsData/Spec.hs +++ b/plutus-tx-plugin/test/IsData/Spec.hs @@ -112,8 +112,8 @@ fieldAccessor :: CompiledCode (RecordConstructor Integer -> Integer) fieldAccessor = plc (Proxy @"fieldAccessor") (\r -> x r) tests :: TestNested -tests = testNestedGhc "IsData" [ - goldenUEval "int" [plc (Proxy @"int") (isDataRoundtrip (1::Integer))] +tests = testNested "IsData" . pure $ testNestedGhc + [ goldenUEval "int" [plc (Proxy @"int") (isDataRoundtrip (1::Integer))] , goldenUEval "tuple" [plc (Proxy @"tuple") (isDataRoundtrip (1::Integer, 2::Integer))] , goldenUEval "tupleInterop" [ getPlcNoAnn (plc (Proxy @"tupleInterop") (\(d :: P.BuiltinData) -> case IsData.fromBuiltinData d of { Just t -> t P.== (1::Integer, 2::Integer); Nothing -> False})) diff --git a/plutus-tx-plugin/test/Lift/Spec.hs b/plutus-tx-plugin/test/Lift/Spec.hs index 1f888f9695b..39f97e079b1 100644 --- a/plutus-tx-plugin/test/Lift/Spec.hs +++ b/plutus-tx-plugin/test/Lift/Spec.hs @@ -47,8 +47,8 @@ data SynExample = SynExample { unSE :: Syn } Lift.makeLift ''SynExample tests :: TestNested -tests = testNestedGhc "Lift" [ - goldenUPlc "int" (snd (Lift.liftProgramDef (1::Integer))) +tests = testNested "Lift" . pure $ testNestedGhc + [ goldenUPlc "int" (snd (Lift.liftProgramDef (1::Integer))) , goldenUPlc "tuple" (snd (Lift.liftProgramDef (1::Integer, 2::Integer))) , goldenUPlc "mono" (snd (Lift.liftProgramDef (Mono2 2))) , goldenUEval "monoInterop" [ getPlcNoAnn monoCase, snd (Lift.liftProgramDef (Mono1 1 2)) ] diff --git a/plutus-tx-plugin/test/Optimization/Spec.hs b/plutus-tx-plugin/test/Optimization/Spec.hs index 3a79790867a..d579ca7f591 100644 --- a/plutus-tx-plugin/test/Optimization/Spec.hs +++ b/plutus-tx-plugin/test/Optimization/Spec.hs @@ -34,8 +34,8 @@ AsData.asData [d| -- This can be interesting to make sure that important optimizations fire, including -- ones that run on UPLC. tests :: TestNested -tests = testNestedGhc "Optimization" [ - goldenUPlc "maybeFun" maybeFun +tests = testNested "Optimization" . pure $ testNestedGhc + [ goldenUPlc "maybeFun" maybeFun , goldenPirReadable "matchAsData" matchAsData , goldenPirReadable "unsafeDeconstructData" unsafeDeconstructData ] diff --git a/plutus-tx-plugin/test/Plugin/Basic/9.6/ifOptEval.eval.golden b/plutus-tx-plugin/test/Plugin/Basic/9.6/ifOptEval.eval.golden index 64d9a1489c9..5104d4035fc 100644 --- a/plutus-tx-plugin/test/Plugin/Basic/9.6/ifOptEval.eval.golden +++ b/plutus-tx-plugin/test/Plugin/Basic/9.6/ifOptEval.eval.golden @@ -1,4 +1,4 @@ -An error has occurred: User error: +An error has occurred: The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'. Caused by: (divideInteger 1 0) Final budget: ({cpu: 453560 diff --git a/plutus-tx-plugin/test/Plugin/Basic/Spec.hs b/plutus-tx-plugin/test/Plugin/Basic/Spec.hs index a753ec8b7b2..8b674e0f56c 100644 --- a/plutus-tx-plugin/test/Plugin/Basic/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Basic/Spec.hs @@ -25,12 +25,11 @@ import PlutusTx.Prelude qualified as P import PlutusTx.Test (goldenPir, goldenUPlc) import Data.Proxy (Proxy (..)) -import Test.Tasty.Extras (TestNested, testNestedGhc) +import Test.Tasty.Extras (TestNested, testNested, testNestedGhc) basic :: TestNested basic = - testNestedGhc - "Basic" + testNested "Basic" . pure $ testNestedGhc [ goldenPir "monoId" monoId , goldenPir "monoK" monoK , goldenPir "letFun" letFun diff --git a/plutus-tx-plugin/test/Plugin/Coverage/Spec.hs b/plutus-tx-plugin/test/Plugin/Coverage/Spec.hs index 24dc93cabae..b8c4051e318 100644 --- a/plutus-tx-plugin/test/Plugin/Coverage/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Coverage/Spec.hs @@ -49,8 +49,8 @@ boolQualifiedDisappears :: CompiledCode (() -> Bool) boolQualifiedDisappears = plc (Proxy @"boolQualifiedDisappears") (\ () -> Haskell.True) coverage :: TestNested -coverage = testNestedGhc "Coverage" - [ pure $ testGroup "Application heads and line coverage" +coverage = testNested "Coverage" . pure $ testNestedGhc + [ embed $ testGroup "Application heads and line coverage" [ mkTests "noBool" noBool Set.empty [31] , mkTests "boolTrueFalse" boolTrueFalse (Set.singleton "&&") [34] , mkTests "boolOtherFunction" boolOtherFunction (Set.fromList ["&&", "=="]) [37, 41, 42, 43] diff --git a/plutus-tx-plugin/test/Plugin/Data/Spec.hs b/plutus-tx-plugin/test/Plugin/Data/Spec.hs index cc3a1f9a1fd..f52ab917410 100644 --- a/plutus-tx-plugin/test/Plugin/Data/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Data/Spec.hs @@ -30,8 +30,8 @@ import PlutusTx.Test import Data.Proxy datat :: TestNested -datat = testNestedGhc "Data" [ - monoData +datat = testNested "Data" . pure . testNestedGhc $ + [ monoData , polyData , newtypes , recursiveTypes diff --git a/plutus-tx-plugin/test/Plugin/Debug/9.6/fib.pir.golden b/plutus-tx-plugin/test/Plugin/Debug/9.6/fib.pir.golden index cd570b0445c..45afefbea79 100644 --- a/plutus-tx-plugin/test/Plugin/Debug/9.6/fib.pir.golden +++ b/plutus-tx-plugin/test/Plugin/Debug/9.6/fib.pir.golden @@ -296,151 +296,151 @@ n (con { no-src-span } integer) (let - { test/Plugin/Debug/Spec.hs:47:15-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72 } (nonrec) (termbind - { test/Plugin/Debug/Spec.hs:47:15-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72 } (strict) (vardecl - { test/Plugin/Debug/Spec.hs:47:15-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72 } n - (con { test/Plugin/Debug/Spec.hs:47:15-56:72 } integer) + (con { test/Plugin/Debug/Spec.hs:46:15-55:72 } integer) ) - { test/Plugin/Debug/Spec.hs:47:15-56:72 } n + { test/Plugin/Debug/Spec.hs:46:15-55:72 } n ) { - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } { - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } Bool_match [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } equalsInteger - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:48:43-48:43 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:47:43-47:43 } n ] (con - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:48:45-48:45 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:47:45-47:45 } integer 0 ) ] ] (all - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } dead - ({ test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + ({ test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } type) (con - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } integer ) ) } (abs - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } dead - ({ test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + ({ test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } type) (con - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:49:26-49:26 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:48:26-48:26 } integer 0 ) ) ] (abs - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } dead - ({ test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + ({ test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } type) { - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } { - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } Bool_match [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } equalsInteger - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:51:51-51:51 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:50:51-50:51 } n ] (con - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:51:53-51:53 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:50:53-50:53 } integer 1 ) ] ] (all - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } dead - ({ test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + ({ test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } type) (con - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } integer ) ) } (abs - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } dead - ({ test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + ({ test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } type) (con - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:52:34-52:34 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:51:34-51:34 } integer 1 ) ) ] (abs - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } dead - ({ test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + ({ test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } type) [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72 } - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72 } addInteger [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:55:37-55:72 } - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:55:37-55:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:54:37-54:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:54:37-54:72 } fib [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:54:37-54:72, test/Plugin/Debug/Spec.hs:54:42-54:71 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71 } - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:54:37-54:72, test/Plugin/Debug/Spec.hs:54:42-54:71 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:54:37-54:72, test/Plugin/Debug/Spec.hs:54:42-54:71 } subtractInteger - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71, test/Plugin/Debug/Spec.hs:55:68-55:68 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:54:37-54:72, test/Plugin/Debug/Spec.hs:54:42-54:71, test/Plugin/Debug/Spec.hs:54:68-54:68 } n ] (con - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71, test/Plugin/Debug/Spec.hs:55:70-55:70 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:54:37-54:72, test/Plugin/Debug/Spec.hs:54:42-54:71, test/Plugin/Debug/Spec.hs:54:70-54:70 } integer 1 ) @@ -448,20 +448,20 @@ ] ] [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:56:37-56:72 } - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:56:37-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:55:37-55:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:55:37-55:72 } fib [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:56:37-56:72, test/Plugin/Debug/Spec.hs:56:42-56:71 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71 } [ - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:56:37-56:72, test/Plugin/Debug/Spec.hs:56:42-56:71 } - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:56:37-56:72, test/Plugin/Debug/Spec.hs:56:42-56:71 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71 } subtractInteger - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:56:37-56:72, test/Plugin/Debug/Spec.hs:56:42-56:71, test/Plugin/Debug/Spec.hs:56:68-56:68 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71, test/Plugin/Debug/Spec.hs:55:68-55:68 } n ] (con - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72, test/Plugin/Debug/Spec.hs:54:33-56:72, test/Plugin/Debug/Spec.hs:56:37-56:72, test/Plugin/Debug/Spec.hs:56:42-56:71, test/Plugin/Debug/Spec.hs:56:70-56:70 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72, test/Plugin/Debug/Spec.hs:53:33-55:72, test/Plugin/Debug/Spec.hs:55:37-55:72, test/Plugin/Debug/Spec.hs:55:42-55:71, test/Plugin/Debug/Spec.hs:55:70-55:70 } integer 2 ) @@ -471,29 +471,29 @@ ) ] (all - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } dead - ({ test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + ({ test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } type) - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72, test/Plugin/Debug/Spec.hs:51:25-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72, test/Plugin/Debug/Spec.hs:50:25-55:72 } dead ) } ) ] (all - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } dead - ({ test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + ({ test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } type) - { test/Plugin/Debug/Spec.hs:47:15-56:72, test/Plugin/Debug/Spec.hs:48:17-56:72 } + { test/Plugin/Debug/Spec.hs:46:15-55:72, test/Plugin/Debug/Spec.hs:47:17-55:72 } dead ) } ) ) ) - { test/Plugin/Debug/Spec.hs:46:9-58:9 } fib + { test/Plugin/Debug/Spec.hs:45:9-57:9 } fib ) ) ) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Plugin/Debug/9.6/letFun.pir.golden b/plutus-tx-plugin/test/Plugin/Debug/9.6/letFun.pir.golden index f9cfeceb748..4c61eb0073f 100644 --- a/plutus-tx-plugin/test/Plugin/Debug/9.6/letFun.pir.golden +++ b/plutus-tx-plugin/test/Plugin/Debug/9.6/letFun.pir.golden @@ -137,45 +137,45 @@ ds (con { no-src-span } integer) (let - { test/Plugin/Debug/Spec.hs:39:9-39:87 } + { test/Plugin/Debug/Spec.hs:38:9-38:87 } (nonrec) (termbind - { test/Plugin/Debug/Spec.hs:39:9-39:87 } + { test/Plugin/Debug/Spec.hs:38:9-38:87 } (strict) (vardecl - { test/Plugin/Debug/Spec.hs:39:9-39:87 } + { test/Plugin/Debug/Spec.hs:38:9-38:87 } ds - (con { test/Plugin/Debug/Spec.hs:39:9-39:87 } integer) + (con { test/Plugin/Debug/Spec.hs:38:9-38:87 } integer) ) - { test/Plugin/Debug/Spec.hs:39:9-39:87 } ds + { test/Plugin/Debug/Spec.hs:38:9-38:87 } ds ) (lam { no-src-span } ds (con { no-src-span } integer) (let - { test/Plugin/Debug/Spec.hs:39:9-39:87 } + { test/Plugin/Debug/Spec.hs:38:9-38:87 } (nonrec) (termbind - { test/Plugin/Debug/Spec.hs:39:9-39:87 } + { test/Plugin/Debug/Spec.hs:38:9-38:87 } (strict) (vardecl - { test/Plugin/Debug/Spec.hs:39:9-39:87 } + { test/Plugin/Debug/Spec.hs:38:9-38:87 } ds - (con { test/Plugin/Debug/Spec.hs:39:9-39:87 } integer) + (con { test/Plugin/Debug/Spec.hs:38:9-38:87 } integer) ) - { test/Plugin/Debug/Spec.hs:39:9-39:87 } ds + { test/Plugin/Debug/Spec.hs:38:9-38:87 } ds ) [ - { test/Plugin/Debug/Spec.hs:39:9-39:87, test/Plugin/Debug/Spec.hs:39:44-39:86, test/Plugin/Debug/Spec.hs:39:54-39:79 } + { test/Plugin/Debug/Spec.hs:38:9-38:87, test/Plugin/Debug/Spec.hs:38:44-38:86, test/Plugin/Debug/Spec.hs:38:54-38:79 } [ - { test/Plugin/Debug/Spec.hs:39:9-39:87, test/Plugin/Debug/Spec.hs:39:44-39:86, test/Plugin/Debug/Spec.hs:39:54-39:79 } - { test/Plugin/Debug/Spec.hs:39:9-39:87, test/Plugin/Debug/Spec.hs:39:44-39:86, test/Plugin/Debug/Spec.hs:39:54-39:79 } + { test/Plugin/Debug/Spec.hs:38:9-38:87, test/Plugin/Debug/Spec.hs:38:44-38:86, test/Plugin/Debug/Spec.hs:38:54-38:79 } + { test/Plugin/Debug/Spec.hs:38:9-38:87, test/Plugin/Debug/Spec.hs:38:44-38:86, test/Plugin/Debug/Spec.hs:38:54-38:79 } equalsInteger - { test/Plugin/Debug/Spec.hs:39:9-39:87, test/Plugin/Debug/Spec.hs:39:44-39:86, test/Plugin/Debug/Spec.hs:39:54-39:79, test/Plugin/Debug/Spec.hs:39:77-39:77 } + { test/Plugin/Debug/Spec.hs:38:9-38:87, test/Plugin/Debug/Spec.hs:38:44-38:86, test/Plugin/Debug/Spec.hs:38:54-38:79, test/Plugin/Debug/Spec.hs:38:77-38:77 } ds ] - { test/Plugin/Debug/Spec.hs:39:9-39:87, test/Plugin/Debug/Spec.hs:39:44-39:86, test/Plugin/Debug/Spec.hs:39:54-39:79, test/Plugin/Debug/Spec.hs:39:79-39:79 } + { test/Plugin/Debug/Spec.hs:38:9-38:87, test/Plugin/Debug/Spec.hs:38:44-38:86, test/Plugin/Debug/Spec.hs:38:54-38:79, test/Plugin/Debug/Spec.hs:38:79-38:79 } ds ] ) diff --git a/plutus-tx-plugin/test/Plugin/Debug/Spec.hs b/plutus-tx-plugin/test/Plugin/Debug/Spec.hs index df94a4efc27..987405909cb 100644 --- a/plutus-tx-plugin/test/Plugin/Debug/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Debug/Spec.hs @@ -24,8 +24,7 @@ import Data.Proxy debug :: TestNested debug = - testNestedGhc - "Debug" + testNested "Debug" . pure $ testNestedGhc [ goldenPirBy config "letFun" letFun , goldenPirBy config "fib" fib ] diff --git a/plutus-tx-plugin/test/Plugin/Errors/Spec.hs b/plutus-tx-plugin/test/Plugin/Errors/Spec.hs index a9a6b5dcb79..11abfde85f4 100644 --- a/plutus-tx-plugin/test/Plugin/Errors/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Errors/Spec.hs @@ -34,23 +34,23 @@ import GHC.Num.Integer {- HLINT ignore -} errors :: TestNested -errors = testNestedGhc "Errors" - [ goldenUPlc "machInt" machInt - -- FIXME: This fails differently in nix, possibly due to slightly different optimization settings - -- , goldenPlc "negativeInt" negativeInt - , goldenUPlc "caseInt" caseInt - , goldenUPlc "stringLiteral" stringLiteral - , goldenUPlc "recursiveNewtype" recursiveNewtype - , goldenUPlc "mutualRecursionUnfoldingsLocal" mutualRecursionUnfoldingsLocal - , goldenUPlc "literalCaseInt" literalCaseInt - , goldenUPlc "literalCaseBs" literalCaseBs - , goldenUPlc "literalAppendBs" literalAppendBs - , goldenUPlc "literalCaseOther" literalCaseOther - , goldenUPlc "rangeEnumFromTo" rangeEnumFromTo - , goldenUPlc "rangeEnumFromThenTo" rangeEnumFromThenTo - , goldenUPlc "rangeEnumFrom" rangeEnumFrom - , goldenUPlc "rangeEnumFromThen" rangeEnumFromThen - ] +errors = testNested "Errors" . pure $ testNestedGhc + [ goldenUPlc "machInt" machInt + -- FIXME: This fails differently in nix, possibly due to slightly different optimization settings + -- , goldenPlc "negativeInt" negativeInt + , goldenUPlc "caseInt" caseInt + , goldenUPlc "stringLiteral" stringLiteral + , goldenUPlc "recursiveNewtype" recursiveNewtype + , goldenUPlc "mutualRecursionUnfoldingsLocal" mutualRecursionUnfoldingsLocal + , goldenUPlc "literalCaseInt" literalCaseInt + , goldenUPlc "literalCaseBs" literalCaseBs + , goldenUPlc "literalAppendBs" literalAppendBs + , goldenUPlc "literalCaseOther" literalCaseOther + , goldenUPlc "rangeEnumFromTo" rangeEnumFromTo + , goldenUPlc "rangeEnumFromThenTo" rangeEnumFromThenTo + , goldenUPlc "rangeEnumFrom" rangeEnumFrom + , goldenUPlc "rangeEnumFromThen" rangeEnumFromThen + ] machInt :: CompiledCode Int machInt = plc (Proxy @"machInt") (1::Int) diff --git a/plutus-tx-plugin/test/Plugin/Functions/Spec.hs b/plutus-tx-plugin/test/Plugin/Functions/Spec.hs index 1a3738be2f2..a44c8172252 100644 --- a/plutus-tx-plugin/test/Plugin/Functions/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Functions/Spec.hs @@ -30,9 +30,9 @@ import PlutusTx.Test import Data.Proxy functions :: TestNested -functions = testNestedGhc "Functions" [ - recursiveFunctions - , unfoldings +functions = testNested "Functions" . pure $ testNestedGhc + [ recursiveFunctions + , unfoldings ] recursiveFunctions :: TestNested diff --git a/plutus-tx-plugin/test/Plugin/Laziness/Spec.hs b/plutus-tx-plugin/test/Plugin/Laziness/Spec.hs index 2d1928c4d9a..32dc5868ae5 100644 --- a/plutus-tx-plugin/test/Plugin/Laziness/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Laziness/Spec.hs @@ -25,10 +25,10 @@ import PlutusTx.Test import Data.Proxy laziness :: TestNested -laziness = testNestedGhc "Laziness" [ - goldenPir "joinError" joinErrorPir - , goldenUEval "joinErrorEval" [ toUPlc joinErrorPir, toUPlc $ plc (Proxy @"T") True, toUPlc $ plc (Proxy @"F") False] - , goldenPir "lazyDepUnit" lazyDepUnit +laziness = testNested "Laziness" . pure $ testNestedGhc + [ goldenPir "joinError" joinErrorPir + , goldenUEval "joinErrorEval" [ toUPlc joinErrorPir, toUPlc $ plc (Proxy @"T") True, toUPlc $ plc (Proxy @"F") False] + , goldenPir "lazyDepUnit" lazyDepUnit ] joinErrorPir :: CompiledCode (Bool -> Bool -> ()) diff --git a/plutus-tx-plugin/test/Plugin/NoTrace/Spec.hs b/plutus-tx-plugin/test/Plugin/NoTrace/Spec.hs index fd4a09ab823..7d3862ff9af 100644 --- a/plutus-tx-plugin/test/Plugin/NoTrace/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/NoTrace/Spec.hs @@ -13,15 +13,13 @@ import Plugin.NoTrace.Lib qualified as Lib import Plugin.NoTrace.WithoutTraces qualified as WithoutTraces import Plugin.NoTrace.WithTraces qualified as WithTraces import Test.Tasty (testGroup) -import Test.Tasty.Extras (TestNested) +import Test.Tasty.Extras (TestNested, embed) import Test.Tasty.HUnit (assertBool, testCase, (@=?)) noTrace :: TestNested -noTrace = pure do - testGroup - "remove-trace" - [ testGroup - "Trace calls are preserved" +noTrace = embed $ do + testGroup "remove-trace" + [ testGroup "Trace calls are preserved" [ testCase "trace-argument" $ 1 @=? countTraces WithTraces.traceArgument , testCase "trace-show" $ diff --git a/plutus-tx-plugin/test/Plugin/Optimization/Spec.hs b/plutus-tx-plugin/test/Plugin/Optimization/Spec.hs index 63e85767659..0e936ca77e6 100644 --- a/plutus-tx-plugin/test/Plugin/Optimization/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Optimization/Spec.hs @@ -18,8 +18,8 @@ import PlutusTx.Test () import Data.Proxy optimization :: TestNested -optimization = testNestedGhc "Optimization" [ - goldenUPlc "alwaysSucceeds" alwaysSucceeds +optimization = testNested "Optimization" Prelude.. Prelude.pure Prelude.$ testNestedGhc + [ goldenUPlc "alwaysSucceeds" alwaysSucceeds , goldenUPlc "alwaysFails" alwaysFails ] diff --git a/plutus-tx-plugin/test/Plugin/Patterns/Spec.hs b/plutus-tx-plugin/test/Plugin/Patterns/Spec.hs index 9ce7498a4e1..77653cd21b4 100644 --- a/plutus-tx-plugin/test/Plugin/Patterns/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Patterns/Spec.hs @@ -56,7 +56,7 @@ psymRec = plc (Proxy @"psymRec") ( ) patterns :: TestNested -patterns = testNestedGhc "Patterns" [ - goldenPirReadable "psym1" psym1 - , goldenPirReadable "psymRec" psymRec +patterns = testNested "Patterns" Prelude.. Prelude.pure Prelude.$ testNestedGhc + [ goldenPirReadable "psym1" psym1 + , goldenPirReadable "psymRec" psymRec ] diff --git a/plutus-tx-plugin/test/Plugin/Primitives/Spec.hs b/plutus-tx-plugin/test/Plugin/Primitives/Spec.hs index 79e256f7aa2..457e08b47a9 100644 --- a/plutus-tx-plugin/test/Plugin/Primitives/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Primitives/Spec.hs @@ -25,8 +25,8 @@ import PlutusTx.Test import Data.Proxy primitives :: TestNested -primitives = testNestedGhc "Primitives" [ - goldenPir "string" string +primitives = testNested "Primitives" . pure $ testNestedGhc + [ goldenPir "string" string , goldenPir "int" int , goldenPir "int2" int2 , goldenPir "bool" bool diff --git a/plutus-tx-plugin/test/Plugin/Profiling/Spec.hs b/plutus-tx-plugin/test/Plugin/Profiling/Spec.hs index 6a1f874ff12..999acbebbe2 100644 --- a/plutus-tx-plugin/test/Plugin/Profiling/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Profiling/Spec.hs @@ -29,8 +29,8 @@ import Data.Proxy (Proxy (Proxy)) import Prelude profiling :: TestNested -profiling = testNestedGhc "Profiling" [ - goldenPir "fib" fibTest +profiling = testNested "Profiling" . pure $ testNestedGhc + [ goldenPir "fib" fibTest , goldenUEvalLogs "fib4" [toUPlc fibTest, toUPlc $ plc (Proxy @"4") (4::Integer)] , goldenUEvalLogs "fact4" [toUPlc factTest, toUPlc $ plc (Proxy @"4") (4::Integer)] , goldenPir "addInt" addIntTest diff --git a/plutus-tx-plugin/test/Plugin/Strict/Spec.hs b/plutus-tx-plugin/test/Plugin/Strict/Spec.hs index 94ce6cd1226..f948ef9d333 100644 --- a/plutus-tx-plugin/test/Plugin/Strict/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Strict/Spec.hs @@ -23,8 +23,8 @@ import PlutusTx.Test import Data.Proxy strict :: TestNested -strict = testNestedGhc "Strict" [ - goldenPirReadable "strictAdd" strictAdd +strict = testNested "Strict" . pure $ testNestedGhc + [ goldenPirReadable "strictAdd" strictAdd , goldenPirReadable "strictAppend" strictAppend , goldenPirReadable "strictAppend2" strictAppend2 , goldenPirReadable "strictAppendString" strictAppendString diff --git a/plutus-tx-plugin/test/Plugin/Typeclasses/Spec.hs b/plutus-tx-plugin/test/Plugin/Typeclasses/Spec.hs index c7ee38c7226..74fc2112fa5 100644 --- a/plutus-tx-plugin/test/Plugin/Typeclasses/Spec.hs +++ b/plutus-tx-plugin/test/Plugin/Typeclasses/Spec.hs @@ -27,17 +27,17 @@ import PlutusTx.Test import Data.Proxy typeclasses :: TestNested -typeclasses = testNestedGhc "Typeclasses" [ - goldenPir "sizedBasic" sizedBasic - , goldenPir "sizedPair" sizedPair - , goldenPir "multiFunction" multiFunction - , goldenPir "defaultMethods" defaultMethods - , goldenPir "partialApplication" partialApplication - , goldenPir "sequenceTest" sequenceTest - , goldenPir "compareTest" compareTest - , goldenPir "concatTest" concatTest - , goldenPir "sumTest" sumTest - , goldenPir "fmapDefaultTest" fmapDefaultTest +typeclasses = testNested "Typeclasses" . pure $ testNestedGhc + [ goldenPir "sizedBasic" sizedBasic + , goldenPir "sizedPair" sizedPair + , goldenPir "multiFunction" multiFunction + , goldenPir "defaultMethods" defaultMethods + , goldenPir "partialApplication" partialApplication + , goldenPir "sequenceTest" sequenceTest + , goldenPir "compareTest" compareTest + , goldenPir "concatTest" concatTest + , goldenPir "sumTest" sumTest + , goldenPir "fmapDefaultTest" fmapDefaultTest ] class Sized a where diff --git a/plutus-tx-plugin/test/Spec.hs b/plutus-tx-plugin/test/Spec.hs index 5847ced49e5..843de915cbe 100644 --- a/plutus-tx-plugin/test/Spec.hs +++ b/plutus-tx-plugin/test/Spec.hs @@ -1,6 +1,7 @@ module Main (main) where import AsData.Budget.Spec qualified as AsData.Budget +import AssocMap.Spec qualified as AssocMap import Blueprint.Tests qualified import Budget.Spec qualified as Budget import IntegerLiterals.NoStrict.NegativeLiterals.Spec qualified @@ -14,32 +15,33 @@ import Plugin.Spec qualified as Plugin import ShortCircuit.Spec qualified as ShortCircuit import StdLib.Spec qualified as Lib import Strictness.Spec qualified as Strictness -import Test.Tasty (defaultMain, testGroup) -import Test.Tasty.Extras (TestNested, runTestNestedIn) +import Test.Tasty (TestTree, defaultMain) +import Test.Tasty.Extras (embed, runTestNested) import TH.Spec qualified as TH import Unicode.Spec qualified as Unicode main :: IO () -main = defaultMain $ runTestNestedIn ["test"] tests +main = defaultMain tests -tests :: TestNested +tests :: TestTree tests = - testGroup "tests" - <$> sequence - [ Plugin.tests - , IntegerLiterals.NoStrict.NegativeLiterals.Spec.tests - , IntegerLiterals.NoStrict.NoNegativeLiterals.Spec.tests - , IntegerLiterals.Strict.NegativeLiterals.Spec.tests - , IntegerLiterals.Strict.NoNegativeLiterals.Spec.tests - , IsData.tests - , Lift.tests - , TH.tests - , Lib.tests - , Budget.tests - , AsData.Budget.tests - , Optimization.tests - , pure ShortCircuit.tests - , Strictness.tests - , Blueprint.Tests.goldenTests - , pure Unicode.tests - ] + runTestNested ["test"] + [ Plugin.tests + , IntegerLiterals.NoStrict.NegativeLiterals.Spec.tests + , IntegerLiterals.NoStrict.NoNegativeLiterals.Spec.tests + , IntegerLiterals.Strict.NegativeLiterals.Spec.tests + , IntegerLiterals.Strict.NoNegativeLiterals.Spec.tests + , IsData.tests + , Lift.tests + , TH.tests + , Lib.tests + , Budget.tests + , AsData.Budget.tests + , Optimization.tests + , Strictness.tests + , Blueprint.Tests.goldenTests + , AssocMap.goldenTests + , embed ShortCircuit.tests + , embed Unicode.tests + , embed AssocMap.propertyTests + ] diff --git a/plutus-tx-plugin/test/StdLib/Spec.hs b/plutus-tx-plugin/test/StdLib/Spec.hs index 502e1659162..8d45fee88f4 100644 --- a/plutus-tx-plugin/test/StdLib/Spec.hs +++ b/plutus-tx-plugin/test/StdLib/Spec.hs @@ -20,7 +20,7 @@ import Hedgehog (MonadGen, Property) import Hedgehog qualified import Hedgehog.Gen qualified as Gen import Hedgehog.Range qualified as Range -import PlutusCore.Test (TestNested, goldenUEval, testNestedGhc) +import PlutusCore.Test (TestNested, embed, goldenUEval, testNested, testNestedGhc) import PlutusTx.Test (goldenPir) import Test.Tasty (TestName) import Test.Tasty.Hedgehog (testPropertyNamed) @@ -45,15 +45,15 @@ roundPlc = plc (Proxy @"roundPlc") Ratio.round tests :: TestNested tests = - testNestedGhc "StdLib" + testNested "StdLib" . pure $ testNestedGhc [ goldenUEval "ratioInterop" [ getPlcNoAnn roundPlc, snd (Lift.liftProgramDef (Ratio.fromGHC 3.75)) ] , testRatioProperty "round" Ratio.round round , testRatioProperty "truncate" Ratio.truncate truncate , testRatioProperty "abs" (fmap Ratio.toGHC Ratio.abs) abs - , pure $ testPropertyNamed "ord" "testOrd" testOrd - , pure $ testPropertyNamed "divMod" "testDivMod" testDivMod - , pure $ testPropertyNamed "quotRem" "testQuotRem" testQuotRem - , pure $ testPropertyNamed "Eq @Data" "eqData" eqData + , embed $ testPropertyNamed "ord" "testOrd" testOrd + , embed $ testPropertyNamed "divMod" "testDivMod" testDivMod + , embed $ testPropertyNamed "quotRem" "testQuotRem" testQuotRem + , embed $ testPropertyNamed "Eq @Data" "eqData" eqData , goldenPir "errorTrace" errorTrace ] @@ -67,7 +67,7 @@ tryHard :: (MonadIO m, NFData a) => a -> m (Maybe a) tryHard ~a = reoption <$> (liftIO $ try @SomeException $ evaluate $ force a) testRatioProperty :: (Show a, Eq a) => TestName -> (Ratio.Rational -> a) -> (Rational -> a) -> TestNested -testRatioProperty nm plutusFunc ghcFunc = pure $ testPropertyNamed nm (fromString nm) $ Hedgehog.property $ do +testRatioProperty nm plutusFunc ghcFunc = embed $ testPropertyNamed nm (fromString nm) $ Hedgehog.property $ do rat <- Hedgehog.forAll $ Gen.realFrac_ (Range.linearFrac (-10000) 100000) let ghcResult = ghcFunc rat plutusResult = plutusFunc $ Ratio.fromGHC rat diff --git a/plutus-tx-plugin/test/Strictness/9.6/lambda-default.eval.golden b/plutus-tx-plugin/test/Strictness/9.6/lambda-default.eval.golden index 1d4b8b27224..f2c04fe10eb 100644 --- a/plutus-tx-plugin/test/Strictness/9.6/lambda-default.eval.golden +++ b/plutus-tx-plugin/test/Strictness/9.6/lambda-default.eval.golden @@ -1,2 +1,2 @@ -An error has occurred: User error: +An error has occurred: The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'. \ No newline at end of file diff --git a/plutus-tx-plugin/test/Strictness/9.6/lambda-nonstrict.eval.golden b/plutus-tx-plugin/test/Strictness/9.6/lambda-nonstrict.eval.golden index 1d4b8b27224..f2c04fe10eb 100644 --- a/plutus-tx-plugin/test/Strictness/9.6/lambda-nonstrict.eval.golden +++ b/plutus-tx-plugin/test/Strictness/9.6/lambda-nonstrict.eval.golden @@ -1,2 +1,2 @@ -An error has occurred: User error: +An error has occurred: The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'. \ No newline at end of file diff --git a/plutus-tx-plugin/test/Strictness/9.6/lambda-strict.eval.golden b/plutus-tx-plugin/test/Strictness/9.6/lambda-strict.eval.golden index 1d4b8b27224..f2c04fe10eb 100644 --- a/plutus-tx-plugin/test/Strictness/9.6/lambda-strict.eval.golden +++ b/plutus-tx-plugin/test/Strictness/9.6/lambda-strict.eval.golden @@ -1,2 +1,2 @@ -An error has occurred: User error: +An error has occurred: The machine terminated because of an error, either from a built-in function or from an explicit use of 'error'. \ No newline at end of file diff --git a/plutus-tx-plugin/test/Strictness/Spec.hs b/plutus-tx-plugin/test/Strictness/Spec.hs index 29ad1e3ea98..6191122eaa0 100644 --- a/plutus-tx-plugin/test/Strictness/Spec.hs +++ b/plutus-tx-plugin/test/Strictness/Spec.hs @@ -15,8 +15,7 @@ import PlutusTx.TH (compile) tests :: TestNested tests = - testNestedGhc - "Strictness" + testNested "Strictness" . pure $ testNestedGhc [ goldenEvalCekCatch "lambda-default" [lambdaDefault `unsafeApplyCode` bot] , goldenPirReadable "lambda-default" lambdaDefault , goldenUPlcReadable "lambda-default" lambdaDefault diff --git a/plutus-tx-plugin/test/TH/Spec.hs b/plutus-tx-plugin/test/TH/Spec.hs index b6d78c1940b..5b0de5f5d14 100644 --- a/plutus-tx-plugin/test/TH/Spec.hs +++ b/plutus-tx-plugin/test/TH/Spec.hs @@ -36,18 +36,18 @@ someData :: (BuiltinData, BuiltinData, BuiltinData) someData = (toBuiltinData (One 1), toBuiltinData Two, toBuiltinData (Three ())) tests :: TestNested -tests = testNestedGhc "TH" - [ goldenPir "simple" simple - , goldenPir "power" powerPlc - , goldenPir "and" andPlc - , goldenEvalCek "all" [allPlc] - , goldenEvalCek "convertString" [convertString] - , goldenEvalCekLog "traceDirect" [traceDirect] - , goldenEvalCekLog "tracePrelude" [tracePrelude] - , goldenEvalCekLog "traceRepeatedly" [traceRepeatedly] - -- want to see the raw structure, so using Show - , nestedGoldenVsDoc "someData" "" (pretty $ Haskell.show someData) - ] +tests = testNested "TH" . pure $ testNestedGhc + [ goldenPir "simple" simple + , goldenPir "power" powerPlc + , goldenPir "and" andPlc + , goldenEvalCek "all" [allPlc] + , goldenEvalCek "convertString" [convertString] + , goldenEvalCekLog "traceDirect" [traceDirect] + , goldenEvalCekLog "tracePrelude" [tracePrelude] + , goldenEvalCekLog "traceRepeatedly" [traceRepeatedly] + -- want to see the raw structure, so using Show + , nestedGoldenVsDoc "someData" "" (pretty $ Haskell.show someData) + ] simple :: CompiledCode (Bool -> Integer) simple = $$(compile [|| \(x::Bool) -> if x then (1::Integer) else (2::Integer) ||]) diff --git a/plutus-tx-plugin/test/size/minus.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Additive/minus.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/minus.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Additive/minus.size.golden diff --git a/plutus-tx-plugin/test/size/negate-specialized.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Additive/negate-specialized.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/negate-specialized.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Additive/negate-specialized.size.golden diff --git a/plutus-tx-plugin/test/size/plus.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Additive/plus.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/plus.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Additive/plus.size.golden diff --git a/plutus-tx-plugin/test/size/zero.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Additive/zero.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/zero.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Additive/zero.size.golden diff --git a/plutus-tx-plugin/test/size/fromInteger.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Construction/fromInteger.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/fromInteger.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Construction/fromInteger.size.golden diff --git a/plutus-tx-plugin/test/size/ratio.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Construction/ratio.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/ratio.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Construction/ratio.size.golden diff --git a/plutus-tx-plugin/test/size/unsafeRatio.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Construction/unsafeRatio.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/unsafeRatio.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Construction/unsafeRatio.size.golden diff --git a/plutus-tx-plugin/test/size/equal.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Eq/equal.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/equal.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Eq/equal.size.golden diff --git a/plutus-tx-plugin/test/size/not-equal.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Eq/not-equal.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/not-equal.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Eq/not-equal.size.golden diff --git a/plutus-tx-plugin/test/size/one.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Multiplicative/one.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/one.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Multiplicative/one.size.golden diff --git a/plutus-tx-plugin/test/size/scale.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Multiplicative/scale.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/scale.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Multiplicative/scale.size.golden diff --git a/plutus-tx-plugin/test/size/times.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Multiplicative/times.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/times.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Multiplicative/times.size.golden diff --git a/plutus-tx-plugin/test/size/compare.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Ord/compare.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/compare.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Ord/compare.size.golden diff --git a/plutus-tx-plugin/test/size/greater-than-equal.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Ord/greater-than-equal.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/greater-than-equal.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Ord/greater-than-equal.size.golden diff --git a/plutus-tx-plugin/test/size/greater-than.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Ord/greater-than.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/greater-than.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Ord/greater-than.size.golden diff --git a/plutus-tx-plugin/test/size/less-than-equal.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Ord/less-than-equal.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/less-than-equal.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Ord/less-than-equal.size.golden diff --git a/plutus-tx-plugin/test/size/less-than.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Ord/less-than.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/less-than.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Ord/less-than.size.golden diff --git a/plutus-tx-plugin/test/size/max.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Ord/max.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/max.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Ord/max.size.golden diff --git a/plutus-tx-plugin/test/size/min.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Ord/min.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/min.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Ord/min.size.golden diff --git a/plutus-tx-plugin/test/size/abs-specialized.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Other/abs-specialized.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/abs-specialized.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Other/abs-specialized.size.golden diff --git a/plutus-tx-plugin/test/size/denominator.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Other/denominator.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/denominator.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Other/denominator.size.golden diff --git a/plutus-tx-plugin/test/size/numerator.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Other/numerator.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/numerator.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Other/numerator.size.golden diff --git a/plutus-tx-plugin/test/size/properFraction.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Other/properFraction.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/properFraction.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Other/properFraction.size.golden diff --git a/plutus-tx-plugin/test/size/recip.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Other/recip.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/recip.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Other/recip.size.golden diff --git a/plutus-tx-plugin/test/size/round.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Other/round.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/round.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Other/round.size.golden diff --git a/plutus-tx-plugin/test/size/truncate.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Other/truncate.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/truncate.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Other/truncate.size.golden diff --git a/plutus-tx-plugin/test/size/fromBuiltinData.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Serialization/fromBuiltinData.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/fromBuiltinData.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Serialization/fromBuiltinData.size.golden diff --git a/plutus-tx-plugin/test/size/toBuiltinData.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Serialization/toBuiltinData.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/toBuiltinData.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Serialization/toBuiltinData.size.golden diff --git a/plutus-tx-plugin/test/size/unsafeFromBuiltinData.size.golden b/plutus-tx-plugin/test/size/Golden/Rational/Serialization/unsafeFromBuiltinData.size.golden similarity index 100% rename from plutus-tx-plugin/test/size/unsafeFromBuiltinData.size.golden rename to plutus-tx-plugin/test/size/Golden/Rational/Serialization/unsafeFromBuiltinData.size.golden diff --git a/plutus-tx-plugin/test/size/Main.hs b/plutus-tx-plugin/test/size/Main.hs index 98b5167d589..19ff5982f0d 100644 --- a/plutus-tx-plugin/test/size/Main.hs +++ b/plutus-tx-plugin/test/size/Main.hs @@ -11,64 +11,64 @@ import PlutusTx.Ratio qualified as PlutusRatio import PlutusTx.Test import PlutusTx.TH (compile) import Prelude -import Test.Tasty (TestTree, defaultMain, testGroup) -import Test.Tasty.Extras (TestNested, runTestNestedIn) - -runTestNested :: TestNested -> TestTree -runTestNested = runTestNestedIn ["test", "size"] +import Test.Tasty (defaultMain, testGroup) +import Test.Tasty.Extras (runTestNested, testNested) main :: IO () -main = defaultMain . testGroup "Size regression tests" $ [ - testGroup "Rational" [ - testGroup "Eq" [ - runTestNested $ goldenSize "equal" ratEq, - runTestNested $ goldenSize "not-equal" ratNeq - ], - testGroup "Ord" [ - runTestNested $ goldenSize "compare" ratCompare, - runTestNested $ goldenSize "less-than-equal" ratLe, - runTestNested $ goldenSize "greater-than-equal" ratGe, - runTestNested $ goldenSize "less-than" ratLt, - runTestNested $ goldenSize "greater-than" ratGt, - runTestNested $ goldenSize "max" ratMax, - runTestNested $ goldenSize "min" ratMin - ], - testGroup "Additive" [ - runTestNested $ goldenSize "plus" ratPlus, - runTestNested $ goldenSize "zero" ratZero, - runTestNested $ goldenSize "minus" ratMinus, - runTestNested $ goldenSize "negate-specialized" ratNegate - ], - testGroup "Multiplicative" [ - runTestNested $ goldenSize "times" ratTimes, - runTestNested $ goldenSize "one" ratOne, - runTestNested $ goldenSize "scale" ratScale - ], - testGroup "Serialization" [ - runTestNested $ goldenSize "toBuiltinData" ratToBuiltin, - runTestNested $ goldenSize "fromBuiltinData" ratFromBuiltin, - runTestNested $ goldenSize "unsafeFromBuiltinData" ratUnsafeFromBuiltin - ], - testGroup "Construction" [ - runTestNested $ goldenSize "unsafeRatio" ratMkUnsafe, - runTestNested $ goldenSize "ratio" ratMkSafe, - runTestNested $ goldenSize "fromInteger" ratFromInteger - ], - testGroup "Other" [ - runTestNested $ goldenSize "numerator" ratNumerator, - runTestNested $ goldenSize "denominator" ratDenominator, - runTestNested $ goldenSize "round" ratRound, - runTestNested $ goldenSize "truncate" ratTruncate, - runTestNested $ goldenSize "properFraction" ratProperFraction, - runTestNested $ goldenSize "recip" ratRecip, - runTestNested $ goldenSize "abs-specialized" ratAbs - ], - testGroup "Comparison" [ - fitsUnder "negate" ("specialized", ratNegate) ("general", genNegate), - fitsUnder "abs" ("specialized", ratAbs) ("general", genAbs), - fitsUnder "scale" ("type class method", ratScale) ("equivalent in other primitives", genScale) +main = defaultMain $ testGroup "Size regression tests" + [ runTestNested ["test", "size", "Golden"] + [ testNested "Rational" + [ testNested "Eq" + [ goldenSize "equal" ratEq + , goldenSize "not-equal" ratNeq + ] + , testNested "Ord" + [ goldenSize "compare" ratCompare + , goldenSize "less-than-equal" ratLe + , goldenSize "greater-than-equal" ratGe + , goldenSize "less-than" ratLt + , goldenSize "greater-than" ratGt + , goldenSize "max" ratMax + , goldenSize "min" ratMin + ] + , testNested "Additive" + [ goldenSize "plus" ratPlus + , goldenSize "zero" ratZero + , goldenSize "minus" ratMinus + , goldenSize "negate-specialized" ratNegate + ] + , testNested "Multiplicative" + [ goldenSize "times" ratTimes + , goldenSize "one" ratOne + , goldenSize "scale" ratScale + ] + , testNested "Serialization" + [ goldenSize "toBuiltinData" ratToBuiltin + , goldenSize "fromBuiltinData" ratFromBuiltin + , goldenSize "unsafeFromBuiltinData" ratUnsafeFromBuiltin + ] + , testNested "Construction" + [ goldenSize "unsafeRatio" ratMkUnsafe + , goldenSize "ratio" ratMkSafe + , goldenSize "fromInteger" ratFromInteger + ] + , testNested "Other" + [ goldenSize "numerator" ratNumerator + , goldenSize "denominator" ratDenominator + , goldenSize "round" ratRound + , goldenSize "truncate" ratTruncate + , goldenSize "properFraction" ratProperFraction + , goldenSize "recip" ratRecip + , goldenSize "abs-specialized" ratAbs + ] + ] + ] + , testGroup "Comparison" + [ fitsUnder "negate" ("specialized", ratNegate) ("general", genNegate) + , fitsUnder "abs" ("specialized", ratAbs) ("general", genAbs) + , fitsUnder "scale" ("type class method", ratScale) + ("equivalent in other primitives", genScale) ] - ] ] -- Compiled definitions diff --git a/plutus-tx-test-util/LICENSE b/plutus-tx-test-util/LICENSE new file mode 100644 index 00000000000..0c8a80022ea --- /dev/null +++ b/plutus-tx-test-util/LICENSE @@ -0,0 +1,53 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/plutus-tx-test-util/NOTICE b/plutus-tx-test-util/NOTICE new file mode 100644 index 00000000000..318264c1a98 --- /dev/null +++ b/plutus-tx-test-util/NOTICE @@ -0,0 +1,14 @@ +Copyright 2024 Input Output Global, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/plutus-tx-test-util/plutus-tx-test-util.cabal b/plutus-tx-test-util/plutus-tx-test-util.cabal new file mode 100644 index 00000000000..6f4f06361a8 --- /dev/null +++ b/plutus-tx-test-util/plutus-tx-test-util.cabal @@ -0,0 +1,79 @@ +cabal-version: 3.0 +name: plutus-tx-test-util +version: 0.1.0.0 +description: Test utilities for Plutus Tx +homepage: https://github.com/IntersectMBO/plutus +bug-reports: https://github.com/IntersectMBO/plutus/issues +license: Apache-2.0 +license-files: + LICENSE + NOTICE + +author: Plutus Core Team +maintainer: ana.pantilie@iohk.io +build-type: Simple + +source-repository head + type: git + location: https://github.com/IntersectMBO/plutus + +-- Any files that use a `$$(...)` splice from the plugin should mention +-- `PlutusTx.Plugin()` somewhere, even if it's just `import PlutusTx.Plugin()`. +-- If none of your files mention the plugin explicitly then the code will still +-- compile (assuming that there's a dependence on `plutus-tx-plugin`) but you'll +-- get a warning that `plutus-tx-plugin` was not needed for compilation, and +-- that will cause a CI failure. + + +-- This should be used for anything that depends on plutus-tx-plugin, even +-- transitively. If you miss it out somewhere then nix will probably produce an +-- error message saying "the component is not buildable in the current +-- environment" if e.g. the nix shell supplies an unsupported GCH version. See +-- the section on GHC versions in `CONTRIBUTING.md`. +common ghc-version-support + if (impl(ghc <9.6) || impl(ghc >=9.7)) + buildable: False + +common lang + default-language: Haskell2010 + default-extensions: + DeriveFoldable + DeriveFunctor + DeriveGeneric + DeriveLift + DeriveTraversable + DerivingStrategies + DerivingVia + ExplicitForAll + FlexibleContexts + GeneralizedNewtypeDeriving + ImportQualifiedPost + ScopedTypeVariables + StandaloneDeriving + + -- See Note [-fno-full-laziness in Plutus Tx] + ghc-options: + -fno-specialise -fno-spec-constr -fno-strictness + -fno-ignore-interface-pragmas -fno-omit-interface-pragmas + -fno-unbox-strict-fields -fno-unbox-small-strict-fields + -fno-full-laziness + + ghc-options: + -Wall -Wnoncanonical-monad-instances -Wincomplete-uni-patterns + -Wincomplete-record-updates -Wredundant-constraints -Widentities + -Wunused-packages -Wmissing-deriving-strategies + +library + import: lang + exposed-modules: PlutusTx.Test.Util.Compiled + + -- other-modules: + -- other-extensions: + build-depends: + , base >=4.9 && <5 + , plutus-core ^>=1.28 + , plutus-tx ^>=1.28 + , text + + hs-source-dirs: testlib + default-language: Haskell2010 diff --git a/plutus-tx-test-util/testlib/PlutusTx/Test/Util/Compiled.hs b/plutus-tx-test-util/testlib/PlutusTx/Test/Util/Compiled.hs new file mode 100644 index 00000000000..f5804bca453 --- /dev/null +++ b/plutus-tx-test-util/testlib/PlutusTx/Test/Util/Compiled.hs @@ -0,0 +1,95 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE ViewPatterns #-} + +module PlutusTx.Test.Util.Compiled + ( Program + , Term + , toAnonDeBruijnTerm + , toAnonDeBruijnProg + , toNamedDeBruijnTerm + , compiledCodeToTerm + , haskellValueToTerm + , unsafeRunTermCek + , runTermCek + , cekResultMatchesHaskellValue + ) +where + +import PlutusTx qualified as Tx + +import PlutusCore qualified as PLC +import PlutusCore.Default +import PlutusCore.Evaluation.Machine.ExBudgetingDefaults qualified as PLC + +import UntypedPlutusCore qualified as UPLC +import UntypedPlutusCore.Evaluation.Machine.Cek as Cek + +import Data.Text (Text) + +type Term = UPLC.Term PLC.NamedDeBruijn DefaultUni DefaultFun () +type Program = UPLC.Program PLC.NamedDeBruijn DefaultUni DefaultFun () + +{- | Given a DeBruijn-named term, give every variable the name "v". If we later + call unDeBruijn, that will rename the variables to things like "v123", where + 123 is the relevant de Bruijn index.-} +toNamedDeBruijnTerm + :: UPLC.Term UPLC.DeBruijn DefaultUni DefaultFun () + -> UPLC.Term UPLC.NamedDeBruijn DefaultUni DefaultFun () +toNamedDeBruijnTerm = UPLC.termMapNames UPLC.fakeNameDeBruijn + +{- | Remove the textual names from a NamedDeBruijn term -} +toAnonDeBruijnTerm + :: Term + -> UPLC.Term UPLC.DeBruijn DefaultUni DefaultFun () +toAnonDeBruijnTerm = UPLC.termMapNames UPLC.unNameDeBruijn + +toAnonDeBruijnProg + :: UPLC.Program UPLC.NamedDeBruijn DefaultUni DefaultFun () + -> UPLC.Program UPLC.DeBruijn DefaultUni DefaultFun () +toAnonDeBruijnProg (UPLC.Program () ver body) = + UPLC.Program () ver $ toAnonDeBruijnTerm body + +{- | Just extract the body of a program wrapped in a 'CompiledCodeIn'. We use this a lot. -} +compiledCodeToTerm + :: Tx.CompiledCodeIn DefaultUni DefaultFun a -> Term +compiledCodeToTerm (Tx.getPlcNoAnn -> UPLC.Program _ _ body) = body + +{- | Lift a Haskell value to a PLC term. The constraints get a bit out of control + if we try to do this over an arbitrary universe.-} +haskellValueToTerm + :: Tx.Lift DefaultUni a => a -> Term +haskellValueToTerm = compiledCodeToTerm . Tx.liftCodeDef + +{- | Just run a term to obtain an `EvaluationResult` (used for tests etc.) -} +unsafeRunTermCek :: Term -> EvaluationResult Term +unsafeRunTermCek = + unsafeToEvaluationResult + . (\(res, _, _) -> res) + . runCekDeBruijn PLC.defaultCekParameters Cek.restrictingEnormous Cek.noEmitter + +-- | Just run a term. +runTermCek :: + Term -> + ( Either (CekEvaluationException UPLC.NamedDeBruijn DefaultUni DefaultFun) Term + , [Text] + ) +runTermCek = + (\(res, _, logs) -> (res, logs)) + . runCekDeBruijn PLC.defaultCekParameters Cek.restrictingEnormous Cek.logEmitter + +{- | Evaluate a PLC term and check that the result matches a given Haskell value + (perhaps obtained by running the Haskell code that the term was compiled + from). We evaluate the lifted Haskell value as well, because lifting may + produce reducible terms. The function is polymorphic in the comparison + operator so that we can use it with both HUnit Assertions and QuickCheck + Properties. -} +cekResultMatchesHaskellValue + :: Tx.Lift DefaultUni a + => Term + -> (EvaluationResult Term -> EvaluationResult Term -> b) + -> a + -> b +cekResultMatchesHaskellValue term matches value = + (unsafeRunTermCek term) `matches` (unsafeRunTermCek $ haskellValueToTerm value) diff --git a/plutus-tx/changelog.d/20240516_215552_ana.pantilie95_data_assoclist.md b/plutus-tx/changelog.d/20240516_215552_ana.pantilie95_data_assoclist.md new file mode 100644 index 00000000000..73cd8f8e8af --- /dev/null +++ b/plutus-tx/changelog.d/20240516_215552_ana.pantilie95_data_assoclist.md @@ -0,0 +1,7 @@ +### Added + +- Added `Data.AssocList.Map` module which provides a map implementation based on `Data`. + +### Changed + +- The PlutusTx `These` type had the Haskell implementations of `Show`, `Eq` and `Ord` instances instead of PlutusTx ones. This has been fixed. diff --git a/plutus-tx/plutus-tx.cabal b/plutus-tx/plutus-tx.cabal index fa3513d81f2..151b3a8d978 100644 --- a/plutus-tx/plutus-tx.cabal +++ b/plutus-tx/plutus-tx.cabal @@ -75,6 +75,7 @@ library PlutusTx.Builtins.Internal PlutusTx.Code PlutusTx.Coverage + PlutusTx.Data.AssocMap PlutusTx.Either PlutusTx.Enum PlutusTx.Eq @@ -211,6 +212,7 @@ test-suite plutus-tx-test , hedgehog , hedgehog-fn , lens + , mtl , plutus-core:{plutus-core, plutus-core-testlib} ^>=1.28 , plutus-tx ^>=1.28 , pretty-show @@ -219,4 +221,3 @@ test-suite plutus-tx-test , tasty-hedgehog , tasty-hunit , text - , transformers diff --git a/plutus-tx/src/PlutusTx/AssocMap.hs b/plutus-tx/src/PlutusTx/AssocMap.hs index 12cfce5684c..d5c6c800150 100644 --- a/plutus-tx/src/PlutusTx/AssocMap.hs +++ b/plutus-tx/src/PlutusTx/AssocMap.hs @@ -39,7 +39,7 @@ module PlutusTx.AssocMap ( import Prelude qualified as Haskell -import PlutusTx.Builtins qualified as P +import PlutusTx.Builtins qualified as P hiding (null) import PlutusTx.Builtins.Internal qualified as BI import PlutusTx.IsData import PlutusTx.Lift (makeLift) diff --git a/plutus-tx/src/PlutusTx/Builtins.hs b/plutus-tx/src/PlutusTx/Builtins.hs index cfdd8cbe23e..5e9550d9bb6 100644 --- a/plutus-tx/src/PlutusTx/Builtins.hs +++ b/plutus-tx/src/PlutusTx/Builtins.hs @@ -68,6 +68,7 @@ module PlutusTx.Builtins ( -- * Pairs , pairToPair -- * Lists + , null , matchList , matchList' , headMaybe @@ -388,6 +389,10 @@ trace = BI.trace encodeUtf8 :: BuiltinString -> BuiltinByteString encodeUtf8 = BI.encodeUtf8 +{-# INLINABLE null #-} +null :: forall a. BI.BuiltinList a -> Bool +null l = fromOpaque (BI.null l) + {-# INLINABLE matchList #-} matchList :: forall a r . BI.BuiltinList a -> (() -> r) -> (a -> BI.BuiltinList a -> r) -> r matchList l nilCase consCase = BI.chooseList l nilCase (\_ -> consCase (BI.head l) (BI.tail l)) () diff --git a/plutus-tx/src/PlutusTx/Data/AssocMap.hs b/plutus-tx/src/PlutusTx/Data/AssocMap.hs new file mode 100644 index 00000000000..48712bd3274 --- /dev/null +++ b/plutus-tx/src/PlutusTx/Data/AssocMap.hs @@ -0,0 +1,412 @@ +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE ViewPatterns #-} + +module PlutusTx.Data.AssocMap ( + Map, + lookup, + member, + insert, + delete, + singleton, + empty, + null, + toList, + toBuiltinList, + safeFromList, + unsafeFromList, + unsafeFromBuiltinList, + noDuplicateKeys, + all, + any, + union, + unionWith, + ) where + +import PlutusTx.Builtins qualified as P +import PlutusTx.Builtins.Internal qualified as BI +import PlutusTx.IsData qualified as P +import PlutusTx.Lift (makeLift) +import PlutusTx.Prelude hiding (all, any, null, toList, uncons) +import PlutusTx.These + + +import Prelude qualified as Haskell + +{- | A map associating keys and values backed by `P.BuiltinData`. + +This implementation has the following characteristics: + + * The `P.toBuiltinData` and `P.unsafeFromBuiltinData` operations are no-op. + * Other operations are slower than @PlutusTx.AssocMap.Map@, although equality + checks on keys can be faster due to `P.equalsData`. + * Many operations involve converting the keys and\/or values to\/from `P.BuiltinData`. + +Therefore this implementation is likely a better choice than "PlutusTx.AssocMap.Map" +if it is part of a data type defined using @asData@, and the key and value types +have efficient `P.toBuiltinData` and `P.unsafeFromBuiltinData` operations (e.g., they +are primitive types or types defined using @asData@). + +A `Map` is considered well-defined if it has no duplicate keys. Most operations +preserve the definedness of the resulting `Map` unless otherwise noted. +It is important to observe that, in comparison to standard map implementations, +this implementation provides slow lookup and update operations because it is based +on a list representation. +-} +newtype Map k a = Map (BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData)) + deriving stock (Haskell.Eq, Haskell.Show) + +instance P.ToData (Map k a) where + {-# INLINEABLE toBuiltinData #-} + toBuiltinData (Map d) = BI.mkMap d + +instance P.FromData (Map k a) where + {-# INLINABLE fromBuiltinData #-} + fromBuiltinData = Just . Map . BI.unsafeDataAsMap + +instance P.UnsafeFromData (Map k a) where + {-# INLINABLE unsafeFromBuiltinData #-} + unsafeFromBuiltinData = Map . BI.unsafeDataAsMap + +{-# INLINEABLE lookup #-} +-- | Look up the value corresponding to the key. +-- If the `Map` is not well-defined, the result is the value associated with +-- the left-most occurrence of the key in the list. +-- This operation is O(n). +lookup :: forall k a. (P.ToData k, P.UnsafeFromData a) => k -> Map k a -> Maybe a +lookup (P.toBuiltinData -> k) (Map m) = P.unsafeFromBuiltinData <$> lookup' k m + +lookup' + :: BuiltinData + -> BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) + -> Maybe BuiltinData +lookup' k m = go m + where + go xs = + P.matchList + xs + (\() -> Nothing) + ( \hd -> + let k' = BI.fst hd + in if P.equalsData k k' + then \_ -> Just (BI.snd hd) + else go + ) + +{-# INLINEABLE member #-} +-- | Check if the key is in the `Map`. +member :: forall k a. (P.ToData k) => k -> Map k a -> Bool +member (P.toBuiltinData -> k) (Map m) = member' k m + +member' :: BuiltinData -> BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) -> Bool +member' k = go + where + go :: BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) -> Bool + go xs = + P.matchList + xs + (\() -> False) + ( \hd -> + let k' = BI.fst hd + in if P.equalsData k k' + then \_ -> True + else go + ) + +{-# INLINEABLE insert #-} +-- | Insert a key-value pair into the `Map`. If the key is already present, +-- the value is updated. +insert :: forall k a. (P.ToData k, P.ToData a) => k -> a -> Map k a -> Map k a +insert (P.toBuiltinData -> k) (P.toBuiltinData -> a) (Map m) = Map $ insert' k a m + +insert' + :: BuiltinData + -> BuiltinData + -> BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) + -> BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) +insert' k a = go + where + go :: + BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) -> + BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) + go xs = + P.matchList + xs + (\() -> BI.mkCons (BI.mkPairData k a) nil) + ( \hd tl -> + let k' = BI.fst hd + in if P.equalsData k k' + then BI.mkCons (BI.mkPairData k a) tl + else BI.mkCons hd (go tl) + ) + +{-# INLINEABLE delete #-} +-- | Delete a key value pair from the `Map`. +-- If the `Map` is not well-defined, it deletes the pair associated with the +-- left-most occurrence of the key in the list. +delete :: forall k a. (P.ToData k) => k -> Map k a -> Map k a +delete (P.toBuiltinData -> k) (Map m) = Map $ delete' k m + +delete' :: + BuiltinData -> + BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) -> + BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) +delete' k = go + where + go :: + BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) -> + BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) + go xs = + P.matchList + xs + (\() -> nil) + ( \hd tl -> + let k' = BI.fst hd + in if P.equalsData k k' + then tl + else BI.mkCons hd (go tl) + ) + +{-# INLINEABLE singleton #-} +-- | Create an `Map` with a single key-value pair. +singleton :: forall k a. (P.ToData k, P.ToData a) => k -> a -> Map k a +singleton (P.toBuiltinData -> k) (P.toBuiltinData -> a) = + Map $ BI.mkCons (BI.mkPairData k a) nil + +{-# INLINEABLE empty #-} +-- | An empty `Map`. +empty :: forall k a. Map k a +empty = Map nil + +{-# INLINEABLE null #-} +-- | Check if the `Map` is empty. +null :: forall k a. Map k a -> Bool +null (Map m) = P.null m + +{-# INLINEABLE safeFromList #-} +-- | Create an `Map` from a list of key-value pairs. +-- In case of duplicates, this function will keep only one entry (the one that precedes). +-- In other words, this function de-duplicates the input list. +safeFromList :: forall k a . (P.ToData k, P.ToData a) =>[(k, a)] -> Map k a +safeFromList = + Map + . toOpaque + . foldr (uncurry go) [] + where + go k v [] = [(P.toBuiltinData k, P.toBuiltinData v)] + go k v ((k', v') : rest) = + if P.toBuiltinData k == k' + then (P.toBuiltinData k, P.toBuiltinData v) : go k v rest + else (P.toBuiltinData k', P.toBuiltinData v') : go k v rest + +{-# INLINEABLE unsafeFromList #-} +-- | Unsafely create an 'Map' from a list of pairs. +-- This should _only_ be applied to lists which have been checked to not +-- contain duplicate keys, otherwise the resulting 'Map' will contain +-- conflicting entries (two entries sharing the same key), and therefore be ill-defined. +unsafeFromList :: (P.ToData k, P.ToData a) => [(k, a)] -> Map k a +unsafeFromList = + Map + . toOpaque + . PlutusTx.Prelude.map (\(k, a) -> (P.toBuiltinData k, P.toBuiltinData a)) + +{-# INLINEABLE noDuplicateKeys #-} +-- | Check if the `Map` is well-defined. Warning: this operation is O(n^2). +noDuplicateKeys :: forall k a. Map k a -> Bool +noDuplicateKeys (Map m) = go m + where + go :: BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) -> Bool + go xs = + P.matchList + xs + (\() -> True) + ( \hd tl -> + let k = BI.fst hd + in if member k (Map tl) then False else go tl + ) + +{-# INLINEABLE all #-} +--- | Check if all values in the `Map` satisfy the predicate. +all :: forall k a. (P.UnsafeFromData a) => (a -> Bool) -> Map k a -> Bool +all p (Map m) = go m + where + go :: BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) -> Bool + go xs = + P.matchList + xs + (\() -> True) + ( \hd -> + let a = P.unsafeFromBuiltinData (BI.snd hd) + in if p a then go else \_ -> False + ) + +{-# INLINEABLE any #-} +-- | Check if any value in the `Map` satisfies the predicate. +any :: forall k a. (P.UnsafeFromData a) => (a -> Bool) -> Map k a -> Bool +any p (Map m) = go m + where + go :: BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) -> Bool + go xs = + P.matchList + xs + (\() -> False) + ( \hd -> + let a = P.unsafeFromBuiltinData (BI.snd hd) + in if p a then \_ -> True else go + ) + +{-# INLINEABLE union #-} + +-- | Combine two 'Map's into one. It saves both values if the key is present in both maps. +union :: + forall k a b. + (P.UnsafeFromData a, P.UnsafeFromData b, P.ToData a, P.ToData b) => + Map k a -> + Map k b -> + Map k (These a b) +union (Map ls) (Map rs) = Map res + where + goLeft xs = + P.matchList + xs + (\() -> nil) + ( \hd tl -> + let k = BI.fst hd + v = BI.snd hd + v' = case lookup' k rs of + Just r -> + P.toBuiltinData + ( These + (P.unsafeFromBuiltinData v) + (P.unsafeFromBuiltinData r) + :: These a b + ) + Nothing -> + P.toBuiltinData (This (P.unsafeFromBuiltinData v) :: These a b) + in BI.mkCons (BI.mkPairData k v') (goLeft tl) + ) + + goRight xs = + P.matchList + xs + (\() -> nil) + ( \hd tl -> + let k = BI.fst hd + v = BI.snd hd + v' = case lookup' k ls of + Just r -> + P.toBuiltinData + ( These + (P.unsafeFromBuiltinData v) + (P.unsafeFromBuiltinData r) + :: These a b + ) + Nothing -> + P.toBuiltinData (That (P.unsafeFromBuiltinData v) :: These a b) + in BI.mkCons (BI.mkPairData k v') (goRight tl) + ) + + res = goLeft ls `safeAppend` goRight rs + + safeAppend xs1 xs2 = + P.matchList + xs1 + (\() -> xs2) + ( \hd tl -> + let k = BI.fst hd + v = BI.snd hd + in insert' k v (safeAppend tl xs2) + ) + +-- | Combine two 'Map's with the given combination function. +unionWith :: + forall k a. + (P.UnsafeFromData a, P.ToData a) => + (a -> a -> a) -> + Map k a -> + Map k a -> + Map k a +unionWith f (Map ls) (Map rs) = + Map res + where + ls' :: BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) + ls' = go ls + where + go xs = + P.matchList + xs + (\() -> nil) + ( \hd tl -> + let k' = BI.fst hd + v' = BI.snd hd + v'' = case lookup' k' rs of + Just r -> + P.toBuiltinData + (f (P.unsafeFromBuiltinData v') (P.unsafeFromBuiltinData r)) + Nothing -> v' + in BI.mkCons (BI.mkPairData k' v'') (go tl) + ) + + rs' :: BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) + rs' = go rs + where + go xs = + P.matchList + xs + (\() -> nil) + ( \hd tl -> + let k' = BI.fst hd + tl' = go tl + in if member' k' ls + then tl' + else BI.mkCons hd tl' + ) + + res :: BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) + res = go rs' ls' + where + go acc xs = + P.matchList + xs + (\() -> acc) + (\hd -> go (BI.mkCons hd acc)) + +{-# INLINEABLE toList #-} +-- | Convert the `Map` to a list of key-value pairs. This operation is O(n). +-- See 'toBuiltinList' for a more efficient alternative. +toList :: (P.UnsafeFromData k, P.UnsafeFromData a) => Map k a -> [(k, a)] +toList d = go (toBuiltinList d) + where + go xs = + P.matchList + xs + (\() -> []) + ( \hd tl -> + (P.unsafeFromBuiltinData (BI.fst hd), P.unsafeFromBuiltinData (BI.snd hd)) + : go tl + ) + +{-# INLINEABLE toBuiltinList #-} +-- | Convert the `Map` to a `P.BuiltinList` of key-value pairs. This operation is O(1). +toBuiltinList :: Map k a -> BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) +toBuiltinList (Map d) = d + +{-# INLINEABLE unsafeFromBuiltinList #-} +-- | Unsafely create an 'Map' from a `P.BuiltinList` of key-value pairs. +-- This function is unsafe because it assumes that the elements of the list can be safely +-- decoded from their 'BuiltinData' representation. +unsafeFromBuiltinList :: + forall k a. + BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) -> + Map k a +unsafeFromBuiltinList = Map + +{-# INLINEABLE nil #-} +-- | An empty `P.BuiltinList` of key-value pairs. +nil :: BI.BuiltinList (BI.BuiltinPair BuiltinData BuiltinData) +nil = BI.mkNilPairData BI.unitval + +makeLift ''Map diff --git a/plutus-tx/src/PlutusTx/Eq.hs b/plutus-tx/src/PlutusTx/Eq.hs index 0e7b921dfad..de6e87926c7 100644 --- a/plutus-tx/src/PlutusTx/Eq.hs +++ b/plutus-tx/src/PlutusTx/Eq.hs @@ -4,6 +4,7 @@ module PlutusTx.Eq (Eq(..), (/=)) where import PlutusTx.Bool import PlutusTx.Builtins qualified as Builtins import PlutusTx.Either (Either (..)) +import PlutusTx.These import Prelude (Maybe (..)) {- HLINT ignore -} @@ -77,3 +78,10 @@ instance Eq () where instance (Eq a, Eq b) => Eq (a, b) where {-# INLINABLE (==) #-} (a, b) == (a', b') = a == a' && b == b' + +instance (Eq a, Eq b) => Eq (These a b) where + {-# INLINABLE (==) #-} + (This a) == (This a') = a == a' + (That b) == (That b') = b == b' + (These a b) == (These a' b') = a == a' && b == b' + _ == _ = False diff --git a/plutus-tx/src/PlutusTx/IsData/Instances.hs b/plutus-tx/src/PlutusTx/IsData/Instances.hs index 0da5b45e979..ad0dbf5b5d4 100644 --- a/plutus-tx/src/PlutusTx/IsData/Instances.hs +++ b/plutus-tx/src/PlutusTx/IsData/Instances.hs @@ -12,12 +12,14 @@ import PlutusTx.Bool (Bool (..)) import PlutusTx.Either (Either (..)) import PlutusTx.IsData.TH (makeIsDataIndexed, unstableMakeIsData) import PlutusTx.Maybe (Maybe (..)) +import PlutusTx.These (These (..)) -- While these types should be stable, we really don't want them changing, so index -- them explicitly to be sure. makeIsDataIndexed ''Bool [('False,0),('True,1)] makeIsDataIndexed ''Maybe [('Just,0),('Nothing,1)] makeIsDataIndexed ''Either [('Left,0),('Right,1)] +makeIsDataIndexed ''These [('This,0),('That,1),('These,2)] -- Okay to use unstableMakeIsData here since there's only one alternative and we're sure -- that will never change. diff --git a/plutus-tx/src/PlutusTx/Lift.hs b/plutus-tx/src/PlutusTx/Lift.hs index 01530ca9b4d..acff1543917 100644 --- a/plutus-tx/src/PlutusTx/Lift.hs +++ b/plutus-tx/src/PlutusTx/Lift.hs @@ -220,7 +220,7 @@ typeCheckAgainst -> m () typeCheckAgainst p (PLC.Program _ v plcTerm) = do -- See Note [Checking the type of a term with Typeable] - term <- PIR.embed <$> PLC.rename plcTerm + term <- PIR.embedTerm <$> PLC.rename plcTerm -- We need to run Def *before* applying to the term, otherwise we may refer to abstract -- types and we won't match up with the term. idFun <- liftQuote $ runDefT () $ do diff --git a/plutus-tx/src/PlutusTx/Lift/Instances.hs b/plutus-tx/src/PlutusTx/Lift/Instances.hs index d5132023e16..98832e7b576 100644 --- a/plutus-tx/src/PlutusTx/Lift/Instances.hs +++ b/plutus-tx/src/PlutusTx/Lift/Instances.hs @@ -18,6 +18,7 @@ import PlutusTx.Bool (Bool (..)) import PlutusTx.Either (Either (..)) import PlutusTx.Lift.TH import PlutusTx.Maybe (Maybe (..)) +import PlutusTx.These (These (..)) -- Standard types -- These need to be in a separate file for TH staging reasons @@ -25,6 +26,7 @@ import PlutusTx.Maybe (Maybe (..)) makeLift ''Bool makeLift ''Maybe makeLift ''Either +makeLift ''These makeLift ''[] makeLift ''() -- include a few tuple instances for convenience diff --git a/plutus-tx/src/PlutusTx/Ord.hs b/plutus-tx/src/PlutusTx/Ord.hs index 210826488df..f92baf2e2bb 100644 --- a/plutus-tx/src/PlutusTx/Ord.hs +++ b/plutus-tx/src/PlutusTx/Ord.hs @@ -11,6 +11,7 @@ import PlutusTx.Bool (Bool (..)) import PlutusTx.Builtins qualified as Builtins import PlutusTx.Either (Either (..)) import PlutusTx.Eq +import PlutusTx.These import Prelude (Maybe (..), Ordering (..)) {- HLINT ignore -} @@ -123,3 +124,17 @@ instance (Ord a, Ord b) => Ord (a, b) where case compare a a' of EQ -> compare b b' c -> c + +instance (Ord a, Ord b) => Ord (These a b) where + {-# INLINABLE compare #-} + compare (This a) (This a') = compare a a' + compare (That b) (That b') = compare b b' + compare (These a b) (These a' b') = + case compare a a' of + EQ -> compare b b' + c -> c + compare (This _) _ = LT + compare (That _) (This _) = GT + compare (That _) (These _ _) = LT + compare (These _ _) (This _) = GT + compare (These _ _) (That _) = GT diff --git a/plutus-tx/src/PlutusTx/Show.hs b/plutus-tx/src/PlutusTx/Show.hs index 5b16c1ebf9c..e8d57caedbc 100644 --- a/plutus-tx/src/PlutusTx/Show.hs +++ b/plutus-tx/src/PlutusTx/Show.hs @@ -25,6 +25,7 @@ import PlutusTx.List (foldr) import PlutusTx.Maybe import PlutusTx.Prelude hiding (foldr) import PlutusTx.Show.TH +import PlutusTx.These instance Show Builtins.Integer where {-# INLINEABLE showsPrec #-} @@ -160,3 +161,4 @@ deriveShow ''(,,,,,,,,,,,,,,,,,,,,,,,,,) deriveShow ''(,,,,,,,,,,,,,,,,,,,,,,,,,,) deriveShow ''Maybe deriveShow ''Either +deriveShow ''These diff --git a/plutus-tx/src/PlutusTx/These.hs b/plutus-tx/src/PlutusTx/These.hs index 4ec6742e344..124a37d6102 100644 --- a/plutus-tx/src/PlutusTx/These.hs +++ b/plutus-tx/src/PlutusTx/These.hs @@ -1,6 +1,9 @@ -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE LambdaCase #-} + {-# OPTIONS_GHC -Wno-name-shadowing #-} {-# OPTIONS_GHC -fno-omit-interface-pragmas #-} + module PlutusTx.These( These(..) , these diff --git a/plutus-tx/test/Show/gadt.show.golden b/plutus-tx/test/Show/Golden/gadt.show.golden similarity index 100% rename from plutus-tx/test/Show/gadt.show.golden rename to plutus-tx/test/Show/Golden/gadt.show.golden diff --git a/plutus-tx/test/Show/infix-type-2.show.golden b/plutus-tx/test/Show/Golden/infix-type-2.show.golden similarity index 100% rename from plutus-tx/test/Show/infix-type-2.show.golden rename to plutus-tx/test/Show/Golden/infix-type-2.show.golden diff --git a/plutus-tx/test/Show/infix-type.show.golden b/plutus-tx/test/Show/Golden/infix-type.show.golden similarity index 100% rename from plutus-tx/test/Show/infix-type.show.golden rename to plutus-tx/test/Show/Golden/infix-type.show.golden diff --git a/plutus-tx/test/Show/poly.show.golden b/plutus-tx/test/Show/Golden/poly.show.golden similarity index 100% rename from plutus-tx/test/Show/poly.show.golden rename to plutus-tx/test/Show/Golden/poly.show.golden diff --git a/plutus-tx/test/Show/product-type-2.show.golden b/plutus-tx/test/Show/Golden/product-type-2.show.golden similarity index 100% rename from plutus-tx/test/Show/product-type-2.show.golden rename to plutus-tx/test/Show/Golden/product-type-2.show.golden diff --git a/plutus-tx/test/Show/product-type.show.golden b/plutus-tx/test/Show/Golden/product-type.show.golden similarity index 100% rename from plutus-tx/test/Show/product-type.show.golden rename to plutus-tx/test/Show/Golden/product-type.show.golden diff --git a/plutus-tx/test/Show/record-type.show.golden b/plutus-tx/test/Show/Golden/record-type.show.golden similarity index 100% rename from plutus-tx/test/Show/record-type.show.golden rename to plutus-tx/test/Show/Golden/record-type.show.golden diff --git a/plutus-tx/test/Show/sum-type-1.show.golden b/plutus-tx/test/Show/Golden/sum-type-1.show.golden similarity index 100% rename from plutus-tx/test/Show/sum-type-1.show.golden rename to plutus-tx/test/Show/Golden/sum-type-1.show.golden diff --git a/plutus-tx/test/Show/sum-type-2.show.golden b/plutus-tx/test/Show/Golden/sum-type-2.show.golden similarity index 100% rename from plutus-tx/test/Show/sum-type-2.show.golden rename to plutus-tx/test/Show/Golden/sum-type-2.show.golden diff --git a/plutus-tx/test/Show/Spec.hs b/plutus-tx/test/Show/Spec.hs index e0cd9d00b79..f79086075b7 100644 --- a/plutus-tx/test/Show/Spec.hs +++ b/plutus-tx/test/Show/Spec.hs @@ -9,7 +9,7 @@ import PlutusTx.Builtins import PlutusTx.Builtins.Internal qualified as BI import PlutusTx.Show -import Control.Monad.Trans.Reader as Reader +import Control.Monad.Reader as Reader import Data.ByteString.Base16 qualified as Base16 import Data.ByteString.Char8 qualified as Char8 import Data.Text qualified as Text @@ -41,7 +41,7 @@ goldenShow :: forall a. Show a => TestName -> a -> TestNested goldenShow name x = do path <- ask let fp = foldr () (name ++ ".show.golden") path - pure $ goldenVsText name fp . fromBuiltin $ show x + embed $ goldenVsText name fp . fromBuiltin $ show x data ProductD = ProductC Integer [Bool] deriveShow ''ProductD @@ -70,8 +70,7 @@ deriveShow ''GadtD propertyTests :: TestTree propertyTests = - testGroup - "PlutusTx.Show property-based tests" + testGroup "PlutusTx.Show property-based tests" [ testPropertyNamed "PlutusTx.Show @Integer" "PlutusTx.Show @Integer" @@ -82,10 +81,9 @@ propertyTests = showByteStringBase16 ] -goldenTests :: TestNested +goldenTests :: TestTree goldenTests = - testNested - "Show" + runTestNested ["test", "Show", "Golden"] [ goldenShow "product-type" (ProductC 3 [True, False]) , goldenShow "product-type-2" ((:-:) [-300] False) , goldenShow "sum-type-1" SumC1 diff --git a/plutus-tx/test/Spec.hs b/plutus-tx/test/Spec.hs index a3616397edd..00bd78c9f59 100644 --- a/plutus-tx/test/Spec.hs +++ b/plutus-tx/test/Spec.hs @@ -28,7 +28,6 @@ import Prelude hiding (Enum (..), Rational, negate, recip) import Rational.Laws (lawsTests) import Show.Spec qualified import Test.Tasty (TestTree, defaultMain, testGroup) -import Test.Tasty.Extras (runTestNestedIn) import Test.Tasty.Hedgehog (testPropertyNamed) import Test.Tasty.HUnit (Assertion, assertFailure, testCase, (@?=)) @@ -45,7 +44,7 @@ tests = testGroup "plutus-tx" [ , listTests , lawsTests , Show.Spec.propertyTests - , runTestNestedIn ["test"] Show.Spec.goldenTests + , Show.Spec.goldenTests , Blueprint.Definition.Spec.tests ] diff --git a/scripts/prepare-bins.sh b/scripts/prepare-bins.sh new file mode 100755 index 00000000000..fada66a996f --- /dev/null +++ b/scripts/prepare-bins.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env nix-shell +#! nix-shell -i bash --pure +#! nix-shell -p bash git nix upx + +set -euo pipefail + +banner='\n +Lets prepare binaries for a release:\n + 1. Build `pir`\n + 2. Compress `pir` with `upx`\n + 3. Build `uplc`\n + 4. Compress `uplc` with `upx`\n +' + +echo -e $banner + +echo "Building pir..." + +nix build ".#hydraJobs.x86_64-linux.musl64.ghc96.pir" + +echo "Compressing pir..." + +upx -9 ./result/bin/pir -o pir-x86_64-linux-ghc96 --force-overwrite + +echo "Building uplc..." + +nix build ".#hydraJobs.x86_64-linux.musl64.ghc96.uplc" + +echo "Compressing uplc..." + +upx -9 ./result/bin/uplc -o uplc-x86_64-linux-ghc96 --force-overwrite