IntersectMBO / plutus

The Plutus language implementation and tools
Apache License 2.0
1.57k stars 479 forks source link

Unexpected PLC errors during compilation. #4263

Closed jhodgdev closed 2 years ago

jhodgdev commented 2 years ago

Summary

In trying to add a data type Epoch to a UTxO datum TreasuryState, I encountered a couple of PLC errors during compilation. With:

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE TemplateHaskell #-}

import Data.Aeson (FromJSON, ToJSON)
import Data.OpenApi.Schema (ToSchema)
import GHC.Generics (Generic)
import PlutusTx qualified
import PlutusTx.Natural (Natural)
import PlutusTx.Prelude 
import Prelude (Show)
import Prelude qualified (Eq)

data TreasuryState = TreasuryState
  { executive :: Credential
  , lastRewardEpoch :: Epoch
  }
  deriving stock (Prelude.Eq, Show, Generic)
  deriving anyclass (FromJSON, ToJSON)

PlutusTx.unstableMakeIsData ''TreasuryState

data Epoch = Epoch
  { epochNumber :: Natural
  }
  deriving stock (Prelude.Eq, Show, Generic)
  deriving anyclass (ToJSON, FromJSON, ToSchema)

instance Eq Epoch where
  {-# INLINEABLE (==) #-}
  e == e' = e.epochNumber == e'.epochNumber

PlutusTx.unstableMakeIsData ''Epoch
PlutusTx.makeLift ''Epoch

I experienced error trace (A), listed in "Screenshots and attachments" below. Please note that LiqwidX.Treasury.Init is the module, which calls mkTypedValidatorParam on TreasuryState's script. Making the components of TreasuryState strict:

data TreasuryState = TreasuryState
  { executive :: !Credential
  , lastRewardEpoch :: !Epoch
  }
  deriving stock (Prelude.Eq, Show, Generic)
  deriving anyclass (FromJSON, ToJSON)

results in error trace (B). It is only when I alter Epoch to be a newtype wrapper:

newtype Epoch = Epoch
  { epochNumber :: Natural
  }
  deriving stock (Show, Prelude.Eq, Generic)
  deriving anyclass (ToJSON, FromJSON, ToSchema)

or add an additional record constructor:

data Epoch = Epoch
  { epochNumber :: Natural
  , foo :: Natural
  }
  deriving stock (Show, Prelude.Eq, Generic)
  deriving anyclass (ToJSON, FromJSON, ToSchema)

that the project compiles without issue.

Steps to reproduce

Steps to reproduce the behavior:

For each example listed in the summary:

  1. Duplicate the relevant code snippet.
  2. Attempt to place it "on-chain" by compiling a TypedValidator using TreasuryState.
  3. Run cabal v2-build on your project.

Expected behavior

That the code compiles without issue.

System info (please complete the following information):

Screenshots and attachments

Error Trace (A)

...
[63 of 67] Compiling LiqwidX.Treasury.Init ( src/LiqwidX/Treasury/Init.hs, /home/jack/repos/lqx/dist-newstyle/build/x86_64-linux/ghc-8.10.4.20210212/liqwidx-contracts-0.1/build/LiqwidX/Treasury/Init.o, /home/jack/repos/lqx/dist-newstyle/build/x86_64-linux/ghc-8.10.4.20210212/liqwidx-contracts-0.1/build/LiqwidX/Treasury/Init.dyn_o ) [LiqwidX.Treasury changed]
GHC Core to PLC plugin: E016:Error: Error from the PIR compiler:
            E016: Error during PIR typechecking:
            Type mismatch at () in term
              '(lam
                ds
                [ [ Tuple2 (con bytestring) ] (con bytestring) ]
                (lam
                  ds
                  [ [ Tuple2 (con bytestring) ] (con bytestring) ]
                  (lam
                    ds
                    Credential
                    (lam
                      dt
                      (con integer)
                      (let
                        (nonrec)
                        (termbind
                          (nonstrict)
                          (vardecl
                            wild
                            [ [ Tuple2 (con bytestring) ] (con bytestring) ]
                          )
                          ds
                        )
                        [
                          {
                            [
                              {
                                { Tuple2_match (con bytestring) }
                                (con bytestring)
                              }
                              ds
                            ]
                            [
                              [
                                (lam
                                  k
                                  (type)
                                  (lam v (type) [ List [ [ Tuple2 k ] v ] ])
                                )
                                (con bytestring)
                              ]
                              [
                                [
                                  (lam
                                    k
                                    (type)
                                    (lam v (type) [ List [ [ Tuple2 k ] v ] ])
                                  )
                                  (con bytestring)
                                ]
                                (con integer)
                              ]
                            ]
                          }
                          (lam
                            c
                            (con bytestring)
                            (lam
                              t
                              (con bytestring)
                              [
                                [
                                  {
                                    Cons
                                    [
                                      [ Tuple2 (con bytestring) ]
                                      [
                                        [
                                          (lam
                                            k
                                            (type)
                                            (lam
                                              v
                                              (type)
                                              [ List [ [ Tuple2 k ] v ] ]
                                            )
                                          )
                                          (con bytestring)
                                        ]
                                        (con integer)
                                      ]
                                    ]
                                  }
                                  [
                                    [
                                      {
                                        { Tuple2 (con bytestring) }
                                        [
                                          [
                                            (lam
                                              k
                                              (type)
                                              (lam
                                                v
                                                (type)
                                                [ List [ [ Tuple2 k ] v ] ]
                                              )
                                            )
                                            (con bytestring)
                                          ]
                                          (con integer)
                                        ]
                                      }
                                      c
                                    ]
                                    [
                                      [
                                        {
                                          Cons
                                          [
                                            [ Tuple2 (con bytestring) ]
                                            (con integer)
                                          ]
                                        }
                                        [
                                          [
                                            {
                                              { Tuple2 (con bytestring) }
                                              (con integer)
                                            }
                                            t
                                          ]
                                          (con integer 100)
                                        ]
                                      ]
                                      {
                                        Nil
                                        [
                                          [ Tuple2 (con bytestring) ]
                                          (con integer)
                                        ]
                                      }
                                    ]
                                  ]
                                ]
                                {
                                  Nil
                                  [
                                    [ Tuple2 (con bytestring) ]
                                    [
                                      [
                                        (lam
                                          k
                                          (type)
                                          (lam
                                            v (type) [ List [ [ Tuple2 k ] v ] ]
                                          )
                                        )
                                        (con bytestring)
                                      ]
                                      (con integer)
                                    ]
                                  ]
                                }
                              ]
                            )
                          )
                        ]
                      )
                    )
                  )
                )
              )'.
            Expected type
              '(fun
                [ [ Tuple2_1164 (con bytestring) ] (con bytestring) ]
                (fun
                  [ [ Tuple2_1164 (con bytestring) ] (con bytestring) ]
                  (fun
                    Credential_1479
                    (fun
                      (con integer)
                      [
                        List_1128
                        [
                          [ Tuple2_1164 (con bytestring) ]
                          [
                            List_1128
                            [ [ Tuple2_1164 (con bytestring) ] (con integer) ]
                          ]
                        ]
                      ]
                    )
                  )
                )
              )',
            found type
              '(fun
                [ [ Tuple2_1164 (con bytestring) ] (con bytestring) ]
                (fun
                  [ [ Tuple2_1164 (con bytestring) ] (con bytestring) ]
                  (fun
                    Credential_1479
                    (fun
                      Epoch_1546
                      [
                        List_1128
                        [
                          [ Tuple2_1164 (con bytestring) ]
                          [
                            List_1128
                            [ [ Tuple2_1164 (con bytestring) ] (con integer) ]
                          ]
                        ]
                      ]
                    )
                  )
                )
              )'
Context: Compiling expr at "liqwidx-contracts-0.1-inplace:LiqwidX.Treasury.Init:(75,8)-(75,47)"
cabal: Failed to build liqwidx-contracts-0.1 (which is required by
test:scripts from liqwidx-contracts-0.1, test:script-size from
liqwidx-contracts-0.1 and others).

make: *** [Makefile:114: build] Error 1

Error Trace (B)

...
[63 of 67] Compiling LiqwidX.Treasury.Init ( src/LiqwidX/Treasury/Init.hs, /home/jack/repos/lqx/dist-newstyle/build/x86_64-linux/ghc-8.10.4.20210212/liqwidx-contracts-0.1/build/LiqwidX/Treasury/Init.o, /home/jack/repos/lqx/dist-newstyle/build/x86_64-linux/ghc-8.10.4.20210212/liqwidx-contracts-0.1/build/LiqwidX/Treasury/Init.dyn_o ) [LiqwidX.Treasury changed]
GHC Core to PLC plugin: E016:Error: Error from the PIR compiler:
            E016: Error during PIR typechecking:
            Type mismatch at () in term
              'dt'.
            Expected type
              '(con integer)',
            found type
              'Epoch_1552'
Context: Compiling expr at "liqwidx-contracts-0.1-inplace:LiqwidX.Treasury.Init:(75,8)-(75,47)"
cabal: Failed to build liqwidx-contracts-0.1 (which is required by
test:scripts from liqwidx-contracts-0.1, test:script-size from
liqwidx-contracts-0.1 and others).

make: *** [Makefile:114: build] Error 1
ghost commented 2 years ago

Thanks for the issue!

I can't reproduce the error so could you please share some details. Do you use regular plutus's nix-shell environment? What is import PlutusTx.Natural (Natural)? Do you use https://github.com/ndmitchell/record-dot-preprocessor? What version?

jhodgdev commented 2 years ago

Thank you for responding!

I use an impure nix-shell with lorri. PlutusTx.Natural is a package used in-house at MLabs. We do use record-dot-preprocessor but I am unsure which version.

jhodgdev commented 2 years ago

My project manager informed me that the pre-processor version is most likely 0.2.13.

ghost commented 2 years ago

Unfortunately the provided info is not enough to tell what's going wrong. Is there any chance of providing a small reproducible example?

jhodgdev commented 2 years ago

I have been working on a small example but so far have been unable to replicate it myself. I will continue to work on it and update you on my progress.

ghost commented 2 years ago

Thank you!

jhodgdev commented 2 years ago

Managed to recreate the issue! Here is the repo: https://github.com/jhodgdev/plc-errors

ghost commented 2 years ago

@jhodgdev

The source of the problem is the bang pattern for the Epoch here https://github.com/jhodgdev/plc-errors/blob/53fcf08fb41be5a620a0cce6a95e7f036ddf9529/src/PlcErrors.hs#L68.

While we are investigating the behaviour and looking for a proper fix please use {-# OPTIONS_GHC -fno-unbox-small-strict-fields #-} for now. Or you can delete the bang pattern and make the field lazy. It should help with the compilation error and unblock you.

jhodgdev commented 2 years ago

Thank you very much @ak3n :)