From b481080f50d77cf210b2f0e3e6c0ae9f95a45956 Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Tue, 14 Apr 2026 11:04:33 +0200 Subject: [PATCH 01/10] Add failing test: BuiltinCasing crashes when join point exposes Data type GHC optimizer can produce join points with naked PlutusCore.Data.Data in the type signature. The plugin with BuiltinCasing tries to compile Data as a regular ADT, walks B ByteString -> BS Addr# and crashes. Minimal trigger: caseList' applied twice to the same value in a module without BuiltinCasing, then compiled from a BuiltinCasing module. --- plutus-tx-plugin/plutus-tx-plugin.cabal | 1 + plutus-tx-plugin/test/BuiltinCasing/Lib.hs | 24 +++++++++++++++++++++ plutus-tx-plugin/test/BuiltinCasing/Spec.hs | 4 +++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 plutus-tx-plugin/test/BuiltinCasing/Lib.hs diff --git a/plutus-tx-plugin/plutus-tx-plugin.cabal b/plutus-tx-plugin/plutus-tx-plugin.cabal index 8b00accf204..d0a1bcc7689 100644 --- a/plutus-tx-plugin/plutus-tx-plugin.cabal +++ b/plutus-tx-plugin/plutus-tx-plugin.cabal @@ -140,6 +140,7 @@ test-suite plutus-tx-plugin-tests Budget.Spec Budget.WithGHCOptimisations Budget.WithoutGHCOptimisations + BuiltinCasing.Lib BuiltinCasing.Spec BuiltinList.Budget.Spec BuiltinList.NoCasing.Spec diff --git a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs new file mode 100644 index 00000000000..7d7591c7a6b --- /dev/null +++ b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs @@ -0,0 +1,24 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} +{-# OPTIONS_GHC -fplugin PlutusTx.Plugin #-} +{-# OPTIONS_GHC -fplugin-opt PlutusTx.Plugin:target-version=1.1.0 #-} + +{-# HLINT ignore #-} + +module BuiltinCasing.Lib (failsToCompile) where + +import PlutusTx +import PlutusTx.Builtins.Internal (unitval) +import PlutusTx.Data.List (caseList') +import PlutusTx.Prelude + +failsToCompile :: BuiltinData -> BuiltinUnit +failsToCompile bd = + case toBuiltinData (firstOf items) of + _ -> case toBuiltinData (firstOf items) of + _ -> unitval + where + items = unsafeFromBuiltinData bd + firstOf = caseList' Nothing (\(h :: BuiltinData) _t -> Just h) diff --git a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs index 798e207fc6c..f7187933e7f 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs @@ -10,6 +10,7 @@ module BuiltinCasing.Spec where import Test.Tasty.Extras +import BuiltinCasing.Lib qualified as Lib import PlutusTx (compile) import PlutusTx.Builtins (caseInteger, caseList, casePair) import PlutusTx.Builtins.Internal (chooseUnit, unitval) @@ -30,7 +31,7 @@ integerABC :: Integer -> BuiltinString integerABC i = caseInteger i ["a", "b", "c"] head :: BuiltinList Bool -> Bool -head xs = caseList (\_ -> error ()) (\x _ -> x) xs +head = caseList (\_ -> error ()) (\x _ -> x) tests :: TestNested tests = @@ -42,4 +43,5 @@ tests = , goldenUPlcReadable "addPair" $$(compile [||addPair||]) , goldenUPlcReadable "integerABC" $$(compile [||integerABC||]) , goldenUPlcReadable "head" $$(compile [||head||]) + , goldenUPlcReadable "failsToCompile" $$(compile [||Lib.failsToCompile||]) ] From ae30bbb050dffe544984236605d1c2c0eeaa3e1f Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Tue, 14 Apr 2026 18:07:16 +0200 Subject: [PATCH 02/10] Fix BuiltinCasing crash on GHC.Prim.Addr# (#7716) GHC's simplifier unconditionally unwraps single-constructor types. For `data BuiltinData = BuiltinData ~Data`, this exposes `Data` in join point type signatures. The plugin with BuiltinCasing then tries to compile Data as a regular ADT, walks B ByteString -> BS Addr#, and crashes. Fix: add a second (unreachable) constructor to BuiltinData so GHC cannot apply case-of-single-constructor. A COMPLETE pragma ensures existing pattern matches remain exhaustive without warnings. --- plutus-tx/src/PlutusTx/Builtins/Internal.hs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/plutus-tx/src/PlutusTx/Builtins/Internal.hs b/plutus-tx/src/PlutusTx/Builtins/Internal.hs index 4a6993ae2e7..46e41a7e2f0 100644 --- a/plutus-tx/src/PlutusTx/Builtins/Internal.hs +++ b/plutus-tx/src/PlutusTx/Builtins/Internal.hs @@ -104,6 +104,17 @@ we can't handle, but also so that GHC doesn't look inside and try and get clever In particular, we need to use 'data' rather than 'newtype' even for simple wrappers, otherwise GHC gets very keen to optimize through the newtype and e.g. our users see 'Addr#' popping up everywhere. + +Additionally, single-constructor types must have a second (unreachable) constructor. +GHC's simplifier unconditionally unwraps single-constructor types via +case-of-known-constructor, which can expose the inner type (e.g. PLC.Data inside +BuiltinData) in join point type signatures. The plugin with BuiltinCasing then +tries to compile the inner type as a regular ADT, potentially reaching unsupported +primitives like Addr# (#7716). + +A second constructor prevents this — GHC cannot case-simplify multi-constructor +types. The extra constructor is never constructed; COMPLETE pragmas tell GHC +that matching on the real constructor alone is exhaustive. -} error :: BuiltinUnit -> a @@ -531,9 +542,13 @@ that you want to be representable on-chain. For off-chain usage, there are conversion functions 'builtinDataToData' and 'dataToBuiltinData', but note that these will not work on-chain. -} -data BuiltinData = BuiltinData ~PLC.Data + +-- See Note [Opaque builtin types] +data BuiltinData = BuiltinData ~PLC.Data | BuiltinDataUnreachable deriving stock (Data, Generic) +{-# COMPLETE BuiltinData #-} + instance Haskell.Show BuiltinData where show (BuiltinData d) = show d instance Haskell.Eq BuiltinData where From f7efeb3e56a045df733c995e83fe48f7c02e6e28 Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Tue, 14 Apr 2026 18:30:30 +0200 Subject: [PATCH 03/10] Rename test, regenerate goldens Rename failsToCompile -> caseListTwice (it compiles now). Update golden files affected by the BuiltinData second constructor. --- .../BuiltinCasing/9.6/caseListTwice.golden.uplc | 16 ++++++++++++++++ .../test/BuiltinCasing/9.6/head.golden.uplc | 2 +- plutus-tx-plugin/test/BuiltinCasing/Lib.hs | 11 ++++++++--- plutus-tx-plugin/test/BuiltinCasing/Spec.hs | 2 +- .../StageViolation/9.6/builtinData.golden.uplc | 14 ++------------ 5 files changed, 28 insertions(+), 17 deletions(-) create mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwice.golden.uplc diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwice.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwice.golden.uplc new file mode 100644 index 00000000000..262ae1ede39 --- /dev/null +++ b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwice.golden.uplc @@ -0,0 +1,16 @@ +(program + 1.1.0 + (\bd -> + (\nt -> + (\`$j` -> + case + (case nt [(\x eta -> constr 0 [x]), (constr 1 [])]) + [ (\arg -> + (\ds -> force `$j`) (constrData 0 (force mkCons arg []))) + , (force `$j`) ]) + (delay + (case + (case nt [(\x eta -> constr 0 [x]), (constr 1 [])]) + [ (\arg -> (\ds -> ()) (constrData 0 (force mkCons arg []))) + , () ]))) + (unListData bd))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/head.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/head.golden.uplc index d4a7a6050e5..e65a842ea71 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/9.6/head.golden.uplc +++ b/plutus-tx-plugin/test/BuiltinCasing/9.6/head.golden.uplc @@ -1 +1 @@ -(program 1.1.0 (\xs -> case xs [(\x xs ds -> x), (\ds -> error)] (constr 0 []))) \ No newline at end of file +(program 1.1.0 (\l -> case l [(\x xs ds -> x), (\ds -> error)] (constr 0 []))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs index 7d7591c7a6b..4cf9e7b79d7 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs @@ -7,15 +7,20 @@ {-# HLINT ignore #-} -module BuiltinCasing.Lib (failsToCompile) where +module BuiltinCasing.Lib (caseListTwice) where import PlutusTx import PlutusTx.Builtins.Internal (unitval) import PlutusTx.Data.List (caseList') import PlutusTx.Prelude -failsToCompile :: BuiltinData -> BuiltinUnit -failsToCompile bd = +{-| Regression test for #7716. Calling caseList' twice on the same value +makes GHC's simplifier create a join point whose type exposes the raw +PlutusCore.Data.Data inside BuiltinData. Without the second constructor +on BuiltinData (see Note [Opaque builtin types]), the plugin with +BuiltinCasing would try to compile Data as an ADT and crash on Addr#. -} +caseListTwice :: BuiltinData -> BuiltinUnit +caseListTwice bd = case toBuiltinData (firstOf items) of _ -> case toBuiltinData (firstOf items) of _ -> unitval diff --git a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs index f7187933e7f..e2d238038eb 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs @@ -43,5 +43,5 @@ tests = , goldenUPlcReadable "addPair" $$(compile [||addPair||]) , goldenUPlcReadable "integerABC" $$(compile [||integerABC||]) , goldenUPlcReadable "head" $$(compile [||head||]) - , goldenUPlcReadable "failsToCompile" $$(compile [||Lib.failsToCompile||]) + , goldenUPlcReadable "caseListTwice" $$(compile [||Lib.caseListTwice||]) ] diff --git a/plutus-tx-plugin/test/StageViolation/9.6/builtinData.golden.uplc b/plutus-tx-plugin/test/StageViolation/9.6/builtinData.golden.uplc index 8f8725dda3d..0af27d0c901 100644 --- a/plutus-tx-plugin/test/StageViolation/9.6/builtinData.golden.uplc +++ b/plutus-tx-plugin/test/StageViolation/9.6/builtinData.golden.uplc @@ -1,12 +1,2 @@ -Error: Unsupported feature: Cannot construct a value of type: PlutusTx.Builtins.Internal.BuiltinData - - This error often indicates a stage violation in Plinth compilation. - Variables inside compile quotations must be either: - • Top-level variables, or - • Bound inside the quotation itself - - Common causes: - • Using a function defined in a 'where' clause: move it to the top level - • Referencing local variables from outside the quotation - - Note: GHC can generate these unexpectedly, you may need '-fno-strictness', '-fno-specialise', '-fno-spec-constr', '-fno-unbox-strict-fields', or '-fno-unbox-small-strict-fields'. \ No newline at end of file +Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable validator + OtherCon [] \ No newline at end of file From ad474964c1da930a7a46026a7077017791dc3745 Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Wed, 15 Apr 2026 12:40:26 +0200 Subject: [PATCH 04/10] Add stage violation hint for local variables without unfoldings When a local variable (e.g. from a where-clause) has no unfolding, show the stage violation help message instead of a generic FreeVariableError. --- plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs | 17 +++++++++++++++-- .../mutualRecursionUnfoldingsLocal.golden.uplc | 13 +++++++++++-- .../StageViolation/9.6/builtinData.golden.uplc | 13 +++++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs b/plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs index 7ba8793f0e5..474e09c5669 100644 --- a/plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs +++ b/plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs @@ -1257,11 +1257,24 @@ compileExpr mloc e = do -- The "unfolding template" includes things with normal unfoldings and also dictionary functions Just unfolding -> hoistExpr n unfolding Nothing -> - throwSd FreeVariableError $ - "Variable" + throwSd + (if GHC.isLocalId n then UnsupportedError else FreeVariableError) + $ "Variable" GHC.<+> GHC.ppr n GHC.$+$ (GHC.ppr $ GHC.idDetails n) GHC.$+$ (GHC.ppr $ GHC.realIdUnfolding n) + GHC.$+$ if GHC.isLocalId n + then + "" + GHC.$+$ "This error often indicates a stage violation in Plinth compilation." + GHC.$+$ "Variables inside compile quotations must be either:" + GHC.$+$ " • Top-level variables, or" + GHC.$+$ " • Bound inside the quotation itself" + GHC.$+$ "" + GHC.$+$ "Common causes:" + GHC.$+$ " • Using a function defined in a 'where' clause: move it to the top level" + GHC.$+$ " • Referencing local variables from outside the quotation" + else "" -- arg can be a type here, in which case it's a type instantiation l `GHC.App` GHC.Type t -> do l' <- compileExpr Nothing l diff --git a/plutus-tx-plugin/test/Plugin/Errors/9.6/mutualRecursionUnfoldingsLocal.golden.uplc b/plutus-tx-plugin/test/Plugin/Errors/9.6/mutualRecursionUnfoldingsLocal.golden.uplc index 8e0ade0637f..aeeee0b2961 100644 --- a/plutus-tx-plugin/test/Plugin/Errors/9.6/mutualRecursionUnfoldingsLocal.golden.uplc +++ b/plutus-tx-plugin/test/Plugin/Errors/9.6/mutualRecursionUnfoldingsLocal.golden.uplc @@ -1,2 +1,11 @@ -Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable Plugin.Errors.Spec.oddDirectLocal - OtherCon [] \ No newline at end of file +Error: Unsupported feature: Variable Plugin.Errors.Spec.oddDirectLocal + OtherCon [] + + This error often indicates a stage violation in Plinth compilation. + Variables inside compile quotations must be either: + • Top-level variables, or + • Bound inside the quotation itself + + Common causes: + • Using a function defined in a 'where' clause: move it to the top level + • Referencing local variables from outside the quotation \ No newline at end of file diff --git a/plutus-tx-plugin/test/StageViolation/9.6/builtinData.golden.uplc b/plutus-tx-plugin/test/StageViolation/9.6/builtinData.golden.uplc index 0af27d0c901..9bc7309e5e0 100644 --- a/plutus-tx-plugin/test/StageViolation/9.6/builtinData.golden.uplc +++ b/plutus-tx-plugin/test/StageViolation/9.6/builtinData.golden.uplc @@ -1,2 +1,11 @@ -Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable validator - OtherCon [] \ No newline at end of file +Error: Unsupported feature: Variable validator + OtherCon [] + + This error often indicates a stage violation in Plinth compilation. + Variables inside compile quotations must be either: + • Top-level variables, or + • Bound inside the quotation itself + + Common causes: + • Using a function defined in a 'where' clause: move it to the top level + • Referencing local variables from outside the quotation \ No newline at end of file From ed93a46f11aae2fad35bd8d2fb922c7182f16c03 Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Wed, 15 Apr 2026 13:10:10 +0200 Subject: [PATCH 05/10] Add BuiltinByteString regression test for opaque type join points Same pattern as caseListTwice but with BuiltinByteString. Currently does not crash (ByteString is handled differently by the simplifier), but kept as a regression test for future GHC changes. --- .../9.6/caseListTwiceByteString.golden.uplc | 10 +++++++ plutus-tx-plugin/test/BuiltinCasing/Lib.hs | 28 +++++++++++++++---- plutus-tx-plugin/test/BuiltinCasing/Spec.hs | 1 + 3 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc new file mode 100644 index 00000000000..fad30394a49 --- /dev/null +++ b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc @@ -0,0 +1,10 @@ +(program + 1.1.0 + (\bd -> + (\cse -> ()) + (case + (case + (unListData bd) + [(\x eta -> constr 0 [(unBData x)]), (constr 1 [])]) + [ (\arg -> constrData 0 (force mkCons (bData arg) [])) + , (Constr 1 []) ]))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs index 4cf9e7b79d7..2b09eefc630 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs @@ -7,18 +7,25 @@ {-# HLINT ignore #-} -module BuiltinCasing.Lib (caseListTwice) where +module BuiltinCasing.Lib + ( caseListTwice + , caseListTwiceByteString + ) where import PlutusTx -import PlutusTx.Builtins.Internal (unitval) +import PlutusTx.Builtins.Internal (BuiltinByteString, BuiltinUnit, unitval) import PlutusTx.Data.List (caseList') import PlutusTx.Prelude -{-| Regression test for #7716. Calling caseList' twice on the same value +{-| Regression tests for #7716. Calling caseList' twice on the same value makes GHC's simplifier create a join point whose type exposes the raw -PlutusCore.Data.Data inside BuiltinData. Without the second constructor -on BuiltinData (see Note [Opaque builtin types]), the plugin with -BuiltinCasing would try to compile Data as an ADT and crash on Addr#. -} +inner type of the opaque builtin wrapper. Without the second constructor +(see Note [Opaque builtin types]), the plugin with BuiltinCasing would try +to compile the inner type as an ADT and crash on Addr#. + +Each test below targets a different opaque builtin type: + - caseListTwice: BuiltinData (wraps PlutusCore.Data.Data) + - caseListTwiceByteString: BuiltinByteString (wraps ByteString -> BS Addr#) -} caseListTwice :: BuiltinData -> BuiltinUnit caseListTwice bd = case toBuiltinData (firstOf items) of @@ -27,3 +34,12 @@ caseListTwice bd = where items = unsafeFromBuiltinData bd firstOf = caseList' Nothing (\(h :: BuiltinData) _t -> Just h) + +caseListTwiceByteString :: BuiltinData -> BuiltinUnit +caseListTwiceByteString bd = + case toBuiltinData (firstOf items) of + _ -> case toBuiltinData (firstOf items) of + _ -> unitval + where + items = unsafeFromBuiltinData bd + firstOf = caseList' Nothing (\(h :: BuiltinByteString) _t -> Just h) diff --git a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs index e2d238038eb..6fb07cbc287 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs @@ -44,4 +44,5 @@ tests = , goldenUPlcReadable "integerABC" $$(compile [||integerABC||]) , goldenUPlcReadable "head" $$(compile [||head||]) , goldenUPlcReadable "caseListTwice" $$(compile [||Lib.caseListTwice||]) + , goldenUPlcReadable "caseListTwiceByteString" $$(compile [||Lib.caseListTwiceByteString||]) ] From f4cbd6085cca19774cb398155616c06626ab3109 Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Wed, 15 Apr 2026 13:31:18 +0200 Subject: [PATCH 06/10] Add BuiltinString regression test, use BuiltinList for non-Data types BuiltinByteString and BuiltinString don't have UnsafeFromData instances, so tests use BuiltinList and Builtins.Internal.caseList' directly instead of Data.List.caseList'. --- .../9.6/caseListTwiceByteString.golden.uplc | 16 +++---- .../9.6/caseListTwiceString.golden.uplc | 10 ++++ plutus-tx-plugin/test/BuiltinCasing/Lib.hs | 48 ++++++++++++++----- plutus-tx-plugin/test/BuiltinCasing/Spec.hs | 1 + 4 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceString.golden.uplc diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc index fad30394a49..d53268e7f32 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc +++ b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc @@ -1,10 +1,10 @@ (program 1.1.0 - (\bd -> - (\cse -> ()) - (case - (case - (unListData bd) - [(\x eta -> constr 0 [(unBData x)]), (constr 1 [])]) - [ (\arg -> constrData 0 (force mkCons (bData arg) [])) - , (Constr 1 []) ]))) \ No newline at end of file + (\items -> + case + (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])]) + [ (\ds -> + (\wild -> ()) + (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])])) + , ((\wild -> ()) + (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])])) ])) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceString.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceString.golden.uplc new file mode 100644 index 00000000000..d53268e7f32 --- /dev/null +++ b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceString.golden.uplc @@ -0,0 +1,10 @@ +(program + 1.1.0 + (\items -> + case + (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])]) + [ (\ds -> + (\wild -> ()) + (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])])) + , ((\wild -> ()) + (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])])) ])) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs index 2b09eefc630..a63bedd05bd 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs @@ -10,11 +10,19 @@ module BuiltinCasing.Lib ( caseListTwice , caseListTwiceByteString + , caseListTwiceString ) where import PlutusTx -import PlutusTx.Builtins.Internal (BuiltinByteString, BuiltinUnit, unitval) -import PlutusTx.Data.List (caseList') +import PlutusTx.Builtins.Internal + ( BuiltinByteString + , BuiltinList + , BuiltinString + , BuiltinUnit + , caseList' + , unitval + ) +import PlutusTx.Data.List qualified as Data.List import PlutusTx.Prelude {-| Regression tests for #7716. Calling caseList' twice on the same value @@ -23,9 +31,10 @@ inner type of the opaque builtin wrapper. Without the second constructor (see Note [Opaque builtin types]), the plugin with BuiltinCasing would try to compile the inner type as an ADT and crash on Addr#. -Each test below targets a different opaque builtin type: +Each test targets a different opaque builtin type: - caseListTwice: BuiltinData (wraps PlutusCore.Data.Data) - - caseListTwiceByteString: BuiltinByteString (wraps ByteString -> BS Addr#) -} + - caseListTwiceByteString: BuiltinByteString (wraps ByteString -> BS Addr#) + - caseListTwiceString: BuiltinString (wraps Text -> Array# Char#) -} caseListTwice :: BuiltinData -> BuiltinUnit caseListTwice bd = case toBuiltinData (firstOf items) of @@ -33,13 +42,28 @@ caseListTwice bd = _ -> unitval where items = unsafeFromBuiltinData bd - firstOf = caseList' Nothing (\(h :: BuiltinData) _t -> Just h) + firstOf = Data.List.caseList' Nothing (\(h :: BuiltinData) _t -> Just h) -caseListTwiceByteString :: BuiltinData -> BuiltinUnit -caseListTwiceByteString bd = - case toBuiltinData (firstOf items) of - _ -> case toBuiltinData (firstOf items) of - _ -> unitval +caseListTwiceByteString :: BuiltinList BuiltinByteString -> BuiltinUnit +caseListTwiceByteString items = + case firstOf items of + Nothing -> case firstOf items of + Nothing -> unitval + Just _ -> unitval + Just _ -> case firstOf items of + Nothing -> unitval + Just _ -> unitval where - items = unsafeFromBuiltinData bd - firstOf = caseList' Nothing (\(h :: BuiltinByteString) _t -> Just h) + firstOf = caseList' Nothing (\(h :: BuiltinByteString) _ -> Just h) + +caseListTwiceString :: BuiltinList BuiltinString -> BuiltinUnit +caseListTwiceString items = + case firstOf items of + Nothing -> case firstOf items of + Nothing -> unitval + Just _ -> unitval + Just _ -> case firstOf items of + Nothing -> unitval + Just _ -> unitval + where + firstOf = caseList' Nothing (\(h :: BuiltinString) _ -> Just h) diff --git a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs index 6fb07cbc287..0a7c01772cc 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs @@ -45,4 +45,5 @@ tests = , goldenUPlcReadable "head" $$(compile [||head||]) , goldenUPlcReadable "caseListTwice" $$(compile [||Lib.caseListTwice||]) , goldenUPlcReadable "caseListTwiceByteString" $$(compile [||Lib.caseListTwiceByteString||]) + , goldenUPlcReadable "caseListTwiceString" $$(compile [||Lib.caseListTwiceString||]) ] From 0ac46653d70e060d35448ddadddc46352e3b9791 Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Wed, 15 Apr 2026 13:46:14 +0200 Subject: [PATCH 07/10] Rename tests to useTwice* scheme, add BuiltinString regression test useTwiceData (was caseListTwice), useTwiceByteString, useTwiceString. ByteString and String tests pass opaque types directly as arguments instead of wrapping in BuiltinList. --- .../9.6/caseListTwiceByteString.golden.uplc | 10 --- .../9.6/caseListTwiceString.golden.uplc | 10 --- .../9.6/useTwiceByteString.golden.uplc | 1 + ...e.golden.uplc => useTwiceData.golden.uplc} | 0 .../9.6/useTwiceString.golden.uplc | 1 + plutus-tx-plugin/test/BuiltinCasing/Lib.hs | 68 +++++++------------ plutus-tx-plugin/test/BuiltinCasing/Spec.hs | 6 +- 7 files changed, 30 insertions(+), 66 deletions(-) delete mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc delete mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceString.golden.uplc create mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceByteString.golden.uplc rename plutus-tx-plugin/test/BuiltinCasing/9.6/{caseListTwice.golden.uplc => useTwiceData.golden.uplc} (100%) create mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceString.golden.uplc diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc deleted file mode 100644 index d53268e7f32..00000000000 --- a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceByteString.golden.uplc +++ /dev/null @@ -1,10 +0,0 @@ -(program - 1.1.0 - (\items -> - case - (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])]) - [ (\ds -> - (\wild -> ()) - (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])])) - , ((\wild -> ()) - (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])])) ])) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceString.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceString.golden.uplc deleted file mode 100644 index d53268e7f32..00000000000 --- a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwiceString.golden.uplc +++ /dev/null @@ -1,10 +0,0 @@ -(program - 1.1.0 - (\items -> - case - (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])]) - [ (\ds -> - (\wild -> ()) - (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])])) - , ((\wild -> ()) - (case items [(\ds ds -> constr 0 [ds]), (constr 1 [])])) ])) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceByteString.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceByteString.golden.uplc new file mode 100644 index 00000000000..a34c3c8d93b --- /dev/null +++ b/plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceByteString.golden.uplc @@ -0,0 +1 @@ +(program 1.1.0 (\bs -> (\cse -> ()) (appendByteString bs bs))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwice.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceData.golden.uplc similarity index 100% rename from plutus-tx-plugin/test/BuiltinCasing/9.6/caseListTwice.golden.uplc rename to plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceData.golden.uplc diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceString.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceString.golden.uplc new file mode 100644 index 00000000000..8edcd9fff96 --- /dev/null +++ b/plutus-tx-plugin/test/BuiltinCasing/9.6/useTwiceString.golden.uplc @@ -0,0 +1 @@ +(program 1.1.0 (\s -> (\cse -> ()) (appendString s s))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs index a63bedd05bd..284707cc434 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs @@ -8,35 +8,29 @@ {-# HLINT ignore #-} module BuiltinCasing.Lib - ( caseListTwice - , caseListTwiceByteString - , caseListTwiceString + ( useTwiceData + , useTwiceByteString + , useTwiceString ) where import PlutusTx -import PlutusTx.Builtins.Internal - ( BuiltinByteString - , BuiltinList - , BuiltinString - , BuiltinUnit - , caseList' - , unitval - ) +import PlutusTx.Builtins.Internal (BuiltinByteString, BuiltinString, BuiltinUnit, unitval) +import PlutusTx.Builtins.Internal qualified as BI import PlutusTx.Data.List qualified as Data.List import PlutusTx.Prelude -{-| Regression tests for #7716. Calling caseList' twice on the same value -makes GHC's simplifier create a join point whose type exposes the raw -inner type of the opaque builtin wrapper. Without the second constructor -(see Note [Opaque builtin types]), the plugin with BuiltinCasing would try -to compile the inner type as an ADT and crash on Addr#. +{-| Regression tests for #7716. The simplifier unwraps single-constructor +opaque types via case-of-known-constructor, potentially exposing inner types +(Data, ByteString, Text) in join point type signatures. Without the second +constructor (see Note [Opaque builtin types]), the plugin with BuiltinCasing +would try to compile the inner type as a regular ADT and crash. Each test targets a different opaque builtin type: - - caseListTwice: BuiltinData (wraps PlutusCore.Data.Data) - - caseListTwiceByteString: BuiltinByteString (wraps ByteString -> BS Addr#) - - caseListTwiceString: BuiltinString (wraps Text -> Array# Char#) -} -caseListTwice :: BuiltinData -> BuiltinUnit -caseListTwice bd = + - useTwiceData: BuiltinData (wraps PlutusCore.Data.Data) + - useTwiceByteString: BuiltinByteString (wraps ByteString -> BS Addr#) + - useTwiceString: BuiltinString (wraps Text -> Array# Char#) -} +useTwiceData :: BuiltinData -> BuiltinUnit +useTwiceData bd = case toBuiltinData (firstOf items) of _ -> case toBuiltinData (firstOf items) of _ -> unitval @@ -44,26 +38,14 @@ caseListTwice bd = items = unsafeFromBuiltinData bd firstOf = Data.List.caseList' Nothing (\(h :: BuiltinData) _t -> Just h) -caseListTwiceByteString :: BuiltinList BuiltinByteString -> BuiltinUnit -caseListTwiceByteString items = - case firstOf items of - Nothing -> case firstOf items of - Nothing -> unitval - Just _ -> unitval - Just _ -> case firstOf items of - Nothing -> unitval - Just _ -> unitval - where - firstOf = caseList' Nothing (\(h :: BuiltinByteString) _ -> Just h) +useTwiceByteString :: BuiltinByteString -> BuiltinUnit +useTwiceByteString bs = + case BI.appendByteString bs bs of + _ -> case BI.appendByteString bs bs of + _ -> unitval -caseListTwiceString :: BuiltinList BuiltinString -> BuiltinUnit -caseListTwiceString items = - case firstOf items of - Nothing -> case firstOf items of - Nothing -> unitval - Just _ -> unitval - Just _ -> case firstOf items of - Nothing -> unitval - Just _ -> unitval - where - firstOf = caseList' Nothing (\(h :: BuiltinString) _ -> Just h) +useTwiceString :: BuiltinString -> BuiltinUnit +useTwiceString s = + case BI.appendString s s of + _ -> case BI.appendString s s of + _ -> unitval diff --git a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs index 0a7c01772cc..756dc75e0ef 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Spec.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Spec.hs @@ -43,7 +43,7 @@ tests = , goldenUPlcReadable "addPair" $$(compile [||addPair||]) , goldenUPlcReadable "integerABC" $$(compile [||integerABC||]) , goldenUPlcReadable "head" $$(compile [||head||]) - , goldenUPlcReadable "caseListTwice" $$(compile [||Lib.caseListTwice||]) - , goldenUPlcReadable "caseListTwiceByteString" $$(compile [||Lib.caseListTwiceByteString||]) - , goldenUPlcReadable "caseListTwiceString" $$(compile [||Lib.caseListTwiceString||]) + , goldenUPlcReadable "useTwiceData" $$(compile [||Lib.useTwiceData||]) + , goldenUPlcReadable "useTwiceByteString" $$(compile [||Lib.useTwiceByteString||]) + , goldenUPlcReadable "useTwiceString" $$(compile [||Lib.useTwiceString||]) ] From 257ca7ff7dfb603514613f349c8fda4cd5ed2092 Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Thu, 16 Apr 2026 09:23:18 +0200 Subject: [PATCH 08/10] Fix unused imports warning in Lib.hs --- plutus-tx-plugin/test/BuiltinCasing/Lib.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs index 284707cc434..ca48bb09949 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/Lib.hs +++ b/plutus-tx-plugin/test/BuiltinCasing/Lib.hs @@ -14,7 +14,7 @@ module BuiltinCasing.Lib ) where import PlutusTx -import PlutusTx.Builtins.Internal (BuiltinByteString, BuiltinString, BuiltinUnit, unitval) +import PlutusTx.Builtins.Internal (unitval) import PlutusTx.Builtins.Internal qualified as BI import PlutusTx.Data.List qualified as Data.List import PlutusTx.Prelude From 13fda0274891a9225f88f7b3155d34bb68fab1d1 Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Thu, 16 Apr 2026 09:25:35 +0200 Subject: [PATCH 09/10] Add changelog entry for BuiltinData fix --- ...2502_yuriy.lazaryev_fix_builtin_casing_addr_joinpoint.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 plutus-tx/changelog.d/20260416_092502_yuriy.lazaryev_fix_builtin_casing_addr_joinpoint.md diff --git a/plutus-tx/changelog.d/20260416_092502_yuriy.lazaryev_fix_builtin_casing_addr_joinpoint.md b/plutus-tx/changelog.d/20260416_092502_yuriy.lazaryev_fix_builtin_casing_addr_joinpoint.md new file mode 100644 index 00000000000..d8fc5a5a243 --- /dev/null +++ b/plutus-tx/changelog.d/20260416_092502_yuriy.lazaryev_fix_builtin_casing_addr_joinpoint.md @@ -0,0 +1,6 @@ +### Fixed + +- Added second constructor to `BuiltinData` to prevent GHC's simplifier from + exposing `PlutusCore.Data.Data` in join point types, which caused the plugin + to crash with `Unsupported feature: Type constructor: GHC.Prim.Addr#` when + using `datatypes=BuiltinCasing`. From 6d710a2c48b9d05b30f9105e3a20c8fd60a7eb11 Mon Sep 17 00:00:00 2001 From: Yuriy Lazaryev Date: Fri, 17 Apr 2026 10:12:56 +0200 Subject: [PATCH 10/10] Regenerate GHC 9.12 golden files The BuiltinData second constructor affects PIR output and budget values slightly (CPU +0.7-1.5%, memory +1.5%, but AST/Flat size decreases). Also updates stage violation error messages and renames from fourmolu. --- .../Spec/Data/Budget/9.12/geq1.golden.eval | 8 +- .../Spec/Data/Budget/9.12/geq2.golden.eval | 8 +- .../Spec/Data/Budget/9.12/geq3.golden.eval | 8 +- .../Spec/Data/Budget/9.12/geq4.golden.eval | 8 +- .../Spec/Data/Budget/9.12/geq5.golden.eval | 8 +- .../Spec/Data/Budget/9.12/gt.golden.pir | 92 +++++++++---------- .../Spec/Data/Budget/9.12/gt1.golden.eval | 8 +- .../Spec/Data/Budget/9.12/gt2.golden.eval | 8 +- .../Spec/Data/Budget/9.12/gt3.golden.eval | 8 +- .../Spec/Data/Budget/9.12/gt4.golden.eval | 8 +- .../Spec/Data/Budget/9.12/gt5.golden.eval | 8 +- .../test/Budget/9.12/map2.golden.eval | 8 +- .../test/Budget/9.12/map2.golden.pir | 15 ++- .../test/Budget/9.12/map2.golden.uplc | 62 ++++++------- .../test/Budget/9.12/map3.golden.eval | 8 +- .../test/Budget/9.12/map3.golden.pir | 86 ++++++++--------- .../test/Budget/9.12/map3.golden.uplc | 50 +++++----- .../test/BuiltinCasing/9.12/head.golden.uplc | 2 +- .../9.12/useTwiceByteString.golden.uplc | 1 + .../9.12/useTwiceData.golden.uplc | 16 ++++ .../9.12/useTwiceString.golden.uplc | 1 + ...mutualRecursionUnfoldingsLocal.golden.uplc | 13 ++- .../Errors/9.12/rangeEnumFrom.golden.uplc | 2 +- .../Errors/9.12/rangeEnumFromThen.golden.uplc | 2 +- .../9.12/builtinData.golden.uplc | 7 +- 25 files changed, 225 insertions(+), 220 deletions(-) create mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceByteString.golden.uplc create mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceData.golden.uplc create mode 100644 plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceString.golden.uplc diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq1.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq1.golden.eval index 305c4bb9f8e..e704fbf105a 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq1.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq1.golden.eval @@ -1,6 +1,6 @@ -CPU: 337_547_895 -Memory: 988_745 -AST Size: 639 -Flat Size: 949 +CPU: 341_387_895 +Memory: 1_012_745 +AST Size: 629 +Flat Size: 939 (con bool True) \ No newline at end of file diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq2.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq2.golden.eval index 7df13110969..cc372b0bc3b 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq2.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq2.golden.eval @@ -1,6 +1,6 @@ -CPU: 355_097_594 -Memory: 1_055_015 -AST Size: 639 -Flat Size: 1_000 +CPU: 359_033_594 +Memory: 1_079_615 +AST Size: 629 +Flat Size: 990 (con bool False) \ No newline at end of file diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq3.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq3.golden.eval index d7e1cb55530..0d802492131 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq3.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq3.golden.eval @@ -1,6 +1,6 @@ -CPU: 368_720_887 -Memory: 1_100_329 -AST Size: 639 -Flat Size: 1_000 +CPU: 372_656_887 +Memory: 1_124_929 +AST Size: 629 +Flat Size: 990 (con bool True) \ No newline at end of file diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq4.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq4.golden.eval index 92bd54c53ab..683e1c2e606 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq4.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq4.golden.eval @@ -1,6 +1,6 @@ -CPU: 331_212_553 -Memory: 946_336 -AST Size: 639 -Flat Size: 956 +CPU: 335_148_553 +Memory: 970_936 +AST Size: 629 +Flat Size: 946 (con bool False) \ No newline at end of file diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq5.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq5.golden.eval index 5747005a96f..1c0d1874041 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq5.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/geq5.golden.eval @@ -1,6 +1,6 @@ -CPU: 349_612_383 -Memory: 1_021_500 -AST Size: 639 -Flat Size: 956 +CPU: 353_548_383 +Memory: 1_046_100 +AST Size: 629 +Flat Size: 946 (con bool True) \ No newline at end of file diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt.golden.pir b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt.golden.pir index ee74ddedcc5..00a2808b998 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt.golden.pir +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt.golden.pir @@ -268,6 +268,12 @@ let = case data hd [(\(l : data) (r : data) -> r)] !k : data = case data hd [(\(l : data) (r : data) -> l)] + !`$j` : data -> list (pair data data) + = \(v' : data) -> + mkCons + {pair data data} + (mkPairData k v') + (goRight tl) in Maybe_match {data} @@ -275,33 +281,25 @@ let {all dead. list (pair data data)} (\(r : data) -> /\dead -> - mkCons - {pair data data} - (mkPairData - k - (`$fToDataThese_$ctoBuiltinData` + `$j` + (`$fToDataThese_$ctoBuiltinData` + {a} + {b} + `$dToData` + `$dToData` + (These {a} {b} - `$dToData` - `$dToData` - (These - {a} - {b} - (`$dUnsafeFromData` v) - (`$dUnsafeFromData` r)))) - (goRight tl)) + (`$dUnsafeFromData` v) + (`$dUnsafeFromData` r)))) (/\dead -> - mkCons - {pair data data} - (mkPairData - k - (`$fToDataThese_$ctoBuiltinData` - {a} - {b} - `$dToData` - `$dToData` - (That {a} {b} (`$dUnsafeFromData` v)))) - (goRight tl)) + `$j` + (`$fToDataThese_$ctoBuiltinData` + {a} + {b} + `$dToData` + `$dToData` + (That {a} {b} (`$dUnsafeFromData` v)))) {all dead. dead}) , [] ] in @@ -318,6 +316,12 @@ let = case data hd [(\(l : data) (r : data) -> r)] !k : data = case data hd [(\(l : data) (r : data) -> l)] + !`$j` : data -> list (pair data data) + = \(v' : data) -> + mkCons + {pair data data} + (mkPairData k v') + (goLeft tl) in Maybe_match {data} @@ -325,33 +329,25 @@ let {all dead. list (pair data data)} (\(r : data) -> /\dead -> - mkCons - {pair data data} - (mkPairData - k - (`$fToDataThese_$ctoBuiltinData` + `$j` + (`$fToDataThese_$ctoBuiltinData` + {a} + {b} + `$dToData` + `$dToData` + (These {a} {b} - `$dToData` - `$dToData` - (These - {a} - {b} - (`$dUnsafeFromData` v) - (`$dUnsafeFromData` r)))) - (goLeft tl)) + (`$dUnsafeFromData` v) + (`$dUnsafeFromData` r)))) (/\dead -> - mkCons - {pair data data} - (mkPairData - k - (`$fToDataThese_$ctoBuiltinData` - {a} - {b} - `$dToData` - `$dToData` - (This {a} {b} (`$dUnsafeFromData` v)))) - (goLeft tl)) + `$j` + (`$fToDataThese_$ctoBuiltinData` + {a} + {b} + `$dToData` + `$dToData` + (This {a} {b} (`$dUnsafeFromData` v)))) {all dead. dead}) , [] ] in diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt1.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt1.golden.eval index d5495f9b829..ef19118eefe 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt1.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt1.golden.eval @@ -1,6 +1,6 @@ -CPU: 388_148_300 -Memory: 1_166_660 -AST Size: 1_023 -Flat Size: 1_324 +CPU: 391_988_300 +Memory: 1_190_660 +AST Size: 1_013 +Flat Size: 1_314 (con bool False) \ No newline at end of file diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt2.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt2.golden.eval index eaef2037302..637845b642f 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt2.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt2.golden.eval @@ -1,6 +1,6 @@ -CPU: 355_465_594 -Memory: 1_057_315 -AST Size: 1_023 -Flat Size: 1_375 +CPU: 359_401_594 +Memory: 1_081_915 +AST Size: 1_013 +Flat Size: 1_365 (con bool False) \ No newline at end of file diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt3.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt3.golden.eval index 5bbeabe17a0..790c04fb66f 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt3.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt3.golden.eval @@ -1,6 +1,6 @@ -CPU: 420_042_992 -Memory: 1_282_209 -AST Size: 1_023 -Flat Size: 1_375 +CPU: 423_978_992 +Memory: 1_306_809 +AST Size: 1_013 +Flat Size: 1_365 (con bool True) \ No newline at end of file diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt4.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt4.golden.eval index e1d6a166af4..887b462be70 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt4.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt4.golden.eval @@ -1,6 +1,6 @@ -CPU: 331_580_553 -Memory: 948_636 -AST Size: 1_023 -Flat Size: 1_331 +CPU: 335_516_553 +Memory: 973_236 +AST Size: 1_013 +Flat Size: 1_321 (con bool False) \ No newline at end of file diff --git a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt5.golden.eval b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt5.golden.eval index 45be5fc853e..a38e06c8557 100644 --- a/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt5.golden.eval +++ b/plutus-tx-plugin/test-ledger-api/Spec/Data/Budget/9.12/gt5.golden.eval @@ -1,6 +1,6 @@ -CPU: 373_819_011 -Memory: 1_110_324 -AST Size: 1_023 -Flat Size: 1_331 +CPU: 377_755_011 +Memory: 1_134_924 +AST Size: 1_013 +Flat Size: 1_321 (con bool True) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Budget/9.12/map2.golden.eval b/plutus-tx-plugin/test/Budget/9.12/map2.golden.eval index 7efa7cc75ef..315ade87985 100644 --- a/plutus-tx-plugin/test/Budget/9.12/map2.golden.eval +++ b/plutus-tx-plugin/test/Budget/9.12/map2.golden.eval @@ -1,7 +1,7 @@ -CPU: 67_827_382 -Memory: 197_790 -AST Size: 423 -Flat Size: 458 +CPU: 68_307_382 +Memory: 200_790 +AST Size: 418 +Flat Size: 453 (constr 1 diff --git a/plutus-tx-plugin/test/Budget/9.12/map2.golden.pir b/plutus-tx-plugin/test/Budget/9.12/map2.golden.pir index 07b4448c160..c302a5fa58f 100644 --- a/plutus-tx-plugin/test/Budget/9.12/map2.golden.pir +++ b/plutus-tx-plugin/test/Budget/9.12/map2.golden.pir @@ -159,20 +159,19 @@ in {all dead. dead}) , (Nothing {data}) ] in + let + !`$j` : data -> list (pair data data) + = \(v'' : data) -> + mkCons {pair data data} (mkPairData k' v'') (go tl) + in Maybe_match {data} (go nt) {all dead. list (pair data data)} (\(r : data) -> /\dead -> - mkCons - {pair data data} - (mkPairData - k' - (iData (addInteger (unIData v') (unIData r)))) - (go tl)) - (/\dead -> - mkCons {pair data data} (mkPairData k' v') (go tl)) + `$j` (iData (addInteger (unIData v') (unIData r)))) + (/\dead -> `$j` v') {all dead. dead}) , [] ] in diff --git a/plutus-tx-plugin/test/Budget/9.12/map2.golden.uplc b/plutus-tx-plugin/test/Budget/9.12/map2.golden.uplc index a3fe621186f..39598866676 100644 --- a/plutus-tx-plugin/test/Budget/9.12/map2.golden.uplc +++ b/plutus-tx-plugin/test/Budget/9.12/map2.golden.uplc @@ -70,41 +70,41 @@ tl -> (\v' -> (\k' -> - (\s -> - case - (s s nt) - [ (\r -> - force mkCons - (mkPairData - k' + (\`$j` -> + (\s -> + case + (s s nt) + [ (\r -> + `$j` (iData (addInteger (unIData v') (unIData r)))) - (s s tl)) - , (force mkCons - (mkPairData k' v') - (s s tl)) ]) - (\s - xs -> - case - xs - [ (\hd -> - case - (equalsData - k' - (case - hd - [(\l r -> l)])) - [ (\x -> s s x) - , (\ds -> - constr 0 - [ (case - hd - [ (\l - r -> - r) ]) ]) ]) - , (constr 1 []) ])) + , (`$j` v') ]) + (\s + xs -> + case + xs + [ (\hd -> + case + (equalsData + k' + (case + hd + [(\l r -> l)])) + [ (\x -> s s x) + , (\ds -> + constr 0 + [ (case + hd + [ (\l + r -> + r) ]) ]) ]) + , (constr 1 []) ])) + (\v'' -> + force mkCons + (mkPairData k' v'') + (s s tl))) (case hd [(\l r -> l)])) (case hd [(\l r -> r)])) , [] ]))) diff --git a/plutus-tx-plugin/test/Budget/9.12/map3.golden.eval b/plutus-tx-plugin/test/Budget/9.12/map3.golden.eval index 706b9483d42..da011ae4937 100644 --- a/plutus-tx-plugin/test/Budget/9.12/map3.golden.eval +++ b/plutus-tx-plugin/test/Budget/9.12/map3.golden.eval @@ -1,7 +1,7 @@ -CPU: 111_907_732 -Memory: 333_684 -AST Size: 664 -Flat Size: 705 +CPU: 112_771_732 +Memory: 339_084 +AST Size: 654 +Flat Size: 695 (constr 1 diff --git a/plutus-tx-plugin/test/Budget/9.12/map3.golden.pir b/plutus-tx-plugin/test/Budget/9.12/map3.golden.pir index ea60b2b264d..308022a9f2a 100644 --- a/plutus-tx-plugin/test/Budget/9.12/map3.golden.pir +++ b/plutus-tx-plugin/test/Budget/9.12/map3.golden.pir @@ -200,6 +200,9 @@ in let !v : data = case data hd [(\(l : data) (r : data) -> r)] !k : data = case data hd [(\(l : data) (r : data) -> l)] + !`$j` : data -> list (pair data data) + = \(v' : data) -> + mkCons {pair data data} (mkPairData k v') (goLeft tl) in Maybe_match {data} @@ -207,33 +210,25 @@ in {all dead. list (pair data data)} (\(r : data) -> /\dead -> - mkCons - {pair data data} - (mkPairData - k - (`$fToDataThese_$ctoBuiltinData` + `$j` + (`$fToDataThese_$ctoBuiltinData` + {integer} + {integer} + `$dToData` + `$dToData` + (These {integer} {integer} - `$dToData` - `$dToData` - (These - {integer} - {integer} - (unIData v) - (unIData r)))) - (goLeft tl)) + (unIData v) + (unIData r)))) (/\dead -> - mkCons - {pair data data} - (mkPairData - k - (`$fToDataThese_$ctoBuiltinData` - {integer} - {integer} - `$dToData` - `$dToData` - (This {integer} {integer} (unIData v)))) - (goLeft tl)) + `$j` + (`$fToDataThese_$ctoBuiltinData` + {integer} + {integer} + `$dToData` + `$dToData` + (This {integer} {integer} (unIData v)))) {all dead. dead}) , [] ] in @@ -273,6 +268,9 @@ in let !v : data = case data hd [(\(l : data) (r : data) -> r)] !k : data = case data hd [(\(l : data) (r : data) -> l)] + !`$j` : data -> list (pair data data) + = \(v' : data) -> + mkCons {pair data data} (mkPairData k v') (goRight tl) in Maybe_match {data} @@ -280,33 +278,25 @@ in {all dead. list (pair data data)} (\(r : data) -> /\dead -> - mkCons - {pair data data} - (mkPairData - k - (`$fToDataThese_$ctoBuiltinData` + `$j` + (`$fToDataThese_$ctoBuiltinData` + {integer} + {integer} + `$dToData` + `$dToData` + (These {integer} {integer} - `$dToData` - `$dToData` - (These - {integer} - {integer} - (unIData v) - (unIData r)))) - (goRight tl)) + (unIData v) + (unIData r)))) (/\dead -> - mkCons - {pair data data} - (mkPairData - k - (`$fToDataThese_$ctoBuiltinData` - {integer} - {integer} - `$dToData` - `$dToData` - (That {integer} {integer} (unIData v)))) - (goRight tl)) + `$j` + (`$fToDataThese_$ctoBuiltinData` + {integer} + {integer} + `$dToData` + `$dToData` + (That {integer} {integer} (unIData v)))) {all dead. dead}) , [] ] in diff --git a/plutus-tx-plugin/test/Budget/9.12/map3.golden.uplc b/plutus-tx-plugin/test/Budget/9.12/map3.golden.uplc index 56d7e41ebe4..73aba1edfbc 100644 --- a/plutus-tx-plugin/test/Budget/9.12/map3.golden.uplc +++ b/plutus-tx-plugin/test/Budget/9.12/map3.golden.uplc @@ -107,13 +107,11 @@ tl -> (\v -> (\k -> - case - (lookup' k nt) - [ (\r -> - force - mkCons - (mkPairData - k + (\`$j` -> + case + (lookup' k nt) + [ (\r -> + `$j` (case (constr 0 [ `$dToData` @@ -124,11 +122,7 @@ , (unIData r) ]) ]) [ `$fToDataThese_$ctoBuiltinData` ])) - (s s tl)) - , (force - mkCons - (mkPairData - k + , (`$j` (case (constr 0 [ `$dToData` @@ -136,8 +130,11 @@ , (constr 0 [ (unIData v) ]) ]) - [ `$fToDataThese_$ctoBuiltinData` ])) - (s s tl)) ]) + [ `$fToDataThese_$ctoBuiltinData` ])) ]) + (\v' -> + force mkCons + (mkPairData k v') + (s s tl))) (case hd [(\l r -> l)])) (case hd [(\l r -> r)])) , [] ]))) @@ -179,13 +176,11 @@ tl -> (\v -> (\k -> - case - (lookup' k nt) - [ (\r -> - force - mkCons - (mkPairData - k + (\`$j` -> + case + (lookup' k nt) + [ (\r -> + `$j` (case (constr 0 [ `$dToData` @@ -196,11 +191,7 @@ , (unIData r) ]) ]) [ `$fToDataThese_$ctoBuiltinData` ])) - (s s tl)) - , (force - mkCons - (mkPairData - k + , (`$j` (case (constr 0 [ `$dToData` @@ -208,8 +199,11 @@ , (constr 2 [ (unIData v) ]) ]) - [ `$fToDataThese_$ctoBuiltinData` ])) - (s s tl)) ]) + [ `$fToDataThese_$ctoBuiltinData` ])) ]) + (\v' -> + force mkCons + (mkPairData k v') + (s s tl))) (case hd [(\l r -> l)])) (case hd [(\l r -> r)])) , [] ]))) diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.12/head.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.12/head.golden.uplc index d4a7a6050e5..e65a842ea71 100644 --- a/plutus-tx-plugin/test/BuiltinCasing/9.12/head.golden.uplc +++ b/plutus-tx-plugin/test/BuiltinCasing/9.12/head.golden.uplc @@ -1 +1 @@ -(program 1.1.0 (\xs -> case xs [(\x xs ds -> x), (\ds -> error)] (constr 0 []))) \ No newline at end of file +(program 1.1.0 (\l -> case l [(\x xs ds -> x), (\ds -> error)] (constr 0 []))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceByteString.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceByteString.golden.uplc new file mode 100644 index 00000000000..a34c3c8d93b --- /dev/null +++ b/plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceByteString.golden.uplc @@ -0,0 +1 @@ +(program 1.1.0 (\bs -> (\cse -> ()) (appendByteString bs bs))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceData.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceData.golden.uplc new file mode 100644 index 00000000000..262ae1ede39 --- /dev/null +++ b/plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceData.golden.uplc @@ -0,0 +1,16 @@ +(program + 1.1.0 + (\bd -> + (\nt -> + (\`$j` -> + case + (case nt [(\x eta -> constr 0 [x]), (constr 1 [])]) + [ (\arg -> + (\ds -> force `$j`) (constrData 0 (force mkCons arg []))) + , (force `$j`) ]) + (delay + (case + (case nt [(\x eta -> constr 0 [x]), (constr 1 [])]) + [ (\arg -> (\ds -> ()) (constrData 0 (force mkCons arg []))) + , () ]))) + (unListData bd))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceString.golden.uplc b/plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceString.golden.uplc new file mode 100644 index 00000000000..8edcd9fff96 --- /dev/null +++ b/plutus-tx-plugin/test/BuiltinCasing/9.12/useTwiceString.golden.uplc @@ -0,0 +1 @@ +(program 1.1.0 (\s -> (\cse -> ()) (appendString s s))) \ No newline at end of file diff --git a/plutus-tx-plugin/test/Plugin/Errors/9.12/mutualRecursionUnfoldingsLocal.golden.uplc b/plutus-tx-plugin/test/Plugin/Errors/9.12/mutualRecursionUnfoldingsLocal.golden.uplc index 8e0ade0637f..aeeee0b2961 100644 --- a/plutus-tx-plugin/test/Plugin/Errors/9.12/mutualRecursionUnfoldingsLocal.golden.uplc +++ b/plutus-tx-plugin/test/Plugin/Errors/9.12/mutualRecursionUnfoldingsLocal.golden.uplc @@ -1,2 +1,11 @@ -Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable Plugin.Errors.Spec.oddDirectLocal - OtherCon [] \ No newline at end of file +Error: Unsupported feature: Variable Plugin.Errors.Spec.oddDirectLocal + OtherCon [] + + This error often indicates a stage violation in Plinth compilation. + Variables inside compile quotations must be either: + • Top-level variables, or + • Bound inside the quotation itself + + Common causes: + • Using a function defined in a 'where' clause: move it to the top level + • Referencing local variables from outside the quotation \ No newline at end of file diff --git a/plutus-tx-plugin/test/Plugin/Errors/9.12/rangeEnumFrom.golden.uplc b/plutus-tx-plugin/test/Plugin/Errors/9.12/rangeEnumFrom.golden.uplc index ccfe1880ce9..fffee266f68 100644 --- a/plutus-tx-plugin/test/Plugin/Errors/9.12/rangeEnumFrom.golden.uplc +++ b/plutus-tx-plugin/test/Plugin/Errors/9.12/rangeEnumFrom.golden.uplc @@ -1,2 +1,2 @@ Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable GHC.Num.Integer.integerAdd - No unfolding \ No newline at end of file + No unfolding diff --git a/plutus-tx-plugin/test/Plugin/Errors/9.12/rangeEnumFromThen.golden.uplc b/plutus-tx-plugin/test/Plugin/Errors/9.12/rangeEnumFromThen.golden.uplc index ccfe1880ce9..fffee266f68 100644 --- a/plutus-tx-plugin/test/Plugin/Errors/9.12/rangeEnumFromThen.golden.uplc +++ b/plutus-tx-plugin/test/Plugin/Errors/9.12/rangeEnumFromThen.golden.uplc @@ -1,2 +1,2 @@ Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable GHC.Num.Integer.integerAdd - No unfolding \ No newline at end of file + No unfolding diff --git a/plutus-tx-plugin/test/StageViolation/9.12/builtinData.golden.uplc b/plutus-tx-plugin/test/StageViolation/9.12/builtinData.golden.uplc index 8f8725dda3d..9bc7309e5e0 100644 --- a/plutus-tx-plugin/test/StageViolation/9.12/builtinData.golden.uplc +++ b/plutus-tx-plugin/test/StageViolation/9.12/builtinData.golden.uplc @@ -1,4 +1,5 @@ -Error: Unsupported feature: Cannot construct a value of type: PlutusTx.Builtins.Internal.BuiltinData +Error: Unsupported feature: Variable validator + OtherCon [] This error often indicates a stage violation in Plinth compilation. Variables inside compile quotations must be either: @@ -7,6 +8,4 @@ Error: Unsupported feature: Cannot construct a value of type: PlutusTx.Builtins. Common causes: • Using a function defined in a 'where' clause: move it to the top level - • Referencing local variables from outside the quotation - - Note: GHC can generate these unexpectedly, you may need '-fno-strictness', '-fno-specialise', '-fno-spec-constr', '-fno-unbox-strict-fields', or '-fno-unbox-small-strict-fields'. \ No newline at end of file + • Referencing local variables from outside the quotation \ No newline at end of file