morley-1.9: src/Michelson/Typed/Scope.hs
-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ
{-# LANGUAGE UndecidableSuperClasses #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
{- | Module, containing restrictions imposed by instruction or value scope.
Michelson have multiple restrictions on values, examples:
* @operation@ type cannot appear in parameter.
* @big_map@ type cannot appear in @PUSH@-able constants.
* @contract@ type cannot appear in type we @UNPACK@ to.
Thus we declare multiple "scopes" - constraints applied in corresponding
situations, for instance
* 'ParameterScope';
* 'StorageScope';
* 'ConstantScope'.
Also we separate multiple "classes" of scope-related constraints.
* 'ParameterScope' and similar ones are used within Michelson engine,
they are understandable by GHC but produce not very clarifying errors.
* 'ProperParameterBetterErrors' and similar ones are middle-layer constraints,
they produce human-readable errors but GHC cannot make conclusions from them.
They are supposed to be used only by eDSLs to define their own high-level
constraints.
* Lorentz and other eDSLs may declare their own constraints, in most cases
you should use them. For example see 'Lorentz.Constraints' module.
-}
module Michelson.Typed.Scope
( -- * Scopes
ConstantScope
, StorageScope
, PackedValScope
, ParameterScope
, PrintedValScope
, UnpackedValScope
, ProperParameterBetterErrors
, ProperStorageBetterErrors
, ProperConstantBetterErrors
, ProperPackedValBetterErrors
, ProperUnpackedValBetterErrors
, ProperPrintedValBetterErrors
, properParameterEvi
, properStorageEvi
, properConstantEvi
, properPackedValEvi
, properUnpackedValEvi
, properPrintedValEvi
, (:-)(..)
, BadTypeForScope (..)
, CheckScope (..)
-- * Implementation internals
, HasNoBigMap
, HasNoNestedBigMaps
, HasNoOp
, HasNoContract
, ContainsBigMap
, ContainsNestedBigMaps
, ForbidOp
, ForbidContract
, ForbidBigMap
, ForbidNestedBigMaps
, FailOnBigMapFound
, FailOnNestedBigMapsFound
, FailOnOperationFound
, OpPresence (..)
, ContractPresence (..)
, BigMapPresence (..)
, NestedBigMapsPresence (..)
, checkOpPresence
, checkContractTypePresence
, checkBigMapPresence
, checkNestedBigMapsPresence
, opAbsense
, contractTypeAbsense
, bigMapAbsense
, nestedBigMapsAbsense
, forbiddenOp
, forbiddenContractType
, forbiddenBigMap
, forbiddenNestedBigMaps
-- * Re-exports
, withDict
, SingI (..)
) where
import Data.Constraint ((:-)(..), Dict(..), withDict, (\\))
import qualified Data.Constraint as C
import Data.Singletons (Sing, SingI(..))
import Data.Type.Bool (type (||))
import Fmt (Buildable(..))
import GHC.TypeLits (ErrorMessage(..), TypeError)
import Michelson.Typed.Sing (KnownT, SingT(..))
import Michelson.Typed.T (T(..))
----------------------------------------------------------------------------
-- Constraints
----------------------------------------------------------------------------
-- | Whether this type contains 'TOperation' type.
--
-- In some scopes (constants, parameters, storage) appearing for operation type
-- is prohibited.
-- Operations in input/output of lambdas are allowed without limits though.
type family ContainsOp (t :: T) :: Bool where
ContainsOp 'TKey = 'False
ContainsOp 'TUnit = 'False
ContainsOp 'TSignature = 'False
ContainsOp 'TChainId = 'False
ContainsOp ('TOption t) = ContainsOp t
ContainsOp ('TList t) = ContainsOp t
ContainsOp ('TSet t) = ContainsOp t
ContainsOp 'TOperation = 'True
ContainsOp ('TContract t) = ContainsOp t
ContainsOp ('TPair a b) = ContainsOp a || ContainsOp b
ContainsOp ('TOr a b) = ContainsOp a || ContainsOp b
ContainsOp ('TLambda _ _) = 'False
ContainsOp ('TMap k v) = ContainsOp k || ContainsOp v
ContainsOp ('TBigMap k v) = ContainsOp k || ContainsOp v
ContainsOp _ = 'False
-- | Whether this type contains 'TContract' type.
--
-- In some scopes (constants, storage) appearing for contract type
-- is prohibited.
-- Contracts in input/output of lambdas are allowed without limits though.
type family ContainsContract (t :: T) :: Bool where
ContainsContract 'TKey = 'False
ContainsContract 'TUnit = 'False
ContainsContract 'TSignature = 'False
ContainsContract 'TChainId = 'False
ContainsContract ('TOption t) = ContainsContract t
ContainsContract ('TList t) = ContainsContract t
ContainsContract ('TSet _) = 'False
ContainsContract 'TOperation = 'False
ContainsContract ('TContract _) = 'True
ContainsContract ('TPair a b) = ContainsContract a || ContainsContract b
ContainsContract ('TOr a b) = ContainsContract a || ContainsContract b
ContainsContract ('TLambda _ _) = 'False
ContainsContract ('TMap _ v) = ContainsContract v
ContainsContract ('TBigMap _ v) = ContainsContract v
ContainsContract _ = 'False
-- | Whether this type contains 'TBigMap' type.
type family ContainsBigMap (t :: T) :: Bool where
ContainsBigMap 'TKey = 'False
ContainsBigMap 'TUnit = 'False
ContainsBigMap 'TSignature = 'False
ContainsBigMap 'TChainId = 'False
ContainsBigMap ('TOption t) = ContainsBigMap t
ContainsBigMap ('TList t) = ContainsBigMap t
ContainsBigMap ('TSet _) = 'False
ContainsBigMap 'TOperation = 'False
ContainsBigMap ('TContract t) = ContainsBigMap t
ContainsBigMap ('TPair a b) = ContainsBigMap a || ContainsBigMap b
ContainsBigMap ('TOr a b) = ContainsBigMap a || ContainsBigMap b
ContainsBigMap ('TLambda _ _) = 'False
ContainsBigMap ('TMap _ v) = ContainsBigMap v
ContainsBigMap ('TBigMap _ _) = 'True
ContainsBigMap _ = 'False
-- | Whether this type contains a type with nested 'TBigMap's .
--
-- Nested big_maps (i.e. big_map which contains another big_map inside of it's value type). Are
-- prohibited in all contexts. Some context such as PUSH, APPLY, PACK/UNPACK instructions are more
-- strict because they doesn't work with big_map at all.
type family ContainsNestedBigMaps (t :: T) :: Bool where
ContainsNestedBigMaps 'TKey = 'False
ContainsNestedBigMaps 'TUnit = 'False
ContainsNestedBigMaps 'TSignature = 'False
ContainsNestedBigMaps 'TChainId = 'False
ContainsNestedBigMaps ('TOption t) = ContainsNestedBigMaps t
ContainsNestedBigMaps ('TList t) = ContainsNestedBigMaps t
ContainsNestedBigMaps ('TSet _) = 'False
ContainsNestedBigMaps 'TOperation = 'False
ContainsNestedBigMaps ('TContract t) = ContainsNestedBigMaps t
ContainsNestedBigMaps ('TPair a b) = ContainsNestedBigMaps a || ContainsNestedBigMaps b
ContainsNestedBigMaps ('TOr a b) = ContainsNestedBigMaps a || ContainsNestedBigMaps b
ContainsNestedBigMaps ('TLambda _ _) = 'False
ContainsNestedBigMaps ('TMap _ v) = ContainsNestedBigMaps v
ContainsNestedBigMaps ('TBigMap _ v) = ContainsBigMap v
ContainsNestedBigMaps _ = 'False
-- | Constraint which ensures that operation type does not appear in a given type.
--
-- Not just a type alias in order to be able to partially apply it
-- (e.g. in 'Each').
class (ContainsOp t ~ 'False) => HasNoOp t
instance (ContainsOp t ~ 'False) => HasNoOp t
-- | Constraint which ensures that contract type does not appear in a given type.
class (ContainsContract t ~ 'False) => HasNoContract t
instance (ContainsContract t ~ 'False) => HasNoContract t
-- | Constraint which ensures that bigmap does not appear in a given type.
class (ContainsBigMap t ~ 'False) => HasNoBigMap t
instance (ContainsBigMap t ~ 'False) => HasNoBigMap t
-- | Constraint which ensures that there are no nested bigmaps.
class (ContainsNestedBigMaps t ~ 'False) => HasNoNestedBigMaps t
instance (ContainsNestedBigMaps t ~ 'False) => HasNoNestedBigMaps t
-- | Report a human-readable error about 'TOperation' at a wrong place.
type family FailOnOperationFound (enabled :: Bool) :: Constraint where
FailOnOperationFound 'True =
TypeError ('Text "Operations are not allowed in this scope")
FailOnOperationFound 'False = ()
-- | Report a human-readable error about 'TContract' at a wrong place.
type family FailOnContractFound (enabled :: Bool) :: Constraint where
FailOnContractFound 'True =
TypeError ('Text "Type `contract` is not allowed in this scope")
FailOnContractFound 'False = ()
-- | Report a human-readable error about 'TBigMap' at a wrong place.
type family FailOnBigMapFound (enabled :: Bool) :: Constraint where
FailOnBigMapFound 'True =
TypeError ('Text "BigMaps are not allowed in this scope")
FailOnBigMapFound 'False = ()
-- | Report a human-readable error that 'TBigMap' contains another 'TBigMap'
type family FailOnNestedBigMapsFound (enabled :: Bool) :: Constraint where
FailOnNestedBigMapsFound 'True =
TypeError ('Text "Nested BigMaps are not allowed")
FailOnNestedBigMapsFound 'False = ()
-- | This is like 'HasNoOp', it raises a more human-readable error
-- when @t@ type is concrete, but GHC cannot make any conclusions
-- from such constraint as it can for 'HasNoOp'.
-- Though, hopefully, it will someday:
-- <https://gitlab.haskell.org/ghc/ghc/issues/11503 #11503>.
--
-- Use this constraint in our eDSL.
type ForbidOp t = FailOnOperationFound (ContainsOp t)
type ForbidContract t = FailOnContractFound (ContainsContract t)
type ForbidBigMap t = FailOnBigMapFound (ContainsBigMap t)
type ForbidNestedBigMaps t = FailOnNestedBigMapsFound (ContainsNestedBigMaps t)
-- | Evidence of that 'HasNoOp' is deducable from 'ForbidOp'.
forbiddenOpEvi :: forall t. (SingI t, ForbidOp t) :- HasNoOp t
forbiddenOpEvi = Sub $
-- It's not clear now to proof GHC that @HasNoOp t@ is implication of
-- @ForbidOp t@, so we use @error@ below and also disable
-- "-Wredundant-constraints" extension.
case checkOpPresence (sing @t) of
OpAbsent -> Dict
OpPresent -> error "impossible"
-- | Reify 'HasNoOp' contraint from 'ForbidOp'.
--
-- Left for backward compatibility.
forbiddenOp
:: forall t a.
(SingI t, ForbidOp t)
=> (HasNoOp t => a)
-> a
forbiddenOp = withDict $ forbiddenOpEvi @t
forbiddenBigMapEvi :: forall t. (SingI t, ForbidBigMap t) :- HasNoBigMap t
forbiddenBigMapEvi = Sub $
case checkBigMapPresence (sing @t) of
BigMapAbsent -> Dict
BigMapPresent -> error "impossible"
forbiddenNestedBigMapsEvi :: forall t. (SingI t, ForbidNestedBigMaps t) :- HasNoNestedBigMaps t
forbiddenNestedBigMapsEvi = Sub $
case checkNestedBigMapsPresence (sing @t) of
NestedBigMapsAbsent -> Dict
NestedBigMapsPresent -> error "impossible"
forbiddenBigMap
:: forall t a.
(SingI t, ForbidBigMap t)
=> (HasNoBigMap t => a)
-> a
forbiddenBigMap = withDict $ forbiddenBigMapEvi @t
forbiddenNestedBigMaps
:: forall t a.
(SingI t, ForbidNestedBigMaps t)
=> (HasNoNestedBigMaps t => a)
-> a
forbiddenNestedBigMaps = withDict $ forbiddenNestedBigMapsEvi @t
-- | Reify 'HasNoContract' contraint from 'ForbidContract'.
forbiddenContractTypeEvi
:: forall t. (SingI t, ForbidContract t) :- HasNoContract t
forbiddenContractTypeEvi = Sub $
case checkContractTypePresence (sing @t) of
ContractAbsent -> Dict
ContractPresent -> error "impossible"
-- | Reify 'HasNoContract' contraint from 'ForbidContract'.
forbiddenContractType
:: forall t a.
(SingI t, ForbidContract t)
=> (HasNoContract t => a)
-> a
forbiddenContractType = withDict $ forbiddenContractTypeEvi @t
-- | Whether the type contains 'TOperation', with proof.
data OpPresence (t :: T)
= ContainsOp t ~ 'True => OpPresent
| ContainsOp t ~ 'False => OpAbsent
data ContractPresence (t :: T)
= ContainsContract t ~ 'True => ContractPresent
| ContainsContract t ~ 'False => ContractAbsent
data BigMapPresence (t :: T)
= ContainsBigMap t ~ 'True => BigMapPresent
| ContainsBigMap t ~ 'False => BigMapAbsent
data NestedBigMapsPresence (t :: T)
= ContainsNestedBigMaps t ~ 'True => NestedBigMapsPresent
| ContainsNestedBigMaps t ~ 'False => NestedBigMapsAbsent
-- @rvem: IMO, generalization of OpPresence and BigMapPresence to
-- TPresence is not worth it, due to the fact that
-- it will require more boilerplate in checkTPresence implementation
-- than it is already done in checkOpPresence and checkBigMapPresence
-- | Check at runtime whether the given type contains 'TOperation'.
checkOpPresence :: Sing (ty :: T) -> OpPresence ty
checkOpPresence = \case
-- This is a sad amount of boilerplate, but at least
-- there is no chance to make a mistake in it.
-- We can't do in a simpler way while requiring only @Sing ty@ / @SingI ty@,
-- and a more complex constraint would be too unpleasant and confusing to
-- propagate everywhere.
STKey -> OpAbsent
STSignature -> OpAbsent
STChainId -> OpAbsent
STUnit -> OpAbsent
STOption t -> case checkOpPresence t of
OpPresent -> OpPresent
OpAbsent -> OpAbsent
STList t -> case checkOpPresence t of
OpPresent -> OpPresent
OpAbsent -> OpAbsent
STSet a -> case checkOpPresence a of
OpPresent -> OpPresent
OpAbsent -> OpAbsent
STOperation -> OpPresent
STContract t -> case checkOpPresence t of
OpPresent -> OpPresent
OpAbsent -> OpAbsent
STPair a b -> case (checkOpPresence a, checkOpPresence b) of
(OpPresent, _) -> OpPresent
(_, OpPresent) -> OpPresent
(OpAbsent, OpAbsent) -> OpAbsent
STOr a b -> case (checkOpPresence a, checkOpPresence b) of
(OpPresent, _) -> OpPresent
(_, OpPresent) -> OpPresent
(OpAbsent, OpAbsent) -> OpAbsent
STLambda _ _ -> OpAbsent
STMap k v -> case (checkOpPresence k, checkOpPresence v) of
(OpAbsent, OpAbsent) -> OpAbsent
(OpPresent, _) -> OpPresent
(_, OpPresent) -> OpPresent
STBigMap k v -> case (checkOpPresence k, checkOpPresence v) of
(OpAbsent, OpAbsent) -> OpAbsent
(OpPresent, _) -> OpPresent
(_, OpPresent) -> OpPresent
STInt -> OpAbsent
STNat -> OpAbsent
STString -> OpAbsent
STBytes -> OpAbsent
STMutez -> OpAbsent
STBool -> OpAbsent
STKeyHash -> OpAbsent
STTimestamp -> OpAbsent
STAddress -> OpAbsent
-- | Check at runtime whether the given type contains 'TContract'.
checkContractTypePresence :: Sing (ty :: T) -> ContractPresence ty
checkContractTypePresence = \case
STKey -> ContractAbsent
STSignature -> ContractAbsent
STChainId -> ContractAbsent
STUnit -> ContractAbsent
STOption t -> case checkContractTypePresence t of
ContractPresent -> ContractPresent
ContractAbsent -> ContractAbsent
STList t -> case checkContractTypePresence t of
ContractPresent -> ContractPresent
ContractAbsent -> ContractAbsent
STSet _ -> ContractAbsent
STOperation -> ContractAbsent
STContract _ -> ContractPresent
STPair a b -> case (checkContractTypePresence a, checkContractTypePresence b) of
(ContractPresent, _) -> ContractPresent
(_, ContractPresent) -> ContractPresent
(ContractAbsent, ContractAbsent) -> ContractAbsent
STOr a b -> case (checkContractTypePresence a, checkContractTypePresence b) of
(ContractPresent, _) -> ContractPresent
(_, ContractPresent) -> ContractPresent
(ContractAbsent, ContractAbsent) -> ContractAbsent
STLambda _ _ -> ContractAbsent
STMap _ v -> case checkContractTypePresence v of
ContractPresent -> ContractPresent
ContractAbsent -> ContractAbsent
STBigMap _ v -> case checkContractTypePresence v of
ContractPresent -> ContractPresent
ContractAbsent -> ContractAbsent
STInt -> ContractAbsent
STNat -> ContractAbsent
STString -> ContractAbsent
STBytes -> ContractAbsent
STMutez -> ContractAbsent
STBool -> ContractAbsent
STKeyHash -> ContractAbsent
STTimestamp -> ContractAbsent
STAddress -> ContractAbsent
-- | Check at runtime whether the given type contains 'TBigMap'.
checkBigMapPresence :: Sing (ty :: T) -> BigMapPresence ty
checkBigMapPresence = \case
-- More boilerplate to boilerplate god.
STKey -> BigMapAbsent
STSignature -> BigMapAbsent
STChainId -> BigMapAbsent
STUnit -> BigMapAbsent
STOption t -> case checkBigMapPresence t of
BigMapPresent -> BigMapPresent
BigMapAbsent -> BigMapAbsent
STList t -> case checkBigMapPresence t of
BigMapPresent -> BigMapPresent
BigMapAbsent -> BigMapAbsent
STSet _ -> BigMapAbsent
STOperation -> BigMapAbsent
STContract t -> case checkBigMapPresence t of
BigMapPresent -> BigMapPresent
BigMapAbsent -> BigMapAbsent
STPair a b -> case (checkBigMapPresence a, checkBigMapPresence b) of
(BigMapPresent, _) -> BigMapPresent
(_, BigMapPresent) -> BigMapPresent
(BigMapAbsent, BigMapAbsent) -> BigMapAbsent
STOr a b -> case (checkBigMapPresence a, checkBigMapPresence b) of
(BigMapPresent, _) -> BigMapPresent
(_, BigMapPresent) -> BigMapPresent
(BigMapAbsent, BigMapAbsent) -> BigMapAbsent
STLambda _ _ -> BigMapAbsent
STMap _ v -> case checkBigMapPresence v of
BigMapPresent -> BigMapPresent
BigMapAbsent -> BigMapAbsent
STBigMap _ _ ->
BigMapPresent
STInt -> BigMapAbsent
STNat -> BigMapAbsent
STString -> BigMapAbsent
STBytes -> BigMapAbsent
STMutez -> BigMapAbsent
STBool -> BigMapAbsent
STKeyHash -> BigMapAbsent
STTimestamp -> BigMapAbsent
STAddress -> BigMapAbsent
-- | Check at runtime whether the given type contains 'TBigMap'.
checkNestedBigMapsPresence :: Sing (ty :: T) -> NestedBigMapsPresence ty
checkNestedBigMapsPresence = \case
-- More boilerplate to boilerplate god.
STKey -> NestedBigMapsAbsent
STSignature -> NestedBigMapsAbsent
STChainId -> NestedBigMapsAbsent
STUnit -> NestedBigMapsAbsent
STOption t -> case checkNestedBigMapsPresence t of
NestedBigMapsPresent -> NestedBigMapsPresent
NestedBigMapsAbsent -> NestedBigMapsAbsent
STList t -> case checkNestedBigMapsPresence t of
NestedBigMapsPresent -> NestedBigMapsPresent
NestedBigMapsAbsent -> NestedBigMapsAbsent
STSet _ -> NestedBigMapsAbsent
STOperation -> NestedBigMapsAbsent
STContract t -> case checkNestedBigMapsPresence t of
NestedBigMapsPresent -> NestedBigMapsPresent
NestedBigMapsAbsent -> NestedBigMapsAbsent
STPair a b -> case (checkNestedBigMapsPresence a, checkNestedBigMapsPresence b) of
(NestedBigMapsPresent, _) -> NestedBigMapsPresent
(_, NestedBigMapsPresent) -> NestedBigMapsPresent
(NestedBigMapsAbsent, NestedBigMapsAbsent) -> NestedBigMapsAbsent
STOr a b -> case (checkNestedBigMapsPresence a, checkNestedBigMapsPresence b) of
(NestedBigMapsPresent, _) -> NestedBigMapsPresent
(_, NestedBigMapsPresent) -> NestedBigMapsPresent
(NestedBigMapsAbsent, NestedBigMapsAbsent) -> NestedBigMapsAbsent
STLambda _ _ -> NestedBigMapsAbsent
STMap _ v -> case checkNestedBigMapsPresence v of
NestedBigMapsPresent -> NestedBigMapsPresent
NestedBigMapsAbsent -> NestedBigMapsAbsent
STBigMap _ v -> case checkBigMapPresence v of
BigMapPresent -> NestedBigMapsPresent
BigMapAbsent -> NestedBigMapsAbsent
STInt -> NestedBigMapsAbsent
STNat -> NestedBigMapsAbsent
STString -> NestedBigMapsAbsent
STBytes -> NestedBigMapsAbsent
STMutez -> NestedBigMapsAbsent
STBool -> NestedBigMapsAbsent
STKeyHash -> NestedBigMapsAbsent
STTimestamp -> NestedBigMapsAbsent
STAddress -> NestedBigMapsAbsent
-- | Check at runtime that the given type does not contain 'TOperation'.
opAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoOp t)
opAbsense s = case checkOpPresence s of
OpPresent -> Nothing
OpAbsent -> Just Dict
-- | Check at runtime that the given type does not contain 'TContract'.
contractTypeAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoContract t)
contractTypeAbsense s = case checkContractTypePresence s of
ContractPresent -> Nothing
ContractAbsent -> Just Dict
-- | Check at runtime that the given type does not containt 'TBigMap'
bigMapAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoBigMap t)
bigMapAbsense s = case checkBigMapPresence s of
BigMapPresent -> Nothing
BigMapAbsent -> Just Dict
-- | Check at runtime that the given type does not contain nested 'TBigMap'
nestedBigMapsAbsense :: Sing (t :: T) -> Maybe (Dict $ HasNoNestedBigMaps t)
nestedBigMapsAbsense s = case checkNestedBigMapsPresence s of
NestedBigMapsPresent -> Nothing
NestedBigMapsAbsent -> Just Dict
----------------------------------------------------------------------------
-- Scopes
----------------------------------------------------------------------------
data BadTypeForScope
= BtNotComparable
| BtIsOperation
| BtHasBigMap
| BtHasNestedBigMap
| BtHasContract
deriving stock (Show, Eq, Generic)
deriving anyclass (NFData)
instance Buildable BadTypeForScope where
build = \case
BtNotComparable -> "is not comparable"
BtIsOperation -> "has 'operation' type"
BtHasBigMap -> "has 'big_map'"
BtHasNestedBigMap -> "has nested 'big_map'"
BtHasContract -> "has 'contract' type"
-- | Alias for constraints which Michelson applies to parameter.
type ParameterScope t =
(KnownT t, HasNoOp t, HasNoNestedBigMaps t)
-- | Alias for constraints which Michelson applies to contract storage.
type StorageScope t =
(KnownT t, HasNoOp t, HasNoNestedBigMaps t, HasNoContract t)
-- | Alias for constraints which Michelson applies to pushed constants.
type ConstantScope t =
(SingI t, HasNoOp t, HasNoBigMap t, HasNoContract t)
-- | Alias for constraints which Michelson applies to packed values.
type PackedValScope t =
(SingI t, HasNoOp t, HasNoBigMap t)
-- | Alias for constraints which Michelson applies to unpacked values.
--
-- It is different from 'PackedValScope', e.g. @contract@ type cannot appear
-- in a value we unpack to.
type UnpackedValScope t =
(PackedValScope t, ConstantScope t)
-- | Alias for constraints which are required for printing.
type PrintedValScope t = (SingI t, HasNoOp t)
----------------------------------------------------------------------------
-- Conveniences
----------------------------------------------------------------------------
-- | Should be present for common scopes.
class CheckScope (c :: Constraint) where
-- | Check that constraint hold for a given type.
checkScope :: Either BadTypeForScope (Dict c)
instance SingI t => CheckScope (HasNoOp t) where
checkScope = maybeToRight BtIsOperation $ opAbsense sing
instance SingI t => CheckScope (HasNoBigMap t) where
checkScope = maybeToRight BtHasBigMap $ bigMapAbsense sing
instance SingI t => CheckScope (HasNoNestedBigMaps t) where
checkScope = maybeToRight BtHasNestedBigMap $ nestedBigMapsAbsense sing
instance SingI t => CheckScope (HasNoContract t) where
checkScope = maybeToRight BtHasContract $ contractTypeAbsense sing
instance KnownT t => CheckScope (ParameterScope t) where
checkScope =
(\Dict Dict -> Dict)
<$> checkScope @(HasNoOp t)
<*> checkScope @(HasNoNestedBigMaps t)
instance KnownT t => CheckScope (StorageScope t) where
checkScope =
(\Dict Dict Dict -> Dict)
<$> checkScope @(HasNoOp t)
<*> checkScope @(HasNoNestedBigMaps t)
<*> checkScope @(HasNoContract t)
instance KnownT t => CheckScope (ConstantScope t) where
checkScope =
(\Dict Dict Dict -> Dict)
<$> checkScope @(HasNoOp t)
<*> checkScope @(HasNoBigMap t)
<*> checkScope @(HasNoContract t)
instance KnownT t => CheckScope (PackedValScope t) where
checkScope =
(\Dict Dict -> Dict)
<$> checkScope @(HasNoOp t)
<*> checkScope @(HasNoBigMap t)
instance KnownT t => CheckScope (UnpackedValScope t) where
checkScope =
(\Dict Dict -> Dict)
<$> checkScope @(PackedValScope t)
<*> checkScope @(ConstantScope t)
-- Versions for eDSL
----------------------------------------------------------------------------
{- These constraints are supposed to be used only in eDSL code and eDSL should
define its own wrapers over it.
-}
type ProperParameterBetterErrors t =
(KnownT t, ForbidOp t, ForbidNestedBigMaps t)
type ProperStorageBetterErrors t =
(KnownT t, ForbidOp t, ForbidNestedBigMaps t, ForbidContract t)
type ProperConstantBetterErrors t =
(SingI t, ForbidOp t, ForbidBigMap t, ForbidContract t)
type ProperPackedValBetterErrors t =
(SingI t, ForbidOp t, ForbidBigMap t)
type ProperUnpackedValBetterErrors t =
(ProperPackedValBetterErrors t, ProperConstantBetterErrors t)
type ProperPrintedValBetterErrors t =
(SingI t, ForbidOp t)
properParameterEvi :: forall t. ProperParameterBetterErrors t :- ParameterScope t
properParameterEvi = Sub $
Dict \\ forbiddenOpEvi @t \\ forbiddenNestedBigMapsEvi @t
properStorageEvi :: forall t. ProperStorageBetterErrors t :- StorageScope t
properStorageEvi = Sub $
Dict \\ forbiddenOpEvi @t
\\ forbiddenContractTypeEvi @t
\\ forbiddenNestedBigMapsEvi @t
\\ forbiddenContractTypeEvi @t
properConstantEvi :: forall t. ProperConstantBetterErrors t :- ConstantScope t
properConstantEvi = Sub $
Dict \\ forbiddenOpEvi @t
\\ forbiddenBigMapEvi @t
\\ forbiddenContractTypeEvi @t
properPackedValEvi :: forall t. ProperPackedValBetterErrors t :- PackedValScope t
properPackedValEvi = Sub $
Dict \\ forbiddenOpEvi @t
\\ forbiddenBigMapEvi @t
properUnpackedValEvi :: forall t. ProperUnpackedValBetterErrors t :- UnpackedValScope t
properUnpackedValEvi = properPackedValEvi @t C.*** properConstantEvi @t
properPrintedValEvi :: forall t. ProperPrintedValBetterErrors t :- PrintedValScope t
properPrintedValEvi = Sub $
Dict \\ forbiddenOpEvi @t